STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。7 J, V# k P8 ?2 H$ ^
: b7 D/ }( I! z/ T
即使用输入捕获来统计。
' R9 |- j. [( }7 {$ ~! a$ ^1 q
0 J8 L! q4 o. C4 W5 l- ?输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。
3 C2 L# ~/ g0 Q5 R _# S2 ^4 s8 h9 @( c6 d0 g$ q3 H
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)) @# E P, f: `3 R2 e
9 b& u) c' G% Z3 J1 z4 u; b" i
' h) D5 S* y& e( Y) I0 ]
, E* e+ |6 u: Y9 x* E2 r这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。. W0 ^* E& Y' N" R. K. K& P$ @
& c! M5 J0 |1 s$ v0 X; ~
4 s5 Q2 q4 c( {% J
" ]* D0 p; z6 T+ |/ {( L9 j
这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。
' j: ^1 n) Q" D) }, S
% W" f$ K1 q8 E1 E* k
, i7 U# j. t2 l6 e a
7 K) ^% ?6 _! I$ t
触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。
4 t: c! F3 x' g5 ^; W9 O( A5 Y" `. i. M; U2 F$ o0 ~% c o
最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)
8 _" J7 Y2 ]. X* o/ [
7 K: h, y7 o$ D! p% G# a
1 D4 ~( w/ O8 U8 D6 o h' v0 B: r
: _# m3 W, K% h5 [& l4 r! m2 ?$ w$ ~. ~5 x5 G5 F
开启定时器中断。
$ t) N( L. l, O
7 j7 q! L4 D/ w( q& ]/ j2 O这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。+ s I* ^) v6 M7 e1 v7 j
2 O7 |; W; I. D由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。
5 G, m: ?" N- P$ w- ^& D& h3 B% ?( ^7 u! z- y, h
这里分频系数也不能太高,我就干脆不分频了。$ l: U/ U( J% x7 M4 o9 a
; N8 c5 z4 M; m1 I' }
因为等会我们会清除计数器' W8 ]) Q' b3 y/ B- _2 U
! z7 ] V& {* b! }0 ~- struct Pre0 I) D$ @- [5 n# `. [
- {
( G" E7 x2 J+ W8 y0 z/ l, u- R - float HighTime;//高电平时间' ?- g: n3 g( }+ p; N
- float LowTime;//低电平时间
% b" T3 ]& H* _+ R* G* k - uint8_t CapStatus;//计算是否是第二次捕获
" w& q: P- k- l3 f) Z( W, b - float Frequent;//频率值# i% |; k. k! Z+ b% [! R# Y2 {
- float Time;
9 ]; P2 c( C( b* \( h$ e - uint8_t EndFlag;//捕获结束
# M0 [7 ?& O R) |: ?+ o; N+ v - float Duty;//占空比
: r$ w8 c( G( v# I# g - };
6 M- x1 I, Z0 J5 C1 K( a9 ^6 I: S
9 H! a5 k# s! ?* H- _! M- 6 G' _, |' o0 ~6 `
- . \, u- l/ l% t- H- i* ^4 s
) C( {3 f4 s# m9 Q! B1 Y2 S- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
- V% b1 ?, c9 s5 \% L6 X8 z - {* ?2 \6 n8 J/ h/ s
- if(!pre->EndFlag)
" i5 o4 l5 N3 s6 t8 H K - {4 l5 \; m6 H( W M( [9 [* S/ c
- if(pre->CapStatus == 0) //第一个上升沿% A& p- q" R& t6 N- T
- {
2 z7 G- G4 \% \; ^& Q" g7 l' m& V, [ - pre->CapStatus = 1;* c8 u- x+ l& _. p$ T, u
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
5 v4 _, a9 K" y' | - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值
+ f( }6 C6 [/ n+ e h+ b$ e - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置
( q0 r5 V8 E/ S3 v Z1 z - }else if(pre->CapStatus == 1) //第一个下降沿8 H3 [2 |* f4 z
- {
+ n2 m2 M2 T4 u' F - pre->CapStatus = 2;
( H* H7 `9 f4 u1 d; V5 q - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置6 x3 c; d0 _4 x" u4 G# F0 E
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发6 }' x7 N% z4 Z E' f1 [
- }else if(pre->CapStatus == 2) //第二个上升沿7 O2 ~; s4 J f1 H1 O/ R
- {3 A4 H8 R/ m$ k+ p, T
- pre->CapStatus = 0;
c8 N) ^! I* Q# F! A$ N/ F3 Z: m5 @' P4 E - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);
; P& f: m) A2 ~7 f D - //计算频率2 r) c& O; P* N8 T8 A v
- pre->Frequent = 1/pre->HighTime*100000;
0 Q8 Y8 L( F2 w& N - //计算占空比( n9 T: |7 p# F# N
- pre->Duty = (float)pre->LowTime / (pre->HighTime+1);, s( M- T! r5 [5 U, m/ X
- pre->EndFlag = 1;
, p. f& C( w) m: t - }
- }2 n# ?! ]$ R f( o - }
; ^) A' M9 H% _; o8 S1 m - 1 B2 W: X( t# u) y4 @ F' Z
T9 d1 J7 \' J3 l6 R- }
复制代码
5 v* H: ]' z, Z! m3 b! @+ H我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
" O$ J( Y+ q0 {% g
3 n* e3 }- R8 f+ N* K; d主要统计两个上升沿之间的时间。
: s, F K8 e5 m& h# p+ O4 t! t( H& g3 a4 m7 g" @' Y0 m7 P8 k
- HAL_TIM_Base_Start_IT(&htim16);
8 y8 z7 [, E* d' X - HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
7 S) p, {4 N: F" g - __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断0 R4 {& \. P3 n7 U# @1 k1 \
- HAL_TIM_Base_Start_IT(&htim8);
5 ~1 l5 ~' E9 Y/ w+ O - HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
7 H: j# U3 z. R, |- p6 N - __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码
' k! Q' y; R+ a9 j( C" ]# r开启定时器计数以及使能中断。0 i, ~, v" Z+ D9 i
" E+ @% z ?" y3 I0 v8 P! n, `4 Q$ }
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)8 B2 L7 r \9 |$ o
- {2 ]0 p/ P# B$ g& m7 R6 o
- if(htim==&htim8)4 ^% ]% A4 F# r3 j
- {4 F+ W2 G, y3 B7 @
- GetFreq(&pre1,htim,TIM_CHANNEL_1);
# v' a* H4 R6 A% i8 B0 J- N - }- x e4 P4 a8 W% W8 k# S
- }
复制代码 : |7 r7 V. G& F& h6 e
输入捕获到频率检测。
9 Z1 V- p- s6 m: T0 m& g7 T `9 o- A, z- l. s$ ^* L) x" f
- if(pre1.EndFlag) U; B+ d: ~7 i( b
- {
" N( C& a* A6 c3 n+ V - sprintf(pr,"FreQuent:%.2f",pre1.Frequent);
+ ~7 L" j0 E/ M$ J& z8 W3 T' q - LCD_DisplayStringLine(Line4,pr);
$ O. G- b1 z, D: w! J- }* L4 v - pre1.EndFlag = 0;
' \7 ?- j1 f G1 e4 M: K! d - }
复制代码 . Z0 J9 T1 c! P( L7 c( P
如果检测结束则打印频率值。8 T+ q9 i4 g: E1 \
0 X- n. B! T! T- M" h5 ]
5 j- e. }$ U+ X
) {- E) D+ k( k% r) W$ a- ?2 N$ B$ S% c) o% S! b$ f
9 P0 c3 Z0 {) Q% \, k
5 A7 K: Y6 k9 i- k" k5 ^
3 s" q ^/ `5 o. ~! r1 q我们可以看到理论最低频率为716.41HZ5 b8 H- K( X8 L& n6 s" c3 k0 @
" [% t" t& \# i6 }+ a, Z& i z
) ? F) u' t2 L/ j, y) v, U/ I
- M( F3 ~% \! i" ?; f
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。
% ~0 U" ^4 i" i6 |
Z; b& e o6 [/ m4 P' W7 F2 G4 o& e) V( @- w* q8 g4 |
/ |$ S; a$ n c( \9 l9 f转载自:电路小白
) t$ k+ h8 Z' I& T如有侵权请联系删除
' i: l' a# w5 Z6 ?. o
2 i$ A9 r2 Y8 E6 W9 N0 w+ p# T. q$ @( f! b/ ?% m- ~1 x
|