ESP32学习之定时器和PWM

news2024/11/26 21:27:07

一.定时器代码如下:


#include <Arduino.h>

hw_timer_t *timer = NULL;
int interruptCounter = 0;


//	函数名称:onTimer()
//	函数功能:中断服务的功能,它必须是一个返回void(空)且没有输入参数的函数
//  为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性
//  https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.3/zesp32/api-reference/storage/spi_flash_concurrency.html
void IRAM_ATTR TimerEvent()
{
    Serial.println(interruptCounter++);
    if (interruptCounter > 5)
    {
        interruptCounter = 1;
    }
}

void setup() {


    Serial.begin(115200);

    //	函数名称:timerBegin()
    //	函数功能:Timer初始化,分别有三个参数
    //	函数输入:1. 定时器编号(0到3,对应全部4个硬件定时器)
    //			 2. 预分频器数值(ESP32计数器基频为80Mhz,80分频得到1Mhz 单位是微秒)1Mhz=1/1000000,单位是微秒
    //			 3. 计数器向上(true)或向下(false)计数的标志
    //	函数返回:一个指向 hw_timer_t 结构类型的指针
    timer = timerBegin(0, 80, true);

    //	函数名称:timerAttachInterrupt()
    //	函数功能:绑定定时器的中断处理函数,分别有三个参数
    //	函数输入:1. 指向已初始化定时器的指针(本例子:timer)
    //			 2. 中断服务函数的函数指针
    //			 3. 表示中断触发类型是边沿(true)还是电平(false)的标志
    //	函数返回:无
    timerAttachInterrupt(timer, &TimerEvent, true);

    //	函数名称:timerAlarmWrite()
    //	函数功能:指定触发定时器中断的计数器值,分别有三个参数
    //	函数输入:1. 指向已初始化定时器的指针(本例子:timer)
    //			 2. 第二个参数是触发中断的计数器值(1000000 us -> 1s)
    //			 3. 定时器在产生中断时是否重新加载的标志
    //	函数返回:无
    timerAlarmWrite(timer, 1000000, true);
    timerAlarmEnable(timer); //	使能定时器
}


void loop() {

}

代码功能为:用定时器,每隔一秒触发中断,在串口打印interruptCounter的值

结果为(过一会再打开串口,不然会重启):

二.PWM代码如下:


#include <Arduino.h>

/*
 * LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0  => Group: 0, Channel: 0, Timer: 0
** ledc: 1  => Group: 0, Channel: 1, Timer: 0
** ledc: 2  => Groupiimer: 1
** ledc: 4  => Group: 0, Channel: 4, Timer: 2
** ledc: 5  => Group: 0, Channel: 5, Timer: 2
** ledc: 6  => Group: 0, Channel: 6, Timer: 3
** ledc: 7  => Group: 0, Channel: 7, Timer: 3
** ledc: 8  => Group: 1, Channel: 0, Timer: 0
** ledc: 9  => Group: 1, Channel: 1, Timer: 0
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
*/

// 绑定的IO
const int PWM_Pin = 2;

// PWM的通道,共16个(0-15),分为高低速两组,
// 高速通道(0-7): 80MHz时钟,低速通道(8-15): 1MHz时钟
// 0-15都可以设置,只要不重复即可,参考上面的列表
// 如果有定时器的使用,千万要避开!!!
const int LEDC_PWM_Channel = 0;//低速高速最后得到的占空比都一样,没差别,可能80MHz计数更快一点?

// PWM频率,直接设置即可(就是周期,一个周期有多少时间,1000hz代表1ms)
int Base_freq_PWM = 1000;

// PWM分辨率,取值为 0-20 之间,这里填写为10,那么后面的ledcWrite
// 这个里面填写的pwm值就在 0 - 2的10次方 之间 也就是 0-1024
int Freq_resolution_PWM = 10;

void setup() {

  pinMode(PWM_Pin, OUTPUT);

    ledcSetup(LEDC_PWM_Channel, Base_freq_PWM, Freq_resolution_PWM); // 设置通道
    ledcAttachPin(PWM_Pin, LEDC_PWM_Channel);                   //将 LEDC 通道绑定到指定 IO 口上以实现输出
}


