ESP32 - Micropython ESP-IDF 双线教程 脉宽调制(PWM)(1)

ESP32 - Micropython ESP-IDF 双线教程 脉宽调制(PWM)

    • [PWM 的基本原理](#PWM 的基本原理)
    • [PWM 的应用](#PWM 的应用)
    • [PWM 的优点](#PWM 的优点)
    • [PWM 的实现方式](#PWM 的实现方式)
    • [ESP32-micropython 中的 PWM 功能](#ESP32-micropython 中的 PWM 功能)
      • [使用 micropython 控制 PWM 的代码示例](#使用 micropython 控制 PWM 的代码示例)
      • 代码介绍
    • [ESP32-IDF 中的 PWM 功能](#ESP32-IDF 中的 PWM 功能)
        • [1. 初始化配置函数](#1. 初始化配置函数)
        • [2. 引脚绑定函数](#2. 引脚绑定函数)
        • [3. 占空比设置函数](#3. 占空比设置函数)
        • [4. 读取函数](#4. 读取函数)
        • [5. 更改频率函数](#5. 更改频率函数)
        • [6. 其他功能函数](#6. 其他功能函数)
        • 归纳
      • [1. 初始化PWM](#1. 初始化PWM)
      • [2. 配置GPIO引脚](#2. 配置GPIO引脚)
      • [3. 编写呼吸效果函数](#3. 编写呼吸效果函数)
      • [4. 编写主循环](#4. 编写主循环)
      • 示例代码

脉宽调制(PWM,Pulse Width Modulation)是一种模拟控制技术,通过数字手段来产生模拟效果。它基于一种思路:通过对一系列脉冲的宽度进行调制,从而等效地获得所需要的波形(含形状和幅值)。在电子电路中,PWM 波形通常用于控制模拟电路,因为它具有比传统模拟方法更高的分辨率和更简单的电路结构。

PWM 的基本原理

PWM 的基本原理是在一个固定的周期(或称为"载波周期")内,改变脉冲信号的高电平时间(或称为"占空比")来模拟不同的模拟信号。占空比是指在一个周期内,高电平时间(脉冲宽度)与整个周期时间的比值。例如,如果占空比为 50%,则在一个周期内,高电平时间等于低电平时间。

PWM 的应用

PWM 在许多领域都有广泛的应用,包括但不限于:

  1. LED 亮度控制:通过改变 PWM 的占空比,可以控制 LED 的平均电流,从而控制其亮度。这种方法比传统的模拟电压控制更为精确和高效。

  2. 电机速度控制:PWM 可以用于控制直流电机或步进电机的速度。通过改变 PWM 的占空比,可以控制电机的平均输入电压,从而控制其转速。

  3. 音频放大:PWM 可以用于音频放大器的功率控制。与传统的线性放大器相比,PWM 放大器具有更高的效率和更低的失真。

  4. 电源管理:PWM 可以用于电源管理中的电压调节和电流控制。例如,在计算机电源的 DC-DC 转换器中,PWM 用于控制输出电压。

  5. 通信和信号处理:在某些通信和信号处理系统中,PWM 可以用于编码和解码信息。

PWM 的优点

  1. 分辨率高:PWM 的分辨率仅受限于载波频率和脉冲宽度的精度。通过提高载波频率和使用高精度的脉冲宽度控制,可以实现非常高的分辨率。

  2. 效率高:由于 PWM 是一种数字控制方法,因此它可以利用数字电路的高效性。与传统的模拟控制方法相比,PWM 控制通常具有更高的效率。

  3. 灵活性强:PWM 可以很容易地通过改变占空比来模拟不同的模拟信号。这使得 PWM 在许多应用中都非常灵活和方便。

  4. 抗干扰能力强:由于 PWM 是一种数字信号,因此它具有较强的抗干扰能力。即使在存在噪声和干扰的情况下,PWM 信号也能保持较好的稳定性和可靠性。

PWM 的实现方式

PWM 的实现方式有很多种,包括软件 PWM 和硬件 PWM。软件 PWM 是通过编程来产生 PWM 信号的方法,它通常使用定时器中断来周期性地改变脉冲的宽度。硬件 PWM 是通过专门的硬件电路来产生 PWM 信号的方法,它通常具有更高的精度和更低的噪声。在 ESP32 这样的微控制器中,通常提供了硬件 PWM 支持,使得用户可以方便地实现 PWM 控制。

ESP32-micropython 中的 PWM 功能

在 ESP32-micropython 中,可以使用 machine 模块中的 PWM 类来创建和操作 PWM 信号。PWM 对象可以配置为不同的频率和占空比,以产生所需的输出信号。

使用 micropython 控制 PWM 的代码示例

以下是一个简单的示例,展示了如何使用 ESP32-micropython 和 GPIO 来控制一个 LED 的亮度,模拟呼吸效果。我们将使用一个按钮(连接到另一个 GPIO)来改变呼吸速度。

python 复制代码
import machine
import utime

# 配置 PWM 引脚和频率
led_pin = machine.Pin(2, machine.Pin.OUT)  # 假设 LED 连接到 GPIO 2
pwm = machine.PWM(led_pin)
pwm.freq(1000)  # 设置 PWM 频率为 1kHz

# 配置按钮引脚
button_pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)  # 假设按钮连接到 GPIO 0,并启用上拉电阻

# 呼吸效果函数
def breathe(brightness_max, speed):
    brightness = 0
    increment = brightness_max / 10  # 分为 10 步增加/减少亮度
    while True:
        for i in range(brightness_max, 0, -increment):
            pwm.duty_u16(int(i * 65535 / brightness_max))  # 设置 PWM 占空比
            utime.sleep_ms(speed)  # 等待一段时间以控制呼吸速度
        for i in range(0, brightness_max, increment):
            pwm.duty_u16(int(i * 65535 / brightness_max))
            utime.sleep_ms(speed)

# 初始呼吸速度
speed = 50  # 毫秒

try:
    while True:
        if not button_pin.value():  # 检测到按钮按下
            # 等待按钮释放
            while not button_pin.value():
                pass
            # 改变呼吸速度
            speed = speed * 2 if speed < 200 else 50  # 如果速度小于 200ms,则加倍;否则重置为 50ms
            print("Changed breath speed to:", speed, "ms")
        breathe(255, speed)  # 调用呼吸效果函数
except KeyboardInterrupt:
    pwm.deinit()  # 清理 PWM 对象
    machine.reset()  # 重启设备

代码介绍

  1. 导入必要的模块 :我们导入了 machine 模块,用于访问 ESP32 的硬件功能,以及 utime 模块,用于精确的时间控制。
  2. 配置 PWM 和按钮引脚:我们设置了 LED 和按钮连接的 GPIO 引脚,并初始化了 PWM 对象,设置了其频率。
  3. 定义呼吸效果函数:这个函数通过改变 PWM 的占空比来模拟呼吸效果。它使用两个嵌套的 for 循环来逐渐增加和减少亮度。
  4. 主循环:在主循环中,我们不断调用呼吸效果函数。当检测到按钮按下时,我们改变呼吸速度。注意,我们使用了简单的去抖动逻辑来确保只检测一次按钮按下。
  5. 异常处理 :我们使用 try-except 块来处理可能的 KeyboardInterrupt 异常(例如,用户按下了复位按钮)。在异常处理程序中,我们清理了 PWM 对象并重启了设备。

ESP32-IDF 中的 PWM 功能

ESP32的PWM库函数主要用于配置和控制PWM(脉宽调制)信号。这些函数通常是在ESP-IDF(Espressif IoT Development Framework)中提供的,以下是对ESP32 PWM库函数的一些讲解:

1. 初始化配置函数
  • ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits)
    • 功能:设置PWM通道的频率和分辨率。
    • 参数
      • channel:PWM通道号,范围从0到15。
      • freq:PWM频率,最大频率由公式80000000 / 2^bit_num给出,其中bit_num是分辨率位数。
      • resolution_bits:PWM分辨率位数,支持1到16位。分辨率和频率成反比。
2. 引脚绑定函数
  • ledcAttachPin(uint8_t pin, uint8_t channel)
    • 功能:将GPIO引脚绑定到指定的PWM通道。
    • 参数
      • pin:要绑定的GPIO引脚号。
      • channel:PWM通道号,与ledcSetup函数中设置的通道对应。
3. 占空比设置函数
  • ledcWrite(uint8_t channel, uint32_t duty)
    • 功能:设置指定PWM通道的占空比。
    • 参数
      • channel:PWM通道号。
      • duty:占空比值,与PWM分辨率有关。
4. 读取函数
  • ledcRead(uint8_t channel)
    • 功能:读取指定PWM通道的当前占空比值。
    • 参数channel,PWM通道号。
5. 更改频率函数
  • ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num)
    • 功能:更改PWM通道的频率和分辨率。
    • 参数
      • chan:PWM通道号。
      • freq:新的PWM频率。
      • bit_num:新的PWM分辨率位数。
6. 其他功能函数
  • ledcWriteTone(通道,频率)ledcWriteNote(channel, note, oc) (注意:这些函数可能在某些库版本中不存在或名称略有不同)
    • 功能:这些函数允许开发者以特定的频率或音符播放PWM信号,通常用于音频应用。
归纳
  • 初始化 :使用ledcSetup函数设置PWM通道的频率和分辨率。
  • 引脚绑定 :使用ledcAttachPin函数将GPIO引脚绑定到PWM通道。
  • 占空比控制 :使用ledcWrite函数设置PWM通道的占空比。
  • 读取 :使用ledcRead函数读取PWM通道的当前占空比。
  • 更改频率 :使用ledcChangeFrequency函数更改PWM通道的频率和分辨率(如果需要)。
  • 其他功能 :使用其他函数(如ledcWriteToneledcWriteNote)实现特定应用需求。

请注意,以上函数和参数是基于ESP-IDF库的一般描述,实际使用时可能需要根据具体的库版本和开发环境进行调整。建议查阅ESP-IDF的官方文档以获取最准确和最新的信息。

1. 初始化PWM

首先,需要初始化PWM模块,并配置PWM通道的参数,如频率、占空比等。

2. 配置GPIO引脚

需要配置用于PWM输出的GPIO引脚,以及用于按钮输入的GPIO引脚。

3. 编写呼吸效果函数

这个函数将循环改变PWM的占空比,以模拟呼吸效果。

4. 编写主循环

在主循环中,检测按钮的输入,并根据需要改变呼吸速度。

示例代码

c 复制代码
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/pwm.h"
#include "driver/gpio.h"

#define LED_PWM_CHANNEL  0   // 假设使用PWM通道0
#define LED_GPIO_NUM     2   // 假设LED连接到GPIO 2
#define BUTTON_GPIO_NUM  0   // 假设按钮连接到GPIO 0
#define PWM_HZ           1000// PWM频率设置为1kHz
#define BREATHE_MAX      1023// 占空比最大值(10位PWM)

static void breathe_led(uint16_t max_brightness, uint32_t speed_ms);

void app_main(void)
{
    // 初始化PWM
    pwm_config_t pwm_config = {
        .freq_hz = PWM_HZ,
        .duty_mode = PWM_DUTY_MODE_MS,
        .intr_mode = PWM_INTR_DISABLE,
        .output_select_low = PWM_OUTPUT_LOW_HIGH,
        .clk_sel = PWM_SEL_APB_CLK,
    };
    pwm_init(LED_PWM_CHANNEL, &pwm_config, 1, NULL);
    pwm_set_pin(LED_PWM_CHANNEL, LED_GPIO_NUM);

    // 初始化GPIO(按钮)
    gpio_pad_select_gpio(BUTTON_GPIO_NUM);
    gpio_set_direction(BUTTON_GPIO_NUM, GPIO_MODE_INPUT);
    gpio_set_pull_mode(BUTTON_GPIO_NUM, GPIO_PULLUP_ONLY);

    // 初始呼吸速度
    uint32_t speed_ms = 50;

    // 呼吸效果主循环
    while (1) {
        if (gpio_get_level(BUTTON_GPIO_NUM) == 0) { // 检测到按钮按下
            // 等待按钮释放(简单去抖动)
            vTaskDelay(pdMS_TO_TICKS(20));
            if (gpio_get_level(BUTTON_GPIO_NUM) == 0) {
                // 改变呼吸速度
                speed_ms = (speed_ms < 200) ? speed_ms * 2 : 50;
                printf("Changed breath speed to: %d ms\n", speed_ms);
                // 稍微等待以确保按钮完全释放
                vTaskDelay(pdMS_TO_TICKS(20));
            }
        }
        breathe_led(BREATHE_MAX, speed_ms);
    }
}

static void breathe_led(uint16_t max_brightness, uint32_t speed_ms)
{
    uint16_t brightness = 0;
    uint16_t increment = max_brightness / 10; // 分为10步增加/减少亮度

    while (1) {
        for (brightness = 0; brightness <= max_brightness; brightness += increment) {
            pwm_set_duty(LED_PWM_CHANNEL, 0, brightness);
            vTaskDelay(pdMS_TO_TICKS(speed_ms));
        }
        for (brightness = max_brightness; brightness > 0; brightness -= increment) {
            pwm_set_duty(LED_PWM_CHANNEL, 0, brightness);
            vTaskDelay(pdMS_TO_TICKS(speed_ms));
        }
    }
}
相关推荐
懒大王爱吃狼42 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
深度学习lover3 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
API快乐传递者4 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq5 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
阡之尘埃6 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
hairenjing11236 小时前
使用 Mac 数据恢复从 iPhoto 图库中恢复照片
windows·stm32·嵌入式硬件·macos·word
青花瓷7 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode