STM32 HAL库高级定时器输入捕获脉宽测量
- 相关篇《STM32 HAL库定时器输入捕获SlaveMode脉宽测量》
- ✨相比于上面所使用的高级定时器输入捕获从模式来测量PWM信号,实现方法更为复杂一下,但是还是将实现的方法记录下来。
- 本篇实现方法内容参考《定时器TIM的输入捕获——正交编码器模式与PWM输入》
本工程主要改善了,减少测量误差,将测量换算内容,换到了中断函数中执行,用时间换精度。并且采用多次读取测量结果,取多次连续测量值中,出现频率最高的数值作为输出值,有效减少单次数据异常情况。
STM32CubeMX配置
- 高级定时器1配置:(在参数配置上,尽可能的将捕获定时器的自动载计数值设置大一点,减少定时器溢出更新事件)
- 时钟源:外部时钟
- 定时器1分频系数,更具个人使用的芯片型号而定。
- 向上计数方式。
- 不开启自动重装载(auto-reload preload),相对于不使能影子寄存器。
- 其他都是默认选项配置。
功能代码实现部分
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{
static uint8_t RisingEdge_count = 0;
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(capture_flag & 0x40)
{
capture_flag &= 0x3F;
value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_DISABLE(htim);
__HAL_TIM_SET_COUNTER(htim, value2);
TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);
__HAL_TIM_ENABLE(htim);
}
else
{
capture_flag |= 0x40;
RisingEdge_count++;
if((RisingEdge_count % 2 == 0))
{
value3 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
capture_flag |= 0x80;
Pulse_Width = value2 + OverflowCount_high * TIM1_Period_Value - value1 + 4;
PWM_Period_ARR[PWM_Period_CNT++] = value3 + OverflowCount_high * TIM1_Period_Value + OverflowCount_low * TIM1_Period_Value - value1 + 7;
if(PWM_Period_CNT == 5)
{
PWM_Period = findMostFrequentNum(PWM_Period_ARR, 5);
PWM_Period_CNT = 0;
}
OverflowCount_high = OverflowCount_low = 0;
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
}
else
{
capture_flag &= 0x7F;
value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
}
__HAL_TIM_DISABLE(htim);
__HAL_TIM_SET_COUNTER(htim, value1);
TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
__HAL_TIM_ENABLE(htim);
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
if((capture_flag & 0X80) == 0)
{
if(capture_flag & 0x40)
{
OverflowCount_high++;
}
else
{
OverflowCount_low++;
}
}
else
{
OverflowCount_high = 0;
OverflowCount_low = 0;
}
}
- ⚡连续读取的数值中获取出现频率最高的数值实现方法:
int compare(const void* a, const void* b)
{
return (*(int*)a - * (int*)b);
}
uint32_t findMostFrequentNum(uint32_t arr[], int size)
{
qsort(arr, size, sizeof(int), compare);
int maxCount = 1;
int currentCount = 1;
uint32_t mostFrequentNumber = arr[0];
for(int i = 1; i < size; i++)
{
if(arr[i] == arr[i - 1])
{
currentCount++;
}
else
{
currentCount = 1;
}
if(currentCount > maxCount)
{
maxCount = currentCount;
mostFrequentNumber = arr[i];
}
}
return mostFrequentNumber;
}
volatile char capture_flag = 0;
volatile uint8_t OverflowCount_high = 0;
volatile uint8_t OverflowCount_low = 0;
volatile uint32_t value1, value2, value3;
volatile uint32_t Pulse_Width = 0;
volatile uint32_t PWM_Period = 0;
uint32_t PWM_Period_ARR[5] = {0};
uint8_t PWM_Period_CNT = 0;
int main(void)
{
uint32_t TimerUART;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM14_Init();
MX_USART1_UART_Init();
uint32_t sysclock = 0;
sysclock = HAL_RCC_GetSysClockFreq();
TimerUART = HAL_GetTick();
printf("STM32F030 SysClockFreq:%d \r\n", sysclock);
HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);
while(1)
{
if((HAL_GetTick() - TimerUART) > 1000)
{
printf("/********************/\r\n");
printf("脉宽为: %d us\r\n", Pulse_Width);
printf("周期为: %d us\r\n", PWM_Period);
printf("/********************/\r\n");
TimerUART = HAL_GetTick();
}
}
}
- 测试调试输出:
- ✨修改PWM相关参数测试了几次,结果也没有发现测量的输出结果异常,符合预期。
测试工程
链接:https:
提取码:rotp
- 此文章仅作为个人学习探索知识的总结,不作为他人或引用者的理论依据,由于学识所限,难免会出现错误或纰漏,欢迎大家指正。