STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。
( @4 V! ?7 U) M0 u7 k1 K
4 P x+ {) w, n+ f; d9 c, s2 K1 _即使用输入捕获来统计。
) x. n: }5 D4 ]
, O L4 \* y9 I. m8 X9 U输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。
* k# i; z% k q! I5 L, F( m& ]
2 V6 B# i. G/ M: {9 T我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)0 {0 B3 _ b$ E. X$ O# w, }
+ k& |! J1 Q9 G( X5 P4 d
2 |8 ^* `4 }* t% |% F% J! ]& K U- @! F9 V0 y8 h& ^
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。
0 h/ N6 p1 [- x5 Q0 G
' Q% ^, R4 h% }* v, C5 B
$ X' s7 O% t, X7 n" G; d p# }
- `- T3 u) D% W: m, a( B- C这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。8 \" W5 |& \3 s" v. f8 J/ A
' l# W) }; X/ m
! q d6 T0 g- x/ K8 w
3 Y( m! q( \5 p! b$ p触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。
' c. O: ]8 m2 a! v' c0 X1 \7 h2 Q, Z
最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)6 q' O+ K$ m4 n- I/ x
/ f/ V! U: U. }. `8 F
( {, y/ x% f3 a: K0 T) T* j+ j$ A. ?5 T& a2 s+ q
! `5 s5 `3 W5 |/ z开启定时器中断。9 }8 v) o5 | |% r/ q- }) `- g
$ ]! X5 A+ B5 A' ^
这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。* s: c- N( a! O1 F
" k) D. e7 @8 l* g7 f2 \" q& o% }
由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。
6 A# D7 }, _, b2 [! e7 {
" w: \& `1 X0 u- G; e% P" D8 N这里分频系数也不能太高,我就干脆不分频了。" }! w& d' ]( ~. {7 w) Q
# Q# p) ?6 j, A" U6 I因为等会我们会清除计数器# h3 N- C+ U/ E. P$ y9 t, ?
1 E; |3 i0 p+ E7 p& r0 h- struct Pre
; G' l$ Z3 Z; A3 v - {
z: ]9 h5 w- B0 d7 f+ M8 Q7 L$ u - float HighTime;//高电平时间
2 g- I; D/ d/ g - float LowTime;//低电平时间0 {2 R( d, D$ L' B
- uint8_t CapStatus;//计算是否是第二次捕获& U' p9 j, J9 J5 ]
- float Frequent;//频率值
2 D/ J5 d1 G1 b0 _; D! P% R: n" F5 a - float Time;3 P+ y: h( i2 ?/ h& k1 `
- uint8_t EndFlag;//捕获结束8 o3 t: u: z* }) h$ v. c
- float Duty;//占空比3 Z& n/ K. p; t) z& n
- }; u e5 p) b2 X' X
- 2 H+ ]5 f8 L5 b* ?& F b- u
5 t( f0 L M% c5 \8 R2 r- y5 J7 ~) B% a2 ~& c
- X( q2 K0 P% A
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
4 s1 e' U6 z: B' d4 r% \ - {
5 Q" X/ ^- X% X* j) F( K - if(!pre->EndFlag)
0 k/ t8 m# c) P5 C - {
2 p o, d. ]+ J; u2 B - if(pre->CapStatus == 0) //第一个上升沿
4 f! f C1 a; N# j9 W - {) ?$ ]8 U2 }# R& F' R! X' N
- pre->CapStatus = 1;- u# G+ I# T) J( P/ [- P
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
y4 L: {4 T8 ^. L" M: }: }0 g - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值9 s6 Q2 e* b$ w- N, l& O! c7 y
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置
( E7 B3 G. Z2 Y* n; T - }else if(pre->CapStatus == 1) //第一个下降沿0 k! s m( ^- w$ F9 [2 o: W
- {; m: [9 q A- L8 L
- pre->CapStatus = 2;. W! _% Z! @. Q( @
- pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置3 w, N6 @) `5 @5 S0 P! R! e
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发
+ W9 I# v7 b) `% j( o3 r3 l# m2 S/ Q - }else if(pre->CapStatus == 2) //第二个上升沿* v8 q% o6 g. @; h( q
- {2 x: ]0 P% {+ [1 M2 ?- o, f: c
- pre->CapStatus = 0;" i& X2 w" e! p2 D2 `
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);! s4 k9 Y# V! M# y
- //计算频率
" r/ ?6 m. M- D# g3 O0 p- ? - pre->Frequent = 1/pre->HighTime*100000;$ W1 E/ i) W$ `4 o6 p
- //计算占空比' v' z# D6 S2 \' u+ \1 ^0 J
- pre->Duty = (float)pre->LowTime / (pre->HighTime+1);# u, Z: \7 _" f+ O+ w
- pre->EndFlag = 1;
( O- H, c4 _. m* a/ L5 ~ - }4 Q/ \ _7 {, j& Q
- }
7 `: t& [. d- g6 M7 Y, Y0 n' N
5 z5 Z8 x) Q9 v& z' Z7 y, Z7 H
3 _0 k' |. P/ {$ i$ d7 B. g- }
复制代码
: o8 H0 f! b( L3 q* W, r我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
$ }! T2 Z/ ^) {" q2 E: m% a o9 W1 _6 w7 j
主要统计两个上升沿之间的时间。
: u, w' \) \7 e# X, I% j! _
& H! x& \# H( B- HAL_TIM_Base_Start_IT(&htim16);
% r. Q/ e) ?: D - HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);2 j; s4 B1 ?1 O! J( e% S
- __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断# `4 h6 @" h5 g, |
- HAL_TIM_Base_Start_IT(&htim8);( u; w+ P/ R& [# r2 ?9 a
- HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);8 C9 \8 u% M3 Q2 F- t
- __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码
! W7 y0 y( B6 J3 S开启定时器计数以及使能中断。5 @/ P7 Z2 {8 W& t
( {% z" k' @1 O2 l' G- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)6 B/ Y/ o [$ _5 h
- {' Q; y, `2 P- {
- if(htim==&htim8)$ S! g6 E' x0 C( D
- {
- Z$ d- h8 d5 s {4 ^8 z - GetFreq(&pre1,htim,TIM_CHANNEL_1);
. {/ N) L' Z* ^( M; ^, W - }( A5 E% v# x9 i2 G
- }
复制代码 1 K4 L9 r7 _. y! Q" w# p; J: ]
输入捕获到频率检测。6 m% T/ a/ C# e6 Y8 Q& e
5 W1 r6 m1 T& p6 G# V
- if(pre1.EndFlag)3 w0 ?8 d' `$ e+ U
- {
" z- t& ^5 K- R& f" L - sprintf(pr,"FreQuent:%.2f",pre1.Frequent);
( W3 X7 u2 W* V - LCD_DisplayStringLine(Line4,pr);! ~0 z6 [, S1 }; g- x4 l
- pre1.EndFlag = 0;
$ L6 C% w* q V# p' `8 ?, y - }
复制代码
) N$ C7 H: s( W7 A; ^! X2 Y/ V" l I如果检测结束则打印频率值。0 G2 ^$ P) c( \0 u$ t
% L& J3 ~1 F4 E& M/ f7 i$ B' }7 |
3 A) z1 I z" a/ g6 a+ f$ O. y
: p& l8 ?% Z1 h- ?. L% Z2 z4 s4 L8 i% \8 o% X
& {/ k% l% [1 o
8 B# q- v' Z1 Y4 H% H
; A0 e. r P) E' [. Q我们可以看到理论最低频率为716.41HZ
9 L3 S7 ]# _4 Y) {1 K1 s9 H1 t; l8 P/ c8 t9 t) l
; w5 c+ h# C, u
: J4 [" g7 [! @
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。
' I4 F- J3 b" z" g( ^0 \2 n: R2 a8 T! y
5 a! O, E! i: x/ t# D n" V! W, n1 t/ U$ r
转载自:电路小白
1 O: e( _ l4 T如有侵权请联系删除7 ^/ Y3 |, X/ N7 G" K5 B+ }& R) Z. h
; m! B7 D+ ]. T6 R1 C6 s2 l
* ]: `2 N7 k y6 `7 v7 X" Q7 S1 c |