3

RP2040(树莓派Pico) PWM

 3 years ago
source link: https://www.taterli.com/7548/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

RP2040(树莓派Pico) PWM

树莓派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功能也太基础了点,感觉做控制搞不定,是用来驱动舵机什么的吧.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK