
C 语言内存怎么划分C 语言内存主要分为代码区、只读区、全局/静态区、堆区和栈区。代码区存放程序的机器指令比如函数代码一般位于 Flash 或 ROM 中通常只读。只读区存放只读常量比如字符串常量、const修饰的全局变量一般也放在 Flash 中。全局/静态区存放全局变量和 static 变量。其中已经初始化的变量放在data 段 / RW 段未初始化或初始化为 0 的变量放在bss 段 / ZI 段。堆区用于动态内存分配比如malloc、free由程序员手动申请和释放。栈区用于存放局部变量、函数参数、返回地址等由编译器自动管理函数调用结束后自动释放。在嵌入式 STM32 中通常代码区和只读区放在 Flash 中data、bss、heap、stack 放在 RAM 中。程序启动时会把 data 段从 Flash 拷贝到 RAM并把 bss 段清零。链表与数组在内存中的区别数组在内存中是连续存储的所以可以通过下标直接访问访问效率高时间复杂度是 O(1)。但是数组大小通常固定插入和删除元素时需要移动数据。链表在内存中一般是非连续存储的是一种线性数据结构通过节点的指针进行连接数据每个节点有数据和指向下一个节点的指针构成。每个节点通过指针连接。它插入和删除比较方便但查找某个元素时需要从头遍历访问效率低时间复杂度一般是 O(n)。在嵌入式中如果数据量固定、追求访问效率我会优先用数组如果数据量变化较大或者需要频繁插入删除可以考虑链表。但链表一般涉及动态内存分配要注意堆碎片问题。SPI和I2C通信的区别SPI 和 I2C 都是常见的板级通信总线。SPI通常有四根线SCLK、MOSI、MISO、CS。它是全双工通信速度比较快没有固定地址机制靠片选 CS 选择不同从设备适合高速传感器、Flash、无线模块等。比如我项目中的Si24R1 无线模块就使用 SPI 通信。I2C通常只有两根线SCL 和 SDA是半双工通信通过设备地址区分不同从机总线需要上拉电阻速度相对 SPI 慢一些但引脚占用少适合低速传感器。比如我项目中的MPU6050就使用 I2C 读取加速度和角速度数据。总结来说SPI 速度快、线多、适合高速外设I2C 线少、支持多设备、适合低速传感器。IIC 叫做集成电路总线是一种串行半双工通信总线支持多主多从由 SDA 数据线和 SCL 时钟线两条线构成其中 SDA 线读的时候是输入、写的时候是输出SCL 只能是输出。它有三种类型信号开始信号、结束信号及应答信号开始信号指的是当 SCL 为高电平时SDA 由高电平向低电平跳变。结束信号是当 SCL 为高电平时SDA 由低电平向高电平跳变。应答信号是当接收到 8 位的数据之后第九位向主机发送一个低电平信号表示已接收到数据。主机与从机通信写首先主机先发送一个开始信号然后发送 7 位通信地址加 1 个方向位0 代表写1 代表读此处的方向位是 0接下来等待从机的应答信号等到从机应答以后主机发送需要访问的寄存器地址继续等待从机应答从及应答后主机开始向从机发送 8 位数据然后再次等待从机的接收应答。应答后主机发送结束信号代表通信结束。主机与从机通信读首先主机发送开始信号然后发送 7 位通信地址加方向位 0 给从机等待从机应答从机应答后主机发送要访问的从机寄存器地址再次等待从机应答从机应答后主机重新发送开始信号因为这里需要读然后主机重新发送从机 7 位通信地址在加读的方向位“1”再次等待从机的应答信号。等待从机应答后主机开始读取数据。读取完毕后主机发送结束信号停止通信。SPI 是串行外围设备接口是一种高速的同步、全双工通信总线仅支持一主多从一般使用四根线进行通信SCLK、MOSI、MISO 及片选线 CS。其通信原理是主机和从机都有一个串行移位寄存器主机通过向它的 SPI 串行寄存器写入一个字节来发起一次传输。寄存器通过 MOSI 信号线将字节传送给从机从机也将自己的移位寄存器中的内容通过 MISO 信号线返回给主机。这样两个移位寄存器中的内容就被交换。工作模式其工作模式有四种通过 CPHA时钟相位、CPOL时钟极性来决定。如果 CPOL0串行同步时钟的空闲状态为低电平如果 CPOL1串行同步时钟的空闲状态为高电平。时钟相位CPHA能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA0在串行同步时钟的第一个跳变沿上升或下降数据被采样如果 CPHA1在串行同步时钟的第二个跳变沿上升或下降数据被采样。SPI 主模块和与之通信的外设备时钟相位和极性应该一致。个人对进入公司的发展如果我有机会进入公司短期内我希望先快速熟悉公司的产品、代码规范、开发流程和硬件平台先把分配到的驱动、调试、维护类任务做好。中期我希望能够独立负责某个嵌入式软件模块比如外设驱动、通信协议、RTOS 任务框架或者设备联调相关工作提升自己在问题定位、系统调试和代码质量方面的能力。长期来看我希望自己能成长为既懂底层驱动又懂系统架构和产品业务的嵌入式工程师能够独立承担模块设计、软硬件联调和现场问题定位为公司产品稳定落地提供支持。这类回答重点是稳定、愿意学、能落地、愿意长期发展指针函数与函数指针的区别指针函数是返回指针的函数函数指针是指向函数的指针。在嵌入式中函数指针常用于回调函数、驱动抽象、状态机、协议解析表等场景FreeRTOS 线程是什么FreeRTOS 里通常叫任务 Task本质上可以理解为轻量级线程。每个任务都有自己的任务控制块 TCB和独立的任务栈。任务有不同状态比如运行态、就绪态、阻塞态、挂起态。FreeRTOS 调度器会根据任务优先级和系统节拍进行任务切换任务之间通信可以使用队列、信号量、互斥量、事件组、任务通知等机制在线程中如何确保一个线程在内存中的大小在 FreeRTOS 中每个任务创建时都会分配独立栈空间比如使用xTaskCreate()时会指定栈大小。要确保任务内存大小合理我一般从三个方面考虑。第一根据任务复杂度预估栈大小。比如任务中是否有较深函数调用、局部数组、printf、协议解析缓冲区等。大的数组尽量不要放在任务栈里而是放到全局区或静态区。第二运行时使用 FreeRTOS 提供的接口检查剩余栈空间比如它可以查看任务运行过程中最小剩余栈空间用来判断栈是否设置过小。第三开启 FreeRTOS 的栈溢出检测比如配置configCHECK_FOR_STACK_OVERFLOW这样在任务栈溢出时可以进入钩子函数方便定位问题。如果对内存可控性要求高还可以使用xTaskCreateStatic()静态创建任务明确指定任务栈数组和 TCB避免动态内存分配带来的不确定性。三极管的工作原理标准回答三极管可以理解为一种用小电流控制大电流的器件常见有 NPN 和 PNP。以 NPN 三极管为例它有三个极基极 B、集电极 C、发射极 E。三极管主要有三个工作区截止区基极没有足够电压三极管不导通相当于开关断开。放大区集电极电流约等于 β 倍基极电流常用于信号放大。饱和区三极管充分导通常用于开关控制。在嵌入式中我更多把三极管作为开关管使用比如 MCU 的 GPIO 输出电流能力有限可以通过三极管驱动蜂鸣器、继电器、小电机或者 LED 等负载。PNP输出为高电平NPN输出为低电平笔试题UART 是通用异步收发器是一种异步串行通信方式。它不需要额外时钟线通信双方通过约定波特率、数据位、停止位和校验位来完成数据收发。UART 通常使用 TX 和 RX 两根信号线全双工通信时需要交叉连接并共地。数据帧一般由起始位、数据位、可选校验位和停止位组成常见配置是 115200、8N1。它常用于串口调试、MCU 与蓝牙/WiFi/GPS 模块通信、上位机通信等场景ADC 是模数转换器用于把模拟电压转换为数字量。常见 ADC 类型有逐次逼近型、Flash 型、积分型和 Sigma-Delta 型其中 STM32 常用的是 12 位逐次逼近型 ADC。转换结果范围为 0 到 4095。逐次逼近的原理是 ADC 内部通过 DAC 从高位到低位逐位试探并与输入电压比较最终得到对应的数字码。