“嵌入式开发代码复用,你咋玩才省心?”
嵌入式开发老写重复代码,烦得要命。你们咋搞代码复用的?模块化封装一顿秀,还是抄个HAL库改改?快来聊聊你的代码复用妙招,或者讲讲哪次代码抄来抄去抄出Bug的糗事!
嵌入式开发里老重复造轮子,代码写得手抽筋,还容易埋雷!我跟你唠唠我的代码复用骚操作,顺便吐槽下抄代码翻车的糗事。
其实代码复用的“骚操作”是非常的常见的,又想用便宜的IC,但是又想把IC的资源全部都用上,就会出现很多利用的现象,而且很多都会封装成模块。
之前写过个GPIO驱动模块,把ADC采集、PWM输出、中断触发这些功能全封装成接口。用GPIO_Init()初始化引脚,ADC_Read()读电压,GPIO_Set()当普通IO输出,这样做有的是时候功能稍微没有配合好,就会出现很多复杂的用法,会增加蛮多的代码量而且当自己写好的时候也会感觉 自己有一些提升,但是如果没有配合好就会出现一定有BUG,就会让自己拼命的在DUG,找问题解决问题。
这个也有一定的好处,如果封装成模块,那出现问题时就直接模块,而且换项目时直接拖模块,改个引脚号就能用,省得每次翻手册查寄存器。 不过用STM32的HAL库时,发现它的ADC初始化代码太啰嗦,有经验的工程师都会有自己的想法,我就封装了个ADC的模块,把配置参数塞进去,一键生成驱动。
当需要改模块和库时,肯定会出问题改库得谨慎!比如把ADC引脚复用成普通IO时,得先调HAL_GPIO_DeInit()释放资源,不然下次用ADC会炸,配合不会就会严重影响工作。有次项目里,ADC采集和普通IO口复用同一个引脚。调试时发现ADC读数不稳定,排查半天发现是GPIO模式和ADC模式切换时引脚状态冲突——ADC采样时引脚被其他模块偷偷当IO口拉低了电压,导致采样值跳变。最后增加了一个加锁机制,确保同一时间只有一种模式生效。
// 全局管理器实例
PinMuxManager io_manager;
void ADC_Task(void) {
if(PINMUX_SafeSwitchMode(&io_manager, PIN_ADC_MODE, 100) == HAL_OK) {
HAL_ADC_Start(io_manager.adc_handle);
if(HAL_ADC_PollForConversion(io_manager.adc_handle, 10) == HAL_OK) {
uint16_t value = HAL_ADC_GetValue(io_manager.adc_handle);
printf("ADC Value: %d\n", value);
}
PINMUX_SafeSwitchMode(&io_manager, PIN_FREE, 100); // 释放引脚
}
}
void GPIO_Task(void) {
if(PINMUX_SafeSwitchMode(&io_manager, PIN_GPIO_OUT_MODE, 100) == HAL_OK) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
HAL_Delay(10);
PINMUX_SafeSwitchMode(&io_manager, PIN_FREE, 100); // 释放引脚
}
}
// 安全异常处理
void HardFault_Handler(void) {
PINMUX_ForceUnlock(&io_manager); // 强制解锁
while(1);
}
|