[单片机框架][bsp层][esp32s3][bsp_pwm] PWM的使用

2023-10-22 07:50

本文主要是介绍[单片机框架][bsp层][esp32s3][bsp_pwm] PWM的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LED PWM 控制器

概述
LED 控制器 (LEDC) 主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。 该控制器有 8 路通道,可以产生独立的波形来驱动 RGB LED 等设备。

LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实现亮度和颜色渐变。

功能概览
设置 LEDC 通道分三步完成。注意,与 ESP32 不同,ESP32-S3 仅支持设置通道为低速模式。

定时器配置 指定 PWM 信号的频率和占空比分辨率。

通道配置 绑定定时器和输出 PWM 信号的 GPIO。

改变 PWM 信号 输出 PWM 信号来驱动 LED。可通过软件控制或使用硬件渐变功能来改变 LED 的亮度。

另一个可选步骤是可以在渐变终端设置一个中断。
在这里插入图片描述

定时器配置

要设置定时器,可调用函数 ledc_timer_config(),并将包括如下配置参数的数据结构 ledc_timer_config_t 传递给该函数:

速度模式(值必须为 LEDC_LOW_SPEED_MODE)

定时器索引 ledc_timer_t

PWM 信号频率

PWM 占空比分辨率

时钟源 ledc_clk_cfg_t

频率和占空比分辨率相互关联。PWM 频率越高,占空比分辨率越低,反之亦然。如果 API 不是用来改变 LED 亮度,而是用于其它目的,这种相互关系可能会很重要。更多信息详见 频率和占空比分辨率支持范围 一节。

时钟源同样可以限制PWM频率。选择的时钟源频率越高,可以配置的PWM频率上限就越高。

频率和占空比分辨率支持范围

LED PWM 控制器主要用于驱动 LED。该控制器 PWM 占空比设置的分辨率范围较广。比如,PWM 频率为 5 kHz 时,占空比分辨率最大可为 13 位。这意味着占空比可为 0 至 100% 之间的任意值,分辨率为 ~0.012%(2 ** 13 = 8192 LED 亮度的离散电平)。然而,这些参数取决于为 LED PWM 控制器定时器计时的时钟信号,LED PWM 控制器为通道提供时钟(具体可参考 定时器配置 和 ESP32-S3 技术参考手册 > LED PWM 计时器 (LEDC) [PDF])。

LED PWM 控制器可用于生成频率较高的信号,足以为数码相机模组等其他设备提供时钟。此时,最大频率可为 40 MHz,占空比分辨率为 1 位。也就是说,占空比固定为 50%,无法调整。

LED PWM 控制器 API 会在设定的频率和占空比分辨率超过 LED PWM 控制器硬件范围时报错。例如,试图将频率设置为 20 MHz、占空比分辨率设置为 3 位时,串行端口监视器上会报告如下错误:

E (196) ledc: requested frequency and duty resolution cannot be achieved, try reducing freq_hz or duty_resolution. div_param=128

此时,占空比分辨率或频率必须降低。比如,将占空比分辨率设置为 2 会解决这一问题,让占空比设置为 25% 的倍数,即 25%、50% 或 75%

参考:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/peripherals/ledc.html

/********************************************************************************* @file    pwm.cpp* @author  jianqiang.xue* @version V1.0.0* @date    2022-04-24* @brief   ********************************************************************************/
#include "pwm.h"
#include <driver/ledc.h>
#include "esp_log.h"static const char TAG[] = "pwm";
static const unsigned short PWM_DUTY = 8192; //  (2 ^ duty_resolution) - 1static uint32_t _tim_freq[LEDC_TIMER_MAX] = {0};void PWM::init(uint32_t freq) {esp_err_t ret;int8_t timer_id = -1;for (uint8_t i = 0; i < LEDC_TIMER_MAX; i++){if (_tim_freq[i] == freq){timer_id = i;break;}else if (_tim_freq[i] == 0){timer_id = i;}}if (timer_id == -1){ESP_LOGE(TAG, "init fail! timer num > max");return;}ledc_timer_config_t ledc_timer;ledc_timer.duty_resolution = LEDC_TIMER_13_BIT;	 // resolution of PWM duty (2 ^ duty_resolution) - 1ledc_timer.freq_hz         = freq;ledc_timer.speed_mode      = LEDC_LOW_SPEED_MODE;ledc_timer.timer_num       = (ledc_timer_t)(timer_id % LEDC_TIMER_MAX);// Set configuration of timer0 for high speed channelsret = ledc_timer_config(&ledc_timer);if (ret != ESP_OK){ESP_LOGE(TAG, "timer cfg fail! freq:%d, err:0x%x", freq, ret);return;}_tim_freq[timer_id] = freq;ledc_channel_config_t ledc_channel = {0};ledc_channel.gpio_num            = PWM::_pin;ledc_channel.channel             = (ledc_channel_t)PWM::_channel;ledc_channel.speed_mode          = LEDC_LOW_SPEED_MODE;ledc_channel.timer_sel           = (ledc_timer_t)(timer_id % LEDC_TIMER_MAX);ledc_channel.duty                = 0;ledc_channel.intr_type           = LEDC_INTR_FADE_END;ledc_channel.flags.output_invert = 0;// Set LED Controller with previously prepared configurationret = ledc_channel_config(&ledc_channel);if (ret != ESP_OK){ESP_LOGE(TAG, "ch cfg fail! ch:%d, err:0x%x", PWM::_channel, ret);return;}ledc_fade_func_install(0);
}void PWM::set_duty_cycle(float dc)
{ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM::_channel, (uint32_t)(PWM_DUTY * dc), 0xFFFF);
}float PWM::get_duty_cycle()
{return (float)(ledc_get_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM::_channel)) / PWM_DUTY;
}
#pragma once
#include <stdint.h>class PWM {
public:PWM(uint8_t channel, uint8_t pin):_channel(channel),_pin(pin) {}void init(uint32_t freq);void set_duty_cycle(float dc);float get_duty_cycle();
private:uint8_t _channel;uint8_t _pin;
};

这篇关于[单片机框架][bsp层][esp32s3][bsp_pwm] PWM的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/260085

相关文章

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意