STM32 ADC读取电压和USART串口输出实践日志
ADC读取电压和USART串口输出
这几天做实习程序开发,遇到了一些和ADC和USART的相关问题,做个记录。如果有错误也请各位大佬批评指正!
环境
- 芯片型号:STM32G070
- CubeMX生成Keil工程后使用VSCode配合Keil Assistant插件共同编程并build下载
- SSCOM、波特律动助手(
serial.keysking.com
)
需求很简单:
- 小灯以640ms为周期闪烁
- 每20ms对芯片上链接的三个引脚Temp、Ref、Sig读取电压值
- 将读到的电压值通过USART4串口输出到外界
初步的实现思路
首先,不能使用STM32学习初期“HAL_Delay()”的方式实现定时功能。否则“何时解决冲突”、“如何计时”、“在哪里完成这些功能”这种问题很难解决。
可以使用STM32的TIM定时器来实现这个功能。定时器在内部时钟计时达到设定值之后便会触发中断处理函数,在中断处理函数中完成我们需要实现的功能即可。
由于存在两个定时功能,我们需要两个定时器。我选择了TIM16和TIM17,上网查说这两个是通用定时器(General Purpose)。之后在中断处理函数中加入触发来源的判断,来自16即是LED的需求,来自17就是另一个。
if (htim == &htim16) // LED Flashing!
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
else if (htim == &htim17) // Read Pin, and sent it through Port(USART)
{
// ...
}
开始遇到问题
第一个遇到的问题就是程序无法下载。Target DLL has been cancelled.
尝试了各种方法:
- 下载驱动
- 调节Keil项目设置(J-Link等)
都不太好使。最后在网上找到这样的解决方法:
找到MDK-ARM/J-LinkSettings.ini
,把Device
的值改为Cortex-M0+
,成功烧录!
Device="Cortex-M0+"
第二个问题,串口助手接收不到发送的数据
到底是硬件配置有问题,还是CubeMX工程参数有问题,抑或是代码逻辑有问题呢?在遇到问题初期,我不能确定是哪一种,于是我只能一一排查。(最后证明三者都有问题)
首先在硬件上,直接说结论。Waveshare的USB to RS232/485/TTL那个小开关应该拨到“3.3V”档,否则没有任何输出。同时,两边的TXD/RXD线应该交叉连接而不是对应连接。
改正之后,发现开始有输出了,但是输出乱码。最后发现是缺共地线。也就是说,两者的地线没有接到一起导致乱码。
此时,测试信息已经没有问题了。
Hello World!
但是继续测试发现电压输出仍然是乱码。
HAL_UART_Transmit_IT(&huart4, (uint8_t *)voltageStr, strlen(voltageStr));
太奇怪了,几乎同样的位置,输出两个字符串竟然一个乱码一个正常?
之后我把这句代码放在函数的不同位置进行测试,又惊奇地发现:只有这句代码在最后一行的时候会乱码。而业务逻辑已经决定了这句代码在最后一行,因为一定是最后串口输出。
于是我想到:中断模式的串口输出只开启输出流程,但是不监控其是否结束,而只是在结束时触发一个中断处理函数。而这里输出的字符串voltageStr
是一个局部变量!因此,如果代码在最后一句,函数马上就会结束,变量也会随着函数一起被析构。你传过去的是一个地址,那么USART通过地址寻址的时候当然是一个脏数据。
原因明晰了,解决方法自然就出来了。与其自己想办法等待传输结束之后再结束函数,倒不如直接使用阻塞模式传输数据。阻塞模式会让CPU一直处在忙的状态,直到传输结束,那句代码结束一定是传输结束,因此函数一定在代码执行结束之后结束。自己写一个等待本质上还是让CPU等,此时已经失去了中断模式CPU利用率高的优势,没有任何必要。
于是,在CubeMx里面关闭中断,最后将代码改成阻塞模式:
HAL_UART_Transmit(&huart4, (uint8_t *)voltageStr, strlen(voltageStr), 20);
这样,输出的问题就解决啦。
关于ADC的使用
这里反而几乎没有遇到问题。只是,当时在CubeMX里面似乎无法打开连续扫描模式,后来发现是要求启用通道数大于1的时候才允许打开连续扫描。
- 点赞
- 收藏
- 关注作者
评论(0)