实验目的:
在串口调试助手上打印出按键按下的时间
实验步骤:
实验程序:
/*******************************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.按键那块,处理不是很好,有时会一连打出好几串数字;
更准确的说是按键有时会有些抖动,就相当于按了好几下,但没有滤掉波段较小的那一部分;
上一篇:STM32学习笔记之__attribute__ ((at())绝对定位分析
下一篇:STM32的输入捕获
推荐阅读最新更新时间:2024-03-16 15:59