昨天深夜调一个嵌入式驱动的时候,我又遇到了那个老问题——I2C从设备在连续读写时偶尔会丢数据。示波器抓波形看起来都正常,但每几百次操作就会有一次数据对不上。这种玄学问题最头疼,寄存器配置翻来覆去检查了三遍,硬件同事咬定电路没问题,只能从软件时序上找突破口。
就在我准备手动调整延时函数参数,一遍遍试错的时候,突然想起刚拿到测试权限的Claude Code。抱着试试看的心态,我在编辑器里写下一段描述:
“帮我写一段STM32的I2C恢复函数,当前遇到从设备偶尔无响应的情况。需要先发送STOP条件,然后拉低SCL产生9个时钟脉冲,最后重新初始化I2C外设。硬件是STM32F407,使用HAL库。”
十秒后,生成的代码出现在屏幕上:
void I2C_Bus_Recovery(GPIO_TypeDef* scl_port, uint16_t scl_pin,
GPIO_TypeDef* sda_port, uint16_t sda_pin) {
// 先转成GPIO模式把总线控制权拿回来
// 这里踩过坑:直接操作外设寄存器比用HAL快,关键时刻得自己来
I2C1->CR1 &= ~(I2C_CR1_PE);
// 配置成开漏输出模式,注意别忘记使能时钟
GPIO_InitTypeDef gpio_init = {0};
gpio_init.Mode = GPIO_MODE_OUTPUT_OD;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
// 先确保SDA为高,这是起始条件
HAL_GPIO_WritePin(sda_port, sda_pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_SET);
delay_us(5); // 这个延时很关键,短了器件反应不过来
// 核心恢复逻辑:如果SDA还被卡在低电平,就通过SCL时钟把它“挤”出来
for(int i = 0; i < 9; i++) {
if(HAL_GPIO_ReadPin(sda_port, sda_pin) == GPIO_PIN_SET) {
break; // 总线已经释放了,赶紧溜
}
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_RESET);
delay_us(5); // 别写死循环,一定要加延时!
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_SET);
delay_us(5);
}
// 重新初始化I2C,这里记得把参数填对
MX_I2C1_Init();
}
最让我惊讶的不是代码本身,而是它自动添加的那些注释——完全就是我平时写代码的思考方式。那个“这里踩过坑”的标注,简直像是我自己写上去的。更关键的是,它知道在关键位置加延时,还特意提醒“别写死循环”,这种细节只有真正调过I2C总线的人才会注意。
自然语言编程到底是什么? 我的理解是:它不是你对着AI说“给我写个操作系统”就能变出完整代码的魔法,而是像跟一个经验丰富的同事结对编程。你说清楚场景、约束条件和真实需求,它帮你搭框架、填细节、避坑。你仍然需要懂业务逻辑,但不用再花时间查手册找API,或者写那些重复的样板代码。
下午我把这个恢复函数加到超时处理里,重新跑压力测试。两万次连续读写,零丢包。问题解决了,但更大的收获是工作流程的变化——我现在会把调试时遇到的问题用自然语言描述出来,让Claude Code生成几种可能的解决方案,然后基于它的输出快速验证。这比在搜索引擎里翻三年前的论坛帖子高效得多。
几个实战建议:第一,描述问题要像跟同事交接工作那样具体,别只说“I2C有问题”,要说“从地址0x50的EEPROM在连续写第128字节时无ACK”;第二,生成的代码一定要过一遍脑子,特别是硬件相关部分,AI不知道你的PCB布局和负载电容;第三,复杂功能拆分成多个小指令,先让AI写框架,再逐步填充细节。
调试嵌入式系统十几年,我习惯了和机器打交道,现在突然多了个能理解自然语言的编程伙伴,感觉像是从命令行界面突然跳到了图形界面。它不会取代工程师,但会重新定义我们解决问题的方式——从“怎么写代码”转向“怎么描述问题”。这大概就是自然语言编程最本质的东西:让机器理解我们的意图,而不仅仅是执行我们的指令。

214

被折叠的 条评论
为什么被折叠?



