嵌入式八股
一、关键字1、volatile防止编译器对变量进行优化。什么是编译器优化适用场景1、并行设备的硬件寄存器2、一个中断服务程序中修改的供其他程序检测的变量3、多线程应用中被几个任务共享的变量。2、static作用声明为静态类型变量分为静态全局变量和静态局部变量静态变量如果没有被初始化 则自动初始化为0。为什么只初始化一次其初始化后一直没有被销毁保存再内存区域中所以不会再次初始化。static修饰的全局变量只能在本文件被调用修饰的函数也只能在本文件调用。3、const定义变量为常量修饰指针常量指针const int *p;int const *p;指针常量(int* const p)指向常量的常指针(const int*const p)修饰参数不能改这个参数值修饰返回值。4、typedef 和 define原理不同#define是预处理指令typedef是关键字具有类型检查的功能。功能不同typedef用来定义类型的别名#define还可以定义常量、变量、编译开关等。作用域不同#define无限制对指针的操作不同5、malloc和new的区别他们动态申请的内存都位于堆中无法被操作系统回收需要对应的free/delete来释放空间。delete会调用析构函数释放指针成员变量的空间再销毁对象本身的空间而free只释放了对象本身的空间而指针成员所指向的空间没有被释放malloc 特点函数需要指定大小手动计算返回void指针需要类型转化不调用构造函数。需要库文件stdlib.hnew 特点运算符自动计算大小返回具体类型指针自动调用构造函数可进行数组初始化。可重载自定义内存分配。6、inline用来声明内联函数编译时将函数调用替换位函数体减少开销提高效率7、 extern”C”extern C的主要作用就是为了能够正确实现C代码调用其他C语言代码。加上extern C后会指示编译器这部分代码按C语言的进行编译而不是C的。8、 C语言宏中#和###可以把一个宏参数直接转换成相应的字符串 #define con(a) #a##将宏定义的多个形参转换成一个实际参数名。#define con(a,b) a##b9、 strlen(\0) sizeof(\0)?strlen(\0) 0sizeof(\0)2。strlen 从内存的某个位置开始扫描到碰到第一个\0为止a、定义常量谁更好# define还是 constdefine只是单纯的文本替换止于编译器只是一个常数const在堆栈中分配了空间可以被调用、传递。const常量有数据类型而define常量没有数据类型。编译器可以对const常量进行类型安全检査。很多IDE支持调试 const定义的常量。b、全局变量和局部变量的区别是什么?作用域程序块/当前函数内存存储方式全局数据区/栈区生命周期随主程序创建销毁/局部函数内部使用方式程序的各个部分都可以用到/在局部使用c、全局变量可不可以定义在可被多个.C文件包含的头文件中为什么可以在不同的C文件中以static形式来声明同名全局变量。只能有一个初始化d、局部变量能否和全局变量重名能局部会屏蔽全局。e、struct结构体 和 union联合体的区别union所有成员共用一块地址空间不同时存在对联合体的不同成员赋值将会对其他成员重写struct成员占空间是累加的同时存在不同成员赋值是互不影响的假设为32位机器int型占4个字节 double型占8个字节char型占1个字节而DATE是一个联合型变 量联合型变量共用空间uion里面最大的变量类型是int[5]所以占用20个字节它的大小是20而 由于 union中 double占了8个字节因此 union是要8个字节对齐所占内存空间为8的倍数。为了实现 8个字节对齐所占空间为24.而data是一个结构体变量每个变量分开占用空间依次为 sizeofint sizeofDATE sizeof double424836按照8字节对齐占用空间为40所以结果为 402464。二、数组1、数组指针指向数组的指针它表示的是一个指针这个指针指向的是一个数组int b[12]{1,2,3,4,5,6,7,8,9,10,11,12};int (*p)[4];pb;这里**(p)0为5p相当于把p所指向的地址向后移动4个int所占用的空间。2、指针数组指针数组表示的是一个数组而数组中的元素是指针。int *p[4]数组下标可以为负数。三、指针1、函数指针函数的地址是函数存储空间的首地址用函数名表示这个地址可以定义一个指针变量来存放这个叫函数指针 int (*p)(int, int)。指向函数的指针变量没有 和 --运算。2、指针函数返回值是一个地址的函数。函数返回值必须用同类型的指针变量来接受。Int *p(int, int)。a、数组和指针的区别与联系是什么存储方式数值存在静态存储区或栈连续根据下标访问指针指向任意类型的内存块。sizeof数组内存sizeof数组名数组大小sizeof数组名/sizeof数据类型指针sizeof指针名根据32位/64位平台来数据访问方面指针对数据的访问方式是间接访问数组对数据的访问则是直接访问。使用环境指针多用于动态数据结构如链表等等和动态内存开辟。 数组多用于存储固定个 数且类型统一的数据结构如线性表等等和隐式分配。b、指针和引用的异同是什么如何相互转换C相同都是地址的概念指针指向某一内存、内容是所指内存的地址引用则是某块内存的别名。两者都占内存程序为指针会分配内存区别1. 指针是实体而引用是别名。2. 指针和引用的自增运算符意义不同指针是对内存地址自增引用是对值的自增。3. 引用使用时无需解引用(*)指针需要解引用4. 引用只能在定义时被初始化一次之后不可变指针可变。5. 引用不能为空指针可以为空。6. “sizeof 引用”得到的是所指向的变量(对象)的大小而“sizeof 指针”得到的是指针本身的大小在32 位系统指针变量一般占用4字节内存。转换1. 指针转引用把指针用*就可以转换成对象可以用在引用参数当中。2. 引用转指针把引用类型的对象用取地址就获得指针了。c、野指针是什么1 野指针是指向不可用内存的指针当指针被创建时指针不可能自动指向NULL这时默认值是随机的此时的指针成为野指针。2 当指针被free或delete释放掉时如果没有把指针设置为NULL则会产生野指针因为释放掉的仅仅是指针指向的内存并没有把指针本身释放掉。3 第三个造成野指针的原因是指针操作超越了变量的作用范围。d、C中的智能指针是什么智能指针是一个类用来存储指针指向动态分配对象的指针。其如何解决内存泄漏引入了弱指针 weak_ptr weak_ptr 的构造函数不会修改引用计数的值从而不会对对象的内存进行管理但是可以检测到所管理的对象是否已经被释放从而避免非法访问。e、this指针是什么?this指针本质上其实是一个成员函数的形参是对象调用成员函数时将对象地址作为实参传递给this形参。所以对象中不存储this指针f、数组名和指针的区别数组名表示整个数组的起始地址编译时分配连续空间指针可变的地址变量运行时可动态分配四、内存a、C语言中内存分配的方式有几种静态存储区分配程序编译前栈上分配函数执行时堆上分配 New开辟的空间在堆上b、堆与栈有什么区别申请方式栈的空间由操作系统自动分配/释放堆上的空间手动分配/释放。申请大小的限制栈空间有限栈是向低地址扩展的数据结构是一块连续的内存的区域最大容量已规定。堆是向高地址扩展的数据结构是不连续的内存区域。申请效率栈由系统自动分配速度较快。但程序员是无法控制的。 堆是由new分配的内存一般速度比较慢而且容易产生内存碎片,不过用起来最方便。c、队列和栈的区别原理 后进先出 先进先出访问元素 栈顶元素 队首元素实现方式 可用数组和列表内存利用 更高效 较低效应用场景 函数调用 任务调度表达式求值 消息缓冲d、栈在c语言中有什么作用C语言中栈用来存储临时变量;多线程编程的基础是栈用来存储本线程运行时各个函数的临时变量 和 维系函数调用和函数返回时的函数调用关系和函数运行场景。栈的范围是由 ss * 10H 至 ss * 10H spss指堆栈寄存器存放堆栈段起始地址的高16位sp指堆栈指针e、C语言函数参数压栈顺序是怎样的从右至左主要原因是为了支持可变长参数形式。f、C的内存管理是怎么样的代码段只读存储区cangl和文本区机械代码数据段BSS段堆区调用new/malloc函数时在堆区自动分配内存映射区存储动态链接库以及调用mmap函数进行的文件映射栈使用栈空间存储函数的返回地址、参数、局部变量、返回值g、什么是内存泄漏申请的内存未被释放导致内存减少。h、什么是内存对齐cpu访问内存是按照特定字节大小进行访问提高存储效率可能炸藕才能空间浪费五、预处理a、预处理器标识#error的目的是什么编译程序时遇到#error生成一个编译错误提示消息并停止编译。b、 # include filename. h和#include filename. h有什么区别编译器先从标准库路径开始搜索filename.h使得系统文件调用较快。 “编译器先从用户的工作路径开始搜索filename.h然后去寻找系统路径使得自定义文件较快。c、头文件的作用通过头文件来调用库加强类型安全检查。d、在头文件中定义静态变量是否可行为什么不可行如果在头文件中定义静态变量会造成资源浪费的问题同时也可能引起程序错误。原理编译阶段预处理器会将头文件的内容原封不动地复制到每一个包含它的.c文件中。假设header.h定义了int g 0;a.c和b.c都包含了它那么编译后a.o和b.o中各自都生成了一个名为g的全局符号。链接阶段链接器负责将多个.o文件合并为一个可执行文件。当链接器发现a.o里有一个gb.o里也有一个g且这两个都是“强符号”全局变量默认是强符号时它会认为程序员意图不明确到底该用哪个地址于是直接报错error: multiple definition of g。六、其他a、左值和右值是什么编辑 文章左值出现在等号左边的变量或表达式可写值可改右值出现在等号右边的变量或表达式可读通常左值可以作为右值但是右值不一定是左值。b、有符号和无符号的运算会强制转化位无符号的运算。int a -20 unsigned int b 6ab是否大于6 大于c、短路求值|| 和 如果看左边可以判断后不用再计算右边七、ARM1、CPU、MPU、MCU、SOC、SOPC2、交叉编译为什么3、ROM只读存储器易失RAM读写寄存器非易失4、ARM有几种工作模式用户模式用户程序的工作模式、系统模式特权模式、一般中断模式快速中断模式、管理模式CPU上电后的默认模式、终止模式、未定义模式5、ARM指令集分为几类2类Thumb类16位ARM类32位6、Cortex_M3寄存器组R1-R12 通用寄存器 R0-R3传参R4-R11保存局部变量R12内部调用暂时寄存器IPR13 主推栈指针MSP进程堆栈指针psp用于出栈和入栈操作R14 连接寄存器LR保存函数返回地址R15 程序计数器PC跳转下一个执行的命令R16 程序状态寄存器PSR特殊功能寄存器7、单片机启动流程1、内核初始化2、强制PC指向复位中断执行复位中断函数3、在复位中断函数中调用SystemIint函数初始化时钟配置中断向量表4、调用_main函数完成变量初始化和重定位初始化堆栈和库函数5、调转到main执行8、中断、中断外中断和异常内中断异同都有cpu发给内核去处理产生源不同异常cpu中断硬件设备中断异步异常时钟同步上下文不同、中断和DMADMA不需cpu参与中断需要。、什么是中断工作原理中断是一种硬件或软件机制用于暂停CPU当前执行的程序转而执行特定的服务程序中断服务程序处理完成后再返回原程序继续执行。原理中断源产生中断请求信号cpu检测到中断请求完成当前指令执行CPU保存当前程序状态CPU跳转到中断服务程序执行中断服务程序执行完成后恢复之前保存的程序状态继续执行被中断程序、中断向量表是什么其作用存储中断服务程序入口地址的数组或表格每个中断源对应一个表项。作用提供中断源与对应服务程序之间的映射关系使cpu能快速找到并跳转正确的中断服务程序支持多种中断源的统一管理、优先级反转优先级反转是指低优先级任务持有高优先级任务所需的资源而中优先级任务抢占低优先级任务导致高优先级任务被中优先级任务间接阻塞的现象。避免方法优先级继承、优先级天花板、禁用中断、资源设计优化9、GPIO定义为控制器上可以由用户程序控制的引脚可配置为输入输出。工作模式1 GPIO_Mode_AIN 模拟输入2 GPIO_Mode_IN_FLOATING 浮空输入3 GPIO_Mode_IPD 下拉输入将引脚默认拉至低电平4 GPIO_Mode_IPU 上拉输入将引脚默认拉至高电平5 GPIO_Mode_Out_OD 开漏输出输出高电平时需要外部上拉电阻6 GPIO_Mode_Out_PP 推挽输出可主动输出高电平和低电平7 GPIO_Mode_AF_OD 复用开漏输出8 GPIO_Mode_AF_PP 复用推挽输出。八、通信协议1、串口UART通信标准RS232 单端TXD、RXD、GND 全双 100m 两个节点RS485 差分 半双工 1200m 多节点RS422 差分 中等 点对点比特率波特率UART是一种串行通信协议特点异步通信不需要时钟线全双工点对点通信数据格式灵活a、波特率选择通信距离距离越长波特率应越低抗干扰要求波特率越低抗干扰性越好数据吞吐量需求高吞吐量需要高波特率硬件支持能力考虑时钟精度和误差b、校验方式无校验、奇校验、偶校验、标记校验、空格校验c、UART如何实现异步通信如何保证数据同步异步通信原理不使用时钟线发送方和接收方各自使用本地时钟通过起始位和停止位标记数据帧边界同步机制起始位触发接收方开始采样接收方通常使用比波特率高的时钟(如16倍)进行过采样在每个位的中间点采样减少误差影响双方必须预先约定相同的波特率和帧格式。2、12C基本时序STARTSCL 高时SDA 高→低STOPSCL 高时SDA 低→高数据传输SCL 低时 SDA 可变化SCL 高时 SDA 必须稳定。MSB 先发。ACK/NACK每 8 位数据后跟 1 位应答——ACK 拉低NACK 保持高。传输时主机产生时钟在第9个时钟时数据发送端会释放SDA的控制权由数据接收端控制SDA若SDA为高电平表示非应答信号 (NACK)低电平表示应答信号(ACK)。R/W传输方向选择位1为读0为写地址是多少位7位最常用0x00~0x7F(112个部分保留)传输占1字节7个地址位1位R/W10位拓展0x000~0x3FF占 2 字节第一字节11110XX R/WXX 为地址高 2 位第二字节为低 8 位开漏输出高电平无驱动能力SDA和SCL只能被拉低需借助外部上拉输出高电平。SDA线在输入时配置成上下拉输入模式。多主机怎么通信仲裁两个主机同时发各自读 SDA。自己发 1、线上却是 0说明输了立刻停发。低电平优先。时钟同步SCL 也是线与。任一主机拉低 SCL线上就是低。大家跟着最慢的那个走。上拉电阻具体作用定义空闲状态无通信时SDA和SCL为高实现线与多设备共享总线谁都可以拉低发信号不会硬碰短路配合开漏输出设备只负责拉低拉高靠电高阻4.7千欧为什么要求开漏输出多设备共享开漏才能线与推免输出多设备同时驱动会冲突电平兼容3.3v和5.5v设备可以挂同一总线上拉接到最高电压即可时钟拉伸从机可以拉低SCL拖慢时钟等自己处理完数据多主机总裁多主机同时发时谁发高、线上却是低谁就退出的——低电平优先时钟同步 vs 时钟拉伸时钟同步多主机SCL 是所有设备的与结果——有一个拉低线上就低全部释放才变高。时钟拉伸从机控速从机处理不过来可以一直拉着 SCL 不放。主机必须等 SCL 真正变高才能继续发下一个 bit。这是从机主动降速的唯一手段。适用场景设备多、引脚少就两根线速率要求不高传感器、EEPROM、RTC需要标准寻址不想额外接 CS 线不适大数据量、高吞吐Flash 读写、屏幕刷新→ 用 SPI。对延迟极度敏感、要全双工 → 用 SPI。3、SPI物理层CS线NSS线从设备选择线也称为片选信号线。哪个NSS线设为低电平就是选中对应的模块。NSS线为高电平时为结束信号。独立片选方式菊花链方式SCK时钟信号线用于通讯主机产生决定了通讯的速率STM32的SPI时钟频率最大为fPCLK/2一般通讯过程中通讯速率受限于低速设备。MOSI主机发送从机接收端口。MISO主机接收从机发送端口。协议层a、什么是SPI通信协议其基本特点是什么spi是一种同步串行通信协议。特点全双工主从架构使用专用的片选线选择从设备无应答机制b、SPI与I2C、UART相比有哪些优缺点优速度快全双工效率高协议简单硬件实现容易无寻址开销传输效率高缺需要更多信号线无应答机制通信距离有限多从设备时需要多条片选线引脚占用多c、SPI有几种工作模式其区别SPI有4种工作模式Mode 0-3由CPOL和CPHA两个参数决定CPOLClock Polarity时钟极性决定空闲状态下SCLK的电平 CPOL0空闲状态为低电平CPOL1空闲状态为高电平CPHAClock Phase时钟相位决定数据采样的时刻 CPHA0在第一个时钟边沿采样CPHA1在第二个时钟边沿采样常见设备的默认模式 SD卡初始化时使用Mode 0大多数FLASH存储器Mode 0或Mode 3某些传感器Mode 1或Mode 2d、SPI通信的基本时序主设备将对应从设备的CS线拉低激活主设备开始产生时钟信号SCLK主设备通过MOSI线发送数据同时可以通过MISO线接收数据数据传输完成后主设备停止时钟将CS线拉高释放e、SPI通信中数据是如何传输的数据传输是基于移位寄存器的主设备和从设备各有一个8位移位寄存器每个时钟周期两个寄存器同时移位一位8个时钟周期后主从设备完成一个字节的交换通常MSB最高有效位先传输但也有LSB先传输的设备f、影响spi通信速度因素主设备时钟频率信号线长度和布线数量设备之间电平兼容性从设备的最大支持频率软件实现效率g、如何提高SPI通信的效率硬件优化使用更高的时钟频率在设备支持范围内优化PCB布线减少干扰使用适当的上拉/下拉电阻确保信号质量软件优化使用DMA进行数据传输减少CPU干预批量传输数据减少CS切换开销使用中断而非轮询方式处理数据优化缓冲区管理减少数据拷贝h、 SPI通信中常见的问题及解决方法时序问题症状数据传输错误或不稳定。解决确认正确的工作模式检查时钟频率是否过高多主机冲突症状总线数据混乱。解决SPI不支持多主机需要使用额外的仲裁机制长线传输问题症状高速时数据错误。解决降低时钟频率使用差分信号增加缓冲器电平不兼容症状通信不稳定或无法通信。解决使用电平转换器匹配不同设备的电平要求I、在嵌入式RTOS环境中如何管理SPI资源使用互斥量或信号量保护SPI总线访问实现设备管理器处理多个任务对SPI的访问请求优化任务优先级确保关键任务能及时访问SPI考虑使用消息队列缓冲SPI请求减少任务切换开销实现超时机制防止某个任务长时间占用SPI资源4、can物理层开环网络和闭环网络CAN 通讯节点由一个 CAN 控制器及 CAN 收发器负责把 CAN 控制器的逻辑信号转换成 CAN 总线上的差分信号。组成控制器与收发器之间通过 CAN_Tx 及 CAN_Rx 信号线相连收发器与 CAN 总线之间使用 CAN_High 及 CAN_Low 信号线相连。其中 CAN_Tx 及 CAN_Rx 使用普通的类似 TTL 逻辑信号而 CAN_High 及 CAN_Low 是一对差分信 号线使用比较特别的差分信号。can总线的基本特点多主控制任何节点都可以在总线空闲时发送消息非破坏性总线仲裁基于消息优先级的仲裁机制错误检测与处理具有5种错误检测机制高可靠性抗电磁干扰能力强实时性确定性延迟适合实时控制物理层差分信号传输CAN_H和CAN_LCAN总线的仲裁机制是如何工作的CAN总线采用非破坏性总线仲裁机制基于消息标识符的优先级仲裁标识符越小优先级越高发送节点在发送每一位的同时监听总线状态当节点发送隐性位1而检测到显性位0时自动退出仲裁退出仲裁的节点转为接收模式不会破坏优先级更高的消息确保在冲突情况下优先级最高的消息能够成功发送CAN总线的帧类型有哪些各自特点是什么数据帧用于传输数据包含标识符、控制域、数据域和CRC校验标准帧11位标识符或扩展帧29位标识符数据长度0-8字节CAN FD可达64字节远程帧请求特定标识符的数据与数据帧结构类似但无数据域RTR位为隐性1错误帧检测到错误时发送由错误标志和错误界定符组成主动错误标志6个连续显性位被动错误标志6个连续隐性位过载帧请求延迟发送下一帧结构类似错误帧只能在帧间空间发送CAN总线的错误处理机制有哪些答CAN总线具有5种错误检测机制位错误发送节点监听自己发送的位检测到不一致时报错填充错误连续5个相同位后必须插入一个相反的位违反此规则时报错CRC错误接收方计算的CRC与发送方不一致时报错格式错误帧中固定格式的位如界定符不符合规范时报错应答错误发送方在应答槽未检测到显性位时报错CAN节点有三种错误状态错误主动正常工作状态可主动发送错误帧错误被动当错误计数器超过127时进入只能发送被动错误帧总线关闭当发送错误计数器超过255时进入节点停止通信can过滤器五、TCP和UDP应用场景TCP可靠性要求高UDP实时性要求高游戏数据传输物联网设备通信连接性面向连接通信前需建立连接无连接可靠性提供可靠传输保证完整性和顺序性提供流量控制和拥塞控制机制不提供可靠传输可靠性可在应用层自定义实现传输方式面向字节面向报文效率相对较低有连接管理开销开销小头部大小头部20-60字节头部固定8字节TCP的三次握手和四次挥手三次握手意义确认双方发送和接收能力正常同步双方初始序列号防止历史连接请求突然到服务器造成错误四次挥手意义确保双方都完成数据传输后再关闭连接实现全双工连接的单独关闭TIME_WAIT状态确保最后的ACK能到达服务器TIME_WAIT:保证最后一个ACK能到达对方2MSL报文最大生存时间的两倍足以确保网络中的报文都消失a、TCP如何保证可靠传输序列号和确认应答、超时重传、校验和、流量控制通过滑动窗口机制防止接收方缓冲区溢出拥塞控制避免网络拥塞动态调整发送速率包括慢启动、拥塞避免、快重传、快恢复、数据排序和去重处理乱序和重复的数据包丢包问题处理超时重传、快速重传、选择性重传、动态调整RTO拥塞控九、操作系统a、什么是进程什么是线程区别进程是资源分配的基本单位他是程序执行时的一个实例在程序运行时创建。有自己的独立空间线程启动系统为他分配空间。开销较小。之间的通信需要一通信方式进行。有一个程序运行的入口、顺序执行序列和程序入口线程是程序执行时的最小单位是进程的一个执行流一个进程由多个线程组成。无自己的独立空间共享进程数据有自己的堆栈。涉及频繁切换。不能独立执行必须依存在应用程序中由应用程序提供多个线程执行控制。b、内核线程和用户线程的区别内核支持线程是OS内核可感知的而用户级线程是OS内核不可感知的。用户级线程的创建、撤消和调度不需要OS内核的支持是在语言如Java这一级处理的而内核支持线程的创建、撤消和调度都需OS内核提供支持而且与进程的创建、撤消和调度大体是相同的。用户级线程执行系统调用指令时将导致其所属进程被中断而内核支持线程执行系统调用指令时只导致该线程被中断。在只有用户级线程的系统内CPU调度还是以进程为单位处于运行状态的进程中的多个线程由用户程序控制线程的轮换运行在有内核支持线程的系统内CPU调度则以线程为单位由OS的线程调度程序负责线程的调度。用户级线程的程序实体是运行在用户态下的程序而内核支持线程的程序实体则是可以运行在任何状态下的程序。十、FreeRtos任务的概念任务是FreeRTOS中的执行单元类似于线程每个任务有自己的栈空间和上下文任务通常包含一个无限循环不应该退出任务的状态运行就绪阻塞挂起删除a、FreeRTOS的调度算法是怎样的如何实现时间片轮转FreeRTOS默认使用抢占式优先级调度高优先级任务可以抢占低优先级任务。同优先级任务通过时间片轮转方式调度。时间片轮转通过以下方式实现配置configUSE_TIME_SLICING为1默认是否启用时间片轮转调度每个系统时钟节拍调度器检查是否有同优先级的就绪任务如果有则切换到下一个同优先级任务时间片长度等于系统时钟节拍周期b、FreeRTOS中任务间通信有哪些机制各有什么特点队列(Queue)支持多个数据项的FIFO传输可用于任务间和中断与任务间通信支持阻塞等待和超时机制信号量(Semaphore)二值信号量用于同步计数信号量用于资源管理互斥量(Mutex)带优先级继承的特殊信号量用于解决优先级反转问题事件组(Event Group)支持多事件等待和同步可实现与和或逻辑等待任务通知(Task Notification)轻量级通信机制性能最高每个任务有一个32位通知值可替代二值信号量、计数信号量和事件组每个任务只有一个通知值只能有一个任务等待特定任务的通知