引言:最近在做串口实验,总结了两种串口收发的方法,第一种是用定时器定的,第二种是使用空闲中断。
第一种 使用定时器
具体做法是在串口接收数据时启动定时器,每接收一帧数据要复位定时值以保证定时器不会溢出。根据波特率计算出大概什么时候接收数据完成,什么时候,缓存数组溢出。比如波特率是115200bit/s,就是1s钟传输115200位,每传输一位就是0.00868ms,一个字符占8位加上起始位和停止位一共是10位,所以每传输一个字符大概需要0.086ms,所以根据传输的数据帧设置传输完成的时间判定,比如想一次传输100个字符,就是1000位,需要时间是8.6ms,可以将传输完成时间设置成20-30ms,因为字符数组的最大长度是255,所以溢出时间是255*0.0868=22.134ms,可以将溢出时间设置成50ms,下面就是CubeMx配置和代码的编写了
1、打开CubeMx选择好单片机芯片后,配置SYS和时钟RCC
![](https://img-blog.csdnimg.cn/d8a8d68cffb545f6ad3128e5bd9c532b.png)
![](https://img-blog.csdnimg.cn/a92958cd03d2426e90b3e655b2b9e9b0.png)
2、配置串口,最后使能中断
![](https://img-blog.csdnimg.cn/5091e4ffffb94c3c8997515c332231fd.png)
3、配置定时器,定时时间为1ms,并使能中断
![](https://img-blog.csdnimg.cn/20d402109e184377be37c122f2ee293c.png)
![](https://img-blog.csdnimg.cn/e5be7f9a15aa402999c594e43e726408.png)
4、生成代码后进行代码编写
在main.c中定义变量和一些函数,对于fputc函数要 #include <stdio.h> 不然会报错
![](https://img-blog.csdnimg.cn/6782d82e34fb4400b6f6e6fbec9c35cc.png)
![](https://img-blog.csdnimg.cn/5b92000c399c4f73856dfd6c27290486.png)
在main.c中使能定时器和串口接收中断
![](https://img-blog.csdnimg.cn/738522d3c4824029aad366f0bcf7ac52.png)
在main.c中重写串口接收中断回调函数,当接收完成时,a=1
![](https://img-blog.csdnimg.cn/cb387daa4f8246c19d9eb8fcf00bfefe.png)
在main.c中的定时器回调函数中编写相应的代码,当定时器计时到50ms时,表示缓存数组溢出
![](https://img-blog.csdnimg.cn/4558d8df50564d8b9c2c7eb7330ab682.png)
最后就是在while循环里的代码编写,当a=1时(即数据接收完成),将数据打印到串口,并将a赋值为0
![](https://img-blog.csdnimg.cn/add4a157d9e94c7eb77d4fcbc7298b17.png)
下载程序测试,如果发送的太过频繁,会有数据粘连
![](https://img-blog.csdnimg.cn/d531edfa6c4e46e79f65a8845664d62f.png)
第二种 使用空闲中断进行串口收发
IDLE空闲中断是在监测到数据接收后(即串口的RXNE位被置位)开始检测,当总线上在一个字节对应的周期内未再有新的数据接收时,控制触发空闲中断的IDLE位被硬件置1, 便会激发一个空闲中断,在中断处理函数中,我们可以解析接收到的不定长数据。下面进行CubeMx配置和代码编写。
1、打开CubeMx选择好单片机芯片后,配置SYS和时钟RCC
![](https://img-blog.csdnimg.cn/d8a8d68cffb545f6ad3128e5bd9c532b.png)
![](https://img-blog.csdnimg.cn/a92958cd03d2426e90b3e655b2b9e9b0.png)
2、配置串口,最后使能中断
![](https://img-blog.csdnimg.cn/5091e4ffffb94c3c8997515c332231fd.png)
![](https://img-blog.csdnimg.cn/dbfe20ca25f44a12a642af549a23a06c.png)
![](https://img-blog.csdnimg.cn/bb185211a90b4dc88a2a340ecaf72a8a.png)
3、生成代码后进行代码编写
main.h中添加
![](https://img-blog.csdnimg.cn/a4d03ebaf3454357a12838a6c137657f.png)
main.c
![](https://img-blog.csdnimg.cn/0944c9b7422f4b2ab8ca387c68e28ebb.png)
main函数中注意确保DMA初始化函数放在串口初始化之前,并在串口初始化之后使能IDLE中断、开启串口DMA接收
![](https://img-blog.csdnimg.cn/0c4e02a602a14a9394263e17aa849bee.png)
在/* USER CODE BEGIN 4 */下添加用户自定义IDLE空闲中断回调函数
![](https://img-blog.csdnimg.cn/559ea17c4d62455e8530d3520b94a9ab.png)
由于hal库中没有定义IDLE空闲中断的中断处理函数,需要用户自行定义打开stm32f1xx_it.c,找到void USART1_IRQHandler(void)函数,并添加如下代码:
![](https://img-blog.csdnimg.cn/77fbb6d4451643f1b646fdb984162344.png)
下载程序测试
![](https://img-blog.csdnimg.cn/649e76139e1c446591342cf990bebcdc.png)
总结:第一种定时器的串口收发,在发送数据频繁的时候,会有数据粘连的情况发生。第二种在发送频繁的时候没有出现数据粘连的情况,如果使用到了freertos,则往往选择第一种定时器的,因为第二种不能做临界保护。
第一次发博客,也算是单片机小白,如果有说的不对的地方,还请指教!感谢!
参考博客:
串口接收不定长数据的几种方式_苏提春晓_的博客-CSDN博客串口IDLE空闲中断+DMA实现接收不定长数据基于stm32cubemx_m0_58976369的博客-CSDN博客_串口空闲中断加dma接收