实验内容:使用通用定时器输入捕获测量信号的脉宽(检测按键按下的时间)。
1 z4 [+ ~1 u, [6 L9 [+ K4 z" Z* Q) }. L9 q3 ^3 k! w0 y
一、原理图
5 A8 E$ U. U, F' N
5 @; V* g$ S1 t6 q
6 P2 I s6 ]$ W
0 A4 z! J7 q9 V: k t3 G R
二、 CubeMX配置
4 G+ l- T7 I0 t/ X2 u
) m* d J" L8 [( M0 ^Step1.打开 STM32CubeMX,点击“New Project”,选择芯片型号,STM32F103VETx。6 _* ^( K$ l( d& ` k! W$ t2 f8 t
2 T- p, P+ C7 s9 D5 [2 A' S
$ ^0 d2 [9 C2 X6 t, V) E; t
3 h4 U! N3 @+ A; o' y E Step2.选择时钟源,并配置时钟树。选择Crystal/Ceramic Resonator,并配置系统时钟为72M。
/ m/ X1 e$ v. v
0 |- c( ]! A0 w
3 X/ l5 P! K% ?) I- g& M
- i) v$ E. r7 D4 ]1 Q: Q% j: Y2 ^
3 K* r4 S0 P" y
" Q/ H" G; L1 f9 @* c- S2 w! bStep3.配置SYS,我们这里选择的是Serial Wire。(正常情况配置不配置不影响,debug可以使用。但是你不可以把这两个引脚用于其他复用功能,如果用于其他复用功能,debug就不起作用了。)
. Y' V- m* g2 U3 n, D
4 i4 N& I5 l5 a6 V) C
( q( J4 z: Z/ H6 _# ~+ e
4 h$ P' x( ^1 Q ? KStep4.串口配置(主要为了在串口调试助手显示测试的时间),因为没有用到中断和DMA所以我们就不过多讲解。7 r; a$ ~8 B7 c9 ?' N0 Y. W
" z9 a& d, i, z1 z3 ?1 R3 Z
9 ?5 G. |6 e7 o, W# `7 D6 Y ]* Q; q( M5 s) @. D. s
( C/ H" w7 @7 Y& C9 ^3 n/ \" y
3 W; L7 |1 y! `
Step5.接下来进行最主要的定时器配置。原理图中按键引脚PA0和定时器2通道1相关,因此我们选用定时器2进行配置。
7 e, `: D) N- ~: [) M' y: C
! J" r3 P2 U K3 I3 b5 Y
- h& t+ z' N/ O& d* I0 r# z7 e6 G* S! | d
2 y' T" a! M2 k; g' h* g4 p
! u- C z% h, h6 n6 } S1 O 到这里关于相关参数配置基本已经完成,只需要根据之前文章《STM32Cube HAL:GPIO输入/输出(一)》Step4-Step8,设置相关工程参数和生成代码。
" `3 e" O/ m, w" T5 }- ?1 a# l: _ M
三、添加功能代码: `: g+ O" |8 Z& [; v" X
5 D, U \$ }) Z' {4 c2 ?
1、我们等会会向串口调试助手发送数据,进行实验结果的验证。 发送数据我们采用printf函数,所有需要重定向c库函数printf到串口。注意使用时需要在keil设置中勾选微库(use mircolib),同时需要添加头文件#include <stdio.h>。重定向代码如下(usart.c)! v- v9 q* ^& Y% c/ E
+ b0 c% m a" o0 ]% D- G$ |* O6 Q
- //重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数( q# D2 y3 b- `: S
- int fputc(int ch, FILE *f)
$ o u! ^. e* _" T+ ~1 ?" d7 z" |. X - {
0 i3 M2 ^4 x5 }' H - /* 发送一个字节数据到串口DEBUG_USART */
/ O9 l1 B# o8 z5 J8 s2 }% } - HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
. ^' H8 K! e! ^/ T -
, r1 v5 P$ H* A1 ]4 F - return (ch);3 F3 r8 `. e' n+ ?
- }+ H. J& f4 j3 k0 B
/ A' N( G: f* g& D' V, t: x- //重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
5 J. x% c4 b1 T# [( S) t - int fgetc(FILE *f)
9 U* M" ^# P- `: I- m - {
( v! r/ L6 b/ }4 u$ ] - int ch;
4 w/ k0 V* L3 j# _. m - HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000); # J/ J L. S0 f3 Y
- return (ch);" c: X/ f2 K' g+ t; f" Z
- }
; k( L0 f2 ?' H) G
复制代码 ; n2 [, s, ]" M/ v6 Y7 _4 U
2、定义相关变量,以及使能相关定时器和计数处理代码(main.c)
5 {3 `; `. L0 I6 {/ y( d0 o* {7 }! R) K% x; |% s" I9 Q% j u
- //全局变量% k& R9 T( Z5 t, V3 P3 K- V: @: M2 V+ z
- uint32_t ccr_cnt,period_cnt;//CCR寄存器值,中断次数1 c1 B' C9 U! d p$ V. T
- uint8_t tri_flag,end_flag;//触发方式标志位,捕获标记位
复制代码- //局部变量! V6 R M( E. V- e
- uint32_t cnt_cl=72000000/72;;//计数器时钟& `8 D* e( [2 g2 h
- float time;//按键时间
复制代码- //使能相关定时器以及计数结果处理代码" d H7 Q6 X) V/ u( ~
2 i1 Q5 M+ Q- [! {- [- __HAL_TIM_CLEAR_FLAG(&htim2,TIM_IT_UPDATE);//清除中断标志位,防止一使能定时器就进入中断
% ]" M1 h8 d0 f" R. w& ^ - HAL_TIM_Base_Start_IT(&htim2);//使能定时器及更新中断4 k( d% J$ U& r% s
- HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//使能定时器及捕获中断
2 o6 Y0 V- Y. z, u6 |, c* G0 @$ d
; y& F, E/ ^8 f2 Z5 \- printf("\r\n——————————开始按键测试——————————\r\n");0 k+ D% D" X7 f) k! U% G
- ! d. x& O* Q/ `
- while (1)
# J. c2 ]2 q2 G/ a N6 j% M' P0 m - {; |/ Z& l, ^* p) H
- if(end_flag==1)//结束捕获* |/ t" a/ D* h' G6 q2 _) E
- {& ]1 s4 S- E0 E0 X3 u8 W4 z: Z
- time=(float)(period_cnt*1000+(ccr_cnt+1))/cnt_cl;//结果强制转换为浮点型8 l' F# i O- P+ g" U% w0 ~
- printf( "\r\n测得高电平脉宽时间:%.2fs\r\n",time);//输出结果保留小数点后两位) U! C9 {2 M) O% {( P3 ]( u
- end_flag=0;
* w0 H# t! f( @4 H0 u1 a* L/ ` - }
* A' ]& t/ R! R - }
复制代码
, I N6 t) V+ y$ x$ A* q# [% c+ i' S/ B& }
3、中断回调函数(更新中断和捕获中断)(main.c)
' x5 Q0 _8 g, _; N
+ S+ q' y$ b; |7 U* S- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)* P Z9 n8 p/ q
- {
3 C1 o8 j+ J+ }2 t, v1 W - period_cnt++;//中断计数2 ^# N- B% b: \! F
- }+ C0 j, \8 p. s' j; o
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
2 J/ G5 e, l3 \ - {
/ {7 Z5 j! c* ]5 v8 A; n - + r/ Y- ^& h1 ^) r: t
- if(tri_flag==0)//上升沿触发时进入(tri_flag 0 上升沿触发 / 1 下降沿触发)
" T c. I: o+ _' c6 v& p - {( R& l( n/ ^9 M* h. J6 o2 G5 S% B
- period_cnt=0;//中断次数清零9 B `' ?2 ]2 W
- __HAL_TIM_SET_COUNTER(&htim2,0); //计数器清零2 ~2 i. v0 o" `" C- a( F
- ccr_cnt=0;//存捕获寄存器获取的值的变量清零
) i" N* ]$ t& [ @; D - __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);//改变触发极性-下降沿触发. L: ]: J0 G6 m4 u6 q, E0 M
- tri_flag=1;) R. G/ {, ^3 C9 t2 o) Z
- }7 n) v8 B* r s# n: [+ k0 u
- else//下降沿触发时进入
6 H0 Y( U+ D, Z2 m$ t5 T - {$ {& x% Y, ?9 `
- ccr_cnt=__HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_1);//获取捕获寄存器的值
( t" y4 D p6 ~$ [" G - //ccr_cnt=HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);//功能同上
( c& V5 i0 J) T$ c4 o4 M8 @ - __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);//改变触发极性-上降沿触发3 b- L6 N) C) |7 T* h- [$ Y, U
- tri_flag=0;1 R- Q! G* }) Z4 R( C7 _
- end_flag=1;//捕获完成标志/ i; i2 E* d4 q. r; W
- }$ q. a x/ [0 y% P3 O" n+ O* u
- }
复制代码 7 v4 U/ p' a) i8 ~! ^. m# {+ p3 A, J, ?
' O) w. J3 Z) P
总体来这个实验还算简单,主要的思路是先捕获第一个上升沿,然后将计数器值,中断计数值以及CCR寄存器(存捕获寄存器获取的值的变量)清零,同时变换为下降沿触发,进行第二次捕获,通过第二次的触发获取中断计数值以及CCR寄存器的值来计算出按键按住的时间。; F1 a0 [6 V4 V/ B) t( V
2 |/ w' v' v2 @" | U; I
$ H6 }3 @* d2 ]9 w6 i |