OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 20340|回复: 27

DMA串口的接收和发送(里面有我的全部理解以及精简的代码)

[复制链接]

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
发表于 2019-7-26 15:13:19 | 显示全部楼层 |阅读模式
       学习了原子的DMA实验,但是只懂原子的DMA实验的代码是远远不够的,所以我就去网上寻找关于DMA的例子练练手,以加深对DMA的理解。最终决定学习下DMA串口的接收,但果然只懂原子的DMA实验代码是真的远远不够,当我看了别人的代码后才知道自己对DMA的理解是多么的浅显。然后我前前后后的去查资料,找关于相关的代码,终于在两天过后搞出来了。哎,但里面的过程是真的艰辛。为了防止以后学习的人少走弯路,我决定写下这个帖子给初学者们一些经验。在这里我得感谢下这个帖子的大佬http://www.openedv.com/forum.php ... id=76091&extra=,我能搞懂这个实验还多亏这位大佬,但是这位大佬的代码用ucos写的,这可能让初学者不好理解,所以我把大佬的代码用探索者精简了,能让初学者们看的舒服些。最后,我想说的是我其实也是一个菜鸟,可能有些地方理解还是错误的,希望能被理解。

DMA发送配置代码

DMA发送配置代码

       先看这段代码,这是一个关于配置DMA发送的代码,方向是SendBuffer这个数组到USART1->DR串口1数据寄存器。和原子代码不一样的地方就是,这里加了一个DMA数据发送完成中断,有人可能就问为啥这里就要加一个中断呢,为啥就不按照原子代码那样呢,这个问题我想了下,我觉得这两种方法都可以,但是既然有个数据发送完成中断为啥不去用呢,而且假设你要在数据发送完成后做一些其他的事情你也可以在这个中断服务函数里面做,这样就方便了很多。然后这段代码设置中断的目的就是清除完成传输中断的标志位,因为你完成一次发送后只有清除这个标志位你下一次才能发送。最后对这段代码想说的是,这里并没有用DMA传输使能函数,因为你不可能让他一直发送吧。为什么我要说这个,因为这个和后面的DMA接收代码会有所不同。

DMA接收配置代码

DMA接收配置代码

      这段代码是配置DMA接收的代码,方向是USART1->DR串口1数据寄存器到ReceiveBuffer数组,记住啊,这个跟DMA发送的代码的传输方向是相反的。这里你就会发现这里就用了DMA传输使能函数,有人就问为啥这里就要用传输使能函数了呢,这个原因我后面我具体讲解,反正你就记住这里要用DMA传输使能函数。细心的朋友又会发现,为啥这里没用接收中断函数呢,说实话我也不是很清楚,在我上面发的大佬帖子里面的代码是用了接收中断函数的,但是我觉得有点多余,就把它给删了,最后发现也能用。然后我又试着把上面代码的发送中断函数给删了,发现就不行了,发送了一次数据就不能再发送数据了,说明这里就需要清除发送完成标志位。至于为何这里不用接收中断,我觉得跟后面接收数据的方式可能有联系,但是具体的我也不清楚了。

DMA传输代码

DMA传输代码

       这段代码就是DMA的传输代码了,上面我也讲了,最开始配置DMA发送代码的时候,我并没有用DMA传输使能函数。这段函数的作用就是,设置你要传输的代码数据大小和使能传输,然后你装在数组里面的数据就可以发送到你的串口上啦。

DMA传输完成中断代码

DMA传输完成中断代码

        这段代码我就不用说了吧,他就是那个DMA发送完成中断函数,作用就是清除发送完成标志位。对了,我想提醒大家,不要搞混淆了,DMA串口发送通道是DMA2第7通道,接收是DMA2第5通道。
5.PNG
       这段代码就是串口的配置函数了,基本是跟原子的串口配置是一样的,但是!要注意这里使能的是空闲中断,不是接收中断和发送中断,还有注意最后面两行有DMA串口发送和接收使能。然后我继续讲这个空闲中断,如果觉得我讲的不清楚的可以去百度下,下面是我提取百度里面我觉得关键的解释:
1.串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就行就可以了。
2.判断数据接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。
3.IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发的,一旦接收的数据断流,没有接收到数据,即产生IDLE中断

