视频链接
初识数据结构,十天搞定嵌入式数据结构_哔哩哔哩_bilibili
课程目的
学会嵌入式经常使用的数据结构
具备基础知识
具有C语言基础(结构体、指针、内存(malloc))
具有数据结构的基础知识,因此提及到的基础知识比较少
嵌入式数据结构的实现基本上基于结构体 ,在FreeRTOS的源码中体现的很清楚,基本上都是结构体,或者为了描述一个东西(数据)的属性时(数据元素--数据的基本单位)你需要使用结构体,比如学生的成绩、排名、姓名等
学习方法
以分析FreeRTOS中内部存在的数据结构来学习嵌入式数据结构,数据结构在操作系统中体现的淋漓尽致,因此当你分析完FreeRTOS中数据结构的算法后,你就具备了嵌入式数据结构的基础。嵌入式的数据结构内容不是特别的多,因为有些数据结构很少使用到
代码量决定你的能力提升范围
数据结构的作用
让数据的处理更加高效、灵活,使用起来更方便,为了满足更多的情况
数据的逻辑结构
线性、层次、网状,其实就是分线性和非线性结构(按照前趋数和后继数分类的),我们常见的并且使用最多的是线性结构(线性表、栈、队列)
数据的存储结构
如何把数据存储在内存(把内存想象成一个房子的房间)中,连续存储(数组-房间号连续)、非连续数组(链表--房间号不连续---用地址/指针建立连接)
数据结构意义
1:提高编程能力
2:提高程序的复用性、维护性、可读性
3:程序 = 数据结构 + 算法
什么是数据结构
数据结构 = 数据 + 结构(逻辑和存储)
数据和数据元素
比如下面的属性就是数据元素,为了描述数据
顺序存储
缺点:插入和删除不方便
优点:查找方便
根据处理的问题进行选择性的使用存储方式
上图亮点在typedef int data_t中,因为我们的数据类型可以改变
last表示数组长度
顺序存储的使用
1:代码分层处理,把顺序存储分成.c和.h文件,如果别人需要使用我们的写的文件,我们给的是.h和.so文件(动态库)(由.c编译的二进制文件,防止别人知道源码实现,这个操作很常见,比如你不知道printf的源码时如何实现的,你只能打开stdio.h而不存在stdio.c)
2:在写代码的时候,要有代码架构思想,为了提高我们的代码复用性,可以很方便的给别人使用或者换一个场景也能很快使用
在C语言中,一般使用数组(结构体数组)表示顺序存储。因此我们使用结构体数组来点亮我们想要的LED灯---需要借助FreeRTOS的动态内存分配
typedef struct Class LED_t ;
#define N 5 //表示能装多少个LED灯
struct Class
{
uint8_t Num;
uint32_t RCC_CLOCK;
GPIO_TypeDef * GPIOX;
uint16_t GPIO_Pin;
GPIOMode_TypeDef GPIO_Mode;
GPIOSpeed_TypeDef GPIO_Speed;
BitAction BitVal; //赋值电平
const char *str;
};
typedef struct
{
LED_t LED_Data[N];
uint16_t len;
}sqlsitLED, *sqlinkLED;
顺序数组的操作
/*
* 创建顺序表
*/
sqlinkLED List_Create()
{
sqlinkLED class;
class = (sqlinkLED)pvPortMalloc(sizeof(sqlsitLED));
if( class == NULL )
{
printf("List_Create is fail\r\n");
return NULL;
}
else
{
printf("List_Create is sucess\r\n");
memset(class->LED_Data , 0 , sizeof(LED_t)*N);
class->len = 0;
return class;
}
}
/*
* 清空顺序表 0--失败 1--成功
*/
uint8_t Clear_List( sqlinkLED class )
{
if( class == NULL )
return 0;
memset(class->LED_Data , 0 , sizeof(LED_t)*N);
class->len = 0;
return 1;
}
/*
* 判断顺序表是否为空 1--空 0--不为空
*/
uint8_t List_empty( sqlinkLED class )
{
if(class->len == 0)
return 1;
return 0;
}
/*
* 判断顺序表的长度
*/
uint8_t List_length( sqlinkLED class )
{
if(class != NULL )
{
return class->len;
}
}
创建LED灯顺序表
sqlinkLED LED;
LED = List_Create();
if(LED == NULL )
{
printf("create list is fail\r\n");
}
else
{
printf("create list is sucess\r\n");
}
LED灯顺序表赋值
功能行驶函数
void Give_ListValue( sqlinkLED class,uint8_t index )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(class->LED_Data[index].RCC_CLOCK, ENABLE);
GPIO_InitStructure.GPIO_Pin = class->LED_Data[index].GPIO_Pin;
GPIO_InitStructure.GPIO_Mode = class->LED_Data[index].GPIO_Mode ;
GPIO_InitStructure.GPIO_Speed = class->LED_Data[index].GPIO_Speed;
GPIO_Init( class->LED_Data[index].GPIOX, &GPIO_InitStructure);
GPIO_WriteBit(class->LED_Data[index].GPIOX, class->LED_Data[index].GPIO_Pin, class->LED_Data[index].BitVal);
printf("%s\r\n",class->LED_Data[index].str);
}
LED->LED_Data[1].GPIOX = GPIOD;
LED->LED_Data[1].BitVal = 0;
LED->LED_Data[1].GPIO_Pin = GPIO_Pin_2;
LED->LED_Data[1].GPIO_Mode = GPIO_Mode_Out_PP;
LED->LED_Data[1].GPIO_Speed = GPIO_Speed_50MHz;
LED->LED_Data[1].Num = 1;
LED->LED_Data[1].str = "LED1";
LED->LED_Data[1].RCC_CLOCK = RCC_APB2Periph_GPIOD;
LED->len = 2;
点亮LED
改变LED->LED_Data[1].BitVal 的值即可熄灭和点亮LED
Give_ListValue(LED, 1);
为其他数组赋值
LED->LED_Data[0] = LED->LED_Data[1];
printf("S%s\r\n",LED->LED_Data[1].str);
清零数组
memset(&(LED->LED_Data[1]) , 0 , sizeof(LED_t));
插入led数组
/*
* 插入一个LED_t类型的变量插入在数组中去,你需要考虑数组是否满了-插入位置是否合法---插入形式
* pos是位置从1开始
*/
uint8_t List_Insert( sqlinkLED class, LED_t led, uint8_t pos )
{
uint8_t i;
//先判断有没有位置
if(class->len == N)
return 1; //表示满了
//判断pos的值是否符合
if(N < pos ) //不符合,没有这个数组下标
return 1;
//判断pos的值是否是最后一个
if(N == pos)
{
class->LED_Data[pos-1] = led;
class->len++;
return 0;
}
//移动,空出pos的位置
for( i=class->len-1;i>=pos;i--)
class->LED_Data[i] = class->LED_Data[i-1] ;
class->len++;
return 0;
}