我手里这块是ESP32WROOM开发板,20多块钱,性价比非常高。
环境搭建就不在此赘述,CSDN上的大佬写的都很详细,我使用的环境为VSCODE + PlatformioIDE + Arduino 开发,搭建环境是一件十分耗时间的事情,笔者即使用了魔法,也整整花了快一天的时间,所以各位小伙伴一定要耐心。
笔者手上的这块WROOM开发板上的LED对应的引脚为D2,然后我们简单介绍一下ESP32上PWM的使用。
大家可以把这个理解为定时器的通道,一共有0-15,总共16个,然后使用的时候,我们需要先调用一个函数,他从左到右的参数分别为:
通道编号(0-15),频率,分辨率(如果是8,那么他的PWM取值就是0-2^8,也就是0-1024,最大为20,也就是0-2的20次方);
ledcSetup(15,1000,8);
然后我们简单的写个呼吸灯的代码,
#include
int ledPin = 9;
int val = 0;
void setup() {
pinMode(ledPin, OUTPUT);
ledcSetup(15,1000,8);
ledcAttachPin(ledPin,15);
}
void loop() {
for(val=0;val<255;val++){
ledcWrite(15,val);
delay(10);
}
for(val=255;val>=0;val--){
delay(10);
ledcWrite(15,val);
}
delay(1000);
}
(2)注意事项:
//以下转自互联网
// PWM的通道,共16个(0-15),分为高低速两组,
// 高速通道(0-7): 80MHz时钟,低速通道(8-15): 1MHz时钟
// 0-15都可以设置,只要不重复即可,参考上面的列表
// 如果有定时器的使用,千万要避开!!!
** ledc: 0 => Timer: 0
** ledc: 1 => Timer: 0
** ledc: 2 => Timer: 1
** ledc: 3 => Timer: 1
** ledc: 4 => Timer: 2
** ledc: 5 => Timer: 2
** ledc: 6 => Timer: 3
** ledc: 7 => Timer: 3
** ledc: 8 => Timer: 0
** ledc: 9 => Timer: 0
** ledc: 10 => Timer: 1
** ledc: 11 => Timer: 1
** ledc: 12 => Timer: 2
** ledc: 13 => Timer: 2
** ledc: 14 => Timer: 3
** ledc: 15 => Timer: 3
3.定时器
(1)定时器流程
定时器也比较简单,首先我们需要1个指针变量,一个中断回调函数
hw_timer_t *timer;
void timer_Callback()
{
//xxxx
}
然后我们需要配置定时器,利用这个函数:
hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp);
其三个参数是:
定时器x (一共4个,0-3)
分频数(基础时钟80MHZ,分频最大值为65536)
第三个是向上或向下计数标志
//然后我们用刚才定义的指针接收以下:
timer = timerBegin(0,80,true);
然后我们将中断回调函数和timer0链接在一起
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
第一个参数:刚才的timer指针
第二个参数:函数指针
第三个参数:边沿触发和电平触发
边沿触发和电平触发的区别:
定时器进入回调函数之后,定时器还会继续计数,如果在中断回调函数中待的时间大于定时器的定时时间,在电平触发的情况下,可能会多次调用函数。
而边沿触发则不会,在介绍完定时器流程之后,我们做一个小实验,验证其是否正确。
timerAttachInterrupt(timer,&timer_Callback,true);
然后第三个函数
void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload);
第一个参数,timer指针
第二个参数 多会进入中断,按照我们刚才设定的预分频为80,基础时钟为80MHZ,也就是一次计数就是1us,如果我们在这里填100 0000的话,就会1s进一次终端回调。
第三个参数 是否重装载,可以理解为是否自动清除中断标志位,如果不清楚,则只会进入一次中断。
然后我们使能时钟就可以:
timerAlarmEnable(timer);
放个代码,LED亮1s灭1s
#include
int ledPin = 2;
int flag=0;
hw_timer_t *timer;
void timer_event()
{
flag ^= 1;
if(flag)
{
digitalWrite(ledPin,LOW);
}
else
{
digitalWrite(ledPin,HIGH);
}
}
void setup() {
pinMode(ledPin, OUTPUT);
timer = timerBegin(0,80,true);
timerAttachInterrupt(timer,&timer_event,true);
timerAlarmWrite(timer,1000000,true);
timerAlarmEnable(timer);
digitalWrite(ledPin,HIGH);
}
void loop()
{
}
(2)边沿触发与电平触发
题主设置了2个定时器,第一个定时器每1s进入一次中断,中断里设一个flag变量,外加延时2s
第二个定时器每5s进入一次中断函数,函数中利用串口将falg的值发出去。
如果定时器在执行中断函数过程中其标志位电平保持不变的话,那么我们可以推断出,其增加值会小于5,大概在2左右,代码如下:
#include
int ledPin = 2;
int flag=0;
hw_timer_t *timer1;
hw_timer_t *timer2;
void timer2_event()
{
Serial.println(flag);
}
void timer_event()
{
flag++;
delay(2000);
}
void setup()
{
Serial.begin(9600);
timer1 = timerBegin(0,80,true);
timer2 = timerBegin(1,80,true);
timerAttachInterrupt(timer2,&timer2_event,true);
timerAttachInterrupt(timer1,&timer_event,true);
timerAlarmWrite(timer1,1000000,true);
timerAlarmWrite(timer2,5000000,true);
timerAlarmEnable(timer1);
timerAlarmEnable(timer2);
}
void loop()
{
}
其结果如下,我们发现,并不像我们想象的那样,经过初步推测,我们得出了2个结论。
1.在进入中断处理函数的瞬间,标志位电平发生跳变。
2.进入中断处理函数中,定时器仍会开始计时。
这让我有些不解,请各位大佬解惑,定时器模式中选择边沿触发和电平触发是否有意义?
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)