7.5 使用定时器捕获上升/下降沿
$ U$ o0 v6 r. q1 M+ F7.5.1 配置输入捕获中断引脚# Z4 p+ _; {, }1 t
点击“Timers”并选择“TIM2”-“Channel1”将定时器2的通道1选为“Input Capture dirct mode”,使其连接至开发板上的“KEY_UP”按钮。在下方的配置栏中将分频数设为480,得到1MHZ的频率,也就是1us记一次,点击“Counter Period”,再点击右边的齿轮设置,将表达形式设成Hex格式,再将“Counter Period”设置为0xffffffff,这样就支持32位的定时器输入捕获了(部分引脚达不到只能16位)。将捕获方式设为“UP”上升沿捕获,开启自动重置,并将最底下一栏滤波值改为8。
3 J- r* N' G3 A" F: d& J8 ]
' w6 H/ Z2 l' L5 F6 k# r
% F; R( |$ D3 p) P+ b* |+ c- E- R
+ }( x5 I8 c3 ?7 j* d, w/ z. {0 l在“ NVIC Settings”中将使能中断打开。
* `7 n$ _) N. p: Z, r0 z1 ?, S
5 g, K! x8 x3 A- d9 J+ {
; \5 q% {4 X; Q: P7 {; y. G z! E7 z% B7 Z& h: V8 T4 u! }
同时进入“GPIO Settings”将该输入捕获引脚设为下拉,保证无信号时能稳定低电平。( P* l: n0 k2 t* H
( ~! G7 J n+ P
6 n* @# Y) W' E3 e' ]1 E
% z* j. j$ l( D; M' C
接着我们需要再设置一个定时器去隔3秒来统计定时器2捕获到的高电平数。
, j' X! g, q1 C9 }- i4 \0 |: @2 V4 L- F1 a
0 ]% u$ `- u2 n" q. C8 a4 B2 l& h
5 q9 I9 d( R% O5 s7 ~ |1 X6 X
4 l' ^/ R) A( B; J R: k; Y# o0 m# K' {) v
将定时器4设为普通定时器来读取捕获数量,分频数为48000得到10KHZ频率,计数30000为3秒,同时开启自动重载防止溢出。同时在“NVIC Setting”中开启全局中断。
5 B& T' L4 t1 {' J+ Q6 H8 U' E3 `8 n
5 |" l; l% ~7 X! |* G. p/ U# v( X0 X& O0 I, ?& D2 ~* Z1 v
7.5.2 配置串口传输数据6 e4 V" [8 o3 l2 D" X
接下来对串口进行配置,将“USART1”打开。并开启USART1全局中断。$ f2 c$ l8 s2 z' w& [
7 L/ G# a! c- `% i6 Y$ w6 P _" ^
+ o* w- ^2 _+ M& y
) A* X& D3 X+ i8 ~6 p, h8 Y0 A同时进入“NVIC”中断时序管理页面中,将“USART1”的中断优先度取到3。* }" w/ F5 o6 Y( B2 o
/ |) m9 l' V) {3 a7 z
- ~2 }& |5 @- r# [# J/ z
$ j( Y+ D8 p# d8 Y5 H/ q( Z2 Z z; B: z同时找到PA9和PA10将它们设置为USART1的RXD和TXD引脚,方便USB读取。/ j8 y+ v+ t! D" j, o) w% J
4 h/ c! S0 e$ O1 o
4 e. j( y/ D0 w( e
. n( A7 j! ~( F# D. W
点击保存并生成代码。
$ Q. ]8 t6 K8 ^1 }: C
. R1 o3 K% Q0 V# l- m: B/ e9 k2 ]6 v7.5.3 配置定时器捕获代码/ J* p' p5 C k1 A l& e' h
首先我们需要重新到“NVIC.h”中添加“usart.h”以及printf和定时器捕获函数的声名。& w+ d* R! l8 |1 C# s
5 W3 x( K3 D$ L" o: D1 W
# h0 L1 i9 u5 J; Q* ]" A' x; U
7 c4 ?1 r( \5 s. h* O! L7 e. Z
接着到“NVIC.c”文件中添加一些用于储存定时器捕获的缓存变量,并在“NVIC_Init”函数中添加定时器4的初始化用于3秒反馈一次数值。% @ D2 C1 w9 V3 g0 i
4 x4 l& D7 a, w$ f/ o; f5 Q4 m
" ?# I% D0 R {
, m7 |9 R( ^3 @同时添加新的“NVIC_Catch”函数用于在main函数中开启定时器中断并反馈数值。
# g$ A7 S# B: |1 Z2 L& k, O- S2 [; S4 U. i0 f
# u' g( U3 j; S7 |0 V9 Y
9 i9 _9 w: B; |+ v' N; M! E$ K在定时器反馈函数“HAL_TIM_PeriodElapsedCallback”中添加定时器4的反馈值,使其3秒向串口传输一次数据。
4 N) k% L \0 } k% C( O6 |接着再添加一个输入捕获到上升沿的回调函数“HAL_TIM_IC_CaptureCallback”用于对捕获的上升沿信息进行处理并储存至缓存数组中。/ K' G* Q4 ~3 U H
# l' {2 H! O$ M1 i
; E- t. S$ s4 {' m' j2 u9 N9 b
6 [) C: g) L7 @; Y; G最后别忘了在Main函数中添加”NVIC_Catch”。
" u" m: v. r1 a7 w) j8 Q2 Q2 ^2 m2 P( J9 R' G
$ r4 r0 v! u# n# o1 L
4 D3 U! V' ~2 Q! O4 I* w6 l
将程序烧录 至单片机后,将USB MINI线从ST-Link拔下来并连接串口。
+ N; O- g) k% R8 d9 h5 a由于选用的定时器2通道1串联了按键至3.3V,因此在打开串口后,按“KEY_UP”按键即可手动制造一个上升沿给单片机,并在串口中显示出来。0 f# U, c/ v6 M0 W
) s, \0 R3 j5 F9 g
+ P4 ~) v4 E3 {2 u4 b: P
, l* G( s# m( x8 r+ H D
* c: R0 F7 B0 Q' ~( v( s* Y
* R7 Z% e" A; `( G1 L3 N/ T& t- @7.5.4 定时器捕获函数介绍
) x' P2 U- h s__HAL_TIM_SET_CAPTUREPOLARITY不是函数,而是底层操作的一个宏定义. J$ [4 D t0 f9 M
在stm32H7xx_hal_tim.h文件中找到。其作用是修改定时器某一通道的输入捕获极性
! b2 M' z2 b$ m: C
7 R7 x- g: U# v; |: ~2 c
0 _0 N+ K7 w; a4 K6 Z. m
. b6 x% N q2 S其中有两个函数,第一个为清除清除原来的捕获极性,第二个为设置通道捕捉极性
4 X9 K( J# I# Q1 i等价于:
k- x3 Y& w. O/ E6 [! [TIM_RESET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1); //清除原来的捕获极性
5 w& t6 X1 j$ X$ a- MTIM_SET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获(重设捕获极性)
3 i9 N+ @4 ?# s8 x9 T! ~$ e0 @在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性2 R# B/ w5 I. I$ o! }' L
__HAL_TIM_GET_COMPARE也是一个宏定义。
# s. t, T8 x8 S0 m' t& M: C& t- t! B1 B在stm32H7xx_hal_tim.h文件中找到。其作用是获取定时器某一通道的捕获寄存器值
2 z0 t9 `# S) d/ u2 W* ^6 @7 |0 o" o% y# N
0 W; J) A t2 m, k, N& u/ Z( Q- ]5 e
; @2 i _9 `% F v等价于 : HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
/ A) O2 H4 |$ O4 V$ ^5 F, r1 `" m* e两者都是直接读取对应CCRx寄存器的值。附上程序源码:, W8 q1 _1 u# O# B
) n' F& p, c8 y c7 Y7 r- #include "main.h"
) f. K2 o! k* n1 O4 J/ l# [ - #include "tim.h"4 l0 p6 q- s& s3 n! k1 G
- #include "gpio.h"
. {: ^3 D9 @, |& Q - #include "usart.h"* ]( v @2 `7 ]0 c7 @' l, |
- #include "stdio.h"
+ b: D" E7 T7 V; m- s9 y% d - // 重定向printf start {5 ^6 k" |# p B
- __attribute__((weak)) int _write(int file, char *ptr, int len)# N/ g+ }& }6 L7 n
- {
( H7 d0 a" U* ?# c$ v) p - if(HAL_UART_Transmit(&huart1,ptr,len,0xffff) != HAL_OK)
/ H9 ]* b# l: z - {+ C6 s: e! t2 A z% R
- Error_Handler();
Y6 @5 L1 g I; y$ O/ C - }
% B5 _8 {" R# R9 }5 N - }
7 u o2 x$ z* c% X; Z* @' [# D - // 重定向printf end% Y* C* M4 J9 {# ^- a# K, b8 i9 o
- void NVIC_Catch(void);* g, b8 P3 g1 @
- void NVIC_Init(void);
2 ^; k1 H7 K- Y# D
复制代码- #include "NVIC.h"
2 O! j3 a. y% A+ j - static int capture_Buf[3] = {0}; //存放计数值
1 `7 v! n5 o, c2 d - static int capture_Cnt = 0; //状态标志位6 U# H8 X* c4 ]( q, Z& W# Z$ {
- static int high_time=0; //高电平时间
2 ^4 D% e: |3 a, f% B - void NVIC_Init(){
% ?. v; h& C$ S6 q2 S# D* P+ d - HAL_TIM_Base_Start_IT(&htim1); //HAL库开启定时器1
3 @, X3 m1 L4 @6 ?( b6 ~ - HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);//HAL库开启定时器3,并使用通道4输出PWM9 b+ e, o3 `) T' L
- __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 990);//HAL库修改占空比至99%5 Z$ L% h& u- Y: R1 o0 A9 F% ]6 q" i
- HAL_TIM_Base_Start_IT(&htim4); //HAL库开启定时器15 ]$ M( Q3 L. p
- }
复制代码- void NVIC_Catch(){
7 w/ B+ ?( p# p; j6 o) C8 f - switch (capture_Cnt){6 S6 h0 {0 _$ n. m
- case 0:
4 r4 b& N+ G$ J - capture_Cnt++;
/ ~ P7 p$ o6 w/ a; J% X - __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);- ~5 e& U( z/ ^1 [0 D
- HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); //启动输入捕获 或者: __HAL_TIM_ENABLE(&htim2);
( S( g/ }* ~# `8 r; E- X - break;
2 f% z. w/ x7 \& O" s- g - case 3:" x$ T4 \1 E& n" q
- high_time = capture_Buf[1]- capture_Buf[0]; //高电平时间8 E' p+ m8 b5 O
- capture_Cnt = 0; //清空标志位
6 T* Z* I8 I; ~ c c - break;
% U1 J- R' ]6 w C `1 d# J - }
' R, A) n( a N. V2 I4 O1 M8 P - }
复制代码
2 X$ \9 D2 G7 \# r) f k0 o- U/ G J/ G Z9 L$ U& D: V
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //中断回调函数
$ c( l* x4 j5 ]- t" t& e$ {& T - if (htim->Instance == htim1.Instance) { //判断是哪个定时器产生中断7 J6 k% \9 | d1 y
- HAL_GPIO_TogglePin(IO_LED0_GPIO_Port, IO_LED0_Pin); //HAL库控制IO_LED0电平反转# c/ ~. @, z7 Z h3 Q/ m
- {0 b1 [% B7 B* N f; C# R" V I. L
- if(TIM2 == htim->Instance)6 J. Y \1 }4 U
- {
t& j: h' g4 Z - switch(capture_Cnt){, s# Q% W+ z& d4 Q
- case 1: a8 W F# i! v
- capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
, F1 ~- o7 j: b. _2 c; _ - __HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置为下降沿捕获
8 n6 I# m: z+ g% q/ C1 ]0 ~ - capture_Cnt++;) A/ y9 a/ G1 C* U, p! g* a
- break;
2 ]# ^- m7 [* x/ i3 z1 W: Y - case 2:
3 q9 n8 u& w$ [5 y1 f9 O - capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.( w j$ j& B2 J8 y
- HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1); //停止捕获 或者: __HAL_TIM_DISABLE(&htim2);
! y, e+ X- e1 q4 J - capture_Cnt++;5 O7 a% O/ o M; o6 o% V+ D
- break;3 U+ l; f4 B/ K8 j* S
- }2 {/ ]+ |) ?, O' F% i4 V
- }
$ ~; n' G! E* h& W - }
& f' b9 B& i* l7 m - " X( v0 S: g! h) T( M
- , E3 l, f2 _- O$ V% p) ^( ~
- & [5 X7 N! U5 }4 V H' `4 p
复制代码 , z4 P# N$ U- G2 l" D
2 b, `! x& k! G/ I* E* i
|