STM32CubeMX应用 -- 定时器输入捕获

目录

参考链接

一、实现过程

二、STM32CubeMX配置示例

三、C语言示例程序


参考链接

https://blog.csdn.net/m0_37845735/article/details/105395643

一、实现过程

定时器在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器(CNT)的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当捕获事件发生时,相应的CCxIF标志(TIMx_SR寄存器)被置’1’,如果使能了中断或者DMA操作,则将产生中断或者DMA操作。如果捕获事件发生时CCxIF标志已经为高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置’1’。写CCxIF=0可清除CCxIF,或读取存储在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。

当捕获事件发生时,可通过中断的方式将当前捕获/比较寄存器(TIMx_CCRx)中的计数值读取出来假设为 n1,然后更改输入捕获的信号级性(上升沿或下降沿),当再次检测到ICx信号上相应的边沿后,计数器(CNT)的当前值再次被锁存到捕获/比较寄存器(TIMx_CCRx)中假设为 n2;n2 -n1节可算出电平的持续时间

 

在输入捕获配置中,除了要配置 选择要使用的通用定时器(TIM2~TIM5),选择计时器的时钟源为内部时钟(CK_INT)、根据要定时的时间计算预分频系数(TIMx_PSC)、自动重装载值(TIMx_ARR)、内部时钟的分频系数以外,更重要的还需要配置 捕获/比较模式寄存器1/2(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、DMA/中断使能寄存器(TIMx_DIER)

  • 捕获/比较模式寄存器1/2(TIMx_CCMR1/2):有2个寄存器,一个寄存器只能设置2个通道;该寄存器用于设置通道的输入(捕获模式)或输出(比较模式)参数,就输入捕获而言,主要设置滤波器、预分频器、输入映射关系

 

  • 捕获/比较使能寄存器(TIMx_CCER):配置捕获触发的信号级性、捕获使能,每个定时器有4个通道,这里的CC1P/CC1E表示的是第一个通道

DMA/中断使能寄存器(TIMx_DIER):使能计数更新中断或是使能捕获/比较中断

二、STM32CubeMX配置示例

在配置时是需要开启输入捕获中断和计数更新中断的,但是在CubeMX配置中我并没有找到相应的中断配置,而是在配置完成后在工程中手动添加的!!!!!!!在  “Input Capture Channel” 配置项中,

  • Polarity Selection :设置的是TIMx_CCER->CCxP,配置捕获出发的信号极性(上升沿或下降沿)
  • IC Selection:设置的是TIMx_CCMR->CCxS,配置通道的方向(输入或输出),及输入脚的选择;Direct表示CCx通道配置为输入,ICx映射到TI1上
  • Prescaler Division Ratio:设置的是TIMx_CCMR->ICxPSC,配置输入捕获的预分频系数
  • Input Filter:设置的是TIMx_CCMR->ICxF,配置输入捕获的滤波器

三、C语言示例程序

我自己做过超声波测距,就是用CubeMX配置生成的工程,这里做个示例。测距原理也很简单,就是给模块的IO触发引脚发送一个至少10us的高电平触发信号后,模块自动发送8个40KHZ的方波,并自动检测信号返回,当有信号返回时,通过IO向外输出一个高电平,高电平持续时间就是超声波从发射到返回的时间,通过定时器捕获超声波模块这个高电平的持续时间,然后乘上340 / 2就可以测出超声波到障碍物之间的距离了。

/* TIM1_CH1输入捕获 init function */
void MX_TIM1_Init(void)
{
    LL_TIM_InitTypeDef     TIM_InitStruct = {0};
    LL_GPIO_InitTypeDef    GPIO_InitStruct = {0};

    /* Peripheral clock enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
    /**TIM1 GPIO Configuration  
    PA8   ------> TIM1_CH1 超声波输入信号捕获
    PB13  ------> 超声波触发信号
    */
    GPIO_InitStruct.Pin  = LL_GPIO_PIN_8;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin        = LL_GPIO_PIN_13;
    GPIO_InitStruct.Mode       = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed      = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_13);

    TIM_InitStruct.Prescaler         = 71;
    TIM_InitStruct.CounterMode       = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Autoreload        = 0xFFFF;
    TIM_InitStruct.ClockDivision     = LL_TIM_CLOCKDIVISION_DIV1;
    TIM_InitStruct.RepetitionCounter = 0;  //重复计数器
    LL_TIM_Init(TIM1, &TIM_InitStruct);
    LL_TIM_EnableARRPreload(TIM1); //使能自动重装载

    LL_TIM_SetClockSource        (TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
    LL_TIM_SetTriggerOutput      (TIM1, LL_TIM_TRGO_UPDATE);//主从模式下,主模式定时器送到从模式定时器的触发信号
    LL_TIM_DisableMasterSlaveMode(TIM1);//不使能主从模式

	/* TIM1 interrupt Init */
    NVIC_SetPriority(TIM1_UP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),8, 0));//使能向上计数溢出中断
    NVIC_EnableIRQ  (TIM1_UP_IRQn);
    NVIC_SetPriority(TIM1_CC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),9, 0));//使能捕获计较中断
    NVIC_EnableIRQ  (TIM1_CC_IRQn);
	
	/*捕获/比较模式寄存器1(TIMx_CCMR1)*/
    LL_TIM_IC_SetActiveInput(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);//映射到TI1上,TIMx_CCER->CCxS
    LL_TIM_IC_SetPrescaler  (TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); //设置输入分频,不分频,TIMx_CCER->ICxPSC
    LL_TIM_IC_SetFilter     (TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);//设置输入滤波器,不滤波 TIMx_CCER->ICxF
	/*捕获/比较使能寄存器(TIMx_CCER)*/
	LL_TIM_IC_SetPolarity   (TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);//设置输入捕获极性,上升沿捕获 TIMx_CCER->CCxP
	LL_TIM_CC_EnableChannel	(LL_TIM_CHANNEL_CH1);//设置允许捕获计数器的值到捕获寄存器中 TIMx_CCER->CCxE
//	TIM1->CCER|=0<<1; 		//CC1P=0	上升沿捕获
//	TIM1->CCER|=1<<0; 		//CC1E=1 	允许捕获计数器的值到捕获寄存器中

	/*DMA/中断使能寄存器(TIMx_DIER)*/
	LL_TIM_EnableIT_UPDATE(TIM1);//允许更新中断 TIMx_DIER->UIE
	LL_TIM_EnableIT_CC1(TIM1);	 //允许捕获中断 TIMx_DIER->CCxIE
//	TIM1->DIER|=1<<1;   	//允许捕获中断				
//	TIM1->DIER|=1<<0;   	//允许更新中断	

	LL_TIM_SetCounter(TIM1,0);//计数器清空
    TIM1->CNT=0;			//计数器清空
    TIM1->SR=0;             //清除中断标志位 	
      
}
void EnableTIMCounter()
{
   LL_TIM_EnableCounter (TIM1);    
}

unsigned char   TIM1CH1_CAPTURE_STA = 0;	//输入捕获状态		    				
unsigned short  TIM1CH1_CAPTURE_VAL = 0;	//输入捕获值
/**
  * @brief This function handles TIM1 update interrupt.
  */
void TIM1_UP_IRQHandler(void)
{
    if (LL_TIM_IsActiveFlag_UPDATE(TIM1))
    {	    
        if(TIM1CH1_CAPTURE_STA & 0X40)//已经捕获到高电平了,高电平时间太长
        {
            TIM1CH1_CAPTURE_STA = 0;//标记成功捕获了一次
            TIM1CH1_CAPTURE_VAL = 0XFFFF;
            LL_TIM_DisableCounter(TIM1);//成功捕获到了一次高电平,关闭定时器
            LL_TIM_SetCounter(TIM1,0); //计数器清空
            
            /* 把测量数据存入全局变量中 */
            g_tSystemData.UTRang = (float)TIM1CH1_CAPTURE_VAL / 1000.0 * 34.0 / 2.0;//单位为cm
            /* 把测量数据存入保持寄存器中 */
            Write_Holding_Reg((void*)&g_tSystemData.UTRang, eholdreg_utrang1);
        }	
        
        LL_TIM_ClearFlag_UPDATE(TIM1);
    }
}

/**
  * @brief This function handles TIM1 capture compare interrupt.
  */
void TIM1_CC_IRQHandler(void)
{
    if(LL_TIM_IsActiveFlag_CC1(TIM1))
    {
        if(TIM1CH1_CAPTURE_STA & 0X40)		//捕获到一个下降沿 		
        {	  			
            TIM1CH1_CAPTURE_STA = 0;		//标记成功捕获到一次下降沿 	
            TIM1CH1_CAPTURE_VAL = LL_TIM_IC_GetCaptureCH1(TIM1);
            LL_TIM_IC_SetPolarity(TIM1,LL_TIM_CHANNEL_CH1,LL_TIM_IC_POLARITY_RISING); //CC1P=0 设置为上升沿捕获
            LL_TIM_DisableCounter(TIM1);//成功捕获到了一次高电平,关闭定时器
            
            /* 把测量数据存入全局变量中 */
            g_tSystemData.UTRang = (float)TIM1CH1_CAPTURE_VAL / 1000.0 * 34.0 / 2.0;//单位为cm
            /* 把测量数据存入保持寄存器中 */
            Write_Holding_Reg((void*)&g_tSystemData.UTRang, eholdreg_utrang1);
//            printf("HighTime = %d us ,UGage = %f cm\r\n",TIM1CH1_CAPTURE_VAL,g_tSystemData.UTRang);
        }
        else  //还未开始,第一次捕获上升沿
        {
            TIM1CH1_CAPTURE_STA = 0;		//清空
            TIM1CH1_CAPTURE_VAL = 0;
            LL_TIM_SetCounter(TIM1,0);//计数器清空
            TIM1CH1_CAPTURE_STA |= 0X40;	//标记捕获到了上升沿
            LL_TIM_IC_SetPolarity(TIM1,LL_TIM_CHANNEL_CH1,LL_TIM_IC_POLARITY_FALLING);	//CC1P=1 设置为下降沿捕获
        }	
        
        LL_TIM_ClearFlag_CC1(TIM1);
    }
}

/**********************************************************************************************************
*	函 数 名: UGageTrig
*	功能说明: 超声波测距触发信号。1、使能定时器输入捕获 2、发送高电平触发脉冲
*	形    参: _cFlg
*	返 回 值: NULL
**********************************************************************************************************/
void UGageTrig(void)
{
    EnableTIMCounter();

    LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_13);
    Delay_us(20);
    LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_13);
}

 

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值