我是靠谱客的博主 烂漫高跟鞋,最近开发中收集的这篇文章主要介绍用外部触发同步STM32定时器,实现精确测量时间,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

测试芯片:STM32L151RCT6

功能要求:

        通过外部触发,使能脉冲生成同时使能捕获定时器抓取所生产脉冲的上升沿,然后计算从触发到捕获到上升沿的时间。在测量飞行时间的应用场景,例如超声波测距,超声波测流量等场景对时间测量要求比较高,此时就可以用此方法来做。

实现代码如下:

/** 全局变量 */
uint32_t Cap_Cnt; /*!< 存放捕获值 */
uint8_t Status;   /*!< 捕获状态 */
uint8_t Process;  /*!< 状态切换 */

/**
  * 说明 : 产生单脉冲,用于捕获定时器捕获(此定时器开始后会自动关闭)
  * 参数 : 无
  * 返回 : 无
  */
void Pulse_Timer_Init1(void)
{
    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};	
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);	
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
	
	/** PWM_OUT->PA6->TIM3_CH1 */
	GPIO_InitStruct.Pin=LL_GPIO_PIN_6;
	GPIO_InitStruct.Mode=LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed=LL_GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Pull=LL_GPIO_PULL_DOWN;
	GPIO_InitStruct.Alternate=LL_GPIO_AF_2;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/** Cap_IN->PA7->TIM3_CH2 */
	GPIO_InitStruct.Pin=LL_GPIO_PIN_7;	
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	
	/** 定时器时基配置(Fpwm=32M/32/100=10KHz) */
	LL_TIM_SetPrescaler(TIM3, 31);	
	LL_TIM_SetAutoReload(TIM3, 599);	  /*!< 单脉冲周期600us */
	
	LL_TIM_SetCounterMode(TIM3, LL_TIM_COUNTERMODE_UP);
    LL_TIM_EnableARRPreload(TIM3);
    LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  
	/** 使能单脉冲模式 */
	LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE);
	/** 触发设置 */
    /* 通道映射:CH2->TI2 */
    LL_TIM_IC_SetActiveInput(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI);
    /* 选择触发极性:上升沿 */
    LL_TIM_IC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
    /* 设置触发输入通道 */
    LL_TIM_SetTriggerInput(TIM3, LL_TIM_TS_TI2FP2);
    /* 设置从机模式:触发模式 */
    LL_TIM_SetSlaveMode(TIM3, LL_TIM_SLAVEMODE_TRIGGER);

	
	/** 输出模式配置:CH1 */
    TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
    TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
    TIM_OC_InitStruct.CompareValue = 400;            /*!< 单脉冲低电平时间400us */
    TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
    LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);	
	LL_TIM_OC_EnablePreload(TIM3, LL_TIM_CHANNEL_CH1);
    LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH1);	

	LL_TIM_GenerateEvent_UPDATE(TIM3); /*!< 记得调用这个函数 */ 
}

/**
  * 说明 : 用来捕获上升沿
  * 参数 : 无
  * 返回 : 无
  */
void Cap_Timer_Init(void)
{
    LL_TIM_IC_InitTypeDef TIM_IC_InitStruct = {0};	
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);	
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
	
	/** CAP_CH1->PA0->TIM2_CH1 */
	GPIO_InitStruct.Pin=LL_GPIO_PIN_0;
	GPIO_InitStruct.Mode=LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed=LL_GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Pull=LL_GPIO_PULL_DOWN;
	GPIO_InitStruct.Alternate=LL_GPIO_AF_1;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);	
	
	/** Cap_IN->PA1->TIM2_CH2 */
	GPIO_InitStruct.Pin=LL_GPIO_PIN_1;	
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	/** 定时器时基配置 */
	LL_TIM_SetPrescaler(TIM2, 0);
	LL_TIM_SetAutoReload(TIM2, 65535);	
	LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
    LL_TIM_EnableARRPreload(TIM2);
    LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
	
	/** 触发设置 */
    /* 通道映射:CH2->TI2 */
    LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI);
    /* 选择触发极性:上升沿 */
    LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
    /* 设置触发输入通道 */
    LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI2FP2);
    /* 设置从机模式:触发模式 */
    LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_TRIGGER);    
	
    /** 捕获通道配置 */
	TIM_IC_InitStruct.ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
	TIM_IC_InitStruct.ICFilter = LL_TIM_IC_FILTER_FDIV1;
	TIM_IC_InitStruct.ICPolarity = LL_TIM_IC_POLARITY_RISING;
	TIM_IC_InitStruct.ICPrescaler = LL_TIM_ICPSC_DIV1;
	LL_TIM_IC_Init(TIM2, LL_TIM_CHANNEL_CH1, &TIM_IC_InitStruct);
	/** 使能通道 */
	LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);

	/** 配置中断 */
    LL_TIM_EnableIT_CC1(TIM2);
	LL_TIM_EnableIT_UPDATE(TIM2);
    NVIC_EnableIRQ(TIM2_IRQn); 
	NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 2, 0));
	
	LL_TIM_GenerateEvent_UPDATE(TIM2);
	LL_TIM_ClearFlag_CC1(TIM2);	
	LL_TIM_ClearFlag_UPDATE(TIM2);

}

