(九)零基础开发小安派-Eyes-S1【外设篇】——PWM

[复制链接]
查看3159 | 回复29 | 2023-9-21 16:13:04 | 显示全部楼层 |阅读模式

本帖最后由 Ai-Thinker小泽 于 2023-9-21 16:12 编辑

零基础开发小安派-Eyes-S1【外设篇】——PWM

PWM是英文“Pulse Width Modulation”的缩写,简称脉宽调制。一般IO口输出是高低电平,是数字信号,电压是以1或0的重复脉冲来模拟负载,我们可以通过对一个脉冲信号的高低电平时间控制来将数字信号模拟成模拟电压信号,这也是PWM最大的用处。总结下来就是,通过一个周期内改变占空比的方式来改变输出的有效电压。下面普及几个PWM的概念。

PWM频率: 一秒钟内,信号完整的从高电平到低电平的次数(完整的一个脉冲周期),单位是Hz。1Hz也就是一秒钟一个脉冲周期,周期是1000ms。

PWM周期: 周期=1/频率,也就是周期与频率互为倒数,单位一般是ms,若频率为5Hz,周期也就是1/5=0.2S=200ms。

PWM占空比: 一个脉冲周期内,高电平的时间占整个周期时间的比例。单位是%,高电平时间是50ms,周期是100ms。占空比就是50/100*100%=50%。

一、了解小安派-Eyes-S1的PWM

小安派使用的M61模组是BL618芯片,基于LHAL库只支持PWM_V2,该PWM版本支持四个PWM通道。

PWM V2 版本输出有效极性。当正向通道阈值位于设置的低阈值和高阈值之间,为有效极性,如果设置有效极性为高,则输出高电平,反之输出低电平。反向通道相反,阈值位于设置的低阈值和高阈值之外,为有效极性,如果设置有效极性为高,则输出高电平,反之输出低电平。

#define PWM_POLARITY_ACTIVE_LOW  0
#define PWM_POLARITY_ACTIVE_HIGH 1

1.struct bflb_pwm_v2_config_s

说明:pwm_v2初始化配置结构体

struct bflb_pwm_v2_config_s {
uint8_t clk_source;
uint16_t clk_div;
uint16_t period;
};
parameter description
clk_source 时钟源选择:PBCLK or XCLK or 32K_CLK
clk_div 分频值
period 周期值

PWM最终产生的频率为clk_source/clk_div/period


2.struct bflb_pwm_v2_channel_config_s

说明:pwm_v2通道初始化配置结构体

struct bflb_pwm_v2_channel_config_s {
uint8_t positive_polarity;
uint8_t negative_polarity;
uint8_t positive_stop_state;
uint8_t negative_stop_state;
uint8_t positive_brake_state;
uint8_t negative_brake_state;
uint8_t dead_time;
};
parameter description
positive_polarity 正向输出极性
negative_polarity 反向输出极性
positive_stop_state 正向输出空闲状态
negative_stop_state 反向输出空闲状态
positive_brake_state 正向输出刹车状态
negative_brake_state 反向输出刹车状态
dead_time 死区时间

3.bflb_pwm_v2_init

说明:初始化 pwm。使用之前需要选择 gpio 为 pwm 功能。

void bflb_pwm_v2_init(struct bflb_device_s *dev, const struct bflb_pwm_v2_config_s *config);

parameter description
dev 设备句柄
config 配置项

4.bflb_pwm_v2_deinit

说明: 复位 pwm。

void bflb_pwm_v2_deinit(struct bflb_device_s *dev);

parameter description
dev 设备句柄

5.bflb_pwm_v2_start

说明: 启动 pwm 输出。

void bflb_pwm_v2_start(struct bflb_device_s *dev);

parameter description
dev 设备句柄

6.bflb_pwm_v2_stop

说明: 关闭 pwm 输出。

void bflb_pwm_v2_stop(struct bflb_device_s *dev);

parameter description
dev 设备句柄

7.bflb_pwm_v2_set_period

说明: 修改 pwm 周期值,从而更改 pwm 输出的频率。

void bflb_pwm_v2_set_period(struct bflb_device_s *dev, uint16_t period);

parameter description
dev 设备句柄
period 周期值

8.bflb_pwm_v2_channel_init

说明: PWM 通道初始化。

void bflb_pwm_v2_channel_init(struct bflb_device_s *dev, uint8_t ch, struct bflb_pwm_v2_channel_config_s *config);

parameter description
dev 设备句柄
ch 通道号
config 通道配置

9.bflb_pwm_v2_channel_set_threshold

说明: 设置 PWM 占空比。

void bflb_pwm_v2_channel_set_threshold(struct bflb_device_s *dev, uint8_t ch, uint16_t low_threhold, uint16_t high_threhold);

