问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32F103C8T6测量脉冲波信号频率和占空比的完整指南

创作时间:
作者:
@小白创作中心

STM32F103C8T6测量脉冲波信号频率和占空比的完整指南

引用
CSDN
1.
https://blog.csdn.net/Cc20200930/article/details/145801644

本文将介绍如何使用STM32F103C8T6微控制器测量脉冲波信号的频率和占空比。通过配置CubeMX和编写相关代码,可以实现对10kHz以下脉冲信号的精确测量,测量误差不大于2%,显示精度不低于1Hz。

一、题目要求

测量脉冲波信号的频率,测量误差不大于 2%,显示精度不低于 1Hz。对脉冲波的占空比进行测量并显示,精度不低于 2%。

二、测量思路

本文给出的方法主要是测量低频的方法。在测 10 kHz 以下有用。

三、CubeMX 配置

在开始编程之前,需要在CubeMX中进行以下配置:

  • 时钟配置
  • 串口 debug
  • IIC
  • TIM3

  • NVIC 设置
  • GPIO 设置

四、代码实现

变量定义

/* USER CODE BEGIN PV */
volatile float TIM3CH1_Freq = 0.0; // 频率
volatile float TIM3CH1_Duty = 0.0; // 占空比
volatile int capture_end_flag = 0; // 

volatile uint32_t high_val = 0;
volatile uint32_t low_val = 0;
/* USER CODE END PV */

初始化

/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Clear();
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1); // 开启定时器

OLED_Refresh_Gram();
/* USER CODE END 2 */

主循环

在主循环中,需要特别注意HAL_Delay()的使用,将其放在循环里可能会造成问题。

/* USER CODE BEGIN WHILE */
while (1)
{
//		HAL_Delay(3000);
    if(capture_end_flag == 1)
    {
        OLED_Refresh_Gram();
        OLED_ShowNum(0, 0, TIM3CH1_Freq, 6, 16); // 显示频率

        OLED_ShowString(50, 0, str1, 16);

        OLED_ShowNum(0, 16, (uint16_t)(TIM3CH1_Duty * 100) % 100, 2, 16); // 显示占空比的整数
        OLED_ShowChar(16, 16, '.', 16, 1);
        OLED_ShowChar(38, 16, '%', 16, 1);
        if ((uint16_t)(TIM3CH1_Duty * 10000) % 100 < 10 && 0 < (uint16_t)(TIM3CH1_Duty * 10000) % 100){ // 显示占空比的小数
            OLED_ShowChar(21, 16, '0', 16, 1);
        }else if ((uint16_t)(TIM3CH1_Duty * 10000) % 100 == 0){
            OLED_ShowChar(21, 16, '0', 16, 1);
            OLED_ShowChar(28, 16, '0', 16, 1);
        }
        else{
            OLED_ShowNum(21, 16, (uint16_t)(TIM3CH1_Duty * 10000) % 100, 2, 16);
        }
        capture_end_flag = 0;
    }	
    /* USER CODE END WHILE */
}

TIM 捕捉回调函数

/* USER CODE BEGIN 0 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) // TIM 捕捉回调函数 
{
    static uint8_t capture_cnt = 1;    //电平捕捉计数

    if(htim->Instance == TIM3)        //判断是否由 定时器3 产生
    {
        if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)    //TIM3 通道 1
        {    
            if(capture_end_flag == 0)
            {
                if(capture_cnt == 1)        // 第一次进入回调,捕获第一个上升沿
                {
                    capture_cnt = 2; // 下一次要捕获第二个沿事件
                    __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); //设置成下降沿触发
                    __HAL_TIM_SetCounter(htim, 0);    //清空定时器计数值,为了从当前沿开始重新计时
                    high_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);    //由第一个上升沿设为起始位置
                    
                }else if(capture_cnt == 2)    // 第二次进入回调,捕获第一个下降沿
                {
                    capture_cnt = 3; // 下一次要捕获第三个沿事件
                    low_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);    //低电平起始位置
                    __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING); //设置成上升沿触发
                    
                    
                }else if(capture_cnt == 3)    // 第三次进入回调,第二个上升沿
                {
                    capture_cnt = 1; // 准备下一轮测量
                    high_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
                        
                    //计算频率
                    TIM3CH1_Freq = (float)72000000 / 72 / (high_val+1);
                    //计算占空比
                    TIM3CH1_Duty = (float)(low_val+1) / (high_val+1);
                    capture_end_flag = 1;
                }
            }
        }
    }
}	
/* USER CODE END 0 */

五、注意事项

  • 中断处理器中,数字越小,优先级越高
  • 检查引脚是不是插错了, 还真插错了
  • 调示波器的输入电压,要输入 High Level 3V, Low Level 0V
  • 有的时候 OLED 会短暂误码。等一会,多按几次 reset,再烧录几次
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号