
![]() 我们知道,利用单片机定时器捕获功能测量脉冲信号宽度及占空比是种很常见的做法。这里以STM32的定时器为例来介绍基于其捕获功能实现对脉宽的测量的思路及过程。 + Q9 T7 A5 @$ p& Z7 j- _ - f- z1 s* Q- j4 S9 a a 一般来讲,使用STM32定时器的捕获功能来实现脉宽测量,我们可以选用一个通道、也可以使用两个通道。使用1个通道时,只需使用定时器基本的输入捕获功能结合中断或DMA即可实现;若使用两个通道时可以将捕获功能与定时器的从模式来相结合完成。这里就两种方案的实现示例都做个简单介绍。4 w" x7 k' R' V : x# ]; z2 c; T( u+ ^1 U0 V' ~8 @4 c- O 不妨先介绍基于单个通道的输入捕获功能来实现对1路信号脉冲宽度及占空比的测量,并在测量过程中统计用于测量的定时器自身的溢出事件,以保障即使被测信号脉宽长于测量定时器自身的溢出周期时也能有效测量。 ) [1 O! g+ G( T: F ) [$ c: @! c( f8 x6 L* q8 O0 m 这里选用STM32F411 Nucleo 开发板 ,集成开发环境选用了ARM MDK IDE。$ e% v0 I" n8 B% |' f! @ 一、实现思路及步骤7 X7 N9 p+ U5 s9 { W' \ i3 J0 S6 N1 x' x0 Q k3 { 1.1、使用STM32F411Nucleo板的板载芯片内的TIM3的通道1产生一个周期为5s,占空比为40%的PWM输出信号,然后将该信号连线到TIM4的定时器输入通道2,通过它对来自于TIM3的PWM输出信号进行脉宽及占空比的测量。 1 n- _. T" ]! u+ b9 @ 测量过程中,TIM4的通道2对外来信号的捕捉过程是这样的,TIM4的通道2对外来信号的一个完整周期实现 3次捕捉。每次捕捉事件时计数器的值会被装入CCR寄存器。 ![]() 在初始状态0基于上升沿发起第一次捕捉,记录下第1次的捕捉值【Capture_1st】,并对TIM4定时器溢出事件计数器清零,同时将捕获极性切换为下沿捕捉。之后进入状态1,等待后续的下沿捕获。当发生下沿捕获时,记下第2次的捕捉值【Capture_2nd】,并将前面这段时间的定时器溢出次数也记录下来【Front_Num_OvEvent】,再次将极性切换为上沿捕捉,进入状态2,等待第3次捕获。在状态2的情况下,当发生上沿捕获时,记录下第3次的捕捉值【Capture_3rd】,并将整个测试周期内发生的定时器溢出次数记录下来【Total_Num_OvEvent】,然后进入状态3进行占空比【Signal_Duty】和脉宽【Signal_Cycle】的计算。完毕后回到初始状态,准备下次的测量。 & Z+ |# n" t# ^! q5 N 另外,在TIM4的更新中断里对非初始状态的溢出事件累加统计,放在变量【Num_OvEvent】里。 1 \$ R9 j N7 `4 b E$ i6 @ 6 K- v2 y0 o9 ^9 H3 w 示例代码里用到变量Measure_State来记录和表示当前测试状态。; P3 R8 R' v( h( t7 P, a ![]() : q1 Y' x) @- P7 V) |! Y: G 1.2 、测量用到的算式 5 L% A! E; A% v, w& @7 g * k7 i3 p" s5 b7 ?- D9 C# r, k, C% v 根据上面的介绍,一次完整的测量下来,测得的周期和占空比可以用下面算式求得。5 z7 T8 K: N) a; ? 【下面算式貌似复杂,只需把上面测试原理和那几个数据理清自然就会计算】+ F* p' m- F) x% N9 [/ o ![]() 1.3 、基本配置准备 1.3.1、 实现TIM3 通道1【PA6】PWM输出,计数周期5s,占空比40%,用做被测信号。3 @# Y- O- e, A A、选择定时器内部时钟作为时钟源,STM32F411芯片定时器内部时钟为100Mhz;" X& h) M0 Y0 t" I& s2 y O % I$ k9 z* ?# ` B、设置分频比,选择计数模式、设置计数脉冲个数; + _/ c% G1 ~, U8 E 7 p5 C @, w3 _, K( q6 M; w5 a 对时钟源20000分频,PSC=20000-1;选择向上计数模式up counting; & E! c* s& d O9 d# R; W 6 F5 o) ~5 p& G/ \; N 计数器基于分频后的脉冲每计数设置为25000个后,发生溢出并产生更新事件及中断。则:ARR=25000-1* \0 c+ |* t% N! f8 r! C 按照上面参数来设计,定时器的定时周期或者说溢出周期就是5s.$ w8 W6 o0 ~# z4 \+ U& R& G. P % H# {- j4 a( r- N0 J- n5 r: N C、它需做PWM输出,这里选择PWM 模式1,占空比为40%,$ `6 j7 K5 Z* }! K3 H. ~ 0 f" R e/ a! v6 |6 _ 则CCR=(ARR+1)*0.40 =10,000; a! w6 ^& O6 D! N4 ^ ; o7 q8 u8 C4 S) i3 T 使用STM32CubeMx图形化工具进行配置:( k/ t! }' Y0 X' x- ^! b; B ![]() 6 a% { M& P! b" g, x 1.3.2 、实现TIM4通道2的输入捕获,假定TIM4的溢出周期为20ms.9 s6 C/ K# }& L G" a A、选择定时器内部时钟为时钟源,32F411定时器内部时钟为100Mhz;2 [' P5 X9 O2 b) r B、设置分频比,选择计数模式、设置计数脉冲个数;- `& Q- K1 `' j3 Z4 j" S0 v! A$ C 1 n! w% h& {5 e1 z7 U 先对时钟源100分频、即PSC=100-1;选择向上计数模式up counting; 7 l1 }2 x8 X; l% ` ; N+ D2 A; P( p9 d: m 计数器基于分频后的脉冲每计数20000个,发生溢出并产生更新事件及中断。$ L- X% D$ C+ n1 ^ * \ F6 a0 p+ [: p8 V3 @% ^ 则:ARR=20000-1 ' T- \" ?( Q0 F( p 按照上面参数来设计,定时计数周期或者说溢出周期就是20ms.: E8 s8 _7 _4 b; O 另外,通道2配置为输入捕捉,初始捕捉极性位选择上升沿。% H+ k J" W" [9 {. r& u3 ]' Q ![]() ; Q; E7 W" m Y; K1 h! H 1.4 、工程代码的生成、添加和整理5 k% T1 l5 u! F' Z- N, p( l V M2 C; q( c" j- B4 I z 通过STM32CUBEMX依据上述参数完成配置,并开启TIM4的中断使能,然后生成工程。再在工程里添加应用户代码。7 C" W! k, O8 k, { + B3 d( f) r$ c2 s: O ![]() 部分处理代码的简要说明: 3 U' f4 ]- Q9 \2 z/ G4 A& \ 在TIM4通道2的捕获中断里做3次捕捉值的获取以及计算,在TIM4更新中断里对溢出事件进行统计。5 @) _( G' ~" L6 d + i2 T$ e/ S( ?' c: f, b 二、本次示例的结果验证& g% Y$ D1 K, O - M* d& Z, y1 N& s 实验中tim4的时基参数保持不变,可通过调整TIM3的PWM输出的脉宽和占空比,来看看实验结果。下面有一个视频剪辑,就是上面工程验证结果的部分内容,有兴趣可以观看。 上面简单介绍了基于单通道的定时器捕获实现对脉宽及占空比测量的过程,现在继续介绍使用双通道,基于定时器PWM输入模式测量脉宽及占空比。同样,在测量过程中也统计用于测量的定时器自身的溢出事件。所用开发板和开发环境跟上面一致。 $ k/ I% X( @! @1 f 三、实现原理、思路及步骤 1 Q6 ?' t/ e% l+ Q* U6 a" R # x0 p- U. D0 S 3.1、同样,利用板载芯片内的TIM3的通道1产生一个周期为5s,占空比为40%的PWM输出信号,然后将该信号连线到TIM4的定时器通道2【TI2】,作为其直接输入。基于PWM输入模式对来自于TIM3的PWM输出信号进行脉宽及占空比的测量。 L4 h6 x5 U7 c A4 P$ u* L8 B- O 这里先简单介绍下PWM输入模式工作原理。 ( q' A$ X1 }2 J3 r Z, s; J+ s *它是基于输入捕获与定时器从模式相结合的一个具体应用。 * 同一外部输入引脚【仅限于定时器的TI1/TI2】的输入滤波信号【TIxFPx】映射到内部2个捕捉通道【仅限于IC1/IC2】,且配置为相反的捕捉极性,即一个通道捕捉上沿,另一通道捕捉下沿。 *用于测量的定时器配置在复位从模式,外部输入信号的滤波信号TIxFPx作为定时器的触发信号,令定时器复位。/ v+ p& Y4 r. E* l1 P5 W 5 Q" A- d: y$ G5 J6 k: X- u; F! g # }7 u, Z# {4 o s *经过两次连续的捕捉结合定时器的溢出事件统计可方便地测得信号的周期及占空比。 e4 e U2 c# c5 [3 } ![]() 7 H/ H& [' _9 s5 c2 r 具体到这里,触发信号来自待测信号,即TIM3的PWM输出,与TIM4的TI2相连,经过边沿检测和滤波后的TI2FP2做为IC2的输入信号的同时担当TIM4的触发输入信号,其触发极性可以软件配置,此处配置为上沿触发。当TIM4收到触发信号时,定时器的计数器会被复位更新。当计数器配置为UP计数模式时,计数器会被清零并重新开始计数。 , ^( g+ H2 z$ ]" G/ r. E, A+ S+ B6 K / [" h4 ?3 F3 |! o; p; E 3.2、大致测量过程是这样的:TIM4配置在复位从模式。待测信号从TI2输入。 ![]() 当从通道2出现信号的上升沿时,TIM4计数器被复位清零,同时产生更新事件和触发事件,相关标志位会被硬件置1." m% e* l1 A% }& U b ![]() 2 d7 Y5 T% i% k8 n& T$ b; T 在初始状态下,将定时器从模式触发沿配置为上沿触发,捕捉通道1配置下沿捕捉,捕捉通道2配置为上沿捕捉。初始状态下,待测信号的上升沿使得TIM4的计数器被复位清零,并进入测量状态1,并开启定时器的溢出事件实时统计,代码里用到的变量是Num_OvEvent。当发生通道1的下沿捕捉时,记录下第1次的捕捉值【Vaule_1stCap】,并记录下自复位以来到下沿捕捉这段事件的溢出次数,放在变量Front_Num_OvEvent里。然后进入状态2。在状态2的情况下当发生通道2的上沿捕获时,记录下第2次的捕捉值【Vaule_2ndCap】,并将整个测试周期内定时器溢出次数记录在【Total_Num_OvEvent】,然后进入状态3进行占空比【Signal_Duty】和脉宽【Signal_Cycle】的计算。完毕后回到初始状态,准备下次的测量。. o! y1 X2 i; o 4 E: U2 H; _' d: |. M 2 X9 S* F% m" A9 X3 j 另外,在TIM4的更新中断里对非初始状态的溢出事件累加统计,放在变量【Num_OvEvent】里。 " {0 E& _9 ^. d9 Y0 a# ]9 ?5 Y 示例代码里用到一个变量Measure_State来记录和表示当前测试状态,大致流程如下。( O4 e/ R s5 L/ Z8 w1 m; `8 b ![]() 整个测量过程中,我们使用触发脉冲产生的触发事件作为每次开启测量的起始。9 c$ b; c; _! T ^# F: k( Z( B2 d+ ^/ i 3.3、 测量用到的算式# P5 }. P; J' p! @; R/ d ' X# I' b: P& A7 d& u& V! D , w2 k$ U4 R/ m8 X 根据上面的介绍,1次完整的测量下来,测得的周期和占空比可以用下面算式求得: ![]() 6 ?* L% v% K8 a6 j& F; c ![]() 5 `8 [0 p" T1 C0 i& b$ { 3 L/ u/ a, i; v, f, K: a 3.4、基本配置准备6 s" i2 A% d( [4 O' W4 t " d9 x* `# F6 j0 v. E" z8 V 3.4.1 、实现TIM3 通道1的PWM输出,计数周期5s,占空比40%,用做被测信号。( f* }# S# [* N! z . S* P2 F; u$ Q A、选择定时器内部时钟作为时钟源,STM32F411芯片定时器内部时钟为100Mhz;0 v8 }9 c7 x$ D" g ; d$ \6 J/ F- A# P 7 P L7 j" O- Q7 f* _ B、设置分频比,选择计数模式、设置计数脉冲个数; 对时钟源20000分频,PSC=20000-1;选择向上计数模式up counting; - P. d% S9 @5 G; r' `) ^ 计数器基于分频后的脉冲每计数25000个后,发生溢出并产生更新事件及中断。则:ARR=25000-1 8 _9 V! M8 x8 `' t# d 按照上面参数来设计,定时器的定时周期或者说溢出周期就是5s. C、它需做PWM输出,这里选择PWM 模式1,占空比为40%,; M$ q. R, e' i6 P 则CCR=(ARR+1)*0.40 =10,000 CubeMx图形化配置界面:+ Q1 O% I+ ~9 g3 Y ![]() % X3 f! z. g. R 3.4.2、 实现TIM4通道2做PWM模式输入测量,假定tim4计数器溢出周期为20ms。) D+ w. m0 m: W# l& W0 X, H5 @ W. ^: e* j8 B9 L8 M* E 先做时基参数的配置:( R# [7 l0 o6 j9 p. g' x5 J/ O , _2 `* _* l9 O' \ . i& t* f: R5 }! s' a/ @$ r 1、选择定时器内部时钟为时钟源,32F411定时器内部时钟为100Mhz;! Q E" a8 G' F; R' y# f' c* } 2、设置分频比,选择计数模式、设置计数脉冲个数; " t |, c1 L/ J* F( J" U 先对时钟源100分频、即PSC=100-1; 选择向上计数模式up counting;$ F8 Y" [1 d* _7 u B' u 计数器基于分频后的脉冲每计数20000个,发生溢出并产生更新事件及中断。则:ARR=20000-1。注意:TIM4工作在复位从模式。 ( U* U& `! j+ _5 k- ?8 M, x. m" D 按照上面参数来设计,定时计数周期或者说溢出周期就是20ms. ![]() 0 N& z( I/ N) U! h n1 W: b* U ! ?, d0 Y$ T8 C, m. }6 B 再看看定时器TIM4的捕获配置: / t- Z% Q+ y4 ?+ y# Z$ c* y TIM4输入捕捉通道2配置为直接输入捕捉,捕捉极性选择上升沿。 1 T* T! E* f4 h+ Y) ]1 r TIM4输入捕捉通道1配置为间接输入捕捉,捕捉极性选择为下降沿。 ![]() % T6 V( _3 x. r7 Y& r! D 9 I/ s3 ~- P3 J. L/ I f4 \ 3.5、工程代码的生成、添加和整理 # }/ k9 E5 s# m: K9 V) N: ?) R ( p3 w- E) ?7 F1 j0 I; j 通过STM32CUBEMX依据上述参数完成配置,并开启TIM4的中断使能,然后生成工程。再在工程里添加应用户代码。【只列出部分直接有关的】 ![]() 部分处理代码简要说明: C8 [4 D0 ^0 t4 f3 y, x+ ` : a S8 r% ?' h* C 发生触发事件时,进入测量状态: ![]() 在TIM4通道1发生下沿捕捉事件时,将前面时间段的溢出次数记录下来并切换测量状态。 ![]() 9 ~1 x$ x# L) U3 e+ E 在TIM4通道2发生上沿捕捉事件时,将整个测量周期发生的溢出次数记录下来,并转入计算处理状态。 ![]() 另外,在测量状态下,基于TIM4的更新中断对溢出次数进行统计。# U: R; s2 K& D5 V; U/ s: \, { ![]() 四、实验结果验证 Q g- C4 U% s" d' R $ t" m# q! E, g5 Y( X( P1 Y/ M 同样,我们保持实验中tim4的时基参数保持不变,通过调整TIM3的PWM输出波形的脉宽和占空比,来看看实验结果。 ' v8 n- m8 [: j% U9 [, G7 h" K 五、小结- G& a# [7 i( m% y( k' v 6 d5 J4 Q/ f m 上面介绍了两种测量信号脉宽及占空比的方案,都用了捕获中断和更新中断。其中,在第2种方案中用触发事件作为每次测量的起始,这算是个关键点。顺便说下,我们在利用定时器测量脉宽涉及到更新事件次数统计时,比较容易出现多统计一次的问题。因为定时器初始化完成后会软件产生一次更新事件,所以建议在启动定时器更新中断前对该标志位做个清零操作。不过,在我上面两个方案的示例代码的初始化阶段,这个操作倒是可有可无,因为我的代码里对更新事件计数还要结合状态机,并非一有更新中断就累加。 上面提到的实现思路及代码仅供参考,旨在抛砖引玉。当你对原理把握得越清晰时,应用就越灵活。最后,就上面提到的两种测量方案基于个人的理解做个简单比较。 ![]() 【注:2个通道并不意味着需要2个物理管脚,其实1个脚就够了。另外基于定时器捕获功能配合DMA,解码方面也能有很好的发挥。】 " ?, Q- A* Y& c, \3 O2 } ' i% m5 N$ q& r9 M$ N( C |
狂欢三】STM32C031使用TIM定时器DMA方式实现WS2812彩灯输出(三)
【狂欢三】STM32C031使用TIM定时器DMA方式实现PWM输出(二)
【狂欢三】STM32C031使用TIM定时器PWM输出
stm32使用定时器触发dma传输,启动dma没反应的几种情况的解决方法
定时器剩余通道是否可以做PWM输出呢?
基于STM32双定时器+ADC+DMA实战经验分享
基于STM32的定时器触发ADC时可能遇到的情形
【NUCLEO-U545RE-Q评测】5. 基本计时器
基于STM32的定时器不按设定超时产生中断
基于stm32用两个16位定时器级联成32位定时器经验分享