金牌会员
- 积分
- 1427
- 金钱
- 1427
- 注册时间
- 2019-4-22
- 在线时间
- 272 小时
|
学习了原子的DMA实验,但是只懂原子的DMA实验的代码是远远不够的,所以我就去网上寻找关于DMA的例子练练手,以加深对DMA的理解。最终决定学习下DMA串口的接收,但果然只懂原子的DMA实验代码是真的远远不够,当我看了别人的代码后才知道自己对DMA的理解是多么的浅显。然后我前前后后的去查资料,找关于相关的代码,终于在两天过后搞出来了。哎,但里面的过程是真的艰辛。为了防止以后学习的人少走弯路,我决定写下这个帖子给初学者们一些经验。在这里我得感谢下这个帖子的大佬http://www.openedv.com/forum.php ... id=76091&extra=,我能搞懂这个实验还多亏这位大佬,但是这位大佬的代码用ucos写的,这可能让初学者不好理解,所以我把大佬的代码用探索者精简了,能让初学者们看的舒服些。最后,我想说的是我其实也是一个菜鸟,可能有些地方理解还是错误的,希望能被理解。
DMA发送配置代码
先看这段代码,这是一个关于配置DMA发送的代码,方向是SendBuffer这个数组到USART1->DR串口1数据寄存器。和原子代码不一样的地方就是,这里加了一个DMA数据发送完成中断,有人可能就问为啥这里就要加一个中断呢,为啥就不按照原子代码那样呢,这个问题我想了下,我觉得这两种方法都可以,但是既然有个数据发送完成中断为啥不去用呢,而且假设你要在数据发送完成后做一些其他的事情你也可以在这个中断服务函数里面做,这样就方便了很多。然后这段代码设置中断的目的就是清除完成传输中断的标志位,因为你完成一次发送后只有清除这个标志位你下一次才能发送。最后对这段代码想说的是,这里并没有用DMA传输使能函数,因为你不可能让他一直发送吧。为什么我要说这个,因为这个和后面的DMA接收代码会有所不同。
DMA接收配置代码
这段代码是配置DMA接收的代码,方向是USART1->DR串口1数据寄存器到ReceiveBuffer数组,记住啊,这个跟DMA发送的代码的传输方向是相反的。这里你就会发现这里就用了DMA传输使能函数,有人就问为啥这里就要用传输使能函数了呢,这个原因我后面我具体讲解,反正你就记住这里要用DMA传输使能函数。细心的朋友又会发现,为啥这里没用接收中断函数呢,说实话我也不是很清楚,在我上面发的大佬帖子里面的代码是用了接收中断函数的,但是我觉得有点多余,就把它给删了,最后发现也能用。然后我又试着把上面代码的发送中断函数给删了,发现就不行了,发送了一次数据就不能再发送数据了,说明这里就需要清除发送完成标志位。至于为何这里不用接收中断,我觉得跟后面接收数据的方式可能有联系,但是具体的我也不清楚了。
DMA传输代码
这段代码就是DMA的传输代码了,上面我也讲了,最开始配置DMA发送代码的时候,我并没有用DMA传输使能函数。这段函数的作用就是,设置你要传输的代码数据大小和使能传输,然后你装在数组里面的数据就可以发送到你的串口上啦。
DMA传输完成中断代码
这段代码我就不用说了吧,他就是那个DMA发送完成中断函数,作用就是清除发送完成标志位。对了,我想提醒大家,不要搞混淆了,DMA串口发送通道是DMA2第7通道,接收是DMA2第5通道。
这段代码就是串口的配置函数了,基本是跟原子的串口配置是一样的,但是!要注意这里使能的是空闲中断,不是接收中断和发送中断,还有注意最后面两行有DMA串口发送和接收使能。然后我继续讲这个空闲中断,如果觉得我讲的不清楚的可以去百度下,下面是我提取百度里面我觉得关键的解释:
1.串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就行就可以了。
2.判断数据接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。
3.IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发的,一旦接收的数据断流,没有接收到数据,即产生IDLE中断
我上面说为何DMA接收配置函数里面不用中断清除接收完成标志位我觉得可能就与这个用空闲中断接收数据的方式有关。
这段代码就是串口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,第一发帖,可能讲的不是很清楚,有些地方甚至讲错了,但是希望有些地方的理解能帮助到一些人。
我会把我的代码上传上来。
|
|