ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于STM32的离线语音识别智能家居控制系统设计

基于STM32的离线语音识别智能家居控制系统设计 1. 项目概述与整体设计思路1.1 这个项目到底做了什么智能家居语音控制这个方向每隔一段时间就有人问我怎么做尤其是刚学完STM32基础外设的读者总想找个能拿得出手的综合项目。我当初做这个项目的时候想法很简单把“语音识别”和“家电控制”这两件事全部在本地离线完成不依赖云端、不依赖App、不依赖WiFi模块一块STM32F103C8T6核心板加上几个常用外设就把一套完整的语音控制智能家居原型系统跑起来。系统实现的功能包括离线语音识别模块接收语音指令主控STM32解析指令后控制灯光开关、风扇转速、窗帘开合、温湿度采集与显示所有外设的运行状态同步呈现在板载OLED屏幕上。整套硬件可以直接用Proteus仿真跑通代码使用HAL库编写工程结构清晰副产物还包括原理图和PCB图所以这套资料对毕设、课程设计或者想学习嵌入式综合开发的读者都有参考价值。为什么强调“离线语音识别”这一点因为现在很多所谓智能家居语音方案本质是接云端SDK本地只是个收音和播放终端。一旦断网整个系统就瘫痪了。而这个项目使用本地离线语音识别芯片所有唤醒词和命令词都固化在本地词库里识别过程不联网、不收费、响应速度在毫秒级这在实际使用中会踏实很多。1.2 技术选型的关键考量项目的主控芯片选用STM32F103C8T6这颗芯片是ARM Cortex-M3内核主频最高72MHzFlash 64KBRAM 20KB。从这个配置能看出来它并不算高性能但对于这个项目来说是刚好够用、而且留有余量。选型时考虑过几个方案。首先是ESP32这颗芯片带WiFi和蓝牙理论上可以走云端识别路线但成本更高而且对新手来说两个核跑FreeRTOS加WiFi协议栈学习曲线会陡很多。其次是STM32F407系列性能强很多但芯片封装更复杂打板成本更高对这类偏教学和原型验证的项目来说属于性能过剩。最终定了F103C8T6原因很实际开发资料多到泛滥遇到问题随便一搜就有答案芯片便宜核心板二十多块就能买到HAL库生态成熟不管是标准库还是HAL库都有大量现成代码可以参考。更重要的Proteus里头对F103系列的支持已经比较完善可以仿真大部分外设这对那些暂时没买到硬件、想先在电脑上跑通逻辑的读者非常友好。语音识别模块的选择同样经历了对比。市面上常见的离线语音方案有LD3320、ASR M08B、SU-03T等。LD3320是很多老项目里常见的方案支持非特定人识别词条可以动态设置但外围电路比较复杂需要麦克风阵列、功放芯片而且识别率受环境噪音影响比较明显。SU-03T这类新一代离线语音模组则把麦克风、语音识别引擎、功放集成到了一个小板子上用户只需要通过串口发送命令词表模块自己就能完成“唤醒词识别命令词匹配结果输出”整个流程主控MCU只需要接一个串口就够了。实际做下来SU-03T这类方案对项目集成度有质的提升我最终选的就是这种类型的模块。模块和主控之间走UART通信识别到语音命令后通过串口把命令码发给STM32STM32这边只需要做好协议解析和状态机就能准确控制外设。1.3 系统整体架构分析整套系统的数据流和控制流可以分为三层语音输入层、逻辑处理层、执行输出层。语音输入层由离线语音识别模块承担用户说出唤醒词比如“小智小智”后模块被激活接着说出命令词比如“打开客厅灯”模块识别成功后通过串口按预设协议输出对应的命令码。逻辑处理层是STM32主控它通过串口中断接收语音模块发来的命令帧经过帧头校验、命令码映射然后调用对应的外设控制函数。同时它还负责周期性地读取温湿度传感器数据刷新OLED屏幕显示。执行输出层包括四类被控外设LED灯模拟客厅灯光照明使用PWM调节亮度直流减速电机模拟风扇用PWM控制转速SG90舵机模拟窗帘开合DHT11温湿度传感器实现环境监测。所有外设状态最终汇总显示在OLED屏上形成完整的人机交互闭环。考虑到有些读者手头暂时没有语音识别模块或想先在电脑上做仿真验证这套代码设计上做了一层的解耦语音识别模块和STM32之间定义了一个通用协议接口如果暂时没有实物模块可以在上位机串口助手手动发送相同格式的命令帧系统一样能跑通全部逻辑。这个设计在调试阶段帮了大忙也让整套代码的适用范围扩大了不少。2. 核心硬件设计与原理图拆解2.1 主控最小系统电路设计STM32F103C8T6的最小系统电路并不复杂但每一处的细节都值得认真对待。首先是供电部分芯片工作电压是2.0V到3.6V典型值3.3V。虽然F103的IO口标注的是TTL兼容但供电必须稳定我实测下来3.3V电源纹波控制在50mV以内ADC采样和DHT11时序才能保持稳定。VBAT引脚接3.3V用于给备份域供电。VDDA引脚是模拟电源和VDD之间串一个10uH磁珠再加一个0.1uF的去耦电容这是做ADC采集时的常规做法。如果没有磁珠直接短接也能工作但在电磁环境复杂的环境下模拟采集的跳动会明显变大。复位电路用10K电阻上拉NRST引脚并联一个0.1uF电容到地这个RC时间常数约1ms能有效滤除按键抖动。启动模式相关的BOOT0和BOOT1引脚各接10K下拉电阻到地保证系统从主Flash启动。实测中很多新手在这里翻车BOOT0悬空或接错导致芯片进不了程序这个细节要多花两分钟检查。晶振电路是另一个高频翻车点。F103系统时钟可以由内部RC或外部晶振提供但为了串口通信波特率准确强烈建议使用外部8MHz晶振加两个20pF负载电容。注意负载电容的值不是随手选的8MHz晶振的典型负载电容就是12pF到22pF20pF在大多数环境下起振都很稳定。我在布局时把这几个元件紧贴芯片摆放走线尽量短实测起振非常干脆。最小系统电路是整套硬件的基础底板这部分画对了其他外设电路就是在这个基础上做加法。2.2 语音识别模块接口电路语音识别模块和主控之间的接口异常简单本质就是三根线VCC、GND、UART_TX。模块的TX接STM32的PA3USART2_RX因为我的代码里把USART2配置成了语音指令接收通道。3.3V供电由主控板引出模块的电流需求在80mA左右STM32核心板板载的AMS1117-3.3稳压器能轻松满足。这里有一个容易被忽视的坑语音识别模块的串口电平标准。市面上很多离线语音模组的默认电平是3.3V但部分老型号为了兼容5V单片机板载了电平转换电路输出电平可能是3.3V或5V可调。如果模块输出5V电平直接接到STM32的PA3引脚虽然F103的IO口标注是5V容忍但这仅限于输入模式而且这个容忍是通过内部保护二极管实现的长期使用存在可靠性隐患。稳妥的做法是在模块TX和主控RX之间串联一个1K电阻做限流或者加一个电平转换电路。另外一个设计细节是我在语音模块的VCC入口加了100uF电解电容和0.1uF陶瓷电容并联滤波。语音识别模块在工作时尤其是播报提示音的时候电流波动比较明显如果不做滤波这个波动会沿着供电线传导到主控的模拟电路导致ADC采集出现周期性偏差。2.3 外设驱动电路设计灯光控制部分使用PWM驱动。LED灯的额定电流一般在20mA左右直接用STM32的GPIO推挽输出驱动是可以的但要限流电阻。我选的是1K电阻3.3V供电下LED工作电流约2mA到3mA这个亮度在室内环境足够看清状态又不会超过引脚最大灌电流。如果读者想驱动更大功率的灯板需要在IO口后面加三极管或MOS管典型电路是S8050三极管基极串联1K电阻接IO集电极接继电器或灯珠电源发射极接地。风扇控制部分用NPN三极管做开关。STM32的GPIO高电平驱动能力在20mA左右直接驱动直流电机必然烧IO口。驱动电路为PA6输出PWM信号经1K电阻到S8050基极电机串联在5V电源和集电极之间发射极接地同时在电机两端反并联一个1N4148二极管做续流保护。这个二极管不能省电机是感性负载断电瞬间会产生反向电动势没有续流二极管的话高压尖峰很可能击穿三极管。窗帘舵机部分SG90舵机的信号线接PA7电源需要5V供电。这里要特别强调SG90堵转电流能到500mA以上正常工作电流也在100mA到200mA绝对不能用STM32开发板上的3.3V稳压器供电。我的方案是单独准备一路5V电源舵机电源和逻辑电源在物理上分开只在GND端单点相连这样既保证舵机动力充足又避免舵机电流波动干扰主控工作。温湿度采集部分DHT11的数据引脚通过4.7K上拉电阻接3.3V同时接PA1。DHT11是单总线协议数据线空闲状态被上拉到高电平主机发送起始信号后由传感器拉低响应。4.7K上拉是数据手册推荐值实测在20cm以内的杜邦线连接下信号完整性没有问题。OLED显示部分用I2C接口SDA接PB7SCL接PB6。0.96寸OLED模组内部有SSD1306驱动芯片工作电压3.3V功耗只有几十毫瓦可以直接由主控板3.3V供电。2.4 电源系统设计整套系统的电源拓扑分两条支路。5V主电源从USB接口或外部电源适配器引入经过一个SS34肖特基二极管做防反接保护再并联两个滤波电容其中一个大容值的470uF电解电容储能一个0.1uF陶瓷电容滤高频干扰。然后是AMS1117-3.3稳压器降到3.3V为MCU、语音模块、OLED和DHT11供电。AMS1117最大输出电流1A但实际系统电流峰值只有300mA左右余量充足。这里有个经验值得分享不要为了省事直接用开发板上的USB口给整个系统供电尤其是舵机和电机同时动作的时候。开发板板载的稳压器往往只考虑了MCU本身的需求额外挂载电机驱动时电压跌落会非常明显。我做过一个测试在舵机和电机同时动作的瞬间板载3.3V的输出电压会从3.3V跌到2.9V左右这个电压波动足够让DHT11通信超时。所以我的成品方案里电机和舵机都单独从5V取电MCU及其外设的3.3V由独立稳压器提供实测系统运行非常稳定。3. 软件系统设计与核心代码实现3.1 工程结构与HAL库配置软件部分使用STM32CubeMX生成工程框架Keil MDK作为编译环境。在CubeMX里需要使能的外设包括USART2语音指令接收、USART1调试日志输出、TIM2PWM输出、TIM3PWM输出、I2C1OLED、GPIO按键输入、DHT11数据引脚。时钟树配置为外部8MHz晶振经过PLL倍频到72MHz系统主频APB1总线时钟36MHzAPB2总线时钟72MHz。这里有一个容易忽略的坑TIM2和TIM3挂在APB1上APB1的定时器时钟是36MHz而APB2上的定时器时钟是72MHz。如果直接按照72MHz计算PWM频率和占空比输出会有50%的偏差。正确的做法是PSC和ARR的配置必须基于实际的外设时钟频率来计算。以TIM2为例配置PWM输出频率为1kHz。APB1定时器时钟36MHz所以PSC设为3536分频得到1MHz的计数频率ARR设为9991000计数最终PWM频率就是1MHz/10001kHz。占空比 CCRx / 1000CCR为500时就是50%占空比。这段逻辑我在代码注释里写得很详细实际修改灯光明暗时直接改CCR的值就行清晰直白。3.2 语音指令协议解析模块语音模块和主控之间的通信协议是整个软件系统里最关键的一环。协议帧格式定义为帧头0xAA、帧头0x55、命令字、校验字节、帧尾0x0F。其中校验字节取命令字节的取反保证一帧数据长度固定为5个字节方便解析。例如语音模块识别到“打开客厅灯”就会发送 AA 55 01 FE 0F识别到“关闭客厅灯”发送 AA 55 02 FD 0F识别到“打开窗帘”发送 AA 55 05 FA 0F。命令码的映射表在代码里用枚举定义可读性很好。USART2接收中断是系统的消息入口。我在中断服务函数里做的是最朴素的FIFO缓冲压入不做任何业务逻辑处理这个设计能保证语音模块连续发命令时不丢字节。主循环里定期调用协议解析函数从缓冲区中取出字节进行状态机解析。状态机的核心逻辑是四个状态等待帧头1、等待帧头2、等待命令字、等待校验和帧尾。任何一个状态匹配失败都会让状态机回到初始状态。我实际调试时发现最影响解析正确率的是“数据粘包”问题语音模块可能在主控上电时才连上串口缓冲里残留了上电前的垃圾字节导致帧结构错位。解决方案是在协议初始化时清空串口缓冲区同时状态机设计了超时重置机制超过50ms没收到完整帧就强制复位到等待帧头状态。// 语音指令协议解析状态机核心逻辑 uint8_t voice_parse_byte(uint8_t byte) { static uint8_t state 0; static uint8_t cmd 0; uint8_t crc 0; switch (state) { case 0: if (byte 0xAA) state 1; else state 0; break; case 1: if (byte 0x55) state 2; else state 0; break; case 2: cmd byte; crc ~byte; state 3; break; case 3: if (byte crc) state 4; else state 0; break; case 4: if (byte 0x0F) { process_voice_cmd(cmd); } state 0; break; default: state 0; break; } return state; }3.3 外设控制逻辑与状态管理系统运行状态用结构体统一管理避免各外设状态零散分布在代码里。这个结构体包含light_on、light_brightness、fan_speed、curtain_open、temperature、humidity等字段。状态管理的核心设计理念是语音命令只负责修改状态结构体外设硬件层不断读取状态并更新输出。举个例子语音命令“亮度调到百分之五十”解析后只更新light_brightness50和light_ontrue至于TIM2的CCR要改成500那是PWM控制函数去干的活。这个分层逻辑避免了命令解析和控制逻辑耦合在一起后期新增外设时非常方便。PWM控制函数实时刷新灯光和风扇两个通道的占空比。灯光亮度阀值表定义在常量数组里把0到100这101个整数映射到CCR值区间0到900保留10%的最低亮度防灭。这个细节是我实际测试时发现的当PWM占空比低于5%时很多LED灯珠会出现肉眼可见的闪烁这是因为电流过小时接近人眼临界融合频率保留10%的底亮度可以消除这个现象。3.4 OLED显示与状态刷新OLED显示模块用的是SSD1306驱动芯片的0.96寸屏幕I2C接口。驱动代码没有单独移植复杂的图形库而是直接写了一套精简的显示函数。核心思路是建立一个1KB的显存缓冲区128x64/8所有绘制操作都先修改缓冲区再通过一次I2C写操作刷新到屏幕。这样避免了一边写屏幕一边被语音指令打断导致的花屏问题。显示界面分三个区域第一行显示系统状态比如“SYS: RUN”第二行显示灯光和风扇状态第三行显示窗帘状态第四行显示温湿度数据。每个区域的刷新逻辑独立只有对应的状态变化时才触发局部刷新避免整屏刷新导致的I2C总线占用过长时间。我发现一个比较实用的经验OLED刷新频率不要太高人眼观察LED状态变化本来就有视觉暂留效应刷新频率设置在2Hz就够了。我实测过5Hz以上刷新时如果I2C总线上有其他设备或者走线较长偶尔会出现偶发的数据显示不全。降低刷新频率之后这个现象再也没出现过。3.5 串口调试日志系统调试日志是嵌入式开发里的隐形生产力工具我在这套代码里专门留了一个USART1作为调试日志输出通道。日志分了三个等级INFO等级输出系统上电信息和语音命令解析结果DEBUG等级输出外设状态变化ERROR等级输出协议解析失败信息。实际调试时这些日志帮了大忙。比如排查语音命令没响应的问题时通过日志可以看到是串口根本没收到数据还是收到了但协议解析失败了。有一次我遇到一个奇怪现象语音模块说“打开灯”偶尔会变成“打开风扇”查了半天发现是串口波特率两边配置不一致导致的误码把语音模块的波特率从9600改成115200后问题消失。日志里记录解析失败帧的原始字节这类问题定位起来非常快。4. Proteus仿真搭建与验证过程4.1 仿真环境准备与元件选型Proteus 8.10以上版本才支持STM32F103C8T6的仿真模型这是个最低版本要求。如果用的是老版本元件库里找不到这个型号会走不少弯路。新建工程后从元件库中需要添加的器件有STM32F103C8T6、LED-RED、RES电阻、CAP-ELEC电解电容、POT-HG电位器用来模拟风扇调速信号、SERVO舵机模型、LM016LLCD可选方案之一、SWITCH按键、OSCILLOSCOPE示波器用于观察PWM波形。Proteus里的STM32仿真模型不支持直接加载.hex文件它需要我们把Keil编译生成的.elf文件加载到MCU上。具体操作是双击仿真原理图中的STM32芯片在弹出的属性窗口中Program File选择Keil工程输出文件夹里的.axf文件或.elf文件CKS File选择芯片的CKS文件通常自动关联。这一步操作非常关键很多人在仿真时报no stm32 target found就是这里配置不正确。4.2 仿真电路搭建要点仿真环境下不需要把最小系统电路全部画出来但晶振、复位、BOOT引脚这些关键信号仍然要连。语音识别模块在Proteus里没有现成模型我用一个虚拟串口工具模拟它的行为。具体做法是在仿真中添加COMPIM虚拟串口组件把它的物理端口设置为某个COM口比如COM5然后在电脑上用串口助手打开同一个COM口手动发送语音指令对应的协议帧。这个替代方案在功能验证上是完全等价的——STM32代码层面根本不知道数据是来自真实语音模块还是来自串口助手它只关心串口收到的是什么字节。这个方法也适用于有真实硬件的读者在硬件联调之前先用串口助手模拟语音模块发指令把主控逻辑调稳定了再去接语音模块能节省大量排错时间。Proteus的舵机模型设计得很贴心给它对应的PWM信号舵机臂就会旋转。这时候在仿真里能看到舵机角度从0度变到180度的动画效果对展示系统功能有很大帮助。4.3 仿真结果与分析我完整跑了一遍仿真流程如下上电后OLED显示“SYS: RUN”DHT11温湿度数据开始周期刷新模拟环境温度稳定在27度左右。此时所有外设处于待机状态风扇不转、灯不亮、舵机在0度位置。通过串口助手发送“AA 55 01 FE 0F”打开客厅灯OLED第二行状态变成“LIGHT: ON”仿真中的LED_RED亮起电流表显示回路有2.1mA电流通过符合限流电阻的计算值。发送“AA 55 03 FC 0F”打开风扇示波器捕捉到PA6引脚上的PWM波形频率1kHz占空比在60%左右模拟风扇转速明显上升。调整占空比后波形占空比跟随更新。发送“AA 55 07 F8 0F”打开窗帘舵机模型从0度平滑转至180度OLED窗帘状态从“CLOSE”变为“OPEN”。舵机转动过程约1秒PWM信号周期为20ms脉宽从0.5ms渐变到2.5ms和真实SG90舵机的控制协议完全一致。整套仿真流程验证下来系统的功能逻辑是完整的。帧头校验、命令解析、外设控制的每个环节都能在仿真中正确执行这说明软硬件设计的一致性没有问题。5. 常见问题与排查技巧实录5.1 编译环境问题使用Keil MDK打开工程时最常见的报错是找不到芯片头文件。这个基本是Device Pack没装好正确做法是打开Pack Installer搜索STM32F1系列安装对应的Device Family Pack。很多新手下载了STM32CubeMX生成的工程结果Keil版本太老打不开高版本生成的工程文件建议直接用Keil 5.30以上的版本同时安装V5编译器兼容性会好很多。另一个常见的问题是为兼容C51和STM32双平台安装的KeilC51版本和MDK版本安装在同一个目录会导致两个环境互相覆盖文件。解决办法是分开两个目录安装不要共用。这个坑我在早期折腾坏过一次后来一直是分开装的再也没出过问题。5.2 下载调试问题使用ST-Link下载程序时如果出现“No STM32 Target Found”的报错排除顺序是检查ST-Link是否被电脑正确识别为USB设备、确认ST-Link和板子之间的SWD四根线SWDIO、SWCLK、GND、3.3V接线正确、按住板子复位键的同时点击下载按钮在下载开始瞬间松开复位这种“手动复位下载法”能解决不少连接不上的问题。如果ST-Link驱动安装后设备管理器里显示黄色感叹号大概率是驱动冲突或USB口供电不足。换一个USB口或者用USB HUB的独立供电口试验一下能解决大部分供电不足的问题。5.3 DHT11通信异常DHT11偶尔读不到数据是项目里最让我头大的问题。排查思路如下先确认时序。DHT11单总线协议对时序要求比较严格起始信号低电平至少18us响应信号低电平80us数据位高电平26us到70us表示070us表示1。STM32主频72MHz一个微妙大约是72个时钟周期如果直接在主循环里用HAL_Delay函数实现微妙级延时误差会很大。我的解决方案是改用DWTData Watchpoint and Trace模块做精确延时这是ARM内核自带的功能精度在几个时钟周期内效果非常好。再确认供电。DHT11对供电电压比较敏感如果供电跌落超过0.3V传感器可能直接不响应。我用万用表量过在舵机启动瞬间如果供电拓扑设计不合理3.3V电压会跌到2.8VDHT11直接掉线。所以DHT11的供电最好从主控稳压器独立拉线不要再经过其他负载。最后确认时序函数的实现。DHT11读取数据时主机读取每个数据位的过程是一段精细的时序操作编译优化等级过高时比如-O3编译器可能调整语句执行顺序导致时序出错。出现这种诡异问题时把优化等级降到-O0或-O1往往能立竿见影。5.4 语音模块误触发真实硬件调试中语音模块偶尔出现“没人说话它自己动了”的情况这是离线语音识别方案的通病。原因包括环境噪音中的某些频率分量恰好和命令词特征匹配唤醒词门槛设置过低或者模块灵敏度参数太激进。解决手段有三个。第一调低模块的识别灵敏度在SDK配置里把置信度阈值从默认值往上调5%到10%。第二增加唤醒词确认机制第一次唤醒后需要再喊一次确认词才执行操作。第三在硬件上增加语音活动检测VAD比如加一个麦克风信号调理电路只有检测到真实的语音包络才唤醒识别引擎。前两种方法对大多数场景已经够用。6. 项目扩展方向与个人经验总结6.1 从原型到产品化的几个扩展思路这个项目做完以后是天然的产品化起点有几个扩展方向值得尝试。第一个是无线化改造。把语音控制从板载扩展到房间层面可以加入ESP8266或ESP32模块作为WiFi通信节点STM32通过串口和WiFi模块交互实现对其他房间智能设备的中控。这个方案的优点是硬件成本仍然很低软件只是新增一个AT指令解析模块。但要注意如果走MQTT协议上云就涉及到网络安全性、设备注册、消息加密等额外工作复杂度会指数级增长。第二个是显示交互升级。当前使用的是OLED屏只能显示文本和简单图形。如果换成一款2.4寸TFT LCD屏比如ILI9341驱动就能显示完整的控制界面甚至可以做简单的触摸控制。软件上需要移植GUI库常用的有LVGL和u8g2。LVGL功能强大但占用Flash较多F103C8T6的64KB Flash会显得紧张读者需要做好代码裁剪建议优先考虑u8g2这种轻量方案。第三个是多房间多设备组网。当前系统控制的是单房间内的几个设备如果要做全屋方案有两种实现路径一是用CAN总线STM32F103C8T6本身就带CAN控制器只需加一个收发器芯片优点是实时性好、抗干扰强二是用RS485总线适合长距离布线缺点是速率较低。从嵌入式学习的角度CAN总线更值得深入研究这是工业控制里非常常用的总线协议。第四个是语音模型定制。如果使用的语音模块支持自定义命令词可以把“打开客厅灯”这类固定命令改成更自然的口语化说法比如“把灯调亮一点”“屋里有点闷开风扇”。这就需要前期采集更多语音样本做模型训练但能显著提升使用体验。6.2 代码重构与工程规范化建议这个项目我用的是裸机前后台架构主循环加中断。对学习来说足够了但如果你想把这个项目作为简历项目或产品原型有几个工程规范方面的工作值得投入。建议把外设驱动代码从业务逻辑中剥离开来分成bsp层board support package和应用层。bsp层只负责和硬件寄存器打交道比如DHT11驱动、OLED驱动、PWM初始化应用层负责业务逻辑比如语音指令解析、状态管理。这样分层的工程在后期维护和排错时优势非常明显我后来做项目基本都是这个结构。代码注释和命名规范也很关键。这个项目开源后有不少反馈有的读者说看不懂某段代码的逻辑大部分时候不是代码本身复杂而是命名太随意。我写项目代码时有一个习惯变量名至少能解释自己的业务含义比如light_brightness而不是lbprocess_voice_cmd而不是pvc。加上必要的头部注释和函数注释半年后再回来读代码你会感谢自己当初的坚持。6.3 实测过程中的一些感悟整套系统从画原理图、写代码、打样调试到最终跑通前前后后花了我大约两周的业余时间。中间踩过的坑上面问题排查部分已经写了大半这里再额外说几个印象深刻的。第一个是“先仿真后实板”的工作流。我先把整套逻辑在Proteus里跑通了再去做真实硬件这个过程帮我避免了一大堆低级错误。就算你已经有真实硬件了我也建议先在仿真里验证一遍代码逻辑——仿真环境下的信号波形观察比示波器接杜邦线方便太多了。第二个是关于资料整理和版本管理。整个项目过程中原理图、PCB、代码、仿真文件交替修改如果没有版本管理非常容易混淆。强烈建议学习使用Git哪怕只是本地仓库每次修改提交一次后面出了问题也能快速回滚到可用版本。第三个是关于复现的心态。如果你跟着这篇文章做出来的系统没有一次成功这是非常正常的事情。嵌入式开发的特点就是每个环节都有可能出现偏差同样的代码在不同环境下表现不同千万不要怀疑自己。把问题拆开一层一层排查大概率就是上面提到的那几类问题。6.4 最后一点补充关于项目开源我分享一句个人的体会开源的意义不只是把最终结果丢出来让人下载更在于把思考过程、取舍理由、踩坑经历一起分享出去。每一个技术项目都会遇到很多“不说就不明白、一说就很简单”的细节把这些细节写下来对后来者的价值可能比代码本身还要大。这个项目后续有读者做过B站视频演示也有读者在此基础上加了红外遥控和手机蓝牙控制每个人都能在原型上长出自己的想法。这正是开源硬件项目最让人欣慰的回报。如果你做完这个项目后有什么有趣的扩展或改进也欢迎分享出去让更多人看到不同的可能性。
返回列表