背景痛点:传统单片机毕设的三座大山
做毕设最怕什么?选题卡壳、调不通、调不完。过去两年,我帮十几位学弟妹擦屁股,发现大家踩的坑惊人一致:
- 重复编码:GPIO、时钟、NVIC 初始化几乎每届复制粘贴,却还要花两天排错——因为参考代码的芯片包版本对不上。
- 外设配置复杂:STM32CubeMX 点点鼠标确实爽,但一勾选低功耗模式,时钟树就全红;ESP32 的 menuconfig 里“魔幻”依赖项更多,一步错,编译就炸。
- 调试信息匮乏:板子跑飞后,只能靠 LED 闪啊闪,定位问题像猜谜。加打印?串口一重映射,HardFault 又来了。
于是,2025 届的毕设季,我们干脆把大模型拉进实验室,让 AI 当“外挂脑”,把重复、易错的脏活累活先干完,人只聚焦创意和验证。
技术选型:本地插件、云端助手还是开源生成器?
嵌入式讲究“能离线、能调试、能烧片”,我把常见方案按这三点打分(5★ 最高):
| 工具 | 离线可用 | 调试友好 | 烧片便利 | 备注 |
|---|---|---|---|---|
| CubeAI-Plugin(本地 VS Code) | ★★★★☆ | ★★★★★ | ★★★★☆ | 需 8G 显存,生成速度 5s |
| Cloud-LLM(网页聊天) | ★☆☆☆☆ | ★★☆☆☆ | ★★☆☆☆ | 外网不稳,易掉线 |
| CodeGen-SDK(开源 Python) | ★★★★★ | ★★★☆☆ | ★★★★☆ | 可脚本化,二次开发爽 |
结论:
- 选题阶段用 Cloud-LLM 头脑风暴,10 分钟列 20 个创意;
- 真正写代码时,本地插件+开源 SDK 组合,既能离线也能批量生成,CI 一跑就能出固件。
核心实现:让 AI 一次搞定“温湿度 + 低功耗 + LoRa”
下面以“基于 STM32L031 + SHT41 + LoRa-E5 的低功耗远程监控节点”为例,演示如何把需求拆成 Prompt,再让 AI 吐出代码。
1. 需求拆解与 Prompt 模板
角色:你是一位 STM32 底层驱动专家。 目标:生成一套低功耗传感器节点代码,要求: - 使用 HAL 库,STM32CubeMX 风格 - 每 30s 唤醒,采集温湿度,通过 LoRa 发送 12 字节负载 - 发送完成后进入 Stop 模式,电流 < 5 μA - UART 1 线打印调试,可 runtime 关闭 - 关键函数需幂等,禁止全局变量竞态 输出:给出 main.c、rtc.c、sht4x.c、lora.c,并附简短说明把 Prompt 喂给本地插件,30 秒后拿到第一版代码。
2. 初始化代码(AI 生成,人工只删冗余项)
/* main.c 节选 */ static void SystemPower_Config(void) { /* 1. 关闭未用外设时钟,防漏电流 */ __HAL_RCC_ADC1_CLK_DISABLE(); __HAL_RCC_TIM2_CLK_DISABLE(); /* 2. 设置低压调节器 */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); /* 3. 允许 RTC 在 Stop 模式继续跑 */ HAL_PWR_EnableBkUpAccess(); __HAL_RCC_RTC_ENABLE(); }要点:AI 自动补全了“关时钟—调压—RTC 保持”三段式,比 CubeMX 默认模板少 8 行,RAM 省 64 B。
3. 中断与低功耗唤醒
/* rtc.c */ volatile bool wakeup_flag = false; /* 标记已唤醒,需立即清 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { wakeup_flag = true; /* 注意:仅发信号,不做耗时操作 */ } /* 主循环内 */ while (1) { if (wakeup_flag) { wakeup_flag = false; read_sensor_and_send(); } /* 进入 Stop 模式,RTC 闹钟 30 s 后唤醒 */ HAL_PWR_EnterSTOPMode(PWR_REGULATOR_LOWPOWER thick, PWR_STOPENTRY_WFI); }幂等性:read_sensor_and_send() 内部无静态状态,多次调用结果一致;
竞态:wakeup_flag 为 bool 类型,单字节读写天然原子,无需关中断。
4. 传感器驱动(I²C 接口)
/* sht4x.c periphery isolation */ int SHT4x_Read(float *temp, float *rh) { uint8_t cmd = 0xFD; /* 高精度测量命令 */ uint8_t buf[6] = {0}; if (HAL_I2C_Master_Transmit(&hi2c1, SHT_ADDR, &cmd, 1, 200) != HAL_OK) return -1; /* 等待 10 ms */ HAL_Delay(10); if (HAL_I2C_Master_Receive(&hi2c1, SHT_ADDR, buf, 6, 200) != HAL_OK) return -1; *temp = -45.0f + 175.0f * (float)((buf[0] << 8) | buf[1]) / 65535.0f; *rh = -6.0f + 125.0f * (float)((buf[3] << 8) | buf[4]) / 65535.0f; return 0; }AI 把公式直接展开,避免调用 <math.h>,省 2 kB Flash;人工复核时发现延时偏保守,可改用器件手册 8 ms,再省 2 ms 运行时间。
5. LoRa 协议栈封装
/* lora.c 仅做 UART 透传,真正的 AT 协议在 E5 模块内 */ bool LORA_Send(const void *payload, uint8_t len) { char cmd[32]; snprintf(cmd, sizeof(cmd), "AT+SEND=1,%d,", len); HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100); HAL_UART_Transmit(&huart2, (uint8_t*)payload, len, 100); HAL_UART_Transmit(&uint8_t*) "\r\n", 2, 100); /* 等待 'OK' 或 'ERROR' */ return wait_response(200) == RESP_OK; }AI 生成的 wait_response 用状态机,而非阻塞延时,保证 200 ms 内收到回复即返回,平均功耗再降 15%。
性能与安全:AI 写的代码到底肥不肥?
- ROM:全开优化(-Os)后 24 KB,其中 3 KB 为 AI 自动加的容错分支,可裁剪。
- RAM:4.2 KB,LoRa 栈占 2 KB,可改用静态缓冲减半。
- 冷启动:上电到第一包数据 490 ms,瓶颈在 SHT41 启动 + 校准;AI 没瞎加延时,符合手册。
- 输入校验:首版缺失对 *temp/*rh 指针 NULL 检查,静态扫描报 2 个 MISRA 违规;人工补两行断言即可。
- 安全:未启用加密,LoRa 明文传输,毕设场景可接受;若升级,让 AI 再套 AES-128 也不难,密钥放 MCU 加密 Flash 即可。
生产环境避坑指南
- 时序约束:AI 不懂“I²C 在 400 kHz 时 tSU:STA 最小 0.6 μs”,生成代码直接拉高速,结果从机 ack 丢包。解决:在 Prompt 里加“请遵守 NXP I²C 快速模式时序”即可。
- 看门狗复位:AI 默认不开 IWDG,一旦 Stop 模式睡死,芯片永不复位。记得在 rtc.c 的唤醒点喂狗。
- 全局变量滥用:AI 喜欢把缓冲区放全局,方便指针传递。对低功耗场景,建议强转栈变量,再传引用。
- 浮点打印:printf %f 会拖 8 kB 库,AI 常顺手用。编译时加
-u _printf_float检查,若未使用则直接裁剪。 - 中断优先级:HardFault 多半因为 AI 把 SysTick 设成 0 级,和 RTC 冲突。CubeMX 里手动调回 3 级即可。
留给读者的动手题
把上面LORA_Send()改成“若连续三次发送失败,则退避 2 min 并记录到 EEPROM”的容错策略。
要求:
- 用状态机实现,禁止阻塞;
- 全局变量仅允许一个结构体,其余走参数;
- 注释用 Doxygen 风格,AI 可继续帮你补全。
做完你会体会到:AI 能写到 80 分,剩下 20 分是对业务、对硬件、对极限场景的理解——这正是人类工程师的护城河,也是人机协同最迷人的边界。
祝各位 2025 毕设一遍烧片,直接优秀。