STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。
5 ]% Q7 S' a( f, ]+ T4 P$ z7 J' U: H" V5 z
即使用输入捕获来统计。. {& H' w; Q1 \0 Z+ S+ D# E
4 i0 B5 r! c: q; G7 ? h7 p
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。! ?0 } }9 I& X$ E. m, y
+ [$ D* q K8 l+ B7 P
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)
* O; b; w4 X! O, y: L2 ^3 w R7 \+ H
, F- M8 ^* u: F! f9 N9 [5 w |9 P9 D: | Y# M. Y
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。: H" M9 v9 O6 D( p
: X' t( j0 M8 ~; v! {# O$ J' m
( u+ P7 z2 ?& H
0 g& u8 y1 \, r9 L这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。
1 {5 w! }6 Q$ _5 j# ~% M- `: m& |$ W% B% U ^7 P: P/ E
& L4 [0 G1 B& F) F d+ S, q& r3 k
' `0 i- t0 i; Y5 K* s
触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。% V3 f; L3 ^8 ]$ `$ B
5 q$ d4 W: J) g) {1 H2 ?
最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)4 d+ `) I4 L9 w3 W& z: n
7 E( a5 c+ i9 C9 r
5 x3 ^! k0 t/ |' ^
* [5 U5 f' m) C/ u* s6 f( T& k1 o% G9 M8 x# j/ q3 z- p2 b
开启定时器中断。
, ^# o' ?5 h0 Q0 n* ^ h2 j! e' l9 W! a
* {8 q4 A1 t- e) p& ~1 |这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。
3 r, @3 y8 u& ?& c V
+ u$ _" z s- r$ S+ N/ s由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。. s( J, }9 j! ?) Q& ~& M8 N$ Z
9 h! N* a2 ~) y% Z' b" g3 ^' _) d
这里分频系数也不能太高,我就干脆不分频了。
% _" i" f+ q, e9 g' |6 O/ m E% {! @
因为等会我们会清除计数器
: o" v; `$ L0 Y7 ~
# L8 B) O9 j/ I) P9 g# }. X- C- struct Pre
: y' h+ o2 f! s3 f0 U) X- h9 [; { - {4 R' S9 }( m; K, G3 ]- W- i
- float HighTime;//高电平时间0 h3 {6 b6 R' L
- float LowTime;//低电平时间9 F1 r2 v$ C5 _! F( h9 B
- uint8_t CapStatus;//计算是否是第二次捕获
& G" A8 g5 P* { X - float Frequent;//频率值
7 j- I1 F4 D' h" A- i* g4 l - float Time;1 z5 ~. R7 Z7 W" Z0 J3 Q" n
- uint8_t EndFlag;//捕获结束
* U/ {2 j. z# q5 S' S/ n" q9 j - float Duty;//占空比9 R! o- X$ _: ^1 v7 ~" ]
- };
7 I7 M- B. c+ w- w; v3 d6 K# ?
+ U9 y. ^8 t" u6 z8 Q& O
# K D$ a' J( v* ~3 K2 ^- # a; X! n# ^" g5 ^7 Z6 ?
- , Q l: S+ i% a
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
/ z: N1 |% \' J. G, s; k - {% A* E' C. q W
- if(!pre->EndFlag)5 F) o/ `8 J3 g
- {& |/ N# ^! M6 o- h- r0 w2 L0 C
- if(pre->CapStatus == 0) //第一个上升沿& M8 ~" S" d! Q% }% \7 }- G
- {# z/ @) q6 \6 j. q+ l$ D! {
- pre->CapStatus = 1;: c! {* Z1 B6 Y, V. b2 P
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
- p5 F" k& j0 H% S - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值
% W. u" Z6 j* f - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置
; ^1 Q" {. Q- k# B3 G - }else if(pre->CapStatus == 1) //第一个下降沿$ D, `, Z& R5 _: W' A
- {
6 J! d: w& g( D" V* O4 g - pre->CapStatus = 2;
: w) V1 }+ r3 \( z4 n; E - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置- U# f- q7 y4 X* W- p# i) z$ R- z
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发( J) \4 b7 O+ f' T" @: P" Q- [
- }else if(pre->CapStatus == 2) //第二个上升沿
0 ^2 N+ i+ M, b - {6 {5 X5 R# T0 q& k) c
- pre->CapStatus = 0;
6 o. V6 V# ?3 l% R: K( ^ - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);
/ j8 E! j9 H' Z6 P - //计算频率 A$ k2 P8 {2 |( u& k Y3 R
- pre->Frequent = 1/pre->HighTime*100000;3 j, G9 a8 J2 Q" Q3 [
- //计算占空比
^! e, z6 Q7 R: D* f - pre->Duty = (float)pre->LowTime / (pre->HighTime+1);
( ~) e7 ~ l1 j6 u1 X$ ?/ P - pre->EndFlag = 1;9 P3 W# {7 h& `
- }
( F2 J( b. D4 y6 g I - }& d0 V, c V4 y; q6 p- e
5 a4 s$ `/ ?: E, _; ]" ]" u: i! }
W+ v% F; ^) g: R- }
复制代码 3 Q/ @4 c- l/ b$ \& p4 {( n, C; `
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。" @; i ?9 l+ ]7 I. t
! t8 \0 }! t+ M主要统计两个上升沿之间的时间。/ Y2 I( f# B7 ~
& l3 V l( L8 d5 M2 [$ b
- HAL_TIM_Base_Start_IT(&htim16);7 e3 g& p( O- \
- HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
Y1 W6 y& O- Z. z! N# k6 K - __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断
* u o4 ]) e3 P$ R# u - HAL_TIM_Base_Start_IT(&htim8);' Z& p5 M0 w* J3 F r) S" J8 D
- HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
9 Y2 ?' E5 v w- p/ O2 ~! k- c - __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码 + h+ w! J4 j7 Y" r
开启定时器计数以及使能中断。
' d/ P. }2 J$ C2 o
6 v, W2 r& W. I" _* _% `- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
* D* \# A& u$ q4 U) k - {: R5 t3 Z7 K& X# s* U8 B; b3 C
- if(htim==&htim8) B& J& i0 S4 Q8 z0 N9 W& `5 b
- {$ z7 f/ t D2 F
- GetFreq(&pre1,htim,TIM_CHANNEL_1);4 ?2 X" h; p1 X4 f0 q1 F Y& \& Q
- }
9 Z/ }8 E) C& |% Q - }
复制代码 9 z# [) Y* r: u+ B" `, q8 z/ C( [
输入捕获到频率检测。* ~. ^7 B( U5 D( j- A
5 ]3 W* i. `5 Q# g- if(pre1.EndFlag)! k5 W) k% ?7 R8 P7 t
- {3 s& _/ @& I% P: @0 p* }
- sprintf(pr,"FreQuent:%.2f",pre1.Frequent);, ?2 ~( }; v% I8 k
- LCD_DisplayStringLine(Line4,pr);
( \3 K# Q. T5 W/ E! | - pre1.EndFlag = 0;0 t, q. T% W. n5 V% M U/ f
- }
复制代码 / D3 M6 P' q2 z
如果检测结束则打印频率值。
+ \. q5 s; A3 \ [4 p3 R
' }# ]9 G, r3 @# A$ G3 {
3 |1 P6 W) P+ G
; W" G/ {2 ?. c* P# s( A/ N; x' d8 q: N; k! D1 P) O! P
. z2 d6 @+ n' _
. r) f" B9 P" v' P0 \5 K5 q* H
' `! h# Y: y+ F$ l我们可以看到理论最低频率为716.41HZ
0 T; D4 S% \, j' G+ ]" E! {, I+ P
* g' D: n5 |; y2 v
! g/ J$ ?4 |3 ^1 R( v1 {5 Z: E
% |, H- J, E9 g) x( o' Y可以看到测量最低频率为713.17HZ和理论值的差距非常的小。
+ G5 B* s( V! P
- ?# ?, W2 v: A: n6 i1 G
3 j& s/ `& Z \" H2 V( J+ o2 C, n" _+ p5 c/ a, M/ q8 _) H
转载自:电路小白( v$ h' y5 k( L8 _+ ]
如有侵权请联系删除
% I( M$ S& o) @' Z' Y% d( W) J" n1 m+ A2 f) d1 p7 `4 a1 S
, ~! X, l, z" n |