虹软科技 嵌入式开发软件 二面
1. 深入聊聊你的项目,从需求分析到系统设计的完整过程
项目背景
我做的是一个智能环境监测系统,用于工业现场的温湿度、气体浓度等参数的实时监测和数据上报。系统部署了50个监测节点,每个节点每分钟采集一次数据并上报到云平台。
需求分析
项目的核心需求:
- 实时采集多种传感器数据
- 通过4G网络上报到云平台
- 支持远程配置和固件升级
- 对功耗有要求,要支持电池供电,续航至少3个月
- 对可靠性有要求,要保证数据不丢失,设备故障要能自动恢复
硬件选型
主控芯片: STM32F407
- 有丰富的外设接口
- 性能足够,功耗可接受
通信模块: 4G模块
- 支持TCP/IP和MQTT协议
传感器: 数字接口传感器
- 使用I2C或SPI通信
- 精度和稳定性都比较好
电源设计:
- 采用锂电池加太阳能板
- 支持边充电边工作
- 使用低功耗设计,MCU大部分时间处于休眠状态,定时唤醒采集数据
软件架构设计
软件采用分层架构:
BSP层(板级支持包):
- 时钟配置
- GPIO初始化等
驱动层:
- 传感器驱动
- 4G模块驱动
- Flash驱动等
中间层:
- 协议栈
- 文件系统
- 数据管理等
应用层:
- 数据采集
- 数据上报
- 远程配置等业务逻辑
任务管理(使用FreeRTOS):
- 数据采集任务:定时读取传感器数据,存储到本地Flash
- 数据上报任务:从Flash读取数据,通过MQTT上报到云平台
- 通信管理任务:负责4G模块的初始化、网络连接、断线重连等
关键技术难点
难点1:低功耗设计
使用了多种低功耗技术:
- MCU大部分时间处于Stop模式,功耗只有几十微安
- 使用RTC定时唤醒,采集数据后立即休眠
- 传感器使用低功耗型号,不用时断电
- 4G模块使用PSM省电模式,不通信时进入休眠
优化效果: 整机平均功耗降到5mA以下,电池续航达到4个月
难点2:数据可靠性
使用了多重保障机制:
- 数据采集后先存储到本地Flash,上报成功后才删除
- 使用环形缓冲区管理数据,满了就覆盖最老的数据
- 使用MQTT的QoS 1保证消息至少送达一次
- 云平台收到数据后返回确认,设备收到确认才删除本地数据
难点3:远程升级
实现了Bootloader,支持通过4G网络下载固件升级:
- Bootloader占用前32KB Flash
- 应用程序从32KB开始
- 升级时,Bootloader下载新固件到备份区
- 校验通过后复制到应用区,然后跳转到应用程序
- 如果升级失败,可以回滚到旧版本
通信协议设计
设备和云平台使用MQTT协议通信:
- 设备订阅主题
device/设备ID/config接收配置命令 - 发布到主题
device/设备ID/data上报数据 - 数据格式使用JSON,包含设备ID、时间戳、传感器数据等
- 为了节省流量,使用简短的字段名,比如用
t表示temperature - 使用心跳机制保持连接,每5分钟发送一次心跳
- 如果连接断开,自动重连,最多重试3次
测试和优化
实验室测试:
- 进行了长时间测试,模拟各种异常情况
- 测试网络断开、服务器故障、传感器异常等场景
- 验证系统的可靠性
现场优化:
- 通过日志分析发现了一些问题
- 比如某些环境下4G信号不稳定,导致频繁重连
- 优化了重连策略,增加了重连间隔,减少了功耗
- 通过远程升级功能,修复了几个bug,优化了性能
用户反馈: 系统运行稳定,数据准确,满足了项目需求
项目成果
- 系统已经稳定运行半年
- 50个节点的数据上报成功率达到99.5%以上
- 电池续航达到4个月,满足了设计要求
- 远程升级功能使用了5次,都成功完成
- 客户对系统很满意,计划扩大部署规模
2. ARM Cortex-M的异常和中断机制,NVIC的配置
异常和中断
ARM Cortex-M把所有的异常事件统称为异常,包括:
- 复位、NMI、硬件故障等系统异常
- 外部中断
异常号:
- 系统异常的异常号是负数
- 外部中断的异常号从0开始
优先级:
- 每个异常有一个优先级,数字越小优先级越高
- 优先级分为抢占优先级和子优先级
- 抢占优先级决定是否可以嵌套
- 子优先级决定同时发生时的处理顺序
NVIC(嵌套向量中断控制器)
NVIC负责管理外部中断,包括:
- 中断的使能
- 优先级配置
- 挂起状态等
每个中断有独立的使能位、挂起位、活动位。
中断嵌套:
- NVIC支持中断嵌套,高优先级中断可以打断低优先级中断
- 但有一个例外:如果两个中断的抢占优先级相同,后来的中断不能打断先来的中断,要等它执行完
优先级分组
Cortex-M支持优先级分组,把优先级位分为抢占优先级和子优先级。
通过AIRCR寄存器的PRIGROUP字段配置分组。比如STM32有4位优先级,可以配置为:
- 4位抢占优先级 + 0位子优先级
- 3位抢占优先级 + 1位子优先级
- 2位抢占优先级 + 2位子优先级(常用)
- 等等
一般配置为2位抢占优先级2位子优先级,这样有4个抢占级别,每个级别有4个子级别。
中断配置步骤
第一步:配置优先级分组
- 调用
NVIC_SetPriorityGrouping函数 - 一般在系统初始化时配置一次
第二步:配置中断优先级
- 调用
NVIC_SetPriority函数,指定中断号和优先级 - 优先级是一个8位数字,高位是抢占优先级,低位是子优先级
第三步:使能中断
- 调用
NVIC_EnableIRQ函数,指定中断号 - 也可以用
NVIC_DisableIRQ函数禁用中断
第四步:配置外设的中断使能位
- 每个外设有自己的中断使能寄存器
- 比如USART有RXNE中断使能位,TIM有更新中断使能位
中断处理流程
- 外设触发中断
- NVIC检查中断是否使能,是否被屏蔽
- 如果可以响应,CPU保存当前状态到栈,包括R0-R3、R12、LR、PC、xPSR等寄存器
- CPU从向量表读取中断服务程序的地址,跳转执行
- 中断服务程序执行完后,返回指令会自动恢复之前保存的寄存器,返回被中断的程序
中断延迟
硬件延迟:
- 从中断触发到CPU开始执行中断服务程序的时间
- Cortex-M3/M4大约是12个时钟周期
软件延迟:
- 中断服务程序的执行时间
- 要尽量缩短中断服务程序,只做必要的处理
- 复杂的处理放到任务中
中断安全
在中断和任务之间共享数据时,要注意数据竞争:
方法1:使用临界区保护
- 调用
taskENTER_CRITICAL和taskEXIT_CRITICAL
方法2:关闭中断
- 但要尽快打开,避免影响实时性
方法3:使用FreeRTOS中断安全API
- FreeRTOS提供了中断安全的API,以
FromISR结尾 - 比如
xSemaphoreGiveFromISR、xQueueSendFromISR等 - 在中断中只能调用这些API,不能调用普通的API
3. DMA的工作原理,如何配置DMA传输?
DMA概念
DMA是Direct Memory Access的缩写,直接内存访问。它可以在外设和内存之间直接传输数据,不需要CPU参与。这样可以释放CPU,让CPU做其他工作,提高系统效率。
DMA的优势
减少CPU负担:
- 比如串口接收数据,如果用中断方式,每收到一个字节就触发一次中断,CPU要频繁响应中断
- 如果用DMA,可以一次传输一批数据,只在传输完成时触发一次中断
传输速度快:
- 因为不需要CPU参与,没有上下文切换的开销
降低功耗:
- DMA可以在CPU休眠时工作,进一步降低功耗
DMA的工作模式
传输方向(三种):
- 外设到内存(比如ADC采集数据到内存)
- 内存到外设(比如内存数据发送到USART)
- 内存到内存(比如数据拷贝)
工作模式(两种):
- 正常模式:传输完成后停止,需要重新配置才能再次传输
- 循环模式:传输完成后自动重新开始,适合连续采集的场景
其他特性:
- DMA支持不同的数据宽度,可以是字节、半字、字
- 源地址和目标地址可以配置为递增、递减或固定
DMA配置步骤
第一步:使能DMA时钟
- 调用
RCC_AHBPeriphClockCmd函数
第二步:配置DMA通道
- 填充
DMA_InitTypeDef结构体 - 包括外设地址、内存地址、传输方向、数据宽度、传输数量等
第三步:配置DMA中断
- 如果需要在传输完成时得到通知
- 使能传输完成中断,配置NVIC
第四步:使能DMA通道
- 调用
DMA_Cmd函数
第五步:配置外设的DMA使能位
- 每个外设有自己的DMA使能寄存器
- 比如USART有DMAT和DMAR位,ADC有DMA位
DMA使用示例
串口DMA接收:
- 配置DMA从USART的数据寄存器传输到内存缓冲区,使用循环模式
- 这样串口接收的数据会自动存储到缓冲区,不需要CPU参与
ADC DMA采集:
- 配置DMA从ADC的数据寄存器传输到内存数组,使用循环模式
- 配置ADC连续转换模式,每次转换完成触发DMA传输
- 这样可以连续采集ADC数据,不需要CPU参与
DMA的注意事项
1. DMA和CPU同时访问内存的问题
- 如果DMA正在传输数据到缓冲区,CPU同时读取缓冲区,可能读到不完整的数据
- 可以使用双缓冲机制,DMA写一个缓冲区时,CPU读另一个缓冲区
2. 缓存一致性问题
- 在有缓存的MCU上,DMA传输的数据可能在缓存中,没有写回内存
- 要在DMA传输前刷新缓存,传输后使缓存失效
3. DMA传输完成的判断
- 可以使用中断方式,在传输完成中断中处理
- 也可以使用轮询方式,查询DMA的传输完成标志
4. Flash的读写操作,如
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。