RP2040(树莓派Pico) PWM

/ 3评 / 8

树莓派PWM几乎可以用在每一个IO上,有8对,文档里写是16个CH,但其实是8对(但是并不互补,也没有死区功能.),对于传统单片机只会说自己是8个CH,不知道树莓派是怎么说自己16的... 感觉有点扯,另外B输入可以选择很多条,当选择多条时候是OR逻辑到芯片内部.

RP2040的PWM只有向上计数法和中心对齐,当比较值为0或最高时(等于比较值的最大),他可以输出0或者1且不变,由于双缓冲的存在,具有分频器,当在125MHz外设时钟时,可以取得实际频率范围从7.5 Hz ~ 125 MHz,另外B引脚可以用作PWM的启动信号,这就是前面说到的,为什么多个B输入会以OR方式输入到芯片内部,可以配置多种逻辑,上升沿/下降沿时触发一次或高电平连续输出PWM,这个操作也可以用来做占空比测量.

下面代码用于占空比测量,当然用GPIO等待法,毕竟有读取系统运行us的函数,所以也可以测出来.下面这个函数的原理是当B输入达到100个时钟周期,PWM计数+1,延迟10ms后,计算出1s的总周期数量counting_rate,得出10ms的总周期数量max_possible_count,然后取出pwm_get_counter数量,即是占空比比例,这个计算有局限性,比如B输入不是一个单蠢H->L或者L->H周期,而是H->L->H->.....->L这样交替,只能计算出其中的H的比例.

float measure_duty_cycle(uint gpio) {
    // Only the PWM B pins can be used as inputs.
    assert(pwm_gpio_to_channel(gpio) == PWM_CHAN_B);
    uint slice_num = pwm_gpio_to_slice_num(gpio);

    // Count once for every 100 cycles the PWM B input is high
    pwm_config cfg = pwm_get_default_config();
    pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_HIGH);
    pwm_config_set_clkdiv(&cfg, 100);
    pwm_init(slice_num, &cfg, false);
    gpio_set_function(gpio, GPIO_FUNC_PWM);

    pwm_set_enabled(slice_num, true);
    sleep_ms(10);
    pwm_set_enabled(slice_num, false);
    float counting_rate = clock_get_hz(clk_sys) / 100;
    float max_possible_count = counting_rate * 0.01;
    return pwm_get_counter(slice_num) / max_possible_count;
}

现在看到默认PWM例子,会占用stdio串口,看起来不太舒服,还是改掉他.

int main() {
    ///tag::setup_pwm[]

    // Tell GPIO 0 and 1 they are allocated to the PWM
    gpio_set_function(2, GPIO_FUNC_PWM);
    gpio_set_function(3, GPIO_FUNC_PWM);

    // Find out which PWM slice is connected to GPIO 0 (it's slice 0)
    uint slice_num = pwm_gpio_to_slice_num(2);

    pwm_config config = pwm_get_default_config();
    pwm_config_set_clkdiv(&config, 4.f);

    pwm_init(slice_num, &config, true);

    // Set period of 4 cycles (0 to 3 inclusive)
    pwm_set_wrap(slice_num, 4);
    // Set channel A output high for one cycle before dropping
    pwm_set_chan_level(slice_num, PWM_CHAN_A, 1);
    // Set initial B output high for three cycles before dropping
    pwm_set_chan_level(slice_num, PWM_CHAN_B, 3);
    // Set the PWM running
    pwm_set_enabled(slice_num, true);
    ///end::setup_pwm[]

    // Note we could also use pwm_set_gpio_level(gpio, x) which looks up the
    // correct slice and channel for a given GPIO.
}

最终结果:

可见,当到达比较时候会拉低,符合预期,计算频率6.25MHz是因为4分频后,PWM自身时钟为125/4=31.25MHz,然后设定周期是5,所以实际频率是31.25/5=6.25MHz,符合预期.另外的例子led_fade是使用板载的LED进行呼吸灯实验,占空比是在中断里修改的.

最后一点在例子中没写的就是pwm_config_set_phase_correct,如果开启之后,就从向上计数变成中心对齐模式.

总体来说,这个芯片的PWM功能也太基础了点,感觉做控制搞不定,是用来驱动舵机什么的吧.

  1. cl-ei说道:

    按照逻辑分析仪中显示周期为5,但是代码中
    pwm_set_wrap(slice_num, 4)
    为4,这里是不是写错了?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注