FREERTOS第六课-链表 环形缓冲区 队列 结构体 static 链表链表和数组的区别链表Linked List 是一种非连续的线性数据结构和数组最大区别数组数据存在连续一块内存靠下标访问链表数据分散存放在不同内存块每一块叫节点Node。每个节点由两部分组成数据域存你要保存的值指针域后继指针存下一个节点的内存地址把所有节点串成一条链链表没有下标只能从头节点顺着指针一个个往后找。数组和链表的优点和缺点数组的内存分布是连续存储如果分给数组的内存没有使用其他的数据无法占用资源浪费但是对于随机读取元素较为方便比如一个数组只有五个元素那我要读取第五个元素直接可以得到他的地址进行读取对于链表来说他的内存分布是不连续的比较灵活但是随机获取时需要从头开始读取即跳跃读取链表效率很低一句话总结链表适合插入和删除数组适合随机访问队列数据传输方法目前主要是以下几种1.全局变量比如一个任务进行全局变量的自加另一个任务对这个全局变量进行LCD显示2.环形缓冲区本质是一块固定大小的数组配合两个标记指针读指针 read、写指针 write逻辑上把数组首尾相连形成一个圆环先进先出 FIFO常用于高速数据收发、音视频、串口、线程通信解决生产消费速率不匹配问题用来做高速数据缓存。普通数组单纯一块连续内存只是存数据没有读写规则环形缓冲区是「数组 读 / 写索引 一套 FIFO 读写逻辑」数组只是它的存储载体。底层本质是静态数组内存连续和链表相反判空read write判满两种常用方案方案 1空一格不用最常用简单无冲突(write 1) % size read环形缓冲区和数组的区别普通数组直接通过下标随机读写 arr[0]、arr[5]没有 “先进先出” 限制想改哪个位置改哪个满了不会自动绕回开头。环形缓冲区不能随便指定下标读写只能调用 rb_write()、rb_read()严格 FIFO先写的数据必须先读读写到数组末尾时通过 %长度 自动回到数组头部形成 “环”有专门函数判断空、判断满。**队列**数据的读写本质就是环形缓冲区在这个基础上增加了互斥措施、阻塞-唤醒机制。如果这个队列不传输数据只调整“数据个数”它就是信号量。如果信号量中限定“数据个数”最大值为1它就是互斥量。环形缓冲区和RTOS队列的关系环形缓冲区 ≠ RTOS 队列环形缓冲区是裸机纯数据缓存没有操作系统同步能力表格里的 “队列” 特指 RTOS 内核提供的消息队列是带任务调度能力的高级组件。RTOS 系统队列支持阻塞等待读队列为空读取任务自动休眠阻塞有新数据写入时内核唤醒该任务队列存满写入任务自动休眠有数据读出释放空位后唤醒写入任务大幅降低 CPU 占用是实时操作系统任务通信核心功能。全局变量 / 裸机环形缓冲只是纯内存存储RTOS 队列是带多任务同步、任务休眠调度的通信工具。使用队列的流程1.创建队列2.写队列3.读队列对红外遥控器游戏代码的改进点1.对于红外遥控器控制游戏的操作/* 读取红外遥控器 */if(0IRReceiver_Read(dev,data))对于这一步逻辑判断他实际上是一个环形缓冲区只要这个接收器一直没有接受到信息那么一直处于循环检测非常损耗CPU资源intIRReceiver_Read(uint8_t*pDev,uint8_t*pData){if(isKeysBufEmpty())return-1;*pDevGetKeyFromBuf();*pDataGetKeyFromBuf();return0;}因此采用队列进行优化。主要是两个部分进行改造1.原来的环形缓冲区是由红外中断进行写然后通过IRReceiver_Read读信息现在进行修改的就两点1.由红外中断进行写队列2.然后在逻辑判断这里IRReceiver_Read改成读队列,优化的地方就是通过将环形缓冲区换为队列可进行任务阻塞提高CPU效率C语言中定义结构体的方法1.结构体struct把多个不同类型变量打包成一个整体。structstudent{intid;charname[20];floatscore;};2.typedef 简化工程最常用typedef 给类型起别名不用每次写 struct示例一typedefstructNode{intvalue;Node*next;}Node;//定义链表节点示例二typedefstructQueue{Node*front;Node*rear;}Queue;问题 1static 关键字作用分两种场景讲清楚场景 1函数内部局部变量你代码里 static uint64_t pre_time 0;存储位置改变普通局部变量存在栈函数执行完自动销毁static 局部变量存放在全局静态存储区程序整个运行周期都存在。初始化只执行 1 次pre_time 0 只会在第一次调用函数时赋值后续再次进入函数不会重新置 0保留上一次调用结束后的值。作用域依旧仅限当前函数外面其他函数不能访问 pre_time只有 IRReceiver_IRQ_Callback 内部能用。结合你红外代码举例第一次中断pre_time 0第二次中断不会重新赋值 0pre_time 保存上一次中断的时间戳用来计算间隔判断超时。场景 2修饰函数 static void PutKeyToBuf(…)该函数仅当前 .c 文件内可见其他源文件无法调用这个函数起到封装、隔离作用不影响函数内部逻辑只是限制访问范围。