STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。) X, J) J6 t. q7 r" k/ @2 K
5 H1 ~2 a* j6 D. O D即使用输入捕获来统计。
& S% P5 T4 B" q$ E& v5 v( M* }5 V$ ~7 b# X1 F
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。$ o$ k1 b* X. L& a% z1 g
& `$ W; i0 f7 f, K7 I& w我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)% d5 A0 J: _- m; f( _
0 v. ` m! Z% m9 q
( p. O! \" y% d) X0 ?9 s1 q
0 a% M: u$ T0 W7 i( ?
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。9 ^$ _, v' b2 w0 ~$ g# g( ^& n
/ `. g, ~2 h- o: ?0 v/ T
9 U8 }+ M T/ w1 @' ^! R6 z# b- Y3 S" N: W
这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。
9 L* x6 c) }" I4 m, A/ [2 @3 E: C/ @
, [6 m0 Y9 ^- g0 I
1 j8 [ m. y1 w+ S
触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。
% ]% |% b& f; m- L
* l( c2 i5 h! q3 g最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)
, o O' H T( |2 m5 }7 v' @8 i* D$ o
' d7 @# [) [( k1 \7 q( k7 _' L0 Q8 {' @: H' s* G3 U3 [/ r
2 V: }9 |) @' z; q2 K" ]开启定时器中断。' Y. H' f+ l7 F H
, K% m1 z0 x6 L h, A$ m* q
这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。
. g- k0 T6 F4 y9 U/ ^ M, B/ k4 u9 h* I0 q! u
由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。
+ g( H g+ ~" k* {7 y, _7 s9 u& ?# j+ c j, n( R
这里分频系数也不能太高,我就干脆不分频了。
9 S8 ]& ?& T% c$ D8 P, \! q# a$ N! E- \& v) M. \* C1 i1 M! T
因为等会我们会清除计数器2 @* R5 @# K- O9 q2 q! d
+ ?8 e9 w0 j. j: _
- struct Pre
0 Q: j) G. U' J4 y2 n - {
' F9 E2 Q: {9 w - float HighTime;//高电平时间2 N0 h& J: O0 Y p2 O
- float LowTime;//低电平时间
( p; e( x p2 n4 ?# j v - uint8_t CapStatus;//计算是否是第二次捕获; ?$ Y+ v" q. k* |
- float Frequent;//频率值
* i/ a) }- t: C - float Time;$ u; d' O. e5 @1 ^: D2 k
- uint8_t EndFlag;//捕获结束2 L- G% U& b* y5 A+ Y
- float Duty;//占空比
/ t- N0 }+ S* \# m' F6 i, u - };4 D* ]6 K* }" t# v- ?
; V8 |9 _0 p/ c- s- % F O+ M4 E7 q" p" c
! ?2 w9 W0 R/ G! _- 4 j1 ]0 c% y @. A# U9 A
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)( G) U0 P* o ~- n
- {
7 o! l" `; t1 ~ - if(!pre->EndFlag); I% N7 g5 U8 H+ m' l# x1 Y; y
- {
$ d; M+ u, K0 M - if(pre->CapStatus == 0) //第一个上升沿& p- G. R& G+ n% |( c) C+ _& B
- {7 i# x" p6 y( R0 L
- pre->CapStatus = 1;. a) L/ l, ^! D. h+ @
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发7 Z) p6 B0 M! J7 i3 m9 \( _- G
- __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值
! h3 m# V9 Y8 \& `$ M - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置8 r% M" @% V9 z
- }else if(pre->CapStatus == 1) //第一个下降沿
4 ^* d5 S7 a; B6 m - {5 J$ T# S% U. u8 U5 F' |6 k/ i
- pre->CapStatus = 2;
, E+ u% t, m) w( f# Y* E: \* M& }2 J - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置& d+ ?$ f* V$ y1 i/ A, \8 p
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发
; } l8 h: Q& V Y8 |2 o4 [7 @* ^3 ^ - }else if(pre->CapStatus == 2) //第二个上升沿
5 e/ Y" v* Q- Z( e' A) O0 P; B: D - {
/ ^. b: A$ Q8 u0 I - pre->CapStatus = 0;
4 `. \5 `% O# \" Y ?7 m8 k - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);9 R9 ^+ r) @( b9 b M3 V' V
- //计算频率
: E1 G" k" f, J- j1 S' @% w - pre->Frequent = 1/pre->HighTime*100000;
" i' x" O. D- f% W0 v - //计算占空比
/ @8 Q* o1 b! l - pre->Duty = (float)pre->LowTime / (pre->HighTime+1);
' u0 M! p6 C+ m. ~" z: O - pre->EndFlag = 1;
1 T$ ?# k: s A/ x( Y5 k - }
6 }, t$ _+ x+ B8 I - }% ^' \. a9 O3 d& |
1 P( d8 Z: E8 A' g2 `/ {2 w& B- + h0 v. V" s' O5 I h
- }
复制代码 7 h& w( q! x x6 [- S
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。: D1 i- R7 l! g7 c
& d" M$ {- _2 M主要统计两个上升沿之间的时间。
& U; `2 N0 N, y9 |" Z6 x; c$ D8 p9 C/ W( {$ V2 K) ~% N
- HAL_TIM_Base_Start_IT(&htim16);
7 k' l0 ?: d- X/ `5 } - HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);( ]: B0 f) X; W& p( o. s
- __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断% s; j5 _* P6 w ?8 t! u
- HAL_TIM_Base_Start_IT(&htim8);9 S7 L. |9 J4 S) S
- HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
4 W: P* Z0 R& I; R* H - __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码 , s" |0 n2 a- Q4 Q
开启定时器计数以及使能中断。
6 p5 E3 l! s9 Z' \+ Q
# i' W* m7 d; B. B4 |% F- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim), Z0 @6 W t$ K! | X
- {
& _* {+ G! W6 m# |2 {% Y1 i - if(htim==&htim8)
, H+ Y& o4 Z( d9 ~) n+ ^8 z+ c7 V/ e' z - {
& q: E* H8 x) q& j+ l - GetFreq(&pre1,htim,TIM_CHANNEL_1);
% [ g6 S8 s) d; H2 ] N6 g' M3 c - }/ e7 e' Q$ |1 a* J6 U) I% ?
- }
复制代码 5 b+ b! |0 N9 Z
输入捕获到频率检测。. _" C" f+ d6 [ G" `2 y
[) k0 S( @- B* [" J1 j
- if(pre1.EndFlag)
; j) K$ ^7 E% R* c# Y - {
2 Y$ C" R5 W) k2 a/ ^! A - sprintf(pr,"FreQuent:%.2f",pre1.Frequent);' o7 W7 H/ o0 u8 a1 s/ N _
- LCD_DisplayStringLine(Line4,pr);
9 r7 T' @; z2 }( P1 ~# [ - pre1.EndFlag = 0;
9 q Z% z: d3 j, [: K - }
复制代码 * C E+ P* ]) {" Z! m% K( b) d
如果检测结束则打印频率值。
5 }- m( k+ r/ d" X2 u6 Q) u g7 A
) n- f( d9 {2 r! O2 C& O% \4 T
2 O0 q4 ~0 Y; ?9 m
3 T {2 a; f9 a9 J' t' t
* D' e, E% h) T9 [: K* Y! x
6 d: E3 R4 [2 D0 e2 {# ]( p- J6 a9 |9 _
+ v$ B5 b" S1 K, ~1 ?
我们可以看到理论最低频率为716.41HZ
/ w8 H! U2 |$ `/ k
, a1 ]! E- w0 x( _
$ d) [% q& B1 e* J; `
+ }6 d3 J3 k+ G1 x$ J可以看到测量最低频率为713.17HZ和理论值的差距非常的小。
$ ^. ^1 S9 r" D1 g9 C
: I! l5 C0 W- f7 J5 @ ?& Z# }/ ^) S' Y- R8 W# _
: K' T8 G# Q6 n/ I' g4 `4 h- i转载自:电路小白! y; u6 d+ p$ z' P6 b; K
如有侵权请联系删除. A( a1 h/ X% {) Q( o
6 r) F+ J" d) ~7 M$ p3 V8 h7 M+ r# M/ @$ J# U+ O
|