看野火的视频,用正点原子的板子(STM32F4探索者)做输入捕获(脉宽测量)实验

该文详细介绍了如何在STM32微控制器上利用TIM5的通道1进行输入捕获实验,通过捕获PA0引脚(连接到KEY_UP按键)上的高电平脉宽,最终通过串口打印脉宽时间。实验涉及初始化定时器、配置中断优先级、编写中断服务函数以及主函数。在不同按键按压时间下,捕获到的时间会有所不同。
摘要由CSDN通过智能技术生成

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. 实验结果

按下按键时间长短不同,捕获的时间不同。
在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值