IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 用外部触发同步STM32定时器,实现精确测量时间 -> 正文阅读

[嵌入式]用外部触发同步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("%d\n", 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

测试结果:

串口打印值:

?时序波形如下:

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

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:39:31  更:2021-07-24 11:40:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:55:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码