void loop() {


  ledcWrite(LEDC_PWM_Channel, 200);//200就是占空比,200/1000*100% = 20%

}

 运行结果:周期1ms,高电平0.2ms,占空比20%,通道是8通道,属于低速通道(8-15): 1MHz时钟,周期1ms,高电平0.2ms,占空比20%,通道是8通道,属于高速通道(0-7): 80MHz时钟。低速时钟或者高速时钟最后得到的占空比都一样,没差别,可能80MHz计数更快一点?若200改为1024,就都是高电平。

 上图:周期为1ms

 上图:占空比为20%,0.2/1 *100% = 20%

再举一个例子:周期为20ms,高电平持续时间为1ms,占空比为0.05。

f=1/T=1/(20/1000)=50,T的单位为秒,所以要将ms转为s。

占空比=duty/T ===》 duty = 2.5

代码如下:

结果为(正确):

 

三.扩展知识

1、Speed Mode
LED PWM 控制器高速和低速模式,高速模式的优点是可平稳地改变定时器设置。
意思就是说高速模式下,如果定时器的设置发生了改变,那么在下一次定时器的溢出中断中就会自动改变;但是低速模式下不会自动改变的。
2、频率和占空比分辨率支持范围:
这个先了解一下占空比和分辨率
占空比:就是高电平接通时间与周期的比
例如:一个PWM频率为1000hz,那周期是1ms,如果高电平时间是100us,那么占空比就是100us:1ms=1:10;
分辨率:就是占空比的最小值
是根据PWM的位数计算的,1:2^位数,如果位数是8,那么PWM的分辨率就是1:255,要是想要达到这个分辨率那就要计数器从0计算到255才行,如果计数值太小,那么他的分辨率就达不到1:255,那PWM的输出频率就变高了。
对于esp32控制器 PWM 占空比设置的分辨率范围较广。比如,PWM 频率为 5 kHz 时,占空比分辨率最大可为 13 位。这意味着占空比可为 0 至 100% 之间的任意值,分辨率为 ~0.012%(1/(2 * 13 )= 1/8192)。PWM 频率越高,占空比分辨率越低

四.呼吸灯

代码如下:


#include <Arduino.h>

/*
 * LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0  => Group: 0, Channel: 0, Timer: 0
** ledc: 1  => Group: 0, Channel: 1, Timer: 0
** ledc: 2  => Groupiimer: 1
** ledc: 4  => Group: 0, Channel: 4, Timer: 2
** ledc: 5  => Group: 0, Channel: 5, Timer: 2
** ledc: 6  => Group: 0, Channel: 6, Timer: 3
** ledc: 7  => Group: 0, Channel: 7, Timer: 3
** ledc: 8  => Group: 1, Channel: 0, Timer: 0
** ledc: 9  => Group: 1, Channel: 1, Timer: 0
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
*/

// 绑定的IO
const int PWM_Pin = 2;

int i = 1;

// PWM的通道,共16个(0-15),分为高低速两组,
// 高速通道(0-7): 80MHz时钟,低速通道(8-15): 1MHz时钟
// 0-15都可以设置,只要不重复即可,参考上面的列表
// 如果有定时器的使用,千万要避开!!!
const int LEDC_PWM_Channel = 0;//低速时钟或者高速时钟最后得到的占空比都一样,没差别,可能80MHz计数更快一点?

// PWM频率,直接设置即可(就是周期,一个周期有多少时间,1000hz代表1ms)
int Base_freq_PWM = 50;

// PWM分辨率,取值为 0-20 之间,这里填写为10,那么后面的ledcWrite
int Freq_resolution_PWM = 6;

void setup() {

  pinMode(PWM_Pin, OUTPUT);

    ledcSetup(LEDC_PWM_Channel, Base_freq_PWM, Freq_resolution_PWM); // 设置通道
    ledcAttachPin(PWM_Pin, LEDC_PWM_Channel);                   //将 LEDC 通道绑定到指定 IO 口上以实现输出
}


void loop() {

  for(i = 1; i <= 50;i++)
  {
  ledcWrite(LEDC_PWM_Channel, i);
  delay(20);
  }

  for(; i > 0;i--)
  {
  ledcWrite(LEDC_PWM_Channel, i);
  delay(20);
  }

}

五.传统的PWM

1、analogWrite(pin,dutyCycle)

// 引脚命名
# define analogPin 3
void setup()
{
	pinMode(analogPin,OUTPUT);
}
void loop()
{
	analogWrite(analogPin,100);		// 输出PWM,占空比为 100/255
}

2、手动实现 PWM

通过 delayMicroseconds() 手动实现频率可调的 PWM,也被称作数字IO轮转法,使用方法:

  1. 两次的digitalWrite输出状态必须相反;
  2. 可以用delay()实现毫秒级延迟,用delayMicroseconds()实现微秒级延迟。
void setup()
{
  pinMode(8, OUTPUT);				// 设置8号引脚为输出模式
}

void loop()
{
  digitalWrite(8, HIGH);
  delayMicroseconds(100); 			// 输出PWM,占空比为100/1000=10%
  digitalWrite(8, LOW);
  delayMicroseconds(1000 - 100); 	// 修改这里的1000可以调整频率,总周期为1000us,所以频率为1000Hz.
}

上面这段代码会产生一个PWM=0.1的,周期为1ms的方波(1kHz),这种方式的优缺点很明显:

  1. PWM的比例可以更精确;
  2. 周期和频率可控制;
  3. 所有的pin脚都可以输出,不局限于那几个脚;
  4. 缺点:CPU干不了其他事情了;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/651212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【动态规划】路径问题

冻龟算法系列之路径问题 文章目录 【动态规划】路径问题1. 不同路径1.1 题目解析1.2 算法原理1.2.1 状态表示1.2.2 状态转移方程1.2.3 初始化1.2.4 填表顺序1.2.5 返回值 1.3 编写代码 2. 不同路径Ⅱ2.1 题目解析2.2 算法原理2.2.1 状态表示2.2.2 状态转移方程2.2.3 初始化2.2.…

性能测试学习之数据驱动性能测试

了解数据驱动测试理念、能够如何在jmeter中用多种方式实现数据驱动测试。 知识点&#xff1a;字符串拼接、计数器、循环控制器 1. 数据驱动的理念 1.1 定义 从数据文件中读取测试数据,驱动测试过程的一-种测试方法数据驱动可以理解为更高级的参数化 1.2 特点 测试数据与测试…

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

目录 1、socket套接字介绍2、字节序简介字节序转换函数 3、socket地址专用socket地址 4、IP地址转换函数5、套接字函数6、TCP通信实现&#xff08;服务器端和客户端&#xff09; 橙色 1、socket套接字介绍 所谓套接字&#xff0c;就是对网络中不同主机上的应用进程之间进行双…

深入理解深度学习——Transformer:整合编码器(Encoder)和解码器Decoder)

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;基础知识 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;注意力汇聚与Nadaraya-Watson核回归 注意力机制&…

国内唯一可以在本地搭建Stable Diffusion WebUI教程-安装时无需魔法安装全程流畅到尖叫

Stable Diffusion是什么 Stable Diffusion简称SD是一款Ai图片生成工具。“输入几句话,生成精美图片。” 比如说我一开头这幅图片就是用的SD生成的。 我在我的“ChatGPT让我变成了“超人”-如何提升团队30%效能质量提高100%的阶段性总结报告”里提到过midjourney,但是midjou…

使用Google工具类Guava自定义一个@Limiter接口限流注解

在Springboot中引用RateLimiter工具类依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1-jre</version> </dependency> 需要注意的是&#xff0c;Guava 的不同版本可能会有…

新手第一次做性能测试?性能测试流程详全,从需求到报告一篇打通

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、确认需求 确定…

3、互联网行业及产品经理分类

上一篇文章&#xff1a;2、产品经理的工作内容_阿杰学编程的博客-CSDN博客 1、产品经理分类 我们把产品经理划分成这样两个大的类型&#xff0c;一个是传统行业的&#xff0c;一个是互联网行业的。这个简单了解一下就行。 这个里面会发现绝大多数也是体育劳动&#xff0c;你比…

软件测试岗位都是女孩子在做吗?

听我一朋友说&#xff0c;测试岗位基本都是女孩子做。” 不知道是不是以前“软件测试岗”给人印象是“不需要太多技术含量”的错觉&#xff0c;从而大部分外行认为从业软件测试的人员中女生应占了大多数。比如有人就觉得&#xff1a;软件测试主要是细心活&#xff0c;所以女生…

2023 年各大互联网公司常见面试题(Java 岗)汇总

