计算机系统应用教程网站

网站首页 > 技术文章 正文

基于STM32的串口与DMA的完美组合(上)

btikc 2024-10-12 11:45:36 技术文章 14 ℃ 0 评论

在嵌入式开发中,串口通信是产品各功能模块间信息交互的最常用手段,包括单片机与上位机的通信。STM32的串口+DMA的配合使用在做协议解析时简直不要太完美,再加上C语言结构体与指针的使用,串口通信将变得格外简单。

DMA,中文翻译即内存直接存取,而无需CPU参与。初学者习惯使用串口接收完成中断的方式来接收串口数据,对于大数据量时就显得力不从心了,而且做协议解析时将变得相当复杂。而我在项目开发中,已经将串口驱动做成了固定模块,对应于不同的外部串口设备,直接重新封装调用即可。下面来分析一下串口DMA的具体实践。

我这里就以STM32F103ZET6这款芯片的USART2为例来进行说明,编译器使用keil5。这款芯片有两个DMA控制器,查阅芯片开发手册可知,USART2_TX和USART2_RX均是挂在DMA1控制器上,分别使用其通道7和通道6。由下图可以看出:

在初始化USART2外设之前,我们先整理一下思路。首先,需要明确我们需要实现的功能:1.串口+DMA 发送数据包 2.串口+DMA接收数据包 3.发送完成和接收完成状态判断。然后需要注意的就是选择合适的中断方式来接收数据。我这里使用的是串口空闲中断的方式来接收数据,可能对于某些要求比较苛刻的场合不太适用,比如数据量特别大并且需要容忍数据包断帧的异常的情况,但对于一般场合完全可以满足要求,而且在不是特别苛刻的情况下也可以通过补充协议规范,解码错误要求重传等方法来尽量避免上述问题。

这样,我们先定义一个结构体,其成员变量包含接收和发送缓存,接收和发送数据量大小,接收和发送完成标志。如下图所示:

然后进行相关的初始化,注意,下面代码中我对USART2端口做了重映射:

可以清晰的看出,我们只需将对应的缓存地址赋值给DMA_InitStructure.DMA_MemoryBaseAddr变量,设置好DMA_InitStructure.DMA_BufferSize为我们开的缓存大小即可。

DMA_InitStructure结构体中其他的成员变量应该很容易理解,这里不再讲解。然后我们就可以实现串口发送数据包函数,如下图:

备注很详细,应当不难理解,这里带有两个参数,一个是发送缓冲区地址,一个是发送的字节数。如果我们想实现类似与printf()这样的函数来发送字符串,可以将上面的代码稍作修改,如下图:

发送函数比较简单,接下来我们就要去处理串口中断来接收数据了,在串口中断中只需判断是否是串口空闲中断标志置位,是则先清除中断标志,其实就是要接收一次串口数据便会自动清除标志。然后关闭DMA对应通道,计算并获得DMA接收到的数据包大小(也就是用我们设置的缓冲区大小减去剩余的数据量),再重新设置DMA接收缓冲大小,再使能DMA相应通道,最后置位接收完成标志即可。具体实现如下图所示:

好了,到这里,基本上就大功告成了。我们只需要在主函数中不断的去判断接收完成标志是否置位,如果被置位就可以去解析UsartDataHandle2.RxBuf中的数据了,然后实现相应功能,但是不要忘记将接收完成标志重新复位,以为下一次的通信做准备。

以上代码完全可以封装成一个固定模块,当我们实际项目中应用时可以进行再次封装调用,这里暂且不提,下一期再以实际应用来详述!

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表