• 基于STM32G431嵌入式学习笔记——八、PWM脉冲输出(基于第12届蓝桥杯节选PA7作引脚)


    一、真题引入

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    简言之,关于脉冲输出的题目要求如下:
    ①默认低电平
    ②按下key4,切换低电平/脉冲信号
    ③输出脉冲器件LED2点亮,否则熄灭。

    二、基础知识
    1.PWM工作原理

    在这里插入图片描述

    2.与时钟信号的关联

    具体可以查阅STM32G4系列微控制器参考手册
    在这里插入图片描述28-31章均为时钟timer相关资料,我们可以向右方一样查找该类型定时器是否支持PWM,从而判断该定时器是否能调用引脚实现脉冲输出。【实际上只有第31章的定时器不支持PWM输出功能】
    对于我们用户来说,各种输出都是来自于引脚,因此PWM的配置本质依旧是引脚配置

    3.生活中的PWM

    我们的可变亮度的台灯本质是利用了PWM输出,通过调节占空比,实现不同占空比下不同平均电压的输出,从而有了灭->暗->亮->晃眼睛。

    三、PWM在CubeXM中的配置

    该部分是第12届蓝桥杯最后一部分的题目内容,因此我们可以基于第六节的环境进行修改。

    如何在CubeMX中判断哪些定时器支持PWM?
    如图所示,众多的定时器channel中可以选择功能,仅需检查是否有PWM选项
    在这里插入图片描述
    但是本题对引脚做出了限制
    在这里插入图片描述
    因此选择PA7进行配置

    在这里插入图片描述

    实际上PWM是多路输出的,因此在定时器中会有许多通道,而我们仅需要选择其中一个channel即可,且实际上上面四个通道任选其一均可
    如果题目没有指定某引脚,我们平时练习可以只固定一个熟练的引脚一直使用(我固定使用PA7的通道2)

    ①记得在该通道选定PWM generation
    ②配置时钟源(internal clock内部时钟)
    在这里插入图片描述

    操作实现了2K的输出频率
    具体计算如下:
    时钟频率: 80 M H z = 8 ∗ 1 0 7 H z 80MHz=8*10^7Hz 80MHz=8107Hz
    预分频器分频: 8 ∗ 1 0 7 H z / 80 = 1 0 6 H z 8*10^7Hz/80=10^6Hz 8107Hz/80=106Hz
    利用计数周期分频: 1 0 6 H z / 500 = 2 ∗ 1 0 3 H z = 2 K H z 10^6Hz/500=2*10^3Hz=2KHz 106Hz/500=2103Hz=2KHz

    Prescaler:预分频器
    Counter Period:计数周期,指计数多少次发生一次中断

    在这里插入图片描述操作实现占空比20%
    上述Counter Period为一个周期计数500,那么占空比20%
    说明要计数 500 ∗ 20 % = 100 500*20\%=100 50020%=100即100脉冲
    在这里插入图片描述
    在这里还有一个关于Mode的知识点,PWM的两种模式代表不同情况
    在这里插入图片描述

    在进行PWM信号输出时,有两种PWM模式:PWM1模式和PWM2模式。
    这两种PWM模式和输出有效电平的极性共同决定了PWM信号的波形。
    PWM1模式
    递增计数时,当TIMx_CNT(计数值)< TIMx_CCR(捕获/比较值)时,输出为有效电平,否则为无效电平。递减计数模式则刚好相反。
    PWM2模式
    递增计数时,当TIMx_CNT(计数值)< TIMx_CCR(捕获/比较值)时,输出为无效电平,否则为有效电平。递减计数模式则刚好相反。

    下面我们详细分析一下两种PWM模式的区别:
    假设定时器设置为递增计数模式,输出有效电平的极性为高电平。
    PWM1模式下的CCR用于控制高电平持续的时间;
    PWM2模式下的CCR用于控制低电平持续的时间,两种模式下的PWM信号互为互补输出。 在这里插入图片描述
    环境配置完毕

    四、代码书写
    1.将代码对比恢复至第六节最后的内容

    (1)头文件补充
    (2)全局变量有没有遗漏
    (3)函数声明
    (4)主函数

    int main(void)
    {
      /* USER CODE BEGIN 1 */
    
      /* 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_USART1_UART_Init();
      MX_TIM3_Init();
      /* USER CODE BEGIN 2 */
      LCD_Init();
      control_led(LEDALL,OFF);
    	ParkingInit();
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
    	HAL_UART_Receive_IT(&huart1, (uint8_t *)usart_rx,RxLen);
      LCD_Clear(Black);
      while (1)
      {
        /* USER CODE END WHILE */
        lcd_proc();
        key_proc();
        led_proc();
        busi_proc();
        /* USER CODE BEGIN 3 */
    
      }
      /* 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
    2.更新全局变量

    在这里插入图片描述

    3.更新按键函数
    void key_proc(void)
    {
      char value = key_scan();
      switch(value)
      {
        case 1:
          /*切换LCD显示屏界面的操作*/
          lcd_flag = (lcd_flag == 1 ? 0 : 1);
          lcd_update_flag=1;
          break;
        case 2:
          /*CNBR、VNBR费率增加0.5�??*/
          cnbr += 0.5f;
          vnbr += 0.5f;
          lcd_update_flag=1;
          break;
        case 3:
          /*CNBR、VNBR费率减少0.5�??*/
          cnbr -= 0.5f;
          vnbr -= 0.5f;
          lcd_update_flag=1;
          break;
        case 4:
          /*两种频率输出状态*/
          pwm_flag = (lcd_flag == 1 ? 0 : 1);
          break;
      }
    }
    
    • 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
    4.书写pwm函数
    void pwm_proc(void)
    {
      if(pwm_flag)//低电平
      {
        HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_2);
        HAL_Delay(5);
      }
      else//高电平
      {
        HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
        HAL_Delay(5);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    记得在整个文件开头进行函数声明:
    在这里插入图片描述
    代码中有两个函数,分别代表停止/开始PWM输出
    开始输出的时候就是20%占空比2KHz,停止输出后便为低电平
    在这里插入图片描述
    两个函数位于如下图所示的位置
    在这里插入图片描述
    拓展:该函数的另一种实现方式

    void pwm_proc(void)
    {
      if(pwm_flag)//低电平
      {
        HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
        __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,0);//占空比0
        HAL_Delay(5);
      }
      else//高电平
      {
        HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
        __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100);//占空比100/500=20%
        HAL_Delay(5);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100) 是专门用来设置占空比的函数
    最后一个参数的含义为我们的计数周期中有多少计数是脉冲
    我们曾在CubeMX中设置计数周期为500,则500*0.2=100

    在这里插入图片描述
    对于这两种方式,我们都需要记住!!第二种方法尤为重要,通过这个甚至可以设计出我们生活中的可调亮度台灯

    5.重写led函数
    void led_proc(void)
    {
      if(idle>0)
      {
        control_led(LED1,ON);//LED1�??
      }
      else
      {
        control_led(LED1,OFF);
      }
    	if(pwm_flag==1)
    		control_led(LED2,ON);
    	else
    		control_led(LED2,OFF);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    6.书写主函数

    实际上仅需在while循环中新增一行pwm_proc()即可
    在这里插入图片描述

    保存,编译,下载,观察不同按键下的板子状态。
    至此第12届蓝桥杯省赛题目所有任务均完成,后续会更新一期完整的第12届蓝桥杯题目整体思路和流程

  • 相关阅读:
    基金交易场景下,如何利用 Apache APISIX 来稳固 API 安全
    计组——I/O方式
    性能测试基本流程
    2022杭电多校(二)
    java高手进阶之:消息模板
    【重识云原生】第六章容器基础6.4.9.5节——端点切片(Endpoint Slices)
    vue 概述
    【UE5 C++ 學習日志】01. UEnhancedInput
    焱融全闪系列科普|固态存储核心技术 SSD
    【重拾计划】深搜&广搜 | luogu P1135 奇怪的电梯
  • 原文地址:https://blog.csdn.net/qq_53826699/article/details/128066139