学习目标

  1. 理解PWM和定时器的关系
  2. 掌握通用定时器开发流程
  3. 理解周期,分频系数,周期计数,分频计数。
  4. 掌握分频计数、周期计数和占空比的计算策略

    学习内容

    PWM

    PWM全称是脉宽调制(Pulse Width Modulation),是一种通过改变信号的脉冲宽度来控制电路输出的技术。PWM技术在工业自动化、电机控制、LED调光等领域广泛应用。
    PWM是一种将数字信号转换为模拟信号的技术,它通过改变信号的占空比来控制输出的电平。
    在ARM32系列芯片中,PWM输出的频率和占空比可以由程序控制,因此可以用来控制各种电机、灯光和其他设备的亮度、速度等参。
    在ARM32系列芯片中,PWM的调制是通过Timer来实现的。PWM与引脚相关,除了基本定时器以外,其他类型的Timer都可以作为PWM来进行使用。

    需求

    177.png
    PA5对应的LED4为例,我们做一个呼吸灯的效果。
    我们采用TIMER1进行实现:
    204.png

    开发流程

  5. 添加Timer依赖

  6. 初始化PWM
  7. PWM占空比控制

    初始化PWM

    1. static void PWM_config() {
    2. /*************** GPIO config **************/
    3. // 配置时钟
    4. rcu_periph_clock_enable(RCU_GPIOA);
    5. // 配置GPIO模式
    6. gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
    7. // 配置GPIO输出
    8. gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);
    9. // 配置复用功能
    10. gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_5);
    11. /*************** Timer config *************/
    12. // 时钟配置
    13. rcu_periph_clock_enable(RCU_TIMER1);
    14. // 复位定时器
    15. timer_deinit(TIMER1);
    16. // 倍频配置
    17. rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2);
    18. // 初始化定时器
    19. timer_parameter_struct tps;
    20. timer_struct_para_init(&tps);
    21. tps.prescaler = 10000 - 1; // 分频计数
    22. tps.period = SystemCoreClock / 10000 - 1; // 周期计数
    23. timer_init(TIMER1, &tps);
    24. // 配置输出通道
    25. timer_oc_parameter_struct tops;
    26. timer_channel_output_struct_para_init(&tops);
    27. tops.outputstate = TIMER_CCX_ENABLE;
    28. timer_channel_output_config(TIMER1, TIMER_CH_0, &tops);
    29. // 输出模式配置
    30. timer_channel_output_mode_config(TIMER1, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    31. // 初始化
    32. timer_enable(TIMER1);
    33. }

    PWM占空比控制

    1. static void PWM_update(uint32_t pulse) {
    2. // 配置输出的占空比
    3. timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0, pulse);
    4. }

    输出通道

    1. // 配置输出通道
    2. timer_oc_parameter_struct tops;
    3. timer_channel_output_struct_para_init(&tops);
    4. tops.outputstate = TIMER_CCX_ENABLE;
    5. timer_channel_output_config(TIMER1, TIMER_CH_0, &tops);

    这里完整配置为多种:

    1. void timer_channel_output_struct_para_init(timer_oc_parameter_struct *ocpara)
    2. {
    3. /* initialize the channel output parameter struct member with the default value */
    4. ocpara->outputstate = (uint16_t)TIMER_CCX_DISABLE;
    5. ocpara->outputnstate = TIMER_CCXN_DISABLE;
    6. ocpara->ocpolarity = TIMER_OC_POLARITY_HIGH;
    7. ocpara->ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    8. ocpara->ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    9. ocpara->ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    10. }

    我们具体的可以分为两类:

    1. ocpara->outputstate = (uint16_t)TIMER_CCX_DISABLE;
    2. ocpara->ocpolarity = TIMER_OC_POLARITY_HIGH;
    3. ocpara->ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    1. ocpara->outputnstate = TIMER_CCXN_DISABLE;
    2. ocpara->ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    3. ocpara->ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

    特别观察API,带N的为反向,带P的为正向。赋值的结果常量也是需要注意是否带N。
    P和N的配置主要出现在互补PWM中,如果当前的Timer不是高级定时器,那么就不具备互补的功能,那么我们一律认为他是P类型,也就是设置P才有用。
    通过设置outputstate 的 ENABLE来控制输出通道的开启。

    关心的内容

    1. static void PWM_config() {
    2. uint32_t timerx = TIMER1;
    3. uint32_t timerx_chn = TIMER_CH_0;
    4. uint32_t timerx_rcu = RCU_TIMER1;
    5. uint32_t timerx_psc = RCU_TIMER_PSC_MUL2;
    6. uint32_t timerx_prescaler = 10000 - 1; // 分频计数
    7. uint32_t timerx_period = SystemCoreClock / 10000 - 1; // 周期计数
    8. uint32_t timerx_port = GPIOA; // 哪个引脚和端口
    9. uint32_t timerx_port_rcu = RCU_GPIOA;
    10. uint32_t timerx_pin = GPIO_PIN_5;
    11. /*************** GPIO config **************/
    12. // 配置时钟
    13. rcu_periph_clock_enable(timerx_port_rcu);
    14. // 配置GPIO模式
    15. gpio_mode_set(timerx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_pin);
    16. // 配置GPIO输出
    17. gpio_output_options_set(timerx_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_pin);
    18. // 配置复用功能
    19. gpio_af_set(timerx_port, GPIO_AF_1, timerx_pin);
    20. /*************** Timer config *************/
    21. // 时钟配置
    22. rcu_periph_clock_enable(timerx_rcu);
    23. // 复位定时器
    24. timer_deinit(timerx);
    25. // 倍频配置
    26. rcu_timer_clock_prescaler_config(timerx_psc);
    27. // 初始化定时器
    28. timer_parameter_struct tps;
    29. timer_struct_para_init(&tps);
    30. tps.prescaler = timerx_prescaler; // 分频计数
    31. tps.period = timerx_period; // 周期计数
    32. timer_init(timerx, &tps);
    33. // 配置输出通道
    34. timer_oc_parameter_struct tops;
    35. timer_channel_output_struct_para_init(&tops);
    36. tops.outputstate = TIMER_CCX_ENABLE;
    37. timer_channel_output_config(timerx, timerx_chn, &tops);
    38. // 输出模式配置
    39. timer_channel_output_mode_config(timerx, timerx_chn, TIMER_OC_MODE_PWM0);
    40. // 初始化
    41. timer_enable(timerx);
    42. }
  • 哪个定时器
  • 哪个引脚输出pwm
  • 周期和分频系数

    重要的关键词

    周期

    012.png
    pwm中,一个周期就是一次高低电平的变化。

    分频

    将原来的活增加几倍时间干完。

    占空比

    013.png
    1个周期内,高电平出现的比例。

练习

  1. 实现pwm点灯
  2. 实现pwm控制震动马达
  3. 实现pwm控制蜂鸣器