stm32输入捕获,捕获高电平

输入捕获就是用定时器检测引脚上的电平时间,可以检测高电平时间和低电平时间,然后可以算引脚上信号的频率和占空比。

基本思路就是利用定时器的输入捕获功能。

定时器捕获到高电平或低电平就会进入捕获中断

例如:

我们要捕获高电平时间

0 设置定时器计数频率和装载值,一般设置1MHz,65535

1 设置定时器捕获为高电平捕获

2 进入捕获中断后,获取CNT计数值或CCRx值,定时器捕获到电平后会把CNT的值保存到CCRx。

   设置成低电平捕获。

3 再次进入捕获中断,获取CNT计数值-上次的CNT值=总高电平时间。

   设置成高电平捕获。

4 重复2-3即可完成下一次捕获。当然还要考虑溢出的情况,代码里有处理。

下面我写的一个实例:

1 定时器1 PA8产生PWM信号,可改变占空比,检测高电平时间

2 捕获定时器是定时器2,初始化如上例。

3 仿真改变PA8占空比,查看捕获出的高电平时间。

实测:

duty=1000就是高电平维持1000us,

捕获时间也是对应的1000us,一点误差都没有。

代码如下:

//高电平标志
u8  gao_flag=0;
//高电平时间
u32 gao_timer=0;
//捕获成功标志
u8  buhuo_flag=0;
//溢出次数
u8  yichu_c=0;

//定时器 5 中断服务程序
extern "C" void TIM2_IRQHandler(void)
{
  if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
   {

		 
		 if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)		//这个是溢出中断
		 {
			 //如果已经得到高电平了,CNT溢出了
			 if(gao_flag==1)
			 {
				 
				 yichu_c++;  //溢出加1
				 
			
			 }
			 
		 }
		 
			
		if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获 1 发生捕获事件
		{
			  if(0==gao_flag&&buhuo_flag==0) //说明之前没有捕获到高电平
				{
					gao_timer=TIM2->CCR1;  //获取高电平时间

					yichu_c=0;       //溢出清零
					
					gao_flag=1;			//高电平标志
					
					TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //改成下降沿捕获
				}
				//再一次进入捕获中断说明是捕获到下降沿了
				else
				{
					if(buhuo_flag==0)   //判断是否捕获成功了,如果捕获成功了就不在捕获了
					{
					
						gao_timer=TIM2->CCR1-gao_timer;  //获取捕获到的高电平时间
						gao_timer+=yichu_c*65536;       //加上溢出时间

						TIM2->CNT=0;									//计数清零
						
						gao_flag=0;                   //高电平标志清零
						
						buhuo_flag=1;		            //标志捕获成功了
						
						TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //改成上沿捕获
						
						
					}
					
				}

		}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}

void TIM1_PWM_Init(u16 arr,u16 psc)
{
		GPIO_InitTypeDef     GPIO_InitStrue;
    TIM_OCInitTypeDef     TIM_OCInitStrue;
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseInitStrue;
    
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);        //使能TIM3和相关GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 使能GPIOB时钟(LED在BP5引脚),使能AFIO时钟(定时器3通道2需要重映射到BP5引脚)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitStrue.GPIO_Pin=GPIO_Pin_8;     // TIM_CH2
    GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;    // 复用推挽
    GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;    //设置最大输出速度
    GPIO_Init(GPIOA,&GPIO_InitStrue);                //GPIO端口初始化设置
    
		//TIM1->CCMR1&=0xF7F7; //关闭事件更新值
		//TIM1->CCMR1|=0x808; //开启事件更新值

    TIM_TimeBaseInitStrue.TIM_Period=50000;    //设置自动重装载值
    TIM_TimeBaseInitStrue.TIM_Prescaler=71;        //预分频系数
    TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up;    //计数器向上溢出
    TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1;        //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1
    TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStrue);        //TIM3初始化设置(设置PWM的周期)
    
    TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2;        // PWM模式2:CNT>CCR时输出有效
    TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_Low;// 设置极性-有效为高电平
    TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
		
		TIM_OCInitStrue.TIM_Pulse=100;
		
    TIM_OC1Init(TIM1,&TIM_OCInitStrue);        //TIM3的通道2PWM 模式设置

    TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);        //使能预装载寄存器
    
    TIM_Cmd(TIM1,ENABLE);        //使能TIM3
		TIM_CtrlPWMOutputs(TIM1, ENABLE);  
		
		TIM1->CCMR1&=0xF7F7; //关闭事件更新值
		
}

void capture_init(u16 arr,u16 psc)
{
	TIM_OCInitTypeDef TIM2_OCInitStructure;
	TIM_ICInitTypeDef TIM2_ICInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能 TIM2 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前设置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉

	//初始化定时器 2 TIM2
	TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化 TIMx 的时间基数单位

	//初始化 TIM2 输入捕获参数

	TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上
	TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
	TIM2_ICInitStructure.TIM_ICPrescaler = TIM_CKD_DIV1; //配置输入分频,不分频
	TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
	TIM_ICInit(TIM2, &TIM2_ICInitStructure);
	
	


	//中断分组初始化
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2 中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 2 级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
	NVIC_Init(&NVIC_InitStructure); //初始化外设 NVIC 寄存器
	TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	

	
	TIM_Cmd(TIM2,ENABLE ); 	//使能定时器3
	
}

