本篇主要结合代码落实,之前串口已经配置好的DMA方式。
一、首先我们把串口看成一个对象,它有属性、私有数据和方法;
每个串口都有名字属性;有初始化、发送、接收方法;还有一个私有数据(这个私有数据是每个串口都独立拥有的,例如Hal库函数接口,需要具体到是哪个串口)
私有数据:串口句柄指针、信号量、队列、数组
串口句柄指针:Hal库的函数调用接口需要传递,是哪个串口,因为所有串口都调用同一套函数
例如:启动DMA发送函数 HAL_UART_Transmit_DMA(data->handle, datas, len);
把串口句柄落实到串口对象的一个私有数据,本身也很合理;
信号量:用来协调是否已经发送完毕(串口的发送完毕时会调用中断,中断内部发出信号),在发送的地方会检查,串口是否正在发送还是已经发送完毕,如果已经发送完毕则可以顺利调用,否则可能要阻塞等待。所以这里需要一个信号量,目的就是检查串口是否已经忙完,可以进行发送;
队列:首先是DMA会悄悄自动把数据存入数组,然后触发中断,中断里面把数据存到队列,在任务里面查询队列的数据,并解码数据;
数组:DMA的使用需要传入一个目标地址,即DMA会不经过cpu,自动把外设串口的数据搬到内存数组里面,搬好后会触发中断。
串口私有数据是全局变量,也就是代码运行的时候前就已经
代码这样写兼顾考虑工程可能有多个串口
二、初始化:
初始化前先了解整体的框架背景:
设计了三个串口,除了名字和私有数据不一样,初始化、发送、接收方法都一样。
为了方便使用,用三个指针指向这三个设备
三个方法会根据传入的句柄不一样,启动不一样的动作
使用数组指针去管理三个串口设备
三、在指定的任务中调用以下(如taskUart)
调用(115200等参数没有使用,在CubeMx配置时就搞好了)
四、中断处理
发送完毕后,触发发送完毕回调函数,在回调函数里面,释放信号量。这样调用发送的地方就可以正常发送
接收完毕触发接收回调函数:这里有两种中断情况会触发:1、串口接收完毕;2、空闲中断触发
在回调函数内部做两个事情:1、把DMA的数据发到队列里;2、重新开启Idle中断
五、在任务中获取接收队列的数据,把数据获取到本地数组,满足一定数量后做解码操作
以上代码很多是结合韦东山老师的代码,做了修改和整理