STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。7 E. g% G6 i) D. V8 T; ]9 H
; \3 U" k @+ O! k
即使用输入捕获来统计。
3 x' w' F" I$ s- Y; Q3 F) J5 Q
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。. G) ]/ ^4 d. o( y0 l
. S6 p1 _0 K" G: A& q' G
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)
4 d' G* `# c7 `$ L7 e" p% ~ |- A: V# X z. O% `
9 r m( M8 B/ V' ?4 b9 b! W2 R; I) {4 P& I# G5 z7 |
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。
, A+ I/ c! {, i% L- I" r5 {1 m, W& o, [/ }/ \
2 }0 O' f& U( x. J' H# |) v- x! [! n/ _/ J, r
这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。
. K9 s) G1 G# i6 B! e* ~2 D9 R v; v' T
7 N2 K" P! j" x- t' b R' b- S* E
& r9 E, ]( u9 |3 ^% O8 t
触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。
# }* X! M9 a0 f7 p, T9 S6 C! E
4 u8 }' c1 Q1 `最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)
( ~8 d' X( E1 s: A. E, g7 T; z/ S; i3 o0 b
9 W( s8 H& @# z7 C; v% V8 J* q
. ^7 I1 f5 t8 T `8 d: ~! g4 P3 ]6 U) K% a6 V" }
开启定时器中断。
$ a7 L& A. ~2 ^8 e' z
8 F% k! M( e1 m) Y* Z这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。' @ E6 b: }2 m* X; [
2 e% \8 `( r) Q由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。% U0 L p6 _" e: H/ }
) w0 }: `0 j2 K/ c! O& v% p这里分频系数也不能太高,我就干脆不分频了。( c' J f1 Y. w( o8 C; i8 @
0 Q- L! A, G3 S) l5 C7 V0 I因为等会我们会清除计数器
V `, b$ p9 _0 q5 {( ?3 J
. T* `" E" x4 _3 M- struct Pre
! w" d- c. A& v' \% m- U' e - {2 B- @5 ^9 e$ y1 q
- float HighTime;//高电平时间
9 G( I/ e5 \& L# G2 x0 H0 c - float LowTime;//低电平时间
7 N. A6 j& A$ }) y - uint8_t CapStatus;//计算是否是第二次捕获
/ a& o( e0 i. n# L8 z8 P$ Z( T - float Frequent;//频率值
% s" j( S3 h: S2 e - float Time;2 P0 U! r: ?0 N, f5 o% n, |
- uint8_t EndFlag;//捕获结束9 I% Q4 T$ O6 |% b2 Y; F
- float Duty;//占空比1 h9 q( V, u* V1 T# l, ~- u# Q
- };
7 X; W& m- ]; q8 z& b - 5 Q' ^3 G- x6 b# [9 m8 E" @
. u3 n. w3 N6 `+ G) b) s" ?9 t4 N5 H
! i w& i' w2 l% y- , ]$ ]( @' I b1 j, D' T
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
5 M0 b8 z/ w5 H; V - {
1 N: x9 ] x, ~0 u - if(!pre->EndFlag)
8 r& A* [2 B( `; _2 y# q7 ~ - {
8 o F* e) G. O+ w+ Z+ l3 m - if(pre->CapStatus == 0) //第一个上升沿
( t- a* G2 D. ?2 b - {) [6 l; x* r% O
- pre->CapStatus = 1;% R2 L" Y, P' s6 w" h+ k6 o1 [
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发8 y0 @7 y+ H( g$ g
- __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值& S0 D0 I. y1 j0 d2 [$ X u0 n+ t/ Z
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置/ @$ Q. ~: j4 I
- }else if(pre->CapStatus == 1) //第一个下降沿
$ R o- S/ L( b% C' Q8 v! ^0 C - {2 }5 j$ M K) i# P7 l, K4 E
- pre->CapStatus = 2;. t4 }, s E& L* Q& o9 B1 @
- pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置
8 z/ j1 O, p; z& ~+ v% B6 |' [1 o - __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发" _: r3 G" | I! w! d- v K! T7 }( U
- }else if(pre->CapStatus == 2) //第二个上升沿' f. u+ i3 s0 t; N, ]% O$ r
- {6 l$ m% Y# S9 J) X# h& h& u1 \$ t
- pre->CapStatus = 0;
8 D4 t% z3 P( O8 y0 Z J - pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);
; a" c) d; H4 f; ]7 ]* E6 F4 o - //计算频率
0 o' Z7 L+ @0 Q( x, t" {! `, p. G - pre->Frequent = 1/pre->HighTime*100000;
+ b, j6 X1 Y8 G - //计算占空比
% i+ J% t( F% l - pre->Duty = (float)pre->LowTime / (pre->HighTime+1);6 B3 X. u) u* ^3 \$ u
- pre->EndFlag = 1;- |! W- Q: m& k# P/ z
- }
9 S0 l9 J1 [5 c/ e - }
]& K2 z7 S. O8 v; e - . O( c% y8 m4 l% c
- & O3 W7 H: B6 m* g, p9 a: ^
- }
复制代码 - b U8 c. K0 \0 n
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
1 h, `" r! Q; T% D9 V
G! \# a5 [9 {4 y$ J& i主要统计两个上升沿之间的时间。$ k B1 B) v8 j" e2 T
6 [- b4 h; e2 |9 k3 W8 U- HAL_TIM_Base_Start_IT(&htim16);; R, P0 L8 g! R6 \& I
- HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
0 L1 M: Y3 k5 v) z) k - __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断; p9 h' @. m4 H0 C% @/ W* |: F# D$ l
- HAL_TIM_Base_Start_IT(&htim8);
3 G! W& k3 y3 |4 D. ^4 W) i$ R - HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);: b4 \( V" O1 v+ Z! A
- __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码
! X( o+ G7 R# a. W; ]开启定时器计数以及使能中断。( x$ M N# k. k) }" i8 `
/ h# f; t# a5 m- ?1 k Z' X- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
! {. z6 _$ [5 _1 l0 ]: |+ m6 P) A - {" L1 d9 U/ j/ _1 }6 c' ?
- if(htim==&htim8)" l9 a8 _; A/ Q( Q7 h: q4 k, F
- {: K7 v2 [3 d, o6 w5 E$ R$ w* \
- GetFreq(&pre1,htim,TIM_CHANNEL_1);/ }+ L& {; \4 ]. c
- }
1 a/ d: |( \* w9 ]' f - }
复制代码
, o5 g1 \. K: {输入捕获到频率检测。
) A5 B' F: i7 d( v
. T) G- [* O; z4 `! J" I- if(pre1.EndFlag)7 q( x3 W0 b8 |
- {4 O$ _2 T5 ~) q D8 z% A( u
- sprintf(pr,"FreQuent:%.2f",pre1.Frequent);
/ X1 o5 U: t5 V; y0 X1 q - LCD_DisplayStringLine(Line4,pr);( J1 w% R, D8 V" M* h% [
- pre1.EndFlag = 0;
) T# Y: O0 o! |" V6 b- x( B - }
复制代码
8 q# t8 ?' w. A! _如果检测结束则打印频率值。: r8 C4 t$ r( p& y& C3 E
4 M; j' J0 f/ _& ^
8 K A }0 N7 {2 K6 ?4 o1 ^
0 V" G6 G ^% d
( g4 X- b, y% Y7 B8 X2 f
& z& z. W2 D1 }( ~. j: U- E
" W* }2 Y) J+ x% u. u% I! C9 ]; ~5 W. T8 m5 P- u! C
我们可以看到理论最低频率为716.41HZ
* s: _* M1 }4 V- D/ v* m4 f! I. ^: b! }) e9 \
( d& D( w: l' s
: z- ^: v- F3 R: F- I( O可以看到测量最低频率为713.17HZ和理论值的差距非常的小。; \: f4 d: j: \; s( ?/ [( z' s1 Z5 Q1 U
& r7 ^9 F0 \6 C2 g' w. k' {) k
& F- v, D" S& |; A0 W: N. o7 M2 y& }" Q* f& Z$ O0 a
转载自:电路小白
# W5 v/ N' \0 f2 z如有侵权请联系删除: i0 ]" y* U ~; p) `
# a' C' a- o- K2 S- v& k* q
9 F: i; Q' O; k |