ESP32学习之定时器和PWM

一.定时器代码如下:


#include 

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的值

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

ESP32学习之定时器和PWM_第1张图片

二.PWM代码如下:


#include 

/*
 * 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,就都是高电平。

ESP32学习之定时器和PWM_第2张图片

 上图:周期为1ms

ESP32学习之定时器和PWM_第3张图片

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

ESP32学习之定时器和PWM_第4张图片

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

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

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

代码如下:

ESP32学习之定时器和PWM_第5张图片

结果为(正确):

ESP32学习之定时器和PWM_第6张图片

 ESP32学习之定时器和PWM_第7张图片

三.扩展知识

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 

/*
 * 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干不了其他事情了;

你可能感兴趣的:(ESP32,学习,单片机,c语言,ESP32,stm32)