VSCODE+Arduino生态快速入门ESP32

VSCODE+Arduino生态快速入门ESP32,第1张

VSCODE+Arduino生态快速入门ESP32(一)——点个呼吸灯、开个定时器

我手里这块是ESP32WROOM开发板,20多块钱,性价比非常高。


1.环境搭建

环境搭建就不在此赘述,CSDN上的大佬写的都很详细,我使用的环境为VSCODE + PlatformioIDE + Arduino 开发,搭建环境是一件十分耗时间的事情,笔者即使用了魔法,也整整花了快一天的时间,所以各位小伙伴一定要耐心。


2.呼吸灯

笔者手上的这块WROOM开发板上的LED对应的引脚为D2,然后我们简单介绍一下ESP32上PWM的使用。


(1)LEDC

大家可以把这个理解为定时器的通道,一共有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.进入中断处理函数中,定时器仍会开始计时。


这让我有些不解,请各位大佬解惑,定时器模式中选择边沿触发和电平触发是否有意义?

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/607829.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-14
下一篇 2022-04-14

发表评论

登录后才能评论

评论列表(0条)

保存