很多人都说今年对于 IT 行业根本没有所谓的“金三银四”“金九银十”。在各大招聘网站或者软件上不管是大厂还是中小公司大多都是挂个招聘需求&#xff0c;实际并不招人&#xff1b;在行业内的程序员基本都已经感受到了任老前段时间口中所谓的“寒气”。 虽然事实确实是如此&a…

30个接口自动化测试面试题,赶紧收藏

1. 什么是接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试是指使用自动化工具对接口进行测试&#xff0c;验证接口的正确性、稳定性和性能等方面的指标。2. 为什么要进行接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试可以提高测试效率&#xff0c;减少人…

新能源行业如何进行数据防泄漏

客户情况 某新能源电池企业专业从事于新能源锂离子动力电池和储能电池的研发、生产和销售&#xff0c;具备电芯、模组、BMS及Pack的完整资源开发能力。公司致力于通过持续不断地改进电池技术&#xff0c;为全球锂离子动力和储能领域提供数字化精准高效的新能源解决方案。 该企…

Nautilus Chain 主网上线在即,一文盘点该生态即将上线的项目

Nautilus Chain 是行业内第一个并行化&#xff0c;且运行速度最快 EVM Rollup 的L3扩容方案&#xff0c;作为首个模块化链&#xff0c;存储、计算、共识等都在不同的模块中&#xff0c;意味着其能够获得更高的可拓展性与扩容能力&#xff0c;并在Layer2的基础上进一步提升了网络…

SpringCloud Alibaba-Sentinel

SpringCloud Alibaba-Sentinel 1. Sentinel核心库1.1 Sentinel介绍1.2 Sentinel核心功能1.2.1 流量控制1.2.2 熔断降级 2 Sentinel 限流熔断降级2.1 SentinelResource定义资源2.1.1 blockHandler/blockHandlerClass2.1.2 fallback/fallbackClass2.1.3 defaultFallback 2.2 Sent…

2、产品经理的工作内容

上一篇文章&#xff1a;1、产品经理的宏观定义_阿杰学编程的博客-CSDN博客 接下来这个章节里&#xff0c;我们有三个目标。 第一个通过案例&#xff0c;大家要了解一下产品经理的一个主要的工作内容。 第二个理解产品经理的一个重要性。 第三个我们要熟悉一下MVP的概念&…

Vue实战笔记(四) 引入Mavon Editor

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲如何在 Vue 中引入 Mavon Editor \text{Mavon Editor} Mavon Editor 1、背景介绍 在上篇文章中&#xff0c;我们介绍过如何在 Vue 中引入富文本编辑器 Quill Editor \text{Quill Editor} Quill Editor 在这篇文章中&…

433/315接收芯片 XL520,SOP8封装,适用于低功耗要求产品

XL520是一款高集成度、 低功耗的单片ASK/0OK射频接收芯片。高频信号接收功能全部集成于片内以达到用最少的外围器件和最低的成本获得最可靠的接收效果。 XL520接收芯片为SOP8封装&#xff0c;正常工作电压范围2.0~5.5V&#xff0c;正常工作电流3.0~3.2mA&#xff0c;启动时间2…

pdf可以转换为word文档吗?分享这两个方法给大家!

PDF 是一种常见的文件格式&#xff0c;用于可靠地显示和共享文档。然而&#xff0c;当需要编辑或重用 PDF 内容时&#xff0c;将其转换为可编辑的 Word 文档是一个常见的需求。在本文中&#xff0c;我们将介绍两种方法&#xff0c;以帮助您将 PDF 转换为 Word 文档&#xff0c;…

SpringBoot+Bootstrap图书馆管理系统

主要功能 管理员权限登录&#xff1a; ①管理员拥有最高权限&#xff0c;可以分配角色&#xff0c;使不同角色&#xff08;教师、学生等&#xff09;登录显示不同界面的效果 ②首页、系统设置&#xff1a;菜单管理、角色管理、用户管理、日志管理、数据备份、违规统计、占座统…

Unity基础5——物理检测

一、层级 Layer ​ Unity 中设置了共 32 层 Layer&#xff0c;如图&#xff0c;可以点击 Add Layer 添加自定义的 Layer ​ 通过名字得到层级编号 LayerMask.NameToLayer(string layer) ​ 我们需要通过编号左移构建二进制数&#xff0c;这样每一个编号的层级都是对应位为 1 的…