• STM32 HAL库高级定时器输入捕获脉宽测量


    STM32 HAL库高级定时器输入捕获脉宽测量


    • ✨相比于上面所使用的高级定时器输入捕获从模式来测量PWM信号,实现方法更为复杂一下,但是还是将实现的方法记录下来。
    • 🔖想了解详细的有关实现方法可以前往相关篇内容了解。
    • 🌿本篇基于STM32f030R8单片机。
    📓本工程主要改善了,减少测量误差,将测量换算内容,换到了中断函数中执行,用时间换精度。并且采用多次读取测量结果,取多次连续测量值中,出现频率最高的数值作为输出值,有效减少单次数据异常情况。

    🛠STM32CubeMX配置

    • 🔧高级定时器1配置:(👉🏻在参数配置上,尽可能的将捕获定时器的自动载计数值设置大一点,减少定时器溢出更新事件)
      在这里插入图片描述
    • 🌿时钟源:外部时钟
    • 🌿定时器1分频系数,更具个人使用的芯片型号而定。
    • 🌿向上计数方式。
    • 🌿不开启自动重装载(auto-reload preload),相对于不使能影子寄存器。
    • 其他都是默认选项配置。
    • 🔨 配置定时器14作为一个PWM信号输出源:
      在这里插入图片描述

    • 🔰使能定时器捕获、更新中断,以及中断优先级配置:(TIM1更新中断 > TIM1捕获中断)
      在这里插入图片描述

    📑功能代码实现部分

    • 📝中断回调函数:
    /**
      * @brief 输入捕获回调函数
      * @retval None
      */
    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)										//0X40是0100 0000,高电平期间捕获到下降沿
            {
                capture_flag &= 0x3F;										//0X3F是0011 1111,清除捕获到上升沿的标记位和捕获完成的标记位
                value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);	//获取当前的捕获值
    
                __HAL_TIM_DISABLE(htim);        						//关闭定时器
                __HAL_TIM_SET_COUNTER(htim, value2);						//以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;										//0X40是0100 0000,标记捕捉到了一次上升沿
    
                RisingEdge_count++;
                if((RisingEdge_count % 2 == 0))								//每捕获两次相同跳变沿表示过了一个PWM周期
                {
                    value3 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //检测完一个周期的那个上升沿为value3
                    capture_flag |= 0x80;								 //标记捕获完了一个周期
    								Pulse_Width = value2 + OverflowCount_high * TIM1_Period_Value - value1 + 4;	//经验值:再进行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				 								   //正在检测PWM信号的第一个上升沿,意味着下次捕获下降沿
                {
                    capture_flag &= 0x7F;								 //0X7F是0111 1111,清除PWM捕获完成标志,开始新一轮PWM周期捕获
                    value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //第一个上升沿是value1
                }
                __HAL_TIM_DISABLE(htim);
                __HAL_TIM_SET_COUNTER(htim, value1);					//以value1为基准重新计数
                TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1);  	//复位极性选择才能进行下行配置
                TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);	//下次下降沿捕获
                __HAL_TIM_ENABLE(htim);								//重开定时器
            }
        }
    }
    
    
    /**
      * @brief (高级定时器TIM特有)更新溢出中断函数
      */
    //void TIM1_UP_IRQHandler(void)
    //{
    //    HAL_TIM_IRQHandler(&htim1);
    //}
    /**
      * @brief 更新溢出回调函数
      * @retval None
      */
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
    {
        if((capture_flag & 0X80) == 0)			//PWM的一个周期没检测完
        {
            if(capture_flag & 0x40)				//在高电平期间溢出M次
            {
                OverflowCount_high++;
            }
            else								//在低电平期间溢出N次
            {
                OverflowCount_low++;
            }
        }
        else								   //PWM的一个周期检测完了
        {
    
            OverflowCount_high = 0;
            OverflowCount_low = 0;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • ⚡连续读取的数值中获取出现频率最高的数值实现方法:
    //比较函数,用于排序
    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);//需要包含stdlib.h头文件
    
        int maxCount = 1; // 最大重复次数
        int currentCount = 1; // 当前元素的重复次数
        uint32_t mostFrequentNumber = arr[0]; // 最频繁出现的数
    
        for(int i = 1; i < size; i++)
        {
            if(arr[i] == arr[i - 1])
            {
                // 如果当前元素与前一个元素相同,则重复次数加1
                currentCount++;
            }
            else
            {
                // 如果当前元素与前一个元素不同,则重复次数重置为1
                currentCount = 1;
            }
    
            if(currentCount > maxCount)
            {
                // 如果当前元素的重复次数超过最大重复次数,则更新最大重复次数和最频繁出现的数
                maxCount = currentCount;
                mostFrequentNumber = arr[i];
            }
        }
    
        return mostFrequentNumber;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 📗main函数代码以及相关变量定义:
    /* Private variables ---------------------------------------------------------*/
    
    /* USER CODE BEGIN PV */
    volatile char capture_flag = 0;				//捕获状态标记变量,0x80最高位标记捕获完一个周期,0x40表示捕获到了上升沿
    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;
    /* USER CODE END PV */
    
    int main(void)
    {
      /* USER CODE BEGIN 1 */
        uint32_t TimerUART;
    //    uint16_t plusewidth = 500;//脉冲宽度;f=1000 000/500=2000Hz
    //    uint16_t plusedelay = 20;//脉宽40us
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_TIM1_Init();
      MX_TIM14_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
        uint32_t sysclock = 0;
    //sysclock =RCC_GetHSIFreq();
        sysclock = HAL_RCC_GetSysClockFreq();//RCC_GetHSIFreq()
        TimerUART = HAL_GetTick();
        printf("STM32F030 SysClockFreq:%d \r\n", sysclock);
    //		__HAL_TIM_SET_AUTORELOAD(&htim14, plusewidth - 1); //调整分频系数,可以改变arr以改变频率
    //    __HAL_TIM_SET_COMPARE(&htim14, TIM_CHANNEL_1, plusedelay); //PWM脉冲宽度,修改占空比比较值
        /* 使能PWM输出 */
        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);
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
        while(1)
        {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
            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();
            }
        }
      /* USER CODE END 3 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 📜测试调试输出:
      在这里插入图片描述
      在这里插入图片描述
    • ✨修改PWM相关参数测试了几次,结果也没有发现测量的输出结果异常,符合预期。

    📚测试工程

    链接:https://pan.baidu.com/s/1pgs9OFyiI291pxBMsuutdQ 
    提取码:rotp
    
    • 1
    • 2

    • 🔖此文章仅作为个人学习探索知识的总结,不作为他人或引用者的理论依据,由于学识所限,难免会出现错误或纰漏,欢迎大家指正。
  • 相关阅读:
    Java注解@Transa1ctional失效特殊情况
    我为什么会性格内向,能不能内向性格?
    四招教你样式化界面组件KendoReact,让应用程序主题更个性化
    目前看过最全的一线大厂面试题(题 + 详解),你所不知道的都在这
    自定义el-upload 上传文件
    全国双非院校考研信息汇总整理 Part.5
    [附源码]Python计算机毕业设计SSM家政服务预约小程序(程序+LW)
    【mysql学习笔记23】索引优化
    进程间通信-内存映射二
    软件项目管理 第八章 软件项目的人员与沟通管理 课后习题参考答案——主编:李冰、张桥珍、刘玉娥
  • 原文地址:https://blog.csdn.net/weixin_42880082/article/details/133870576