我上面说为何DMA接收配置函数里面不用中断清除接收完成标志位我觉得可能就与这个用空闲中断接收数据的方式有关。
6.PNG
       这段代码就是串口1空闲中断使能函数啦,因为这个代码很关键我就详细的讲下。最开始第一步就是关闭DMA,因为你现在正在处理数据中,如果你再接收数据的话就会影响你得到的数据,所以就要关闭DMA防止受到影响。接着后面为何要读DR和SR寄存器,我也不知道,我看别人的注释就是说只有这样才能清除空闲中断标志位,代码才能运行。接着就是得到你接收到数据的长度,然后就是把接收标志位置1,这样后面就能通过这个标志位判断是否接收到数据。最后就将你ReceiveBuffer这个数组的值赋值给SendBuffer,这样后面就可以又将你发送的数据就返回给你串口。

最后,我再总结下代码的运行顺序。
1.你在串口助手上随便发送一个小于你定义的数组大小的数据。
2.数据发送完后,DMA就会将你发送的数据赋值给ReceiveBuffer这个数组。
3.同时串口发生空闲中断,开始处理接收的数据,将ReceiveBuffer这个数组赋值给SendBuffer,同时将数据接收标志rx_flag置1。
4.在你主函数里面,判断数据接收标志rx_flag是否为1,如果为1,DMA就将你接收到的数据又发送到你的串口上,同时将数据接收标志rx_flag清0。
通过以上步骤,就实现DMA串口的接收和发送啦。

emmm,第一发帖,可能讲的不是很清楚,有些地方甚至讲错了,但是希望有些地方的理解能帮助到一些人。

我会把我的代码上传上来。



DMA串口接发收.zip

5.04 MB, 下载次数: 3489

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

55

主题

199

帖子

0

精华

高级会员

Rank: 4

积分
628
金钱
628
注册时间
2014-2-24
在线时间
82 小时
发表于 2019-11-1 09:11:58 | 显示全部楼层
1209943162 发表于 2019-10-31 17:00
嗯,不然怎么叫DMA串口接发收,虽然接收和发送用的都是DMA2,但是通道口是不一样的。还有就是,我这个是 ...

唉,没成功,刚把串口接收用DMA实现,想着把发送也用DMA实现吧,结果昨天搞了一天,没弄上,我只要两个都开,就发不上来数据,
我用的是串口2,tx对应的是DMA1_channel7,rx对应的是DMA1_channel6.我是应该用哪个就开哪个吗,不用的就关掉,
回复 支持 1 反对 0

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2019-8-2
在线时间
3 小时
发表于 2019-8-2 19:50:19 | 显示全部楼层
哥你这个不能用啊
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2019-8-4 17:34:18 | 显示全部楼层
fkdstr 发表于 2019-8-2 19:50
哥你这个不能用啊

我是用原子的探索者f407写的,直接把这个代码烧进去就能用了
回复 支持 反对

使用道具 举报

11

主题

35

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2019-7-23
在线时间
11 小时
发表于 2019-8-4 19:21:54 | 显示全部楼层
主要我们单片机的型号不一样,我是103的,我最近也在写DMA接受串口,一直没写出来,看了你的以后,收获很多,我在研究研究争取吧程序弄出来吧,楼主帖子写的很棒!!!!
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2019-9-24
在线时间
2 小时
发表于 2019-9-24 08:38:20 | 显示全部楼层
谢谢,,学习了
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-9-25
在线时间
4 小时
发表于 2019-10-25 15:18:09 | 显示全部楼层
看了你的以后,收获很多,我在研究研究争取吧程序弄出来吧,楼主帖子写的很棒!!!!
回复 支持 反对

使用道具 举报

5

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2017-1-22
在线时间
20 小时
发表于 2019-10-30 15:49:27 | 显示全部楼层
我觉得最好还是不要用DMA发送完成中断,还是用串口的发送完成中断。
查看手册,可以知道,DMA发送完成中断时只要DMA把数据送出去了就会触发DMA发送完成中断,而这个时候数据还没有发送出去。这个问题会导致什么呢?
比如485通信时,在发送完之后需要把模式切换成接收模式,这个时候如果你不等待数据发送完,那么没发出去的数据会丢失
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2019-10-31 09:58:31 | 显示全部楼层
lft900223 发表于 2019-10-30 15:49
我觉得最好还是不要用DMA发送完成中断,还是用串口的发送完成中断。
查看手册,可以知道,DMA发送完成中断 ...

嗯,的确,当初我写这代码时只重点考虑的接收数据部分,而发送数据这部分没考虑那么严谨。谢谢指出不足。
回复 支持 反对

使用道具 举报

55

主题

199

帖子

0

精华

高级会员

Rank: 4

积分
628
金钱
628
注册时间
2014-2-24
在线时间
82 小时
发表于 2019-10-31 15:22:57 | 显示全部楼层
发送和接收同时都用的DMA?我在103上试了试,不行啊,刚才看到有个贴说不能同时一块用,你是分时复用的吗?
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2019-10-31 17:00:45 | 显示全部楼层
疯子韩 发表于 2019-10-31 15:22
发送和接收同时都用的DMA?我在103上试了试,不行啊,刚才看到有个贴说不能同时一块用,你是分时复用的吗?

嗯,不然怎么叫DMA串口接发收,虽然接收和发送用的都是DMA2,但是通道口是不一样的。还有就是,我这个是用F4写的,F4有DMA1和DMA2,但是F1只有DMA1。
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2019-11-1 20:43:59 | 显示全部楼层
疯子韩 发表于 2019-11-1 09:11
唉,没成功,刚把串口接收用DMA实现,想着把发送也用DMA实现吧,结果昨天搞了一天,没弄上,我只要两个都 ...

那我就不清楚了,你完全可以按照我的代码思路来,我前面已经把我的思路讲的很清楚了。我觉得你用F1的板子最主要的就是改下用的那个DMA和DMA的那个通道。
回复 支持 反对

使用道具 举报

8

主题

185

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-15
在线时间
47 小时
发表于 2019-11-3 09:35:47 来自手机 | 显示全部楼层
在UART DMA应用场景方面,其实用DMA更多的是提高CPU的性能,而不是单纯速度,因为uart速率都是在低速率场景。接收空闲中断主要应用在变长帧接收场景!
回复 支持 反对

使用道具 举报

8

主题

185

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2019-7-15
在线时间
47 小时
发表于 2019-11-3 09:42:25 来自手机 | 显示全部楼层
以前在F103时代,我都是用UART中断,再加定时器来控制,处理变长场景,以防死等现象。
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2019-11-4 20:42:51 | 显示全部楼层
五月爸爸 发表于 2019-11-3 09:35
在UART DMA应用场景方面,其实用DMA更多的是提高CPU的性能,而不是单纯速度,因为uart速率都是在低速率场景 ...

嗯嗯,谢谢指导
回复 支持 反对

使用道具 举报

55

主题

199

帖子

0

精华

高级会员

Rank: 4

积分
628
金钱
628
注册时间
2014-2-24
在线时间
82 小时
发表于 2019-12-2 15:29:28 | 显示全部楼层
1209943162 发表于 2019-11-1 20:43
那我就不清楚了,你完全可以按照我的代码思路来,我前面已经把我的思路讲的很清楚了。我觉得你用F1的板子 ...

按我自己的想法弄上了,用DMA实现的485通讯,就是不知道那样用对不对。
现在已经测了一阵子了,目前还没发现问题
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-10-21
在线时间
3 小时
发表于 2020-2-24 21:43:09 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

6

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
99
金钱
99
注册时间
2019-5-5
在线时间
16 小时
发表于 2020-3-24 11:30:17 | 显示全部楼层
多谢大佬
回复 支持 反对

使用道具 举报

17

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
136
金钱
136
注册时间
2020-1-15
在线时间
39 小时
发表于 2020-4-13 11:57:49 | 显示全部楼层
有个问题啊
如果收发都用UART的中断,收用UART_IT_IDLE,发用UART_IT_TC,那么两个中断标记位用的是一个中断函数,这样就有概率会收发抢占了,比如刚发完,正在中断里面处理,这时候收也刚好收完了,就会出现中断等待了。

如果都用DMA的中断也不好,因为DMA的中断,只是内部的中断,是BUFF->硬件,串口中断是硬件->外部总线,所以用DMA中断实际上不是真实的收到了或者发出了。
回复 支持 反对

