STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。
, j2 B$ n7 @; o' E1 S1 u0 B4 ~; }1 T! H% A" o
即使用输入捕获来统计。0 z6 a' F, Q) \5 Y- }) @' B, S
1 f! }+ X$ O: Z9 N
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。6 M- a- h8 n! s4 {. j4 Y% ` t
+ b( M+ r; E& O
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)# t: k1 Y% d2 {, c( q" N3 \
4 g! s1 G1 T$ _# A0 M% I
/ f' ^ j$ d" K9 w: u% X
j7 l0 z5 l+ P' R2 M+ g
这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。: X1 ~0 r4 l! Z" j' v
+ i0 O' c: }! C$ u( U4 a4 s
% w- O2 S: B$ _1 a$ z
' ~3 ^/ s3 _3 F8 W这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。6 h. b. Y* [( F5 E4 D5 r
/ m% Y M, I9 f, F% N
# ]9 u2 Z9 e) K. T5 M0 `$ p: x, h9 |, J
触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。3 U2 g7 q( }/ l& Y- r+ l; j
; J7 q6 H2 p6 }4 O# t最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波)* B# u( l5 }2 Y$ P
$ v+ i' ?! |% N6 t W
$ b1 o; x- k/ l2 q
! _& P* F5 _* V- ~6 K ]+ O% ]! v# [% m
开启定时器中断。5 y& M" h' s2 ~- ^! R/ m# D5 |
( k" m9 z) k# v3 q% n
这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。
: a' t% h% H2 ?" t
( x0 t6 ^' N, h由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。2 P; Q L& t. q9 K% _* [
% k. S! W$ W; r. _
这里分频系数也不能太高,我就干脆不分频了。# v* O w% }& R; k$ b1 R" b- |
, J' v6 w# x$ Q4 K5 w8 z5 y因为等会我们会清除计数器
! Y) J) a1 d- c# U o* M+ f& _
- struct Pre
4 M( |) ~* _ q3 D) K - {
/ s& ], W- T* ] - float HighTime;//高电平时间* f; ?9 j: `" @9 v( |4 q
- float LowTime;//低电平时间5 e- R5 F3 ^5 F' d. `
- uint8_t CapStatus;//计算是否是第二次捕获, g# W& @( W& q1 z
- float Frequent;//频率值
0 G! A3 A0 \3 Z% v - float Time;
6 A+ y# g- n$ M - uint8_t EndFlag;//捕获结束8 d- ]: u! Y' z! W$ M6 |0 i% P* G
- float Duty;//占空比& ^# f6 L! S0 {" o
- };; V0 E; P6 |# @8 _
' |1 \3 _4 T4 X9 w W
! J) A2 k# ^# B- . k( m! E. R, _' Z/ P
- 6 a# @) U+ j5 A2 ?8 V: R, B8 X; [; W
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
* U( D( o; m. K* D& N; N - { U7 J. x* Q4 [) ~8 y: R: e' n
- if(!pre->EndFlag)
! e$ E9 v# s1 x7 P/ W! R2 [ - {# W" k* r( c+ I0 |
- if(pre->CapStatus == 0) //第一个上升沿" C5 Z: f2 R# X ~* J( a
- {
1 W0 u6 g0 ?. ?9 M - pre->CapStatus = 1;4 X3 X8 o9 p, ^4 x3 P! n4 x
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
+ W: |3 h. n4 F! h8 a$ p - __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值% n+ Q4 _7 R( o' @# j
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置 W+ c9 S# w( a1 T
- }else if(pre->CapStatus == 1) //第一个下降沿/ U- a4 Y7 j. S( S. V( f
- {) b3 M5 B' b+ F6 P
- pre->CapStatus = 2;
/ x0 Z8 F }* _) L6 i! ]1 G - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置' q b5 T1 A# b; H2 H
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发
, C' I. U! u7 F5 D3 R - }else if(pre->CapStatus == 2) //第二个上升沿
/ S) m$ ]1 K: _( _- A' N% \ - {; h7 c; ~5 p( u' n$ A7 G
- pre->CapStatus = 0;! S. P7 l1 O3 C! S3 v, i. X/ c
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);; }: D) Y- G# q/ G9 l4 n$ B! P
- //计算频率
+ D5 _- |- A2 x - pre->Frequent = 1/pre->HighTime*100000;
$ W0 t. m' z" [) J$ Y" d9 | - //计算占空比& D; W9 ? \( b; W
- pre->Duty = (float)pre->LowTime / (pre->HighTime+1);3 A/ W/ f7 a5 M0 }9 a. q- \1 b8 A
- pre->EndFlag = 1;& X1 C- m4 ^( e% |( G: s9 M Y7 q1 P
- }4 g# _0 b2 V, A' o
- }
9 P! X7 ?5 P9 `" w8 I* j - , `0 y( M& s- U( U9 h
- ! Y5 i; H5 y3 }; c$ \. T
- }
复制代码 : y5 ?# l. e5 L/ a9 W
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
0 y# w4 w/ P9 t! S8 P( p4 H% \4 o/ E5 ~& X# Y3 i9 m
主要统计两个上升沿之间的时间。3 i0 E: ?2 U2 W7 V8 h- l
# O+ ?( S4 D3 g) P1 ~* @- HAL_TIM_Base_Start_IT(&htim16);0 J$ o5 f# U8 ^ o* V% Y- J8 E1 i
- HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);4 J6 _9 s7 G3 s
- __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断
5 K/ [. Y( _, q- G) q - HAL_TIM_Base_Start_IT(&htim8);
5 r9 a! O0 a6 U+ p - HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);; b. r+ T$ t9 O! X
- __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码 2 K5 u8 ~8 g- {( ~! S# l+ U- A6 \/ F
开启定时器计数以及使能中断。
' r$ R' V4 t+ e
+ [- ~6 r5 T u0 N2 V& \: H2 c, p- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) H# ~3 S3 x$ I! x. c
- {
E8 B5 O5 q* g7 c9 v - if(htim==&htim8)1 a+ |! c1 K% N% r% M6 W# M
- {
8 m! f1 U" X1 }7 s, V s2 T - GetFreq(&pre1,htim,TIM_CHANNEL_1);. C, v$ k1 @9 I- g" N
- }9 j# O0 V6 ]) P- ^1 v; r# M. I
- }
复制代码
6 o# y) p6 j6 G" t2 N输入捕获到频率检测。9 Y {, B4 n! S7 D ?
: S% H' ^9 q+ k4 x' n9 X
- if(pre1.EndFlag)
" |- ~+ @7 A% o- n' X - {
4 v( U, e" E! _6 X, w! s - sprintf(pr,"FreQuent:%.2f",pre1.Frequent);
5 K( M% i5 Q6 M - LCD_DisplayStringLine(Line4,pr);
$ v: K& X9 C4 f. I& @2 M0 M - pre1.EndFlag = 0;
! i0 O0 d! O3 q0 U( [8 b4 z - }
复制代码
6 Z7 r; m2 c( Y* b# j! {+ C0 X9 S如果检测结束则打印频率值。
# u1 I" C5 @1 v8 h# j' ?; I, _; `* Y1 _* Q
) G2 H$ M" U: }; l7 U1 K% Q
0 R7 k5 [9 [2 l# O% i7 m. y
& K% G3 M( T- l) F
# O1 V2 P( L2 P) _ {1 k/ o
5 [) n5 T C2 H J& i3 v; B \. H ? {
我们可以看到理论最低频率为716.41HZ
# e X1 }! J. }0 e' r
2 L) v$ ]5 Z% \9 M) w8 o
4 E( T/ {6 y( `
+ R, o3 T8 @* y! c$ p* c* R- V) x
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。5 _& R/ K+ }% ^& v9 v5 F; w. I. ^
* U& ^2 P7 S9 b/ ]+ A: ^" F% d
& ~ O E, B) q j" k, f) E# W( I% N7 }& T& N' l! h" j
转载自:电路小白$ p5 K: k. v w# y6 N6 n B* v( q
如有侵权请联系删除" p0 ^" l" z" z
; ~8 X- G# J6 u/ L0 _2 H
1 F* w) j3 c) s' a7 H' F9 O- m4 [
|