- 博客(55)
- 收藏
- 关注
原创 【一文吃透】常见通信协议(SPI、IIC、UART、CAN)[面试重点]
主机输入,从机输出(数据来自从机);主机输出,从机输入(数据来自主机);SCLK串行时钟信号,由主机产生发送给从机;SS片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。其他制造商可能会遵循其他命名规则,但是最终他们指的相同的含义。以下是一些常用术语;MISO也可以是SIMO,DOUT,DO,SDO或SO(在主机端);MOSI也可以是SOMI,DIN,DI,SDI或SI(在主机端);NSS也可以是CE,CS或SSEL;SCLK也可以是SCK;
2023-09-27 00:07:25
50189
7
原创 【一文吃透】FreeRTOS之优先级反转
优先级反转指高优先级任务因等待低优先级任务持有的资源,被中优先级任务阻塞的现象。典型场景:低优先级任务L持有资源后,高优先级任务H因资源不可用被阻塞,中优先级任务M趁机长期占用CPU,导致H的实时性受损。解决方法包括优先级继承(使用Mutex):当H等待时,内核临时将L的优先级提升至与H相同,使其快速释放资源,避免M抢占。但该机制无法解决死锁或多层嵌套问题。
2026-03-22 10:58:38
314
原创 FreeRTOS中为什么同优先级的任务后创建的先执行
本文深入解析FreeRTOS Kernel V10.0.1首次启动任务调度机制。关键发现:首次启动时,调度器直接从pxCurrentTCB恢复任务而非从ReadyList选取,且pxCurrentTCB在任务创建过程中会被更新为最后创建的同优先级任务。因此首次运行的是最后创建的任务,之后才进入基于ReadyList的轮转调度。文章详细追踪了从vTaskStartScheduler()到vPortStartFirstTask()的执行流程,对比了首次启动与后续调度的差异,并通过示例说明了任务执行顺序的形成机制
2026-03-21 23:24:15
303
原创 FreeRTOS中将队列(或信号量)加入队列集时,该队列必须是空的。
FreeRTOS队列集使用需严格遵守三条规定:1)加入队列集前必须确保队列为空,否则会导致历史数据隐身或死锁;2)加入后必须通过xQueueSelectFromSet()获取队列句柄再读取,不能直接xQueueReceive();3)每次Select后只能Receive一次。写入操作不受影响,但读取流程必须改为先Select再Receive。违反这些规则将导致任务无法唤醒或消息丢失,属于未定义行为。建议在系统初始化阶段将空队列加入队列集,避免运行时动态添加。
2026-03-20 13:18:19
349
原创 FreeRTOS中创建任务的顺序是否会影响任务运行的顺序?【面试重点】
FreeRTOS采用抢占式调度机制,任务执行顺序仅由优先级决定:高优先级任务始终优先运行。同优先级任务遵循"后创建先运行"原则,新任务会立即抢占CPU。调度器启动前创建的任务则按创建顺序执行。实际开发中不应依赖任务创建顺序控制流程,而应通过设置不同优先级或使用队列/信号量等同步机制。
2026-03-20 11:30:03
176
原创 环形缓冲区(循环队列)的实现和空/满的判断条件【面试重点】
环形缓冲区是嵌入式开发中处理数据缓存的关键数据结构,通过数组模拟环形结构,使用读写指针实现高效数据存取。工业标准方案采用牺牲一个存储单元的方法,通过(rear+1)%size==front判断队满,解决空满状态混淆问题。相比计数法,该方案在多任务环境下更稳定可靠,无需额外保护机制。文中提供了可直接复用的标准实现代码,包括初始化、读写操作和空满判断函数,特别适合STM32串口、CAN等外设的数据缓存场景,具有无内存碎片、线程安全等优势,是嵌入式开发的必备解决方案。
2026-03-18 12:48:27
412
原创 FreeRTOS中 vTaskDelay 与 vTaskDelayUntil 对比
vTaskDelay 与 vTaskDelayUntil 对比
2026-03-18 09:57:48
351
原创 FreeRTOS中heap.c的选择问题
在 CubeMX 里选择后,软件会heap_4.cheap.c加入你的工程。和 C 语言标准库的无关,是 FreeRTOS 为嵌入式单片机的内存管理。
2026-03-17 10:49:35
349
原创 【一文吃透】FreeRTOS之事件标志组
● 每一位事件的含义,由用户自己决定,如:bit0表示按键是否按下,bit1表示是否接受到消息 …用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。------------------------摘自正点原子FreeRTOS相关课程课件,方便大家学习。● 当把队列中的消息通过网络发送输出以后就可以将某个位。,当队列中没有消息需要处理的时候就可以将这个位(● 现在需要向网络中发送一个心跳信息,将某个位。事件标志组中的所有事件位都存储在一个无符号的。● 它的每一个位表示一个事件(高8位不算)
2025-02-06 16:32:03
656
原创 [一文吃透] STM32实现ADC转换并使用DMA传输
在上面的示例中,首先配置了DMA传输的参数,然后调用HAL_DMA_Start()函数启动DMA传输,传输长度为1024字节,源地址为0x20001000,目的地址为0x20002000。在DMA传输完成后,会触发DMA传输完成中断,并调用用户在HAL_DMA_IRQHandler函数中定义的回调函数,用户可以在回调函数中处理传输完成后的操作。HAL_DMA_Start_IT函数是HAL库中DMA传输中断模式启动函数之一,其主要作用是启动DMA传输并使能DMA传输完成中断。
2024-09-06 16:05:57
1536
原创 [一文吃透]CAN通信之波特率相关配置
由于公式中涉及到CAN的时钟,所以我们首先需要了解CAN挂载在哪条总线下,并且该总线的时钟频率是多少。此处采用STM32F103进行举例,从下图中的用户手册中的系统架构可知,基本扩展CAN总线bxCAN挂载在APB1总线,从下下图中的用户手册中的时钟树可知APB1总线的时钟频率为36MHz。以下面的STM32F103的代码为例,其CAN时钟频率为APB1=36MHz,BRP分频器设置为CAN_Prescaler=4,tBS1=CAN_BS1=BS1_5tq,tBS2=CAN_BS2=BS2_3tq。
2024-08-27 17:47:07
2820
原创 一文吃透CAN通信
近年来,它具有的高可靠性 和良好的错误检测能力受到重视,被广泛应用于汽车计算机控制系统和环境温度恶劣、电磁辐射强及振动大的工业环境。和嵌入式工业控制局域网的标准总线,并且拥有以 CAN 为底层协议专为大型货车和重工机械车辆设计的。的简称,它是由研发和生产汽车电子产品著称。两条信号线,共同构成一组差分信号线,以。通讯并不是以时钟信号来进行同步的,等具有时钟信号的同步通讯方式不同,),是国际上应用最广泛的现场总。开发的,并最终成为国际标准(它是一种异步通讯,只具有。差分信号的形式进行通讯。
2024-08-27 17:10:14
414
原创 static和const的作用
值得注意的是虽然局部变量的声明周期得到了很大的提升,但他的作用域没有发生任何的改变,还是只能在那个局部的范围内使用。1.可以用来修饰变量,修饰函数参数,修饰函数返回值,且被const修饰的东西,都受到强制保护,可以预防其它代码无意识的进行修改,从而提高了程序的健壮性(是指系统对于规范要求以外的输入能够判断这个输入不符合规范要求,并能有合理的处理方式。4.编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
2023-11-10 10:22:40
476
原创 牧原二面(技术面)【C语言问题偏多】
牧原共三面,二面为技术面,应聘的岗位为屠宰事业部嵌入式软件方向,主要问到项目经历和C语言基础知识偏多。
2023-10-17 16:20:14
2548
8
原创 一道快速排序结合二分法查找的算法题(综合易考)
在校招笔试时曾看见一道题目比较综合的关于排序的编程题,从动态分配数组到使用快速排序对数组进行排序再到使用二分法查找给定数字,到最后释放数组内存。感觉全方面考察了创建数组、排序、查找的相关知识点,遂记录下来。
2023-10-15 11:56:32
181
原创 计算机网络体系
开放式系统互联(Open System Interconnect)OIS体系结构是一个理想化7层协议。从上到下分别为7应用层、6表示层、5会话层、4运输层、3网络层、2数据链路层、1物理层。OSI实现复杂运行效率低,最终市场没用采用它。
2023-09-25 11:34:39
136
原创 数据结构之——常见排序算法(面试重点)
走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。例如升序排序:首位1号数据与2号数据比较,若1号数据比2号数据大则调换两数据位置,否则位置不变。再比较2号数据与3号数据的大小,若2号数据比3号数据大则调换两数据位置,否则位置不变。这个算法的名字由来是因为越小(大)的元素会经由交换慢慢“浮”到数列的顶端。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
2023-09-22 01:24:11
251
原创 FreeRTOS中的队列特点
如果使用全局变量,兔子(任务 1 )修改了变量 a ,等待树獭(任务 3 )处理,但树獭处理速度很慢,在处理数据的过程中,狐狸(任务 2 )有可能又修改了变量 a ,导致树獭有可能得到的不是正确的数据。队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息。队列中可以存储有限的、大小固定的数据项目。采用实际值传递,即将数据拷贝到队列中进行传递,也可以传递指针,在传递较大的数据的时候。数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。
2023-09-19 11:49:59
214
1
原创 场效应管和MOS管的区别
当金属电极施加电压时,可以改变绝缘层内的电场分布,从而改变半导体通道内的电荷密度,最终影响到通道内的电流大小。NMOS的半导体通道为N型半导体,绝缘层为氧化物,金属电极为N型半导体的源极和漏极,当金属电极施加正电压时,绝缘层内的电场会吸引N型半导体通道内的电子向漏极方向移动,形成电流;PMOS的半导体通道为P型半导体,绝缘层为氧化物,金属电极为P型半导体的源极和漏极,当金属电极施加负电压时,绝缘层内的电场会吸引P型半导体通道内的空穴向漏极方向移动,形成电流。1.场效应管的主要部分由通道、源极和漏极组成。
2023-09-19 10:46:21
8218
原创 字节对齐(内存对齐)
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,计算机并非逐个字节读取,而是以2、4、8的倍数字节块读取内存,它们会要求这些数据的首地址的值是某个数是k(通常是4或8)的倍数 ,这就是所谓的内存对齐。3、减少 cpu 访问数据的出错性(有些 cpu 必须内存对齐,否则指针访问会出错),不同硬件平台进行数据通信,数据对齐可能会不一致,需要加入伪指令进行操作,防止灾难性性bug。为什么需要字节对齐?
2023-09-18 21:14:14
317
原创 静态变量和全局变量区别
(4)静态全局变量也具有全局作用域,他与全局变量的区别在于如果程序包含多个文件的话,他作用于定义它的文件里,不能作用到其他文件里,即被static关键字修饰过的变量具有文件作用域。它只被初始化一次,自从第一次初始化直到程序与你新内阁结束都一直存在,他和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。(3)局部变量也只有局部作用域,他是自动对象,他在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用结束后,变量就被撤销,其所占用的内存也被收回。
2023-09-16 16:29:11
513
原创 原、反、补码
1-1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [0000 0001]补+ [1111 1111]补= [1 0000 0000]补=[0000 0000]补=[0000 0000]原注意:进位1不在计算机字长里。1 - 1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [0000 0001]反+ [1111 1110]反= [1111 1111]反= [1000 0000]原= -0。计算十进制的表达式: 1 - 1 = 0。
2023-09-12 10:02:46
418
1
原创 一文吃透IIC通信协议
5、当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设置成接收模式开始读取数据;2、然后发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/W),“0”表示主机向从机发送数据(写),“1”表示主机从从机接收数据(读);6、这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号(
2023-09-12 09:42:02
1659
2
原创 堆与栈的区别
堆则是C函数库提供的,它的机制很复杂,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大的空间,如果没有足够大的空间(可能是由于内存碎片太多),就有需要操作系统来重新整理内存空间,这样就有机会分到足够大小的内存,然后返回。栈的分配和释放是由编译器完成的,栈的动态分配由alloca()函数完成,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行申请和释放的,无需手工实现。栈的增长方向是向下的,即向着内存地址减小的方向。(1)管理方式不同。
2023-09-02 10:21:32
304
原创 C语言中内存分配的几种方式
由编译器自动分配和释放,在程序编译的时候就已经分配好内存,这块内存在程序的整个运行期间都存在,直到整个程序运行结束时才被释放,如全局变量与静态变量。从栈上分配,其作用域只是在局部函数内,在定义该变量的函数内,只要出了该函数,该局部变量就不再起作用,也即该变量的生命周期和该函数同在。同样由编译器自动分配和释放,在函数执行时,函数内部的局部变量都可以在栈上创建,函数执行结束时,这些存储单元将被自动释放。(需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。
2023-09-02 09:51:45
828
原创 [超详细]内存分区相关知识,面试重点
静态变量是在程序运行期间始终存在的变量,其内存空间在程序开始时就被分配好了,直到程序结束时才被释放。已初始化且不为零的全局变量是指在定义时已经赋值的全局变量,而不是在程序运行时才赋值的变量。堆空间是向上增长的,也就是说,堆顶的地址是越来越大的。因此,常量段的数据是只读的,不能在程序运行期间修改它们的值。栈空间是由操作系统自动分配和回收的,它的大小通常是固定的,不能随意增加。栈空间是向下增长的,也就是说,栈顶的地址是越来越小的。需要注意的是即使是初始化了,但初始化的是0,还是放在BSS区!
2023-08-04 17:22:29
684
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