STM32统计频率有许多种方式,有使用外部中断+定时器的方法,但是还有一种更加准确,可以计算占空比的方法。2 G; }6 E n& w1 J
& F% L% E0 ?% Q2 H即使用输入捕获来统计。
" {4 \. h( P, ^& ~! ?2 |) G% E- [, F/ r/ G: l
输入捕获的基本原理是通过检测TIMx_CHx上的边沿信号(如上升沿或下降沿),在边沿信号发生跳变时,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)中,从而完成一次捕获。此外,还可以配置捕获时是否触发中断或DMA等。$ f, I5 k! D y3 ?! }5 w0 t7 g
0 K& c, |' N8 a$ D/ G
我们可以配置一个外部中断的中断回调函数,在中断回调函数中,我们可以计算两个脉冲的时间差来准确的计算脉冲的周期(频率)
% \+ x0 [9 `( L. A+ c/ s
8 c+ J0 E2 s" y/ u# n- h. |
0 A3 @* _: l' D) p% o$ V+ z: G
; b* X5 d. [$ [这里我使用蓝桥杯的竞赛平台,STM32G431原理图中有两个NE555产生方波连接至PA15和PB4。
! u- o' Q( i/ l' ?. K: s
/ k# h c+ ^0 a! d
2 k+ x! Y5 U) A
4 U) F, h0 M4 b; o) {' _! ?这里的PB4和PA15分别对应了TIM16的CHANNLE1和TIM8的CHANNLE1。7 T) l; e0 Y3 i8 V$ D
9 c* d6 P0 l7 \, n4 e. `! R: i
5 s Z. b# v& c4 `1 L, V+ l
# h% o6 o4 l7 p2 K触发方式选择上升沿触发,这边定时器分频系数选择150-1,1us计数一次,最高计数65535即计数时间65.53ms,对应的最低频率为15HZ。; t' K* m$ F6 y2 f4 L4 W3 S
' C$ F, s9 f8 ]- b最高计数频率为1us即100KHZ,滤波系数选择0(因为不是按键没有杂波). x+ f, D7 C" e3 H
: a! `; P1 `) ~4 J {* c$ L
5 V. |/ j5 Z9 p' l0 \" U, G
7 z" l! i' R# X$ r6 Z& S" F5 B% b& Q2 m& {. k" u9 P. ]
开启定时器中断。
7 o9 Q6 y/ _3 K, v. j9 d" s; D. z
' C5 W3 s+ x5 f) O: s这里的中断触发有两种可能:第一是计数器溢出导致的中断触发,第二种是检测到上升下降沿导致的中断触发。' B; u* x0 l1 l4 H1 ^! `& Y3 J Y
2 A. E+ L% ~5 U. X
由于我们的测量频率在我们的计数频率之内,所以我们不考虑计数溢出导致的中断触发。2 y7 m3 |$ W4 v5 U( s
8 p+ U2 u) x* X. H* m; v
这里分频系数也不能太高,我就干脆不分频了。& X5 ~8 N7 C2 E
" _8 e- ?) [4 X0 M$ E/ ` T' ]4 @( Q因为等会我们会清除计数器
* J5 g$ t7 M: a, F7 V" |* C. F4 b* F7 K5 I4 }4 S+ H- i: e$ K8 B
- struct Pre
7 f2 W( @, C% z - {
& H8 T9 {" X' M4 v7 V; G* Q - float HighTime;//高电平时间
7 ^4 ?$ I! W# C$ A) q) O/ T0 K% L - float LowTime;//低电平时间+ l+ Z6 v, B/ M- J0 w1 v/ z
- uint8_t CapStatus;//计算是否是第二次捕获+ N8 ~) W9 y6 E! W Q+ ~
- float Frequent;//频率值
( I5 x) E8 N. G - float Time;
; ^: P z1 k: ]$ P+ B- [& T! n - uint8_t EndFlag;//捕获结束
5 S7 u y3 {9 U/ o - float Duty;//占空比4 |' `5 }/ Y+ F7 E X6 U. D
- };
7 n8 m' s8 Q/ i( ~1 c5 @ - ' y0 W2 E$ j, O3 U" T
1 Y: \4 c6 n8 L4 T' F3 h
& P- O& M: a, U" S- C: j/ v1 G- 6 q7 i3 s% j3 q( g; l; C0 [
- void GetFreq(struct Pre*pre,TIM_HandleTypeDef * htim,uint32_t Channel)
+ {$ r" s: {4 @ - {) l/ }6 M4 \; H4 m5 M/ J( F* o) g
- if(!pre->EndFlag)+ G4 x/ d" C* ]' |& g" i
- {
3 [2 Z' v5 h# o$ e - if(pre->CapStatus == 0) //第一个上升沿5 B' I% z( s/ K Y9 A/ ]( K C
- {% t: h, P4 k9 B
- pre->CapStatus = 1;
9 [/ e: M3 Y' G+ l, ` f! \$ n5 o - __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发9 ]$ a2 S: x3 Y+ G
- __HAL_TIM_SetCounter(htim, 0); //清空定时器计数值$ i i8 B5 b' E4 X! e" i Q4 S% L3 n
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel); //由第一个上升沿设为起始位置) L! m7 ]. J4 L9 h# c& j
- }else if(pre->CapStatus == 1) //第一个下降沿4 u5 E& u5 T. h, z7 C6 v6 h- h3 ^$ Z$ n
- {
1 d) b5 ~! D% P8 o - pre->CapStatus = 2;
, N' n0 k; J {. [- K - pre->LowTime = HAL_TIM_ReadCapturedValue(htim, Channel); //低电平起始位置! Q+ S- {- {5 _" @7 E
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, Channel,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发* w% c% B: Y/ w& T
- }else if(pre->CapStatus == 2) //第二个上升沿- A4 J7 g; Z1 C: O6 p8 r
- {
; p* x! G9 T' g, w, | - pre->CapStatus = 0;& x0 a+ n5 k( _0 } u
- pre->HighTime = HAL_TIM_ReadCapturedValue(htim, Channel);; @* D0 _4 ]' T' U9 I6 j: W
- //计算频率- `- f4 `3 O% {/ l, S% s" f- u9 {
- pre->Frequent = 1/pre->HighTime*100000;
, T9 t H5 A) P$ ^% K2 g6 S - //计算占空比
9 _: r% {4 l& {. W - pre->Duty = (float)pre->LowTime / (pre->HighTime+1);
9 g) n* i) P3 j5 Z4 K) P! c6 p - pre->EndFlag = 1;- l- t: ]5 Z" |
- }, S; z; g9 i6 s; E
- }8 P% L/ i1 m3 w8 s
# d3 h) R) |, R+ m( Q- 6 n9 X5 v* S; T- e: x* T5 z3 J9 g
- }
复制代码 4 g1 u, X9 q$ a, T6 B( n
我们定义一个结构体存放计数值和频率值,之后写一个函数来计算频率值。
6 Z- O& T2 l, P4 d/ x0 I2 K6 L" d( ?) F' c- ~
主要统计两个上升沿之间的时间。
4 N9 C6 c( V! }7 n2 _
# A9 ? B7 U3 Q6 T) A- HAL_TIM_Base_Start_IT(&htim16);3 v" e5 `' `: i, d4 \
- HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
* \% j6 P4 W' W1 r0 H$ [7 K - __HAL_TIM_ENABLE_IT(&htim16,TIM_IT_UPDATE); //一定要开启TIM16的更新中断, M+ D" r- C' C
- HAL_TIM_Base_Start_IT(&htim8);
$ O0 {( `& q0 ` - HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
9 O8 O$ c! F9 v. ] - __HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE); //一定要开启TIM8的更新中断
复制代码 * W6 c6 j$ ^5 N
开启定时器计数以及使能中断。
1 }( v/ o9 D5 q7 _9 [9 `1 {% j: @9 u8 q7 h, j! c$ D/ P& f
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
4 V; I2 d- V. X0 s4 j7 H& \. I - {
- }8 {' f, _- z6 t& i$ T5 l Z - if(htim==&htim8)
3 N' Y0 P) H0 _) h# s- @ - {6 l) `% R3 k. ^) U: f7 C+ h0 @
- GetFreq(&pre1,htim,TIM_CHANNEL_1);
- [0 m: p6 |; p+ V# H: |( C* Y% g - }. O5 S! I- c7 C, y
- }
复制代码
& v; V- B0 d, d+ d9 u输入捕获到频率检测。
* o1 G( [9 T; F( l6 s) {, ?
- p# U* j! z5 X* r% [- if(pre1.EndFlag)4 m: {$ j2 u* _, t. `! x; w
- { \* Z' U% ?1 x; k5 W: j" Z$ q" a
- sprintf(pr,"FreQuent:%.2f",pre1.Frequent);1 {2 `1 c; k% P; C! b- ^% [5 e
- LCD_DisplayStringLine(Line4,pr);
3 m( e! t# Y) y2 b - pre1.EndFlag = 0;& W2 E* H7 X; {( m
- }
复制代码 + s7 n: D$ O% _2 O. c6 O$ n
如果检测结束则打印频率值。3 t$ R6 |# v- G8 |+ Z
& O2 X' K, I) a8 w
# ~2 `% K; J. N5 W2 v0 q, ]( Y0 L; s' ]$ g. F' g5 z
) g. v7 E1 _1 b: a! D+ g, A' u4 C
! A- s' D# ~) q- H1 X- v
# Y- `( E9 f/ m8 @- u2 s3 Q) ~% k+ `
我们可以看到理论最低频率为716.41HZ$ X8 r% M4 R) k( v" T# m+ [
6 N [1 w4 G9 ]# U% q
. I( C9 n0 Z& Y- T; @% y2 k7 s, ]. c q3 H& W
可以看到测量最低频率为713.17HZ和理论值的差距非常的小。
" B1 z$ m& N3 Y A2 \) Z1 G2 X9 J
, T1 h; v* e' o$ s6 q
% _( Q4 H; W) G8 K" g3 ^- D1 Y转载自:电路小白9 e% b% v+ ~/ S/ H
如有侵权请联系删除& D7 p" M3 j5 e* k6 O
% Q! C5 H* B% r# A& u; }; }
: g; k$ n8 W. R" \# g! z' V |