u16 duty=1000;

int main(void)
	
{
	

   
   serial_init(115200); //串口初始化为 9600
   
   TIM1_PWM_Init(1000,71); //
	
	PAout(1)=1;
	
   capture_init(0XFFFF,72-1); //以 1Mhz 的频率计数
	
	printf("init\r\n");
	
	
	
  while(1)
   {
		 
		 //测试位运算和逻辑运算的速度
	
		 
		PAout(1)=1;
	
	  
		 
		 
		 TIM1->CCR1=duty;
		 
    delay_ms(10);
		 
	
		if(buhuo_flag==1)
		{
			printf("HIGH1:%d us \r\n",gao_timer); //打印总的高点平时间
		
			buhuo_flag=0;  //重新捕获
			
			
		}
		
		PAout(1)=0;
		  delay_ms(10);

   }

		
}

 

  • 5
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的示例代码,用于在STM32上进行输入捕获以测量光电传感器的高电平时间: ```c #include "stm32f4xx.h" #define TIMx TIM2 #define TIMx_CLK RCC_APB1Periph_TIM2 #define TIMx_IRQn TIM2_IRQn #define TIMx_IRQHandler TIM2_IRQHandler #define TIMx_CH1_PIN GPIO_Pin_0 #define TIMx_CH1_PORT GPIOA #define TIMx_CH1_PINSRC GPIO_PinSource0 #define TIMx_CH1_AF GPIO_AF_TIM2 #define SENSOR_PIN GPIO_Pin_1 #define SENSOR_PORT GPIOA volatile uint32_t sensorHighTime = 0; void TIMx_Configuration(void) { TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Enable the TIMx clock */ RCC_APB1PeriphClockCmd(TIMx_CLK, ENABLE); /* Enable the GPIOA clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* Configure TIMx_CH1 pin as input floating */ GPIO_InitStructure.GPIO_Pin = TIMx_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(TIMx_CH1_PORT, &GPIO_InitStructure); /* Connect TIMx_CH1 to GPIO pin */ GPIO_PinAFConfig(TIMx_CH1_PORT, TIMx_CH1_PINSRC, TIMx_CH1_AF); /* TIMx configuration: Input Capture mode --------------------- The external signal is connected to TIMx_CH1 pin (PA.0) The Rising edge is used as active edge, The TIMx CCR1 is used to compute the frequency value ------------------------------------------------------------ */ TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_ICInit(TIMx, &TIM_ICInitStructure); /* Enable the TIMx global Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIMx_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Enable the CC1 Interrupt Request */ TIM_ITConfig(TIMx, TIM_IT_CC1, ENABLE); /* TIMx enable counter */ TIM_Cmd(TIMx, ENABLE); } void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Enable the GPIOA clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* Configure the SENSOR pin as input */ GPIO_InitStructure.GPIO_Pin = SENSOR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(SENSOR_PORT, &GPIO_InitStructure); } int main(void) { /* System Clock Configuration */ SystemInit(); GPIO_Configuration(); TIMx_Configuration(); while (1) { /* Wait for the sensor pin to go high */ while (GPIO_ReadInputDataBit(SENSOR_PORT, SENSOR_PIN) == 0); /* Wait for the input capture interrupt to occur */ while (sensorHighTime == 0); /* Print out the sensor high time */ printf("Sensor High Time: %d us\n", sensorHighTime); /* Reset the high time value */ sensorHighTime = 0; } } void TIMx_IRQHandler(void) { if (TIM_GetITStatus(TIMx, TIM_IT_CC1) != RESET) { static uint32_t lastCaptureValue = 0; uint32_t currentCaptureValue = TIM_GetCapture1(TIMx); uint32_t captureDiff = currentCaptureValue - lastCaptureValue; /* Check for timer overflow */ if (TIM_GetFlagStatus(TIMx, TIM_FLAG_CC1OF) != RESET) { captureDiff = (0xFFFF - lastCaptureValue) + currentCaptureValue + 1; } /* Calculate the sensor high time */ if (captureDiff > 0) { sensorHighTime = captureDiff * (1000000 / SystemCoreClock); } /* Save the current capture value as the last value */ lastCaptureValue = currentCaptureValue; /* Clear the interrupt flag */ TIM_ClearITPendingBit(TIMx, TIM_IT_CC1); } } ``` 在此示例中,我们使用了STM32输入捕获功能来测量光电传感器的高电平时间。我们使用TIM2通道1来进行输入捕获,并将光电传感器连接到GPIOA的Pin1。 在主循环中,我们等待光电传感器Pin1变为高电平,然后等待输入捕获中断发生。一旦中断发生,我们将高电平时间打印到串口,并重置高电平时间值以等待下一个读数。 在输入捕获中断处理程序中,我们计算当前时间和上一个时间捕获之间的时间差,以得到高电平时间。我们还需要注意,如果计数器发生了溢出,我们需要正确地计算时间差。 最后,我们需要在`stm32f4xx.h`头文件中定义`SystemCoreClock`,以便正确计算时间差。 这只是一个简单的示例代码,仅演示了如何使用输入捕获来测量光电传感器的高电平时间。实际应用中可能需要对代码进行修改以满足特定的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值