使用道具 举报

15

主题

137

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1427
金钱
1427
注册时间
2019-4-22
在线时间
272 小时
 楼主| 发表于 2020-4-13 15:35:22 | 显示全部楼层
叶孤城999 发表于 2020-4-13 11:57
有个问题啊
如果收发都用UART的中断,收用UART_IT_IDLE,发用UART_IT_TC,那么两个中断标记位用的是一个中 ...

如果收发都用UART的中断,收用UART_IT_IDLE,发用UART_IT_TC,肯定会发生抢占。但是不会有什么问题,不然要NVIC这个中断管理寄存器干嘛。
DMA中断其实最直接的目的就是为了告诉你数据已经传输完成,假设你DMA设置要传输77个数据,这样DMA只有传输了77个数据才会发生中断。而串口中断的最直接的目的是告诉你此时串口接收到一个数据,比如串口接收到一个数据就会中断一次。
但是现在有一个问题是,怎么判断串口接收完所有数据。不然假如你要接收77个数据,你串口才接收30个,就被拿去是用了,这样数据就不完整,肯定会出问题。原子的代码用的是串口接收中断,然后用0x0d 0x0a来判断是否接收数据完成。而串口空闲中断用的方法是:只要串口一段时间内没有接收到新的数据,就会发生中断。其实这两个中断都可以用,而这里面的重点是怎么知道数据已经接受完成。
回复 支持 反对

使用道具 举报

6

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2019-11-23
在线时间
12 小时
发表于 2020-4-13 15:54:46 | 显示全部楼层

谢谢,学习了
回复 支持 反对

使用道具 举报

17

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
136
金钱
136
注册时间
2020-1-15
在线时间
39 小时
发表于 2020-4-13 15:56:47 | 显示全部楼层
1209943162 发表于 2020-4-13 15:35
如果收发都用UART的中断,收用UART_IT_IDLE,发用UART_IT_TC,肯定会发生抢占。但是不会有什么问题,不然 ...

抢占问题:我试想用UART_IT_IDLE+DMA_IT_TC,这样就是两个中断回调函数,不会抢。但是貌似没用,中断还是有优先级啊,,,,,还是得等高优先的先运行,想了一下还是无法避免,不过冲突的时间非常短,进入中断后中断标志位清掉就退出了,应该不影响系统。

原子哥的例子频繁进中断,原子哥自己视频里面说的这样繁琐。
一般Linux下用read函数读串口就是不定长按帧走,我觉得STM32底层的开发,做好接口给上层用,最好还是弄得形象一点,像串口调试助手那样的用法。

怎么判断数据完整这个事,我目前接触过的蓝牙协议和modbus协议,都是不定长,肯定要用不定长的接受方式,然后就是在上层协议里面封装报头信息和末尾CRC检测完整了
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
4
金钱
4
注册时间
2021-4-8
在线时间
1 小时
发表于 2021-4-8 18:01:07 | 显示全部楼层
感谢楼主分享
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2019-3-28
在线时间
6 小时
发表于 2021-7-4 09:49:45 | 显示全部楼层
楼主请问你有没有输出DMA的ISR寄存器进行查看,我的输出查看ISR寄存器有问题。
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2014-6-7
在线时间
1 小时
发表于 2021-7-4 17:59:13 | 显示全部楼层
谢谢你的分享!
回复 支持 反对

使用道具 举报

16

主题

90

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
365
金钱
365
注册时间
2019-10-24
在线时间
152 小时
发表于 2021-8-5 15:09:40 | 显示全部楼层
加油加油
回复 支持 反对

使用道具 举报

16

主题

90

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
365
金钱
365
注册时间
2019-10-24
在线时间
152 小时
发表于 2021-8-6 11:03:40 | 显示全部楼层
老表,你这个接收是中断接收,接收BUFFER有值吗?(我觉得这个逻辑不应该是DMA收数据到REBUFF,再DMA通过TXBUFF发数据吗)
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2021-5-28
在线时间
2 小时
发表于 2021-9-22 15:45:38 | 显示全部楼层
感谢老铁!!搞了几天,看了你这个帖子终于搞完了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 07:19

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表