框图分析
1.举例通道1输入波形设置采样频率,通过 边沿检测器吗,设置CC1P确定边沿检测方式(上升沿,下降沿,双边沿),设置输入通道映射,设置捕获分频,是能捕获,产生捕获后的信号。
2.捕获产生的信号ICIPS=1 CC1E=1(捕获使能),通过与门为1,与CC1G软件产生捕获事件通过或门。CC1S(模式配置配置为输入)经过或门为1,CCR1捕获比较值读完后为0。下边与门产生捕获信号将 计数器的值写入信号将捕获/比较影子寄存器中,通过与门产生capture_transfer信号将捕获/比较影子寄存器中的值写到捕获/比较预装载寄存器中。就能读到CCR1 的值也就是这个电平的时长。
分析:
原理:比如可以设置开始为上升沿检测,当检测到上升沿时,此时定时器清零失能后使能重新计数,同时设置为下降沿检测,当产生下降沿时读到CCRx2,CCRx2表示高电平时间。(这里是计数时间,和实际时间之间还要换算。)
递增计数模式下CNT==ARR 时产生溢出。
分两类情况
1.脉宽很小,在ARR范围内不产生溢出
即CCRx2比ARR还小 这时直接计算就行了。
2.脉宽很大在ARR范围内产生溢出
需要记录脉宽次数N(通过溢出更新中断+1记录N)。从而产生上图公式。
这里以f407为例子PSC为84-1 ARR=65535 但是我的板子这里电平按下去为地弹上来为高
代码:
#include "tim_ic.h"
#include "usart.h"
#include "stdio.h"
uint8_t g_timxchy_cap_sta = 0; /* 输入捕获状态 */
uint16_t g_timxchy_cap_val = 0; /* 输入捕获值 */
TIM_HandleTypeDef g_timx_handle={0};
void MX_base_time_Init(uint16_t arr,uint16_t psc)
{
TIM_IC_InitTypeDef tim_ic_cap_chy={0};//这里初始化结构体为0为了是防止一些没有设置的成员为随机变量
g_timx_handle.Instance=TIM5;
g_timx_handle.Init.CounterMode=TIM_COUNTERMODE_UP;
//预分频值
g_timx_handle.Init.Prescaler=arr;
//重装载值
g_timx_handle.Init.Period=psc;
HAL_TIM_IC_Init(&g_timx_handle);
tim_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING;//配置上升沿捕获
tim_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;//连接到TI1上
tim_ic_cap_chy.ICPrescaler =TIM_ICPSC_DIV1;//设置分频值,这里的分频值是比如多少个上升沿触发一个事件
tim_ic_cap_chy.ICFilter= 0;// 配置滤波器This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF
HAL_TIM_IC_ConfigChannel(&g_timx_handle,&tim_ic_cap_chy,TIM_CHANNEL_1);//配置输入通道1
__HAL_TIM_ENABLE_IT(&g_timx_handle,TIM_IT_UPDATE);//使能更新中断
HAL_TIM_IC_Start_IT(&g_timx_handle,TIM_CHANNEL_1);//以中断模式开启捕获
}
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==g_timx_handle.Instance)
{
//使能时钟
__HAL_RCC_TIM5_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio_init_struct={0};
gpio_init_struct.Pin=GPIO_PIN_0;
gpio_init_struct.Mode=GPIO_MODE_AF_PP;//虽然是输入但是这里是复用推完
gpio_init_struct.Pull=GPIO_PULLDOWN;
gpio_init_struct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init_struct.Alternate=GPIO_AF2_TIM5;
HAL_GPIO_Init(GPIOA,&gpio_init_struct);
HAL_NVIC_SetPriority(TIM5_IRQn,1,0);
HAL_NVIC_EnableIRQ(TIM5_IRQn);
//配置NVIC
}
}
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_timx_handle);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM5)
{
if((g_timxchy_cap_sta & 0x80)==0)//还没有捕获过
{
if(g_timxchy_cap_sta & 0x40) //检验是否标记捕获到上升沿标记捕获到上升沿
{
g_timxchy_cap_sta |=0x80;//标记捕获过了
g_timxchy_cap_val=HAL_TIM_ReadCapturedValue(&g_timx_handle,TIM_CHANNEL_1);//读出捕获值
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原有设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//设置为上升沿捕获
}
else
{
//这是第一次捕获高电平 捕捉到上升沿开始计数
g_timxchy_cap_sta=0;//清零
g_timxchy_cap_val=0;
g_timxchy_cap_sta|=0x40;//标记捕获到上升沿
__HAL_TIM_DISABLE(&g_timx_handle);//失能定时器
__HAL_TIM_SET_COUNTER(&g_timx_handle,0);// Set the TIM Counter Register value on runtime.计数器清零
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原来的设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_CHANNEL_1);//定时器5设置为下降沿捕获
__HAL_TIM_ENABLE(&g_timx_handle);//使能定时器5
}
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM5)//定时器5产生溢出更新中断
{
if((g_timxchy_cap_sta&0x80)==0)//判读是不是捕获过了
{
if(g_timxchy_cap_sta&0x40)//判断是否捕获到高电平
{
if((g_timxchy_cap_sta&0x3F)==0x3F)//高电平时间 太长超出最大计数值:最大计数值为2^6*65536+65525=4194303us
{
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//重新设置为定时器5通道1上升沿检测
g_timxchy_cap_sta |=0x80;//标记成功捕获一次
g_timxchy_cap_val=0xFFFF;//计数值为最大值
}
else
{
g_timxchy_cap_sta++;//高电平时间没有超出最大计数值 溢出次数累计+1
}
}
}
}
}
main
int main(void)
{
uint32_t temp = 0;
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
MX_GPIO_Init();
usart_Init();
MX_base_time_Init(0XFFFF, 84 - 1);
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("demo!!!\r\n");
while (1)
{
if(g_timxchy_cap_sta&0x80)
{
temp=g_timxchy_cap_sta&0x3F;
temp*=65536;
temp+=g_timxchy_cap_val;
printf("HIGH:%d us\r\n", temp);
g_timxchy_cap_sta = 0;
}
HAL_Delay(10);
}
/* USER CODE END 3 */
}
1、先配置时基MX_base_time_Init(uint16_t arr,uint16_t psc) 配置定时器基地址,预分频值,自动重装载值,计数模式
HAL_TIM_IC_Init()调用这个函数初始化
2、配置输入模式
声明这个结构体TIM_IC_InitTypeDef tim_ic_cap_chy={0};//这里初始化结构体为0为了是防止一些没有设置的成员为随机变量
tim_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING;//配置上升沿捕获
tim_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;//连接到TI1上
tim_ic_cap_chy.ICPrescaler =TIM_ICPSC_DIV1;//设置分频值,这里的分频值是比如多少个上升沿触发一个事件
tim_ic_cap_chy.ICFilter= 0;// 配置滤波器This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF
HAL_TIM_IC_ConfigChannel(&g_timx_handle,&tim_ic_cap_chy,TIM_CHANNEL_1);//配置输入通道1
__HAL_TIM_ENABLE_IT(&g_timx_handle,TIM_IT_UPDATE);//使能更新中断
HAL_TIM_IC_Start_IT(&g_timx_handle,TIM_CHANNEL_1);//以中断模式开启捕获,这两个中断都会到TIM5_IRQHandler函数中去通过HAL_TIM_IRQHandler(&g_timx_handle);判断是哪种中断进而执行哪种回调函数
回调函数处理MSPINIT 配置NVIC GPIO等
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==g_timx_handle.Instance)
{
//使能时钟
__HAL_RCC_TIM5_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio_init_struct={0};
gpio_init_struct.Pin=GPIO_PIN_0;
gpio_init_struct.Mode=GPIO_MODE_AF_PP;//虽然是输入但是这里是复用推完
gpio_init_struct.Pull=GPIO_PULLDOWN;
gpio_init_struct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init_struct.Alternate=GPIO_AF2_TIM5;
HAL_GPIO_Init(GPIOA,&gpio_init_struct);
HAL_NVIC_SetPriority(TIM5_IRQn,1,0);
HAL_NVIC_EnableIRQ(TIM5_IRQn);
//配置NVIC
}
}
3、中断处理函数
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_timx_handle);
}
4、回调函数实现功能
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM5)
{
if((g_timxchy_cap_sta & 0x80)==0)//还没有捕获过
{
if(g_timxchy_cap_sta & 0x40) //检验是否标记捕获到上升沿标记捕获到上升沿
{
g_timxchy_cap_sta |=0x80;//标记捕获过了
g_timxchy_cap_val=HAL_TIM_ReadCapturedValue(&g_timx_handle,TIM_CHANNEL_1);//读出捕获值
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原有设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//设置为上升沿捕获
}
else
{
//这是第一次捕获高电平 捕捉到上升沿开始计数
g_timxchy_cap_sta=0;//清零
g_timxchy_cap_val=0;
g_timxchy_cap_sta|=0x40;//标记捕获到上升沿
__HAL_TIM_DISABLE(&g_timx_handle);//失能定时器
__HAL_TIM_SET_COUNTER(&g_timx_handle,0);// Set the TIM Counter Register value on runtime.计数器清零
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原来的设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_CHANNEL_1);//定时器5设置为下降沿捕获
__HAL_TIM_ENABLE(&g_timx_handle);//使能定时器5
}
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM5)//定时器5产生溢出更新中断
{
if((g_timxchy_cap_sta&0x80)==0)//判读是不是捕获过了
{
if(g_timxchy_cap_sta&0x40)//判断是否捕获到高电平
{
if((g_timxchy_cap_sta&0x3F)==0x3F)//高电平时间 太长超出最大计数值:最大计数值为2^6*65536+65525=4194303us
{
TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除设置
TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//重新设置为定时器5通道1上升沿检测
g_timxchy_cap_sta |=0x80;//标记成功捕获一次
g_timxchy_cap_val=0xFFFF;//计数值为最大值
}
else
{
g_timxchy_cap_sta++;//高电平时间没有超出最大计数值 溢出次数累计+1
}
}
}
}
}
4.main 调用处理
int main(void)
{
uint32_t temp = 0;
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
MX_GPIO_Init();
usart_Init();
MX_base_time_Init(0XFFFF, 84 - 1);
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("demo!!!\r\n");
while (1)
{
if(g_timxchy_cap_sta&0x80)
{
temp=g_timxchy_cap_sta&0x3F;
temp*=65536;
temp+=g_timxchy_cap_val;
printf("HIGH:%d us\r\n", temp);
g_timxchy_cap_sta = 0;
}
HAL_Delay(10);
}
/* USER CODE END 3 */
}