最近两个月我一直在折腾一件事:让各种大模型给我生成嵌入式代码,然后原封不动烧进板子里看看到底能不能跑。测了三块板子,STM32F103C8T6、ESP32-S3 DevKitC-1、还有一块国产的CH32V307,前后折腾了大概37个小时,烧录失败、编译报错、跑飞死机的次数加起来超过60次。这篇文章不讲什么“AI改变嵌入式开发”的大道理,就讲讲我踩过的坑和最后怎么绕过去的。
第一次让AI写GPIO翻转就翻车
我用的第一块板子是STM32F103C8T6最小系统板,手头正好有ST-Link V2。我的操作很简单:打开某国产大模型对话窗口,输入“用STM32标准外设库写一个PB12引脚每隔500ms翻转的代码,包含完整main.c和所有初始化”。模型10秒钟就吐出了80多行代码,看起来结构完整、注释齐全,我复制到Keil MDK 5.38里编译,0 Error 0 Warning,直接烧录。结果呢?板子上的LED纹丝不动。我拿万用表量PB12,电平一直是3.3V,根本没翻转。排查了40分钟才发现问题:AI给的代码里RCC_APB2PeriphClockCmd只开了GPIOB时钟,但PB12属于GPIOB没错啊——等等,它把RCC_APB2Periph_GPIOB写成了RCC_APB2Periph_AFIO,时钟开错了外设,GPIOB压根没上电。这种错误编译器不会报,因为宏定义都存在,但硬件就是不动。更坑的是它还在注释里写“使能GPIOB时钟”,注释和代码对不上,我第一遍扫过去完全没注意。
ESP32上AI把引脚号写成了寄存器地址
第二块板子是ESP32-S3,用ESP-IDF v5.1.2。我让另一个模型生成“ESP32-S3上GPIO4输出PWM呼吸灯”的代码,用的是LEDC外设。模型给的代码用了ledc_timer_config和ledc_channel_config,看起来挺正规。我idf.py build编译通过,flash烧录也成功,但串口监视器里每200ms打印一次“LEDC init OK”,灯就是不亮。这次我学乖了,直接翻ESP-IDF的ledc例程对比,发现AI把ledc_channel_config里的gpio_num设成了4没错,但intr_type写成了LEDC_INTR_DISABLE——这没问题,问题是它把speed_mode设成了LEDC_HIGH_SPEED_MODE,而ESP32-S3的LEDC只有LOW_SPEED_MODE可用,HIGH_SPEED_MODE在S3上根本不存在。编译器居然没报错,因为枚举值在头文件里定义了,只是硬件不支持。我手动改成LOW_SPEED_MODE后灯立刻开始呼吸。这个坑让我意识到,AI训练数据里混了大量ESP32老型号的代码,它根本分不清S3和普通ESP32的外设差异。
国产RISC-V板子上的内存踩踏事故
第三块是CH32V307,用MounRiver Studio编译。我让模型生成“用硬件I2C读取AT24C02 EEPROM数据并通过串口打印”的代码。模型给了完整工程结构,我复制进MRS后编译报了3个错误,都是寄存器名字对不上——CH32V307的I2C寄存器叫I2C1->CTLR1,AI写的是I2C1->CR1,这是STM32的叫法。我手动改了寄存器名后编译通过,烧录运行,串口果然打印出了EEPROM里的数据,前16个字节全是0xFF,正常,新片子嘛。但我写了一段测试数据进去再读,读出来的全是乱码。查了2小时发现AI在I2C初始化里把ACK使能位写反了,本该置1的ACK位它清了零,导致每次读一个字节后主机不回应ACK,从机直接释放总线,后续读到的全是无效数据。更隐蔽的是它把延时函数写成了for循环空转,在144MHz主频下延时严重不足,I2C时序完全错乱。我换成官方库的Delay_Us后数据才正常。这一趟下来光调试I2C时序就花了4个多小时。
为什么AI写的代码“看起来对但跑不了”
三次实测下来我总结出几个共性原因。第一,AI对芯片型号的颗粒度不敏感,你说“STM32F103”,它可能给你混入F4系列的寄存器操作;你说“ESP32-S3”,它照样塞HIGH_SPEED_MODE进去。第二,嵌入式代码的正确性依赖大量编译器不检查的隐式约束,比如时钟必须使能、引脚必须配置为复用模式、中断优先级不能冲突,这些在C语言语法层面全是合法的,但硬件行为完全错误。第三,AI倾向于生成“标准答案”式的代码结构,但真实芯片的勘误手册里经常有反直觉的限制,比如某些寄存器必须按特定顺序写、某些位读出来和写进去含义不同,这些细节训练数据里极少出现。我统计了一下,三次生成的代码里,编译能通过的占70%,烧录能成功的占50%,但真正按预期工作的只有1次,就是CH32V307那次改完寄存器名和ACK位之后。也就是说AI代码的“一次通过率”在我这儿是0%。
我现在怎么用AI写嵌入式代码
踩完这些坑我调整了用法。现在我的流程是:先让AI生成代码框架和注释,但所有外设初始化函数必须对照官方标准外设库或HAL库的例程逐行核对,特别是时钟使能、引脚复用、中断配置这三块,我做了个检查清单,每次至少花15分钟过一遍。对于ESP32这类型号差异大的芯片,我会在提示词里明确写“使用ESP-IDF v5.1.2,目标芯片ESP32-S3,只使用LOW_SPEED_MODE”,把版本号和限制条件喂给它,生成质量明显提升。另外我养成了用逻辑分析仪抓I2C和SPI波形的习惯,AI代码跑不通的时候,看波形比看代码快得多。最后说句实在的,AI生成嵌入式代码不是不能用,但你得把它当成一个打字很快但没摸过硬件的实习生,它写的每一行外设操作你都得自己心里有数。