计算机系统应用教程网站

网站首页 > 技术文章 正文

STM32串口DMA若干问题,记得保存收藏评论

btikc 2024-10-12 11:44:59 技术文章 7 ℃ 0 评论

STM32之串口DMA接收不定长数据

引言

在运用stm32或者其他单片机的时候,会经常运用到串口通讯,那么怎么样有效地接管数据呢?假设这段数据是不定长的有怎么样高效接管呢?

同学A:数据来了就会进入串口中断,在中断中读取数据就行了!
中断就是打断程序正常运行,怎么样能保证高效呢?经常把主程序打断,主程序还要不要运行了?
同学B:串口可以配置成用DMA的方式接收数据,等接收完毕就可以去读取了!
这个同学是对的,我们可以使用DMA去接收数据,不过DMA需要定长才能产生接收中断,怎么接收不定长的数据呢?

DMA简介

题外话:其实,上面的问题是很有必要思考一下的,不断思考,才能进步。

///插播一条:我自己在今年年初录制了一套还比较系统的入门单片机教程和毕业设计指导,想要的同学找我拿就行了免費的,私信我就可以哦~点我头像白色字体加我也能领取哦,记得口令小哥///

什么是DMA

DMA全称Direct Memory Access,即直接存储器访问

DMA 传输将数据从一个地址空间复制到另外一个地址空间。CPU只需初始化DMA即可,传输动作自身是由 DMA 控制器来达到和完成。典型的例子就是挪动一个外部内存的区块到芯片内部更快的内存区。这样的操作并没有让处理器参与处理,CPU能够干其他事情,当DMA传输完成的时候产生一个中断,告诉CPU我已经完成了,其次CPU知道了就能够去处理数据了,这样子提高了CPU的利用率,由于CPU是大脑,主要做数据运算的工作,而不是去搬运数据。DMA 传输对于高效能嵌入式系统算法和网络是很重要的。

在STM32的DMA资源

STM32F1系列的MCU有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道,DMA2有5个通道,每个通道专门用来管理来自于一个或者多个外设对存储器的访问请求。还有一个仲裁器来帮助协调各个DMA请求的优先权。

而STM32F4/F7/H7系列的MCU有两个DMA控制器总共有16个数据流(每个DMA控制器8个),每一个DMA控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共能够有多达8个通道(或称请求)。每个通道都有一个仲裁器,用于处理 DMA 请求间的优先级。

DMA接收数据

DMA在接管数据的时候,串口接管DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上没需做任何事情,只有在初始化配置的时候设置好配置就能够了。等到接管到数据的时候,告诉CPU去处理即可。

判断数据接收完成

那么问题来了,怎么了解数据是否接收完成呢?

其实,有很多方法:

对于定长的数据,只须要判断一下数据的接管个数,就知道是否接管完成,这个很简略,暂不探讨。

对于不定长的数据,其实也有好几种方法,麻烦的我肯定不会介绍,有兴趣做复杂工作的同学能够在网上看看他人怎么做,下面这种方法是最简略的,充分利用了stm32的串口资源,效率也是非常之高。

DMA+串口空闲中断

这两个资源配合,简直就是无敌啊,无论接收什么不定长的数据,管你数据有多少,来一个我就收一个

可能很多人在学习stm32的时候,都不知道idle是啥东西,先看看stm32串口的状态寄存器:

当我们检测到触发了串口总线空闲中断的时候,我们就知道这一波数据传输完成了,其次我们就能得到这些数据,去进行处理即可。这种方法是最简略的,根本不须要我们做多的处理,只须要配置好,串口就等着数据的到来,dma也是处于工作状态的,来一个数据就自动搬运一个数据。

接收完数据时处理

串口接管完数据是要处理的,那么处理的步骤是如何呢?

暂时关闭串口接管DMA通道,有两个理由:一.防止后面又有数据接管到,产生干扰,由于此时的数据还未处理。二.DMA须要重新配置。

清DMA标志位。

从DMA寄存器中获取接管到的数据字节数(可有可没)。

重新设置DMA下次要接管的数据字节数,注意,数据传输数量范围为0至65535。这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。通道开启后该寄存器变为只读,指示剩余的待传输字节数目。寄存器内容在每次DMA传输后递减。数据传输完毕后,寄存器的内容或者变为0;或者当该通道配置为自动重加载模式时,寄存器的内容将被自动重新加载为之前配置时的数值。当寄存器的内容为0时,没论通道是否开启,都不会发生任何数据传输。

给出信号量,发送接管到新数据标志,供前台程序查询。

开启DMA通道,等待下一次的数据接管,注意,对DMA的有关寄存器配置写入,如重置DMA接管数据长度,必需要在关闭DMA的条件进行,否则操作没效。

注意事项

STM32的IDLE的中断在串口没数据接管的情况下,是不会一直产生的,产生的条件是这样的,当革除IDLE标志位后,必需有接管到第一个数据后,才初始触发,一断接管的数据断流,没有接管到数据,即产生IDLE中断。假如中断发送数据帧的速率很快,MCU来不及处理此次接管到的数据,中断又发来数据的话,这里不能开启,否则数据会被笼罩。有两种方式攻克:

在重新开启接管DMA通道之前,将Rx_Buf缓冲区里面的数据复制到另外一个数组中,其次再开启DMA,其次马上处理复制出来的数据。

建设双缓冲,重新配置DMA_MemoryBaseAddr的缓冲区地址,那么下次接管到的数据就会保存到新的缓冲区中,不至于被笼罩。

程序实现

实验效果:
当外部给单片机发送数 据的时候,假设这帧数据长度是1000个字节,那么在单片机接管到一个字节的时候并不会产生串口中断,只是DMA在背后默默地把数据搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时能够利用DMA_GetCurrDataCounter()函数计算出本次的数据承受长度,从而进行数据处理。

想要学习单片机的朋友 ,做毕业设计的同学,关注我们,回复哥,与导师一起学习成长,共同进步,还有更多资料领取。

说了这么多,大家记得留意下方评论第一条(或者私信我)有干货~

-END-

*本文系网络转载,版权归原作者所有,如有侵权请联系删除

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

欢迎 发表评论:

最近发表
标签列表