/**
  * 说明 : 定时器2中断服务函数
  * 参数 : 无
  * 返回 : 无
  */ 
void TIM2_IRQHandler(void)
{
    /** 捕获中断,捕获成功后失能定时器,等待下次捕获 */
	if(LL_TIM_IsActiveFlag_CC1(TIM2) != RESET)
	{
		Cap_Cnt = LL_TIM_IC_GetCaptureCH1(TIM2); 
		LL_TIM_DisableCounter(TIM2);
		Status=0xAA;
	}
    /** 更新中断,产生更新中断说明捕获超时,失能定时器,等待下次捕获 */
	if(LL_TIM_IsActiveFlag_UPDATE(TIM2) != RESET)
	{
		LL_TIM_ClearFlag_UPDATE(TIM2);
		LL_TIM_DisableCounter(TIM2);
		Status=0xFF;
	}    
}

/*
 * 说明: 初始化开发板控制IO(这里用PB6来实现触发)
 * 参数: 无
 * 参数: 无
 */
void EVE_GPIO_Init(void)
{
  LL_GPIO_InitTypeDef  GPIO_InitStruct={0};
  LL_EXTI_InitTypeDef EXTI_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
	
  /* 置位 */
  LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_8);
  LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_6);	
  LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_8);
  LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_9);
	
  /* LED1-> PA8, LED2->PC8, LED3->PC9, PB6 */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6;	
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);	
  GPIO_InitStruct.Pin = LL_GPIO_PIN_8|LL_GPIO_PIN_9;	
  LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
		
}

/*
 * 说明: 用户线程(重复捕获,测试一致性),用户主循环调用
 * 参数: 无
 * 参数: 无
 */
void App_Handle(void)
{
    switch(Process)
	{
		case 0:
			Pulse_Timer_Init();
		    Cap_Timer_Init();
		    Process = 1;
			break;
		case 1:
            /** 拉高PB6此时定时器同步使能并开始工作 */
		    LL_mDelay(1);
		    PB6_H(); 
		    Process = 2;
			break;
		case 2:
            /** 等待捕获 */
			if(Status == 0xAA)
			{
		        printf("%dn", Cap_Cnt);
                /** 刷新定时器寄存器 */				
                LL_TIM_DisableUpdateEvent(TIM2);				
		        LL_TIM_GenerateEvent_UPDATE(TIM2);
				LL_TIM_EnableUpdateEvent(TIM2);
		        LL_TIM_GenerateEvent_UPDATE(TIM3);
                PB6_L();				
				Status = 0;
                Process = 3;	
			}
			break;
		case 3:
			LED1_Toggle();
		    LL_mDelay(100);
		    Process = 1;
			break;
	}		
}

连线:

PB6->PA7
PB6->PA1

PA6->PA0

测试结果:

串口打印值:

 时序波形如下:

 从上述结果可以看出用此方法计时,准确度和一致性还是很好的。

最后

以上就是烂漫高跟鞋为你收集整理的用外部触发同步STM32定时器,实现精确测量时间的全部内容,希望文章能够帮你解决用外部触发同步STM32定时器,实现精确测量时间所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部