【Ai-WB2入门篇】PWM

[复制链接]
查看1195 | 回复3 | 2024-9-2 14:24:27 | 显示全部楼层 |阅读模式
脉冲宽度调制(Pulse width modulation,简称PWM)是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳定电源输出的改变,这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
本文将详细介绍如何使用Ai-WB2中的PWM模块:
一:Ai-WB2的PWM介绍
Ai-WB2的PWM具有如下特性:
      · 支持5通道PWM信号生成
      · 三种时钟源可选择(总线时钟、晶振时钟<xtalck>、慢速时钟<32k>),搭配16-bit时钟分频器
      · 双门限值设定,增加脉冲弹性
      · 最高工作频率为40MHZ

时钟与分频
每个PWM计数器时钟来源都有三种选择,来源如下:
      · bclk-芯片的总线时钟
      · XTAL-外部晶振时钟
      · f32k-系统RTC时钟

每个计数器都有各自的16-bit分频器,可通过APB将选择到的时钟进行分频,PWM计数器将以分频后的时钟作为计数周期单位,每经过-个计数周期进行数一的动作。
脉冲产生原理
PWM内部有计数器,当计数器介于可设定的两个门限值域中间时,PWM的输出为1,反之当计数器在设定的两个门限值之外时,PWM输出为0,如下图所示:
1.png

PWM的周期由两部分决定,一个是时钟分频系数,一个是时钟持续周期。
时钟分频系数由寄存器PWMn_CLK_DIV15:0进行设置,用于对PWM的源时钟进行分频。
时钟持续周期由寄存器PWMn_PERIOD15:0进行设置,用于设置PWM的一个周期由多少个分频后的时钟周期组成。即PWM的周期=PWM源时钟/PWMn_CLK_DIV[15:0]/PWMn PERIOD[15:0]。
PWM的占空比由时钟持续周期和两个阈值决定。第一个阈值由寄存器PWMn_THRE115:0进行设置,第二个阈值由寄存器PWMn_THRE215:0进行设置,PWM的波形会在第一个阈值处拉高,在第二个阈值处拉低。即PWM的占空比=(PWMn_THRE2[15:0]PWMn_THRE1[15:01)/PWMn_ PERIOD[15:0]。
例:PWM源时钟为80MHz,要产生1kHz、占空比20%的PWM波,则设置如下:
PWMn_CLK_DIVI15:0]=2
PWMn_PERIOD[15:01=80000000/2/1000=40000
PWMn_THRE1[15:0]=0
PWMn_THRE2[15:0]=0+40000*20%=8000
PWM中断
对于每一个PWIM通道,可以设置周期计数值,当PWM输出的周期数达到这个计数值时,将产生PWM中断。占空比参数如下:
2.png

二:PWM驱动API介绍
与PWM驱动相关的HOSAL层高级驱动API在文件 components/platform/hosal/include/hosal_pwm.h定义。常用的API如下:
· int hosal_pwm_init(hosal_pwm_dev_t*pwm):PWM初始化。参数说明如下:
      · pwm:PWM设备设备对象,其定义如下:
  1.   typedef struct {
  2.       uint8_t       port;         /**< pwm 端口 */
  3.       hosal_pwm_config_t  config; /**< pwm 配置 */
  4.       void         *priv;         /**< 用户自定义数据 */
  5.   } hosal_pwm_dev_t;
复制代码
其中,hosal_pwm_config_t为为PWM配置定义,其内容如下:
  1. typedef struct {
  2.     uint8_t    pin;        /**< pwm 引脚  */
  3.     uint32_t   duty_cycle; /**< pwm占空比 0 ~ 10000(0 ~ 100%)*/
  4.     uint32_t   freq;       /**< pwm频率 0 ~ 40M */
  5. } hosal_pwm_config_t;
复制代码
      · 返回值:成功时,返回0;否则返回其他非零值。
· int hosal_pwm_start(hosal_pwm_dev_t *pwm):启动PWM。参数说明如下:
      · pwm:PWM设备对象
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pwm_stop(hosal_pwm_dev_t*pwm):停止PWM。参数说明如下:
      · opwm:PWM设备对象
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pum_para_chg(hosal_pum_dev_t *pwm, hosal_pwm_config_t para):PWM配置更新。参数说明如下:
      · pwm:PWM设备设备对象
      · para:新的PWM配置
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pwm_freq_set(hosal_pwm_dev_t*pwm,uint32_t freg):设置PWM频率。参数说明如下:
      · pwm:PWM设备设备对象
      · freq:新的PWM频率
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pwm_freg_get(hosal_pwm_dev_t*pwm, uint32 t*p_freg):查询当前PWM频率。参数说明如下:
      · pwm:PWM设备设备对象
      · pfreq:用于返回当前PWM频率
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pwm_duty_set(hosal_pwm_dev_t*pwm, uint32 t_duty):设置PWM的占空比。参数说明如下:
      · pwm:PWM设备设备对象
      · duty:新的占空比
      · 返回值:成功时,返回0;否则返回其他非零值。

· int hosal_pwm_duty_get(hosal_pwm_dev_t*pwm, uint32_t*p_duty):查询当前PWM的占空比。参数说明如下:
      · pwm:PWM设备对象
      · p_duty:用于返回当前PWM占空比
      · 返回值:成功时,返回0;否则返回其他非零值,

· int hosal_pwm_finalize(hosal_pwm_dev_t *pwm):销毁PWM设备对象并释放相关资源。参数说明如下:
      · pwm:PWM设备对象
      · 返回值:成功时,返回0;否则返回其他非零值

三:PWM使用示例
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <FreeRTOS.h>
  4. #include <task.h>
  5. #include <stdio.h>
  6. #include <stdbool.h>

  7. #include <hosal_pwm.h>
  8. #include <blog.h>

  9. #define TAG "pwm_demo"

  10. hosal_pwm_dev_t pwm;
  11. void demo_hosal_pwm_init(void)
  12. {
  13.     uint32_t p_freq;
  14.     uint32_t duty;
  15.     /* pwm 端口及引脚设置 注意:端口与引脚有对应关系,对于 bl602,映射为端口=引脚%5 */
  16.     pwm.port = 3;
  17.     /* pwm config */
  18.     pwm.config.pin = 3;
  19.     pwm.config.duty_cycle = 5000; //占空比范围为:0~10000相当于0~100%
  20.     pwm.config.freq = 1000;       //频率范围为 0~40MHZ
  21.     /* 初始化PWM */
  22.     hosal_pwm_init(&pwm);
  23. }

  24. void demo_hosal_pwm_change_param(uint8_t duty)
  25. {
  26.     /* 更改PWM配置 */
  27.     hosal_pwm_config_t para;
  28.     para.duty_cycle = duty * 1000; //ex.8000/10000=80%
  29.     para.freq = 500;
  30.         // 更新PWM配置
  31.     hosal_pwm_para_chg(&pwm, para);
  32. }

  33. void pwm_task(void* params) {
  34.     printf("pwm task start...\r\n");
  35.     demo_hosal_pwm_init();
  36.     hosal_pwm_start(&pwm);
  37.     while (true) {

  38.         for(uint8_t duty = 0;duty <= 10;duty++){
  39.             demo_hosal_pwm_change_param(duty);
  40.             vTaskDelay(100);
  41.         }
  42.         vTaskDelay(500);
  43.         for(uint8_t duty = 9;duty >= 0;duty--){
  44.             demo_hosal_pwm_change_param(duty);
  45.             vTaskDelay(100);
  46.         }
  47.     }
  48.     hosal_pwm_stop(&pwm);
  49.     vTaskDelete(NULL);
  50. }

  51. void main(void) {
  52.     printf("pwm demo inited\r\n");
  53.     xTaskCreate(pwm_task, "pwm_task", 1024, NULL, 15, NULL);
  54. }
复制代码

本帖被以下淘专辑推荐:

用心做好保姆工作
回复

使用道具 举报

bzhou830 | 2024-9-2 15:00:51 | 显示全部楼层
学习了,看样子舵机直接可以驱动了
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

iiv | 2024-9-2 18:19:23 | 显示全部楼层
学习了,看样子看样子了
回复 支持 反对

使用道具 举报

djy876 | 2024-9-9 14:30:04 | 显示全部楼层
打卡学习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则