OpenEdv-开源电子网

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

STM32CubeMX和HAL库踩坑记——DMA+TIM输出比较模式

[复制链接]

4

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
98
金钱
98
注册时间
2017-5-16
在线时间
29 小时
发表于 2019-8-7 11:39:08 | 显示全部楼层 |阅读模式
这篇文章是我CSDN写的一篇博客,拿到到此供大家学习
原文链接:https://blog.csdn.net/hyh80227/article/details/98483992

目的:让单片机输出一段可调频率的脉冲,用于驱动步进电机。
方案:1、使用定时器溢出中断,定时中断一次,在中断通过判断来翻转IO口。
                                优点:实现比较简单,对硬件要求不高。
                                缺点:不适合高速脉冲输出,而且脉冲分辨率也很低。
                  2、使用PWM模式,通过改变ARR的值来改变脉冲周期,从而控制IO口反转。
                                  优点:可以输出高速的脉冲。
                                  缺点:一个定时器只能输出一路脉冲,脉冲数量不可设置。
                 3、使用定时器的输出比较模式,设置输出比较匹配时翻转IO口,并开启输出比较中断,
                                 在中断中装载下一次比较值。
                                 优点:可以输出高速脉冲,并且脉冲数量控制。
                                 缺点:进入中断频繁,增加CPU负担。
                 4、使用定时器的输出比较模式,设置输出比较匹配时翻转IO口,不开启输出比较中断,
                                 开启DMA模式。
                                 优点:可以输出高速脉冲,并且脉冲数量控制。
                                 缺点:需要预装载脉冲频率的值,占用空间多。
结论:由于本次需要多个步进电机同时工作,并且步进电机需要加减速启动,电机转动的圈数不多。决定使用方案4。

*我搞这个模式搞了三天,今天终于把这坑踩平了,把这点经验分享给大家,避免重复踩坑。
*网上百度找了好久,稀稀疏疏就一两篇文章有用到这个模式的,而且还不是HAL库的,这个模式对于高速脉冲的输出真的是好用。
好了,直接上配置和代码,以及需要避坑的地方。

# 1、CubeMX配置
##  1.1 基本设置

1、先开始进行时钟配置,如上图,一般选用外部晶振

2、配置下载方式,Serial Wire就是SWD下载

3、配置定时器,我现在只需要通道2的比较输出模式,如图配置,其他模式看简介。
##  1.2时钟配置

我是用的是STM32F103的芯片,系统时钟最高72MHZ,所以如图配置。
##  1.3 具体配置
1、用到定时器肯定要配置定时器,这里的配置是:72分频,向上计数,计数最大值65536,通道2的输出比较模式要反转IO口。

2、DMA配置如图所示,这里不用循环模式,用半字传输,因为定时器是十六位的,CR2寄存器也是十六位的,存储器的地址需要递增,而外设地址不需要地址。

3、最后配置NVIC,这个版本的CubeMX是强制配置DMA中断的,因为用DMA传输数据,所以定时器输出比较中断不需要配置。


# 2 代码
##  2.1使能
首先需要一个数组,然后往数组里面放数据,这个就是输出比较模式里CR2设置的值。第一个数为200,
第二个为400,第三个为800,第四个为1400,看出规律没有。

**第一个坑来了
程序运行完这些就使能定时器和DMA吧,刚开始我是这样写的

其实是可以的,后来点进去第一个函数HAL_TIM_OC_Start_DMA看看,发现里面有这么一段。

就知道第二个函数在第一个函数里面已经调用了,重复调用浪费时间。

##  2.2调试
既然开启了自动装载,那就仿真看看CR2的值是不是真的在改变吧。(当时我们公司没有示波器和逻辑分析仪这些东西)
**第二个坑报道
然后发现,一开始全速运行,CR2的值就马上变成这样子。。。

我在想,应该能看到变化才对,我想,是不是频率太快了,然后就把数组增大,使用6400个数据,大致算了下也要几秒钟的时间,后来仿真一看还是直接变成最后那个值。
后来各种搞,各种不行。今天上班来问隔壁公司借个示波器测测,一看,波形很对。上波形。


第二张波形图可以看到,后面还有无数个波形,而且波形比较大,这个是因为定时器一直没有关闭,所以这个脉冲周期就是定时器溢出周期的两倍(不知道为什么是两倍的同学看看比较输出模式的IO口翻转功能)。

##  2.3中断回调函数
第三个坑,神坑

因为DMA中断已经开启了,在是stm32f1xx_it.c函数里面有这些中断函数,找到这个定时器CH2的DMA中断函数。

然后我小心翼翼地点了进去,然后找回调函数

当时我惊呆了,hdma->XferCpltCallback(hdma);这个是啥玩意,点进去看居然是这样的。

这个写的是DMA传输完成中断回调函数,但是这玩意咋用,学了C语言这么多年,没见过能在结构体里面定义函数的。。。
不知道就百度吧,百度出一筐,看得云里雾里,最后一个热心的群友解答了我的问题,说这是一个指针,不是函数
实体,我个人就认为这只是用来指向某个具体函数的(大佬来解答一下,这个东西真的是第一次见到)。
看完还是不会用,然后试一下直接使用,下载,仿真,DMA进入了中断,但是没有进入这个回调函数,放弃(我是说再百度试试,毕竟搞不出来老板会扣我工资的)。
又百度到说DMA中断调用的其实是和普通中断调用一样的函数,怎么理解,例如不用DMA而用中断,触发中断调用的是A函数,那么用DMA,DMA完成中断也是调用A函数,哇,ST设计的HAL真厉害(这对于小白很好用)。然后我马上在
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);这个函数失能定时器和DMA。发觉不好使,调试也进不去。
搞了一个多小时,想了想可以一步一步地仿真,看看程序到底进入了那个回调函数,发现TMD进入的是这个函数。如图。

好吧,那就用这个函数失能定时器和DMA,注意一下,这里的__weak是弱函数,也就是说你可以重新定义一个同名的函数,而不需要把他删除,程序就会执行你定义的函数。如图。

最终完成了,波形图。

最后说明一下,这个方式可以一个定时器输出4个频率可变的波形,而且数量可以控制,也不需要单片机频繁进入中断。但是会很耗内存,在波形不会因为其他因素而改变的情况下可以放在单片机的ROM,或者可以试试使用8位传输。


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

使用道具 举报

7

主题

237

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1111
金钱
1111
注册时间
2019-5-6
在线时间
128 小时
发表于 2019-10-21 14:13:50 | 显示全部楼层
这么好的帖子难道就我一个人看见么??为楼主点赞感谢分享
一步一个脚印
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2020-4-30
在线时间
8 小时
发表于 2020-5-7 15:47:26 | 显示全部楼层
研究中
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-2-16
在线时间
1 小时
发表于 2020-5-24 18:38:59 | 显示全部楼层
为大佬楼主点赞
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2019-11-7
在线时间
7 小时
发表于 2020-5-28 16:33:16 | 显示全部楼层
本帖最后由 xingchen8910 于 2020-5-28 16:36 编辑

p1.jpg 如上图,上边这些函数指针这么定义,只是为了软件封装接口用的,方便移植和重构,实际上这些函数都在其他地方有定义,举个例子,下图
p2.jpg             <--  声明类型  -->

p3.jpg
          <--  函数定义  -->

p4.jpg
          <--  函数实体  -->
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2019-8-23
在线时间
13 小时
发表于 2020-6-11 17:19:36 | 显示全部楼层
还是没搞懂,没搞出来
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-17 22:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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