实验目的:
在串口调试助手上打印出按键按下的时间
实验步骤:
实验程序:
-
/*******************************timer.c********************************/
-
#include "sys.h"
-
#include "stm32f4xx.h"
-
-
-
extern u8 TIM5CHA1_CAPTURE_STA;
-
extern u16 TIM5CHA1_CAPTURE_VAL;
-
-
-
/*
-
本示例的作用就是,
-
当按键按下时,每次输入捕获的时间差,
-
然后从串口调试助手中打印出其时间差;
-
*/
-
-
-
/*
-
关于输入捕获的操作可参考寄存器版的步骤
-
*/
-
-
-
/*
-
定时器输入捕获的初始化函数:
-
主要是关于寄存器的相关配置
-
*/
-
-
-
/*初始化定时器5为输入捕获*/
-
void TIM5_Init(void){
-
-
/*************************
-
定时器输入捕获的设置:
-
*************************/
-
-
/*将按键KEY_UP复用*/
-
/*1.使能GPIO端口时钟*/
-
RCC->AHB1ENR |=
1;
-
/*这里还需要将其配置成下拉,
-
因为在输入捕获中,将通过上升沿来触发;
-
*/
-
GPIOA->PUPDR |=
0X2;
-
-
/*2.使能复用外设时钟*/
-
RCC->APB1ENR |=
1<<
3;
-
-
/*3.端口模式配置为复用功能*/
-
GPIOA->MODER |=
0X2;
-
-
/*4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器,
-
将IO连接到所需的复用外设*/
-
GPIOA->AFR[
0] |=
0X2;
-
-
-
-
/*设置定时器5的输入捕获*/
-
-
//设置TIM5的分频和自动重装
-
TIM5->PSC =
84
-1;
-
TIM5->ARR =
0XFFFF
-1;
//芯片手册上写着是16位,
-
-
//设置滤波/映射/分频
-
TIM5->CCMR1 |=
0X1;
-
-
-
//设置上升沿触发并使能捕获
-
TIM5->CCER |=
0X1;
-
-
//使能更新中断和使能捕获中断
-
TIM5->DIER |=
0X3;
-
-
//使能计数器
-
TIM5->CR1 |=
1;
-
-
-
//设置中断优先级
-
SCB->AIRCR |=
0x5 <<
8;
//设置分组
-
NVIC->IP[
50] |=
0;
//设置优先级,具体可分析MY_NVIC_Init()函数;
-
-
//只要涉及中断,最后一定记得使能中断;
-
//若不使能,则中断不会发生
-
NVIC->ISER[
1] |=
1<<
18;
//使能中断;
-
-
}
-
-
-
-
/*每次在按键按下时,输入捕获按键,
-
然后每产生两次中断,就在在中断里边
-
算出两次捕获之间的时间差;
-
*/
-
void TIM5_IRQHandler(void){
-
-
/*
-
中断处理函数:
-
*/
-
-
-
if((TIM5CHA1_CAPTURE_STA &
0x80) !=
0x80){
//说明一次完整的输入捕获还没有结束;
-
-
-
-
if((TIM5->SR &
0X1) ==
0X1){
//说明是溢出标志发生
-
-
-
if((TIM5CHA1_CAPTURE_STA &
0x40) ==
0x40){
//只有捕获到高电平之后,
-
//我们才累计计数计数器的值
-
if((TIM5CHA1_CAPTURE_STA &
0x3f)==
0x3f){
//说明能累计的计数器已满;
-
//在这里,高电平持续的时间最多为4s
-
TIM5CHA1_CAPTURE_STA |=
0x80;
-
TIM5CHA1_CAPTURE_VAL =
0xffff;
-
-
-
}
else{
-
-
TIM5CHA1_CAPTURE_STA++;
-
}
-
-
-
}
-
-
}
-
if((TIM5->SR &
0X2) ==
0X2){
//说明上升沿或下降沿已捕获
-
-
-
if((TIM5CHA1_CAPTURE_STA &
0x40) ==
0x40){
//说明下降沿已触发
-
-
TIM5CHA1_CAPTURE_STA |=
0x80 ;
//说明上升沿和下降沿一个周期的捕获已完成 ;
-
TIM5CHA1_CAPTURE_VAL = TIM5->CCR1;
//保存发生下降沿触发时计数器的值;
-
-
//设置上升沿触发并使能捕获
-
TIM5->CCER &= ~(
1<<
1);
-
-
}
else{
//说明上升沿已捕获
-
-
//禁止定时器5的计数器
-
TIM5->CR1 &= ~(
1);
-
-
//让计数器的值为0,以便计算从0到下一次下降沿捕获的值之间的计算;
-
TIM5->CNT =
0;
-
-
//设置输入捕获为下降沿触发
-
TIM5->CCER &= ~(
0XF);
-
TIM5->CCER |=
0X3;
-
-
//初始化要计数的值;
-
TIM5CHA1_CAPTURE_STA =
0;
-
TIM5CHA1_CAPTURE_STA |=
0X40;
-
TIM5CHA1_CAPTURE_VAL =
0;
-
-
//使能计数器
-
TIM5->CR1 |=
1;
-
-
}
-
-
}
-
-
}
-
-
/*
-
在中断里边最后记得清中断标志:
-
*/
-
TIM5->SR &= ~(
0x3);
-
}
-
/*******************************timer.h*********************************/
-
#ifndef _EXTI_H
-
#define _EXTI_H
-
-
-
void TIM5_Init(void);
-
-
-
#endif
-
/*******************************test.c***********************************/
-
#include "sys.h"
-
#include "delay.h"
-
#include "beep.h"
-
#include "exti.h"
-
#include "led.h"
-
#include "uart.h"
-
#include "usart.h"
-
-
-
-
u8 TIM5CHA1_CAPTURE_STA;
-
u32 TIM5CHA1_CAPTURE_VAL;
-
-
-
int main(void){
-
-
u8 i =
0;
-
long
long temp =
0;
//这里的值比较大,所以选择long long
-
-
Stm32_Clock_Init(
336,
8,
2,
7);
//设置时钟,168Mhz
-
delay_init(
168);
//初始化延时函数
-
LED_Init();
-
Beep_Init();
-
TIM5_Init();
-
UART_Init();
-
-
-
while(
1){
-
-
PFout(
9) =
0;
-
delay_ms(
500);
-
PFout(
9) =
1;
-
delay_ms(
500);
-
-
if((TIM5CHA1_CAPTURE_STA &
0x80) ==
0x80){
//若一个完整的捕获周期(上升沿和下降沿)
-
-
-
i = TIM5CHA1_CAPTURE_STA &
0x3f;
-
printf(
"TIM5:%d\r\n",i);
-
//计算累计的时间(高电平到低电平的之间的时间差)
-
temp = (TIM5CHA1_CAPTURE_STA &
0x3f)*
0xffff;
-
temp += TIM5CHA1_CAPTURE_VAL;
-
-
-
printf(
"temp:%lld us\r\n",temp);
//思考printf()函数是如何做的;
-
-
//重新初始化
-
TIM5CHA1_CAPTURE_STA =
0;
-
TIM5CHA1_CAPTURE_VAL =
0;
-
-
}
-
-
}
-
}
实验分析:
1.定时器的框图及输入捕获框图的放大版
注:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,
将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
2.输入捕获的工作流程分析:
<1>
<2>
<3>
<4>
<5>
3.中断处理函数部分的提示
注意事项:
1.只要涉及到中断,在最后一定都要记得使能中断
2.按键那块,处理不是很好,有时会一连打出好几串数字;
更准确的说是按键有时会有些抖动,就相当于按了好几下,但没有滤掉波段较小的那一部分;