parameter description
dev 设备句柄
ch 通道号
low_threhold 低阈值
high_threhold 高阈值,需要大于 low_threhold,并且小于等于 period

PWM占空比=(high_threhold - low_threhold)/period


10.bflb_pwm_v2_channel_positive_start

说明: PWM 正向通道使能输出。

void bflb_pwm_v2_channel_positive_start(struct bflb_device_s *dev, uint8_t ch);

parameter description
dev 设备句柄
ch 通道号

11.bflb_pwm_v2_channel_negative_start

说明: PWM 反向通道使能输出。

void bflb_pwm_v2_channel_negative_start(struct bflb_device_s *dev, uint8_t ch);

parameter description
dev 设备句柄
ch 通道号

12.bflb_pwm_v2_channel_positive_stop

说明: PWM 正向通道停止输出。

void bflb_pwm_v2_channel_positive_stop(struct bflb_device_s *dev, uint8_t ch);

parameter description
dev 设备句柄
ch 通道号

13.bflb_pwm_v2_channel_negative_stop

说明: PWM 反向通道停止输出。

void bflb_pwm_v2_channel_negative_stop(struct bflb_device_s *dev, uint8_t ch);

parameter description
dev 设备句柄
ch 通道号

14.bflb_pwm_v2_int_enable

说明: PWM 中断使能和关闭。

void bflb_pwm_v2_int_enable(struct bflb_device_s *dev, uint32_t int_en, bool enable);

parameter description
dev 设备句柄
int_en 中断使能位
enable 是否开启中断

int_en 可以填入以下值,多个中断可以使用 | 连接:

#define PWM_INTEN_CH0_L  (1 << 0)
#define PWM_INTEN_CH0_H  (1 << 1)
#define PWM_INTEN_CH1_L  (1 << 2)
#define PWM_INTEN_CH1_H  (1 << 3)
#define PWM_INTEN_CH2_L  (1 << 4)
#define PWM_INTEN_CH2_H  (1 << 5)
#define PWM_INTEN_CH3_L  (1 << 6)
#define PWM_INTEN_CH3_H  (1 << 7)
#define PWM_INTEN_PERIOD (1 << 8)
#define PWM_INTEN_BRAKE  (1 << 9)
#define PWM_INTEN_REPT   (1 << 10)

15.bflb_pwm_v2_get_intstatus

说明:获取 PWM 中断标志。

uint32_t bflb_pwm_v2_get_intstatus(struct bflb_device_s *dev);

parameter description
dev 设备句柄
return 返回中断标志

返回值如下:

#define PWM_INTSTS_CH0_L  (1 << 0)
#define PWM_INTSTS_CH0_H  (1 << 1)
#define PWM_INTSTS_CH1_L  (1 << 2)
#define PWM_INTSTS_CH1_H  (1 << 3)
#define PWM_INTSTS_CH2_L  (1 << 4)
#define PWM_INTSTS_CH2_H  (1 << 5)
#define PWM_INTSTS_CH3_L  (1 << 6)
#define PWM_INTSTS_CH3_H  (1 << 7)
#define PWM_INTSTS_PERIOD (1 << 8)
#define PWM_INTSTS_BRAKE  (1 << 9)
#define PWM_INTSTS_REPT   (1 << 10)

16.bflb_pwm_v2_int_clear

说明: 清除 PWM 中断标志。

void bflb_pwm_v2_int_clear(struct bflb_device_s *dev, uint32_t int_clear);

parameter description
dev 设备句柄
int_clear 清除值

int_clear 可以填入以下参数:

#define PWM_INTCLR_CH0_L  (1 << 0)
#define PWM_INTCLR_CH0_H  (1 << 1)
#define PWM_INTCLR_CH1_L  (1 << 2)
#define PWM_INTCLR_CH1_H  (1 << 3)
#define PWM_INTCLR_CH2_L  (1 << 4)
#define PWM_INTCLR_CH2_H  (1 << 5)
#define PWM_INTCLR_CH3_L  (1 << 6)
#define PWM_INTCLR_CH3_H  (1 << 7)
#define PWM_INTCLR_PERIOD (1 << 8)
#define PWM_INTCLR_BRAKE  (1 << 9)
#define PWM_INTCLR_REPT   (1 << 10)

17.bflb_pwm_v2_feature_control

说明: PWM 其他特性相关控制,一般不常用。

int bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);

parameter description
dev 设备句柄
cmd 控制字
arg 控制参数
return 负值表示不支持此命令

cmd 可以填入以下参数:

#define PWM_CMD_SET_TRIG_ADC_SRC       (0x01)
#define PWM_CMD_SET_EXT_BRAKE_POLARITY (0x02)
#define PWM_CMD_SET_EXT_BRAKE_ENABLE   (0x03)
#define PWM_CMD_SET_SW_BRAKE_ENABLE    (0x04)
#define PWM_CMD_SET_STOP_ON_REPT       (0x05)
#define PWM_CMD_SET_REPT_COUNT         (0x06)

二、示例:PWM实现呼吸灯

呼吸灯是PWM最常见的例子,非常的简单,首先将频率调好,人眼识别的频率大于50Hz时,由于识别不了这么高的闪烁频率,看起来就像常亮一样。总结起来就是:

频率很高时,看不到闪烁,占空比越大,LED越亮; 频率很低时,可看到闪烁,占空比越大,LED越亮。

所以我们只需要调好频率,在改变占空比的情况下就可以看到LED灯亮度变化过程。在一个while函数里实现即可。

Main

#include "bflb_mtimer.h"        //mtimer定时器头文件
#include "bflb_pwm_v2.h"      //pwm_v2头文件
#include "bflb_clock.h"           //系统时钟头文件
#include "board.h"                 //开发板头文件,包装的库
#include "bflb_gpio.h"           //gpio头文件


struct bflb_device_s *pwm;     //创建LHAL外设库结构体,名称为pwm

void my_pwm_gpio_init()        //编写一个选择pwm输出的gpio口初始化函数
{
    struct bflb_device_s *gpio;

    gpio = bflb_device_get_by_name("gpio");

    bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_PWM0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
//选择IO0作为pwm输出,
}


int main(void)
{
    int i;                                   //临时变量i,作为改变占空比的变量
    board_init();                       //板子初始化
    my_pwm_gpio_init();         //调用函数,里面设置好了pwm输出的gpio口

    pwm = bflb_device_get_by_name("pwm_v2_0");  //给外设接口赋名pwm_v2_0

    /* period = .XCLK / .clk_div / .period = 40MHz / 40 / 1000 = 1KHz */

    struct bflb_pwm_v2_config_s cfg = {
        .clk_source = BFLB_SYSTEM_XCLK,
        .clk_div = 40,
        .period = 1000,
    };                //设置PWM的频率,选择时钟,分频,和周期。根据上面的公式算出最终的频率。

    /*初始化PWM输出*/
    bflb_pwm_v2_init(pwm, &cfg);
    bflb_pwm_v2_start(pwm);          //将设置好的频率开启pwm输出


    while (1) {
    //蓝灯呼吸亮灭  
    bflb_pwm_v2_channel_positive_start(pwm, PWM_CH0);         //那么问题来了,如何知道IO口对应的PWM通道,后面会解答,IO0是通道0
    for(i=150;i>0;i--)
    {
        bflb_pwm_v2_channel_set_threshold(pwm, PWM_CH0, i, 150); //改变占空比,变量i会不断变化

        bflb_mtimer_delay_ms(10);
    }
    for(i=1;i<150;i++)
    {
        bflb_pwm_v2_channel_set_threshold(pwm, PWM_CH0, i, 150);

        bflb_mtimer_delay_ms(10);
    }
    bflb_pwm_v2_channel_positive_stop(pwm, PWM_CH0);        
    }
}

确定IO对应PWM通道

查看BL616/618的芯片数据手册:bl616_bl618_ds_zh_cn_1.4.pdf (ai-thinker.com)

屏幕截图2023-09-21155809.png

呼吸灯效果

LED01.gif

其他

PWM的玩法还有很多,可以改变频率来控制蜂鸣器输出音频,也可以应用在电机上控制电机的转速,从而达到档位调节的效果。

本帖被以下淘专辑推荐:

回复

使用道具 举报

496199544 | 2023-9-21 17:59:25 来自手机 | 显示全部楼层
学习
回复

使用道具 举报

18350766600@139 | 2023-9-21 18:32:22 | 显示全部楼层
学习打卡
回复

使用道具 举报

ifwz1729 | 2023-9-22 10:28:50 | 显示全部楼层
点灯大师
回复

使用道具 举报

lsrly | 2023-9-22 11:29:22 | 显示全部楼层
PWM控制LED灯挺好,可以省个恒流芯片
好好学习,努力挣钱,专心
回复 支持 反对

使用道具 举报

Alaurb | 2023-10-3 12:20:07 | 显示全部楼层
回复

使用道具 举报

skyjz | 2023-10-6 13:03:15 | 显示全部楼层
学习
回复

使用道具 举报

End | 2023-10-10 19:44:18 | 显示全部楼层
学习打卡
羡慕
回复

使用道具 举报

WangChong | 2023-10-26 21:08:19 | 显示全部楼层
学习打卡
回复

使用道具 举报

iiv | 2023-10-26 21:15:09 | 显示全部楼层
我又来烦泽哥了
回复 支持 反对

使用道具 举报

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

本版积分规则