芯海科技 嵌入式开发软件开发 二面 面经
芯海科技-嵌入式软件开发-一面(续)
1. 先介绍一下你的项目,你在项目中更偏向硬件还是软件?具体负责哪些模块?
参考答案:我做的项目是一个智能环境监测设备,主要采集温湿度、光照、空气质量等数据,通过蓝牙上传到手机APP。我在项目中主要负责软件部分,包括固件开发、驱动编写、通信协议实现等,硬件方面主要是配合硬件工程师做调试和验证。
具体负责的模块包括:传感器驱动模块,我用I2C接口读取温湿度传感器,用SPI接口读取气体传感器,编写了驱动程序实现数据采集。通信模块,集成了BLE蓝牙协议栈,实现了GATT服务,定义了自定义特征用于数据传输。电源管理模块,实现了低功耗策略,在空闲时进入睡眠模式,定时唤醒采集数据。还有报警模块,当检测到异常数据时通过蜂鸣器和LED报警,同时通过蓝牙通知手机。
主控用的是STM32F103,用到的外设包括I2C、SPI、UART、GPIO、ADC、定时器、RTC等。软件架构上使用了FreeRTOS,创建了数据采集任务、通信任务、显示任务等,通过消息队列和信号量进行任务间通信。整个项目我负责了大概70%的软件开发工作,从底层驱动到应用逻辑都有涉及。
2. 你提到用了I2C、SPI、UART,能详细说说这三种通信协议的区别和各自的特点吗?
参考答案:这三种协议我在项目中都用到了,各有特点。
UART是异步串行通信,只需要TX、RX两根线加GND,点对点通信,不需要时钟线,双方约定好波特率就能通信。优点是简单,硬件资源少,传输距离可以比较远,我用UART连接调试串口和GPS模块。缺点是速度相对较慢,而且没有时钟同步,如果波特率设置不对就会乱码。
I2C是同步串行通信,需要SCL时钟线和SDA数据线,支持一主多从,通过7位或10位地址寻址不同的从设备。优点是只用两根线就能连接多个设备,节省IO口,我用I2C连接了温湿度传感器、EEPROM、RTC等多个器件。缺点是速度比较慢,标准模式100Kbps,快速模式400Kbps,而且传输距离短,一般在板内使用。I2C是开漏输出,需要上拉电阻,总线上任何设备都可以拉低电平。
SPI是同步串行通信,需要SCLK、MOSI、MISO、CS四根线,主从模式,全双工通信。优点是速度快,我用SPI连接Flash芯片,速度可以达到几十Mbps,而且硬件实现简单。缺点是需要的IO口多,每个从设备需要一根片选线,如果连接多个设备会占用很多IO口。SPI没有标准的协议规范,不同厂商的实现可能不同,需要查看数据手册。
选择哪种协议主要看应用需求,调试和简单通信用UART,连接多个低速外设用I2C,高速数据传输用SPI。
3. 你说I2C可以挂多个从机,那它是怎么寻址到想要的从机进行通信的?地址冲突怎么办?
参考答案:I2C通过设备地址来寻址不同的从机。每个I2C从设备都有一个唯一的7位地址,主机通信时先发送起始信号,然后发送从机地址加读写位,总共8位。总线上所有从机都会接收这个地址,只有地址匹配的从机会应答ACK,其他从机保持沉默。主机收到ACK后就知道从机已就绪,可以继续传输数据。
具体过程是,主机发送起始信号S,然后发送7位从机地址和1位读写位,如果是写操作R/W=0,读操作R/W=1。从机收到地址后,如果匹配就拉低SDA发送ACK,主机检测到ACK后继续发送数据或接收数据。传输完成后主机发送停止信号P,释放总线。
地址冲突是I2C的一个问题,如果两个设备地址相同,主机无法区分它们。解决方法有几种。一是选择不同地址的器件,很多I2C器件有多个型号,地址不同。二是利用器件的地址引脚,有些器件有A0、A1、A2等地址引脚,通过接高低电平可以配置不同的地址,比如EEPROM的地址是1010+A2A1A0,可以配置8个不同地址。三是使用I2C多路复用器,把总线分成多路,每路连接一个设备,通过切换通道来访问不同设备。
在我的项目中,温湿度传感器地址是0x40,EEPROM地址是0x50,RTC地址是0x68,都不冲突。如果遇到冲突,我会优先选择可配置地址的器件,或者用GPIO模拟I2C,创建多个软件I2C总线。
4. 如果两个MCU之间通过SPI连接,从机有数据想主动发给主机,这种场景你会怎么设计?
参考答案:SPI是主从模式,通信必须由主机发起,从机不能主动发送数据。但实际应用中经常需要从机主动通知主机,我会用几种方案。
最常用的方案是增加一根中断线或握手信号线。从机有数据时,通过GPIO拉高中断线,主机检测到中断后,作为SPI主机发起传输,读取从机的数据。这种方式简单可靠,只需要额外一根线。具体实现是,从机配置一个GPIO为输出,有数据时输出高电平。主机配置一个GPIO为外部中断输入,检测到上升沿触发中断,在中断处理函数中设置标志,主任务检测到标志后发起SPI传输。
另一种方案是利用SPI的全双工特性。主机定期发送查询命令,从机在MISO线上同时返回状态字节,如果状态字节表示有数据,主机继续读取。这种方式不需要额外的线,但主机需要定期轮询,效率较低,而且会增加功耗。
还有一种方案是双向SPI,两个MCU都配置为主从模式,需要发送数据的一方切换为主机发起传输。这需要额外的握手协议,比如通过GPIO信号协商谁是主机,或者使用时分复用,约定时间段内谁是主机。这种方式比较复杂,但灵活性高。
在我的项目中,我用的是第一种方案,从机通过GPIO通知主机。从机检测到按键按下或传感器数据就绪时,拉高中断线,主机在中断中设置标志,主任务中发起SPI传输读取数据。传输完成后从机拉低中断线,等待下次数据。这种方式简单高效,响应及时,是最常用的设计。
5. 你提到项目中有蜂鸣器报警功能,报警之后程序中做了什么处理?如何避免误报?
参考答案:蜂鸣器报警是在检测到异常情况时触发的,比如温度超过阈值、空气质量超标等。报警之后程序会做几个处理。
首先是驱动蜂鸣器发声,我用PWM控制蜂鸣器,设置不同的频率和占空比产生不同的声音。报警时启动定时器输出PWM,蜂鸣器响一段时间后自动停止,避免一直响影响用户。同时点亮LED指示灯,用不同颜色或闪烁频率表示不同的报警类型。
然后是记录报警事件,把报警时间、类型、数值等信息保存到EEPROM或Flash中,方便后续查询和分析。如果设备连接了蓝牙,会立即通过BLE发送通知到手机APP,用户可以远程查看报警信息。报警信息包含时间戳、报警类型、当前数值等。
还会进入报警状态,增加采样频率,比如正常时每分钟采样一次,报警时改为每10秒采样一次,密切监控数据变化。如果连续多次采样都超过阈值,确认是真实报警而不是偶然波动。报警状态下会禁止进入低功耗模式,保持系统活跃,及时响应。
为了避免误报,我做了几个处理。一是数据滤波,对传感器数据进行滑动平均或中值滤波,去除偶然的异常值。二是设置报警阈值和恢复阈值,比如温度超过30度报警,低于28度恢复,避免在临界值附近频繁报警。三是延时确认,检测到异常后不立即报警,而是连续检测几次,都超过阈值才报警,避免瞬时干扰导致误报。四是用户可以通过APP设置报警阈值和灵敏度,适应不同的使用场景。
在实际测试中,通过这些措施,误报率控制在很低的水平,用户反馈报警功能准确可靠。
6. 说说你在项
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。