1. 实验目的
使用定时器TIM5 的通道 1(PA0)来做输入捕获实验,捕获 PA0 上高电平的脉宽(用 KEY_UP 按键输入高电平),最后通过串口打印高电平脉宽时间。
2. 实验准备和流程
如图所示,WK_UP是与引脚PA0相连接的,正常情况下,未按下KEY_UP键,PA0是低电平,按下按键是高电平,实验目标就是捕获高电平脉冲的时间(就是按键按下去的时间)。
如图所示,PA0引脚是通用定时器5的通道1。通过配置PA0引脚的模式来实现输入捕获。
这里TIM5的时钟是84MHZ。
这里定时器的计算公式是:
Tout= ((arr+1)*(psc+1))/Tclk;
arr:自动重装载值;
psc:时钟预分频系数;
Tclk:TIM5 的输入时钟频率(单位为 Mhz),这里TIM5的时钟频率为是84Mhz;
Tout:TIM5 溢出时间。
按照下面的设置:计数一次的时间是 (65536 * 84) / 84000000 = 6.5536ms
输入捕获的原理如上图所示。
具体的流程如下:
初始化定时器;
配置中断优先级;
编写定时器中断函数;
编写main函数。
2.1 初始化定时器
//初始化定时器 TIM5/PA0 时钟是APB1(42M)84M
static void TIM_GPIO_Config(void){
GPIO_InitTypeDef GPIO_InitStructure; //GPIO的结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器时基结构体
TIM_ICInitTypeDef TIM5_ICInitStructure; //输入捕获结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5 时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //GPIOA0复用位定时器5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA0
//时基初始化
TIM_TimeBaseStructure.TIM_Prescaler = 84-1; // 定时器分频 84M/84=1MHZ
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period = 65536 - 1; // 自动重装载值25000,1M / 25000 =40Hz 这里计数一次是25ms
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割,时钟分频因子,配置死区时间的时候用到 ,这里是1分频,就是84M, TIM_CKD_DIV1 ((uint16_t)0x0000)
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //重复计数器的值,没有用到
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); //初始化时基结构体
//输入捕获结构体初始化
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //配置输入捕获的通道,需要根据具体的 GPIO 来配置
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上 ,是选择直连和非直连,1到1就是直连
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE); //允许更新和捕获中断
TIM_Cmd(TIM5,ENABLE); //使能定时器5
}
2.2 配置中断优先级
//中断优先级配置
void BASIC_TIM_NVIC_Config(void){
//NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStruct;
//设置中断优先级的分组
//就是设置主抢占优先级和子抢占优先级各是几,这里是分组为1,代表主优先级可以是0和1(就是1个位来设置主优先级),子优先级是0-7,是2的3次方
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置TIM5_IRQn为中断源
NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
//配置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
//配置子优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
//使能中断
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
调用两个函数,完成初始化
void TIM_Init(void){
BASIC_TIM_NVIC_Config();
TIM_GPIO_Config();
}
2.3 编写定时器中断函数
TIM_IT_CC1是TIM捕获1中断源。
结构体变量声明与初始化
typedef struct{
uint16_t Capture_FinishFlag; //捕获结束标志位
uint16_t Capture_StartFlag; //捕获开始标志位
uint16_t Capture_Period; //自动重装载寄存器更新标志
uint16_t Capture_CcrValue; //捕获寄存器的值
}TIM_ValueTypeDef;
TIM_ValueTypeDef TIM_ValueStructure = {
.Capture_FinishFlag = 0,
.Capture_StartFlag = 0,
.Capture_CcrFlag = 0,
.Capture_CcrValue = 0,
.Capture_Period = 0,
};
void TIM5_IRQHandler(void){
//当要被捕获的信号的周期大于定时器的最长定时时,定时器就会溢出,产生更新中断
//这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去
if(TIM_GetITStatus(TIM5,TIM_IT_Update) != RESET){ //判断更新中断状态位
TIM_ValueStructure.Capture_Period++; //计算加1
TIM_ClearITPendingBit(TIM5,TIM_FLAG_Update); //清除中断标志位
}
//上升沿捕获中断
if(TIM_GetITStatus(TIM5,TIM_IT_CC1) != RESET){ //判断上升/下降沿捕获中断
//判断是否是第一次捕获
if(TIM_ValueStructure.Capture_StartFlag == 0){
TIM_SetCounter(TIM5,0); //计算器清0
TIM_ValueStructure.Capture_Period = 0; //自动重装载寄存器更新标志清0
TIM_ValueStructure.Capture_CcrValue = 0; //存捕获比较寄存器的值的变量的值清0
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //改变捕获的边缘为下降沿
TIM_ValueStructure.Capture_StartFlag = 1; //开始捕获标志置1
}else{ //第二次捕获,就是捕获下降沿
//获取捕获寄存器中的值
TIM_ValueStructure.Capture_CcrValue = TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //改变捕获的边缘为上升沿
TIM_ValueStructure.Capture_StartFlag = 0;
TIM_ValueStructure.Capture_FinishFlag = 1;
}
TIM_ClearITPendingBit(TIM5,TIM_IT_CC1);//清空捕获中断标志位
}
}
2.4 编写main函数
int main(void)
{
uint32_t time;
//TIM计算器的驱动时钟
uint32_t TIM_PscCLK = 84000000/84;
USART_Config();
TIM_Init();
while(1){
if(TIM_ValueStructure.Capture_FinishFlag == 1){
time = TIM_ValueStructure.Capture_Period * 65536 + (TIM_ValueStructure.Capture_CcrValue + 1); //进入更新中断的次数 时间+Capture_CcrValue时间
printf("\r\n 测得高电平脉宽时间:%d.%d s\r\n",time/TIM_PscCLK, time%TIM_PscCLK);
TIM_ValueStructure.Capture_FinishFlag = 0; //标志位清0
}
}
}
3. 实验结果
按下按键时间长短不同,捕获的时间不同。