当前位置:   article > 正文

【快速上手ESP32(基于ESP-IDF&VSCode)】04-PWM_esp32 svpwm

esp32 svpwm

PWM

PWM,即脉冲宽度调制(Pulse Width Modulation),是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而达到控制开关稳压电源输出的目的。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术,广泛应用于测量,通信,功率控制与变换等许多领域。

PWM的一个优点是从处理器到被控系统信号都是数字形式的,无需进行数模转换。让信号保持为数字形式可将噪声影响降到最小。噪声只有在强到足以将逻辑1改变为逻辑0或将逻辑0改变为逻辑1时,也才能对数字信号产生影响。

对模拟信号而言,噪声对其产生的影响较大。另外,PWM还简化了模拟电路与数字逻辑电路之间的接口,因为PWM信号都属于数字形式。从模拟信号转向PWM可以极大地简化系统的结构。

以上介绍来自文心一言。

简单来说就是通过在一段时间内,我们控制高电平和低电平持续时间的比例,可以得到介于一直在低电平和一直在高电平之间的效果。

比如说低电平可以使得LED亮,高电平可以使得LED灭。通过PWM控制每个周期时间里的高低电平的比例,可以让LED亮但是没那么亮。如果动态调整PWM的占空比(高电平在一个周期时间中的占比),还可以实现呼吸灯的效果。

上一篇文章我们讲了定时器,那么根据我们的经验(STM32),PWM和定时器是分不开的,因为PWM的频率就是定时器的频率,PWM的占空比要依赖于定时器的自动重装载寄存器。

因此我们这篇就讲讲PWM。

ESP32中的PWM

ESP32中的PWM有两种。

LEDPWM和MCPWM是两个不同的模块,它们各自具有不同的特点和应用场景。

LEDPWM通常用于控制LED灯的亮度和颜色。它可以产生独立的波形来驱动RGB LED等设备,具有高速和低速两种通道模式。高速通道模式在硬件中实现,可以自动且无干扰地改变PWM占空比,而低速通道模式下,PWM占空比需要由软件中的驱动器改变。通过这种方式,LEDPWM能够实现对LED亮度的精确控制,适用于各种需要调节亮度的场景。

而MCPWM(多通道PWM)外设则更适用于一些复杂的控制场景,如有刷/无刷直流电机控制、RC伺服电机控制等。它基于开关模式的数字电源转换,能够计算外部脉宽并将其转换为其他模拟值,如速度、距离等。此外,MCPWM还可以为磁场定向控制(FOC)生成空间矢量调制(SVPWM)信号。MCPWM具有多个子模块,如定时器模块和操作器模块,这些模块协同工作以生成精确的PWM波形,满足各种控制需求。

总的来说,LEDPWM和MCPWM在ESP-IDF中各自扮演着不同的角色。LEDPWM主要关注于LED亮度和颜色的控制,而MCPWM则更适用于电机控制和电源转换等复杂场景。在选择使用哪个模块时,需要根据具体的应用需求和场景来决定。

以上介绍来自文心一言。

简单来说,给LED就用LEDPWM,给电机就用MCPWM。

LEDPWM

#include "driver/ledc.h"

在ESP32中要控制PWM和STM32中有些许不同,在STM32中我们配置完定时器后再额外加一些配置PWM的函数即可。但是在ESP32中我们需要全部重新配置。

首先我们先配置定时器。

从函数名字我们也看得出(ledc开头)这是专门配置LEDPWM的定时器的。

我们需要传入一个结构体变量的指针,我们来看看这个结构体。

关于参数的选择,我们可以参考立创开发板的文档。

那么我们上面配置完定时器之后,接下来要配置的就是通道,来绑定定时器和输出 PWM 信号的 GPIO。

我们再来看看需要什么参数。

然后再参考一下参数的选择。

hpoint这个参数经过我实测,发现选啥都没影响,控制占空比的还是duty。当然也可能是我没有理解到位。然后这边的定时器选择以及速度选择要和上面的一致。

如果不是很清楚如何选择参数的小伙伴可以参考我之后的代码。

上面两个函数配置完之后我们就可以发出PWM了,但是还不够,我们需要动态地调整PWM的占空比以及频率,这样才能更好的完成我们要达到的目的。

上面两个函数分别是设置和获取频率。

修改频率其实用的不多,用的比较多的还是修改占空比。

上面两个函数分别是设置和获取占空比。

我们这边设置占空比的范围是根据我们之前选择的分辨率动态调整的,假设我们选择了n位的分辨率,那么占空比这边的范围就是0~2^n-1。

另外,和调整频率不一样的是,修改完占空比之后需要手动更新之后才会生效。

知道上面这些函数之后我们就可以来写一个呼吸灯的代码了。

  1. #include <stdio.h>
  2. #include "driver/ledc.h"
  3. #include <unistd.h>
  4. void Z_LEDPWM_Init(void){
  5. ledc_timer_config_t timer_initer={
  6. .clk_cfg=LEDC_AUTO_CLK, //自动选择时钟源
  7. .duty_resolution=LEDC_TIMER_10_BIT, //10bit的分辨率(可以为1~15)
  8. .freq_hz=1000, //1000Hz
  9. .speed_mode=LEDC_LOW_SPEED_MODE, //低速模式
  10. .timer_num= LEDC_TIMER_0 //选择定时器
  11. };
  12. ledc_timer_config(&timer_initer);
  13. ledc_channel_config_t channel_initer={
  14. .channel=0, //0~7一共八个通道,随便选一个就行
  15. .duty=1023, //上面选择了10bit的分辨率,因此占空比选择范围为0~1023
  16. .gpio_num=18, //GPIO18
  17. .hpoint=1023, //随便填
  18. .intr_type=LEDC_INTR_DISABLE, //不需要中断
  19. .speed_mode=LEDC_LOW_SPEED_MODE, //低速模式
  20. .timer_sel= - LEDC_TIMER_0 //选择定时器
  21. };
  22. ledc_channel_config(&channel_initer);
  23. }
  24. void app_main(void){
  25. printf("Hello World!\r\n");
  26. Z_LEDPWM_Init();
  27. while(1){
  28. for(int i=0;i<1023;++i) {
  29. ledc_set_duty(LEDC_LOW_SPEED_MODE,0,i);
  30. ledc_update_duty(LEDC_LOW_SPEED_MODE, 0);
  31. usleep(1000); //delay 1ms
  32. }
  33. for(int i=1023;i>=0;--i) {
  34. ledc_set_duty(LEDC_LOW_SPEED_MODE,0,i);
  35. ledc_update_duty(LEDC_LOW_SPEED_MODE, 0);
  36. usleep(1000); //delay 1ms
  37. }
  38. }
  39. }

不过上面的代码执行起来会有点小问题,那就是会使得ESP-IDF中自带的FreeRTOS中的看门狗无法被喂狗,导致输出一堆警告信息。

解决方法就是把上面的延时函数替换成FreeRTOS中的延时函数vTaskDelay。这个延时函数会进入阻塞状态,会触发调度,而我们使用的usleep是单纯的延时空循环。

  1. #include "freertos/FreeRTOS.h"
  2. #include "freertos/task.h"
  3. //下面是延时10ms,而且最少就是10ms起步延时.
  4. vTaskDelay(10 / portTICK_PERIOD_MS);

关于MCPWM,感兴趣的小伙伴可以自行去编程指南中查阅用法。

电机控制脉宽调制器 (MCPWM) - ESP32 - — ESP-IDF 编程指南 latest 文档 (espressif.com)icon-default.png?t=N7T8https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/mcpwm.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/640335
推荐阅读
相关标签
  

闽ICP备14008679号