STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。) C/ B/ t7 `- H3 N
) m* F* O% R* w1 b# W& g* ]即使用输入捕获来统计。
" N5 @1 ]8 y' U' x# x2 |8 e: E$ s# A
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。
2 C/ `% ?0 N# ]: N* W+ A; P/ g; T$ b% U! J
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)
! R5 I6 m* O/ \3 a7 ^, |6 x1 S: Z
) g. W1 r' {9 e4 n7 p! [5 x
q# O) J% ~/ n/ I. P1 g1 _# i* ?1 b. R* k9 F, B$ f
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。
% V3 p+ {+ U& l+ l2 p3 R3 [% N$ l! W% x: \
9 l3 B6 @1 H( m+ V, \
" M3 j' O! O" N8 m- @6 }
这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。- b A& L1 l3 {6 r" q2 p
0 {+ u7 E; M/ E$ Q# k
2 ^+ g4 t( _* s, M; l
. }, C3 r8 z& ^# Z$ J% l* a- z4 j ?触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。2 V2 w$ a6 W' {5 D: r0 n
" i) J% `+ L. B' }& \最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)3 n+ R* O) q/ _/ z2 D& D9 K
6 y( L$ {4 s. F! j- X) a
$ n9 @7 v. w8 l
# t+ s0 ^# Y1 d: r
3 J- I4 @* l3 c7 @开启定时器中断。
$ A5 R) w5 ] Y: I6 F& h {( \& R* v W) T u
这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。
- p% I9 f ?, |5 o3 m0 M1 O9 ?* @3 c0 y: I6 U
由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。
5 |3 C9 t1 N8 _1 E, X5 M# R1 H$ z! F+ ?$ v) r! _, z
这里分频系数也不能太高,我就干脆不分频了。
% I' s' d+ j! v# @4 a
# h* Z; c; R1 Q# g因为等会我们会清除计数器- }$ r+ k, g: E* R1 [$ x
0 k7 ^' H& z1 }. W! {2 g- struct Pre
) G2 u8 r; S0 F9 d - {
+ k, [0 G5 Q1 ~, A' f% ^7 M q$ [ - float HighTime;//高电平时间7 E' k+ L+ d5 o8 f/ h
- float LowTime;//低电平时间2 c1 d/ I# c/ t7 a7 H
- uint8_t CapStatus;//计算是否是第二次捕获- W( y& r+ t9 B6 B
- float Frequent;//频率值6 Z8 Z& p7 ]+ n6 o
- float Time;
/ Y7 J. D% Q' A% J% ?) |" N7 z - uint8_t EndFlag;//捕获结束: p; e4 v; r0 f1 _( H( A6 j- \
- float Duty;//占空比
' E9 b9 |2 d2 E) B* y - };0 O( R* e+ }, F N$ f
( X9 v/ J% G+ O3 w
W( m) z) J! t) E- 2 U/ F" f, f7 l$ g
- ( A `7 [* g1 }; `3 A+ L
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
8 J- f7 B- {" |7 H* J - {. l$ |8 X4 C1 |4 n7 y
- if(!pre->EndFlag)
+ k @ w8 n% h) X - {/ a' k0 }7 m6 h( N& {8 G) y
- if(pre->CapStatus == 0) //第一个上升沿
4 m7 Y& H- o* X. R: ^0 { - {
; g* Z! r4 N ~ - pre->CapStatus = 1;
' b8 L6 o1 d8 X" l8 W/ A - __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
7 _$ k$ x2 S% z - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值
T% g, Y+ n1 N" c, j6 ~9 R. b: D: g - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置
. V1 ~7 S% P0 \( I A9 K - }else if(pre->CapStatus == 1) //第一个下降沿
2 Y/ i2 i- O) q5 v - {3 h& U( p3 Z/ p- y4 B$ j1 P8 T% x
- pre->CapStatus = 2;, x2 `% J. X# P) h4 O
- pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置, \1 o. q, J# {2 r/ ?
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发
; S! R- V+ n: ~; P l$ Q7 A2 x - }else if(pre->CapStatus == 2) //第二个上升沿; E" Z6 Y. t! F" L3 O- x
- {
6 g% S7 T; [/ P2 [ - pre->CapStatus = 0;8 ~+ e u) _6 R4 u& n5 h3 `4 d; L8 A
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);, d8 H8 h6 x3 c8 v; {
- //计算频率
* h# s6 D+ @3 L& N, I* z. i5 W5 P - pre->Frequent = 1/pre->HighTime*100000;4 \/ {2 {1 T. f# |# M) \
- //计算占空比! J7 @& f- ~7 M) Y
- pre->Duty = (float)pre->LowTime / (pre->HighTime+1);
: A4 S" d* G4 {. S6 i - pre->EndFlag = 1;
9 e/ |+ j8 Q4 y' x: \ s, Q& r( V - }; G G/ ?$ A" K& w; j2 s! p
- }' c+ @, C" B0 D: W
- _2 p( ]4 J" ^: I- * Z! R( w8 G* s# M
- }
复制代码
5 }+ O5 q! F5 p6 g7 y6 P我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。! }4 K4 C2 W5 ^/ l3 L* |
& ]" O( }1 U+ K+ c" W主要统计两个上升沿之间的时间。. u7 d: @4 @3 e8 U
' u3 X4 R! l, |& e
- HAL_TIM_Base_Start_IT(&htim16);
* U" `$ X" F& b6 f" ~& A# A - HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);; j% k- {$ B! ~/ j
- __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断* `& K, [: M5 P2 z. G- S: e6 a8 _
- HAL_TIM_Base_Start_IT(&htim8);0 Y5 P; j7 n9 g+ K
- HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
/ |" z7 @4 r8 V7 V* e - __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码
( Z+ a( C9 `- j( Z6 f) g开启定时器计数以及使能中断。
4 \6 k4 r6 n/ \
" t& R. V6 B; `+ Q6 Y- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
6 { c+ f# Q, [/ _ - {: |9 L2 p r7 y
- if(htim==&htim8)
1 B/ F. E7 H- o# { - {6 c% S: o3 ~) |$ v0 B; i9 |7 D, u
- GetFreq(&pre1,htim,TIM_CHANNEL_1);
5 x7 P1 e5 t: f% Z# D/ b/ y - }
4 g* c# j4 d8 P/ I - }
复制代码
0 G0 k: o4 H! J {输入捕获到频率检测。
: k# y! r, _( C: M, x* a/ P9 R( O! m
- if(pre1.EndFlag)
+ y: x P. v; P) b* {& `+ k# C6 N - {9 ^2 |$ u7 n8 T! K. E3 T- ]
- sprintf(pr,"FreQuent:%.2f",pre1.Frequent);
( `/ {- ?7 U- p3 [ - LCD_DisplayStringLine(Line4,pr);
3 v6 Q9 O2 I" ]7 j q U9 e! F - pre1.EndFlag = 0;, w, n5 {& w3 H# r Y, N
- }
复制代码
4 W- _. o1 r1 F, [1 f如果检测结束则打印频率值。) P0 @. f$ f/ [- p- Q7 E' [* i
N: K; v5 L$ Q) g$ f$ M
2 g2 v/ c; l* {7 h5 F
6 J; l; h; f% F3 R7 R( j8 m5 p* X' `1 N v0 q O
- s% q; u; h/ N* b: ^) R+ I7 p$ U% y6 m2 }! r8 q
/ o3 t( _. a9 b+ r
我们可以看到理论最低频率为716.41HZ9 c5 }5 y U; y' X+ e* o/ m& G4 G
3 ^, b& j0 a& k- s4 z
( x% U" I O5 g8 T1 j/ |7 R" R( Q4 K: f+ Y3 k/ F
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。" {* X5 Y. Y) a3 N" l C+ _
3 ]9 P$ s+ y; }. j) g, N* [/ t+ b" u" h8 V$ F1 G! d
Y9 o' s% F' U$ M) X转载自:电路小白) @8 r1 t: w5 M
如有侵权请联系删除
/ T# U/ W, f) A7 P: d# K
5 y/ z' a0 {# g! Y! ]& K6 f4 a1 x) b% g0 o
|