STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。
* L1 |! y* }( i& ^, Y' k( q5 V1 l6 x4 B' j$ e+ a
即使用输入捕获来统计。( Z9 h" W' X' G" `* }" Y$ F, D% x7 _! c
L ^* B1 B4 f, Z0 l- _2 \1 y输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。2 R/ ~! m& n" r1 X1 Z8 U
* x& t: [. z" _" A
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)
5 X" p! g& o& `, X2 [7 [' @; P% B- I* ?/ N( f
! I# k% d# }+ g/ m
& w1 O1 E+ k; L7 ^这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。3 p2 }- D: I% s
1 l& B8 U9 B7 ?, U( l! Q
5 @9 u9 {2 ~' k/ L/ |+ s1 _8 v
' Y" W2 Q$ h* ` n$ e8 G5 [* l( _
这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。0 |$ ^1 Y2 O) S9 b: b
+ e5 N( F% k7 b* a; i
0 i4 M# ?$ r+ m% V2 J) F; L
& a/ i/ ] o: o$ t6 V% T触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。
! g4 l( |" [6 I/ C( |7 H: u7 U0 R1 _& o. | q
最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波). _. V$ M) Y! j7 B& ^3 r9 A* I
8 w4 `6 u" l. }; I8 P( I2 v
6 h/ t* I& t7 o7 a
0 m/ z& d A* z- O$ Y: b
d0 R, t& L/ l4 f) d1 i/ k开启定时器中断。
. ^3 z- k7 X% p8 [6 V
6 m3 J2 W$ A5 \6 F# _3 B- l/ C这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。; K7 A( W0 k1 {) ]. I1 Z
) h% Q, F0 P$ F) I7 }
由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。
8 s: h# p% r" N6 y# f
$ J/ Y6 I- G( z2 _( I6 e这里分频系数也不能太高,我就干脆不分频了。- C- U' c" x% c' _; _
( ?# ]) R4 Y6 V$ R$ B3 S4 m. a因为等会我们会清除计数器
; A R4 I; s; e. ^
6 h8 J: o4 o2 {5 ~% k& T; I' h9 m+ f- struct Pre$ p [$ A( j0 f5 M- v( a0 v
- {
* U, A f7 V0 H: e - float HighTime;//高电平时间8 r9 U- ~" j0 l: Q! ]
- float LowTime;//低电平时间' L2 g& {6 B% X$ M$ J7 T& x
- uint8_t CapStatus;//计算是否是第二次捕获
/ R# {2 e y$ h5 p6 O - float Frequent;//频率值
/ \9 W+ K5 G) _3 g - float Time;
8 j- o7 K6 @( v - uint8_t EndFlag;//捕获结束
B: l$ T. k. x W3 X I7 H9 | - float Duty;//占空比
" o' e) z1 D4 `5 V4 e" r - };
/ N& \1 t1 e5 m; H' @ V; P
$ e9 u0 d. I' Q! d6 d: s4 S& g1 n: r) h- % L% H* k' i; Y/ p* H" w
+ |# {' X4 }, h* D0 Q3 o
% c* N6 y1 c2 S1 V- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)3 T% J8 i# x5 @6 D! V( C
- {# l) E A( N/ z1 J6 R
- if(!pre->EndFlag)
+ Q6 {6 t, x7 T3 y - {
( S. q; N( ?* n; T" t - if(pre->CapStatus == 0) //第一个上升沿
( a# \ J% q S- ] H, g/ \- t - {
( K8 r! `4 Z9 L- x$ W0 O' J) v - pre->CapStatus = 1;* _+ u4 i! K" N: X) L& k$ n
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
: @4 A) R9 o" c, ?9 F - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值/ s; f; _, {: S; F1 j0 e
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置; G5 K% _! g, C, e
- }else if(pre->CapStatus == 1) //第一个下降沿
1 Q* ]& V& w b# h9 ~' }; z - {
$ M) B+ m" ]8 G - pre->CapStatus = 2;
3 ]6 a3 u- h* s. [2 C - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置
0 j% e, g. g- @ a5 U, R - __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发0 o3 _. I. x' ]; p' V2 A& \
- }else if(pre->CapStatus == 2) //第二个上升沿
( @- o6 n, X3 q) w - {2 G p) b8 U1 Y/ L) B
- pre->CapStatus = 0;
2 x: |& H7 W/ ^ - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);
$ e2 |7 C! y& i& _; w6 p3 f - //计算频率
5 ~" K j ?6 Q# q - pre->Frequent = 1/pre->HighTime*100000;
/ O) e! [6 O4 Y - //计算占空比
8 `; C. b( r. @* A7 q - pre->Duty = (float)pre->LowTime / (pre->HighTime+1);
/ Q! `: Z# T) Q* N - pre->EndFlag = 1;1 f6 Z: I* _& B& K) J9 \# l1 Q9 u8 [
- }
( q4 f5 ]$ a4 Z; V7 u2 O - }
6 M9 I! ?: ^, v# x( K# l
$ ]1 ~9 v8 c, v- 0 W$ Z) Y2 Y# y! R! B& s
- }
复制代码 , D6 u& V+ A8 |9 d5 u8 g7 J
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
& n5 A8 E* ^4 b! I- x& o; n9 z: T. Y/ p$ w' t3 m+ I; ?9 ] T
主要统计两个上升沿之间的时间。' h7 T9 W" o% q# d. e9 m7 H3 I
- e* p% @2 ?9 S- HAL_TIM_Base_Start_IT(&htim16);
; t: l7 T& y/ v) X - HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
+ y& y1 ~0 w) `" ?& F2 B - __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断
9 @9 W* r: f6 m& g: S - HAL_TIM_Base_Start_IT(&htim8);3 X. K) A, u) p" a% w" T
- HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);: a3 x% @1 Y2 } R, n# A- a9 [
- __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码 ; G6 p; |' ?8 j6 R- y: d& W
开启定时器计数以及使能中断。
& F: p" j0 I3 s P8 I% U) n( G' W3 I2 z G! d; y
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
+ r) u' o# _4 |2 x% c3 h3 h - {9 k0 i# x' }8 m4 z
- if(htim==&htim8)- I( h: D/ a) S2 n3 I/ u
- {4 W5 v K$ E7 T) {' P
- GetFreq(&pre1,htim,TIM_CHANNEL_1);
6 X+ P- E, `4 d0 C3 ]% o - }% i; V5 N) Q% z( T
- }
复制代码 / n8 Q& M& R3 ^! k
输入捕获到频率检测。. O! ~1 i* ~1 P! O7 m9 Z1 l
4 l% L+ T7 j; ~% ]6 y3 X e* l1 F/ E
- if(pre1.EndFlag)
4 e- c+ [7 F% s; v7 F; S9 W5 R* ~ - {
9 b" \! i: _" ^2 v - sprintf(pr,"FreQuent:%.2f",pre1.Frequent);1 T4 A3 u: G3 \% O* d c
- LCD_DisplayStringLine(Line4,pr);
% E, F0 Y; V9 Y6 \( m - pre1.EndFlag = 0;
( @$ ~4 h7 A1 t1 ], v( s) ^, s) s - }
复制代码 + \4 u, G* Q `, O9 K
如果检测结束则打印频率值。/ ~+ ?' b5 ]* A7 s0 a6 F! N
4 G4 D8 ?5 F5 n5 i5 R& V
) Y% G4 M! H5 _9 Q) {' v& m
) S% Z: ^; l/ M( L5 h S
8 l+ q1 _- _( c5 N
7 B% g3 h* f, i" T% t% O
' f! D+ r: n6 c0 M g
2 O. c( W8 m7 v1 Q6 P! \. h& ^( ^, \我们可以看到理论最低频率为716.41HZ
* B6 G" w6 ~) V! ]& C8 m# ~/ ~: y. O z5 X) q6 j
$ y/ W D+ B& H4 O3 K' x# R9 k+ u+ |/ M% N
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。- `/ b5 j- Q7 |. \9 @) F0 H' D
3 ^% V7 ]0 F2 H' o L* x
2 F$ \+ l3 @6 l2 ?1 Z& h/ p) M5 U# N k2 n! x4 U
转载自:电路小白
. T, o4 [4 ^5 B8 v# J如有侵权请联系删除
7 i q) C' E$ g3 z' b* V0 D
8 q ]& t ?( ~3 N0 `
9 [2 i9 l9 i4 p- Q* X0 ` |