经常有人想利用STM32定时器输出一些任意波形来满足应用需求。比方最近有人在某论坛发帖咨询想使用STM32芯片的TIM1实现如下4路特征的驱动波形。【下面波形只画出了两个周期】/ n' Y& e3 _) ?2 J6 c$ Y: z
6 ~4 n; i* M. }& o: R# C& X ) j9 ?4 x; y! K! N; R 通过观察不难看出,四路波形是有规律的周期性波形。不过除了/B路外,其它三路不太容易通过定时器PWM输出模式来简单实现。 O& g& y( Y1 _! J# P( ^ ( a3 m/ o6 S* K! l: L! w 我们知道,对于STM32常规定时器,其比较输出功能较常用的输出模式主要是PWM输出模式和比较输出切换模式。其中PWM输出模式是指定时器输出控制单元根据计数器的值与比较寄存器的值的比较结果来决定输出电平的高低。而比较输出切换模式是指定时器输出控制单元在计数器的值与比较寄存器的值匹配相等时,做输出电平的切换。即如果发生匹配之前是高电平的,发生匹配时输出电平切换为低电平。反之亦然。 结合到本案例,对于A路、/A路及B路输出波形我们就可以考虑使用比较输出切换模式来实现。 我们这里假设定时器的计数器采用向上计数模式,每记800个时钟单位为1个计数周期。【向上计数模式,ARR=800-1】2 {& C' K* r( w3 c z( r' w1 ? 对于A路,当CCR=200和 CCR=700时发生输出切换,这样周期性的修改CCR的值,从而实现目前所期望的输出波形。此时我们可以使用比较事件触发DMA,通过DMA将下次要用来做比较的数据从内存传到相应通道的CCR寄存器。 $ e: a7 h- K5 y8 J" `5 Y& ]% J3 x- H 同理,对于/A路,当CCR=300和 CCR=600时发生输出切换。同样开启该通道的比较事件触发DMA传输,实现CCR寄存器的数据循环更新。0 X6 M* R# J9 R) ^8 G- l, A, S% T : k x* T. s& j; c2 Y 同样,对于B路,参照上面的相同做法。当CCR=100和CCR=400时做输出切换。 至于最后的/B路,可以跟上面一样采用比较输出切换模式。不过,该通道直接使用PWM输出模式更方便,具体到这里我们可以使用PWM2输出模式,CCR=500. 5 t% G' T% ~3 k w 下面是基于STM32F4系列芯片的TIM1来实现上述输出波形的配置及相关用户代码介绍。其中,代码是基于STM32CUBE库。! e* q% A2 e% Q ! b% S: d! z" V5 b7 Q' L 一、基于上述分析,使用STM32CubeMx来完成基本的初始化配置。! I! z' v: J+ d! y
从上面两幅图我们可以看出,TIM1的通道1/2/3都被配置为比较输出切换模式。通道4被配置PWM2输出模式。【另外,注意下通道1/2/3三个比较输出通道的初始比较值。】- Y% s* D, C+ x- @8 c& \ / h: J. [4 _; J7 n: T& }/ O- Y 前面说了,我们要利用各通道的比较事件触发DMA做CCR寄存器的数据更新,所以需做基于各个通道比较事件的DMA配置。见下图,各通道CCR寄存器的数据更新都使用循环模式。
2、准备或编写用户应用代码。 2.1 准备3个数组,对应存放用来动态更新3个比较输出通道CCR值的数据。数据的拟定请结合上面的介绍和待实现的波形特征。 4 J% K3 ?5 j4 y% O0 k. c3 X* F uint16_t Data1_to_Comp[]={200,700}; //ch1( j% y) g+ ]6 l* H6 J$ p 3 ?0 M( e3 `7 ]7 j uint16_t Data2_to_Comp[]={600,300}; //ch23 W f- n$ z- r4 m- M . l' g( d( r6 |) c/ W1 S uint16_t Data3_to_Comp[]={400,100}; //ch3 2.2 关闭通道1/2/3的比较寄存器的预装功能,即修改CCR的值后立即生效,无须也不需等待更新事件。 6 j3 S9 O* C6 F/ T7 _8 ] U! i __HAL_TIM_DISABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_1);7 _7 n# n: k) h4 v0 N - x- ?5 D7 Y- d; ?( n. F6 Q1 v4 V __HAL_TIM_DISABLE_OCxPRELOAD(&htim1,TIM_CHANNEL_2);$ L" a- k5 R& q+ D) O __HAL_TIM_DISABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_3);/ A* R# X! ?/ j8 F/ { 2.3 开启TIM1通道1/2/3的比较输出功能。3 I# E' |7 h0 a5 z, q' r" h / |/ |! B! K0 p, Z+ j* I* U# a3 m TIM_CCxChannelCmd(TIM1,TIM_CHANNEL_1, TIM_CCx_ENABLE); ! z1 p, ^* k( C TIM_CCxChannelCmd(TIM1,TIM_CHANNEL_2, TIM_CCx_ENABLE);) b* l( m; N; r1 F 4 T. k' ]0 |5 i3 [8 @+ G TIM_CCxChannelCmd(TIM1,TIM_CHANNEL_3, TIM_CCx_ENABLE);* u: _8 t; e. I0 ^ 2.4允许相应通道比较事件的DMA请求并开启相应通道的DMA传输功能。6 g. J) W9 ~) i0 [4 x; f) F% S ( @: g( P3 y1 D: j1 d- G6 |4 p & g; w$ {. P7 W' l) P hdma_tim1_ch1.State = HAL_DMA_STATE_READY; 6 s- q. a% `" K3 @/ d HAL_DMA_Start_IT(&hdma_tim1_ch1,(uint32_t)Data1_to_Comp, (uint32_t)&TIM1->CCR1, 2);5 t) }8 u8 {2 C 0 h7 C5 `; }7 F6 `1 v9 F+ r% U __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC1);) R( g/ \& N. A/ x6 P4 F hdma_tim1_ch2.State= HAL_DMA_STATE_READY; HAL_DMA_Start_IT(&hdma_tim1_ch2, (uint32_t)Data2_to_Comp, (uint32_t)&TIM1->CCR2,2);5 P/ H j& X: Z& a& x 4 Y. t; f# ~3 l m, u; {/ |5 j G . l i' A3 F, ?7 d- A; p __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC2); U5 Z+ ^' T1 F- f& p8 ^ hdma_tim1_ch3.State= HAL_DMA_STATE_READY; & W8 d( y( ~' \8 B/ D. s , D' @$ Z9 K5 N; k' \ HAL_DMA_Start_IT(&hdma_tim1_ch3, (uint32_t)Data3_to_Comp,(uint32_t)&TIM1->CCR3, 2) $ X' l- A% W' M, e 1 \! ]. d; C2 ^# M/ \" J. j % W) S1 v( h; r; Y- v8 z/ n/ d+ n3 M __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC3); ( z+ ?6 X! l( f* K# b 2.5 使能TIM1通道4的PWM输出功能并使能TIM1, 启动计数器计数。 [+ y. ^3 r3 U3 I4 J7 f4 ` HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);. }2 V+ B2 u( r' b4 d 三、结果验证。2 q* w+ [+ b! K7 n0 V: h3 r 经过上面的准备之后,编译运行工程代码即可看到开篇所期望的结果。【下面图形是我使用MDK环境下的逻辑分析仪所得截图,供参考】 * a: s. c0 F- u# l3 s& h# K9 X # p7 w* |8 @3 P& A' R
6 x: c/ X0 A+ L/ |4 `& ^( b " r% Q& s/ J3 ^ ? 好,到此上面案例就基本介绍完毕,全部配置及用户代码均贴出来了,供有需要的STM32用户参考。 说实话,要彻底搞明白上述过程并实现它,需要对STM32定时器输出比较切换模式原理、定时器的部分寄存器的预装特性、比较事件、DMA传输有较为细致和深入的理解。不像使用PWM输出模式给个CCR的值即可输出PWM波形那么简单。% d( K) I N+ V* V ]$ S & d5 X6 _# a4 F( B" T- D 2 \2 {3 M# Y# \# X, @6 }2 ^ 最后补充两点,上面波形的实现是基于STM32的TIMER1一个定时器来完成的。如果换成别的定时器一个定时器可能实现不了,可能要用到2个定时器。这时往往涉及到定时器的主从同步问题。其中的关键点就是要知道如何让两个定时器上下级联并做同步启动,实现上述输出也是没问题的。 n/ p7 K* D. H6 L! k' i * S7 f3 Z- [ K" e 还有一点,对于上述波形的实现,如果我们使用STM32的高精度定时器实现起来就会更方便,STM32F334,STM32H7,STM32G4等系列都有高精度定时器。: T' \& H7 _8 A( a; j9 z4 ]* t |
微信公众号
手机版