ESP32-学习(3)

 中断的使用

1.外部中断

ESP32的所有引脚都可以作为中断。

1.中断是什么?

中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。就是程序在运行的时候突然要做另一件事,那么就停下当前的事情去做中断里面的事情。

2.中断都有哪些?

常见的有外部中断,定时器中断,串口中断等。

外部中断就是比如设置引脚4为外部中断,当4号引脚发生电平的变化或上升沿,下降沿时跳出正在执行的程序,执行中断里面的程序。应用比如在平衡小车里面通过编码器的脉冲数来获取轮子当前的速度。

定时器中断就是每隔一段时间进入到中断函数里面执行里面的程序。

串口中断进行串口通信的时候,当发过来一个信息,去执行串口中断里面的程序。

在下面我们就先介绍一下外部中断。

3.外部中断的配置

1.外部中断配置,外部中断通过得到引脚电压的改变来触发中断。因此第一步就是设置引脚为输入模式。

int key = 4;   
pinMode(key,INPUT);  // 设置四号引脚输入

2.编写外部中断函数,当引脚触发下降沿或上升沿时或电平变化时进入外部中断函数

void IRAM_ATTR contral()
{
  digitalWrite(led,!digitalRead(led));
}

在这里我们给外部中断函数起一个名字叫contral;他前面的IRAM_ATTR 什么意思,有什么作用?

IRAM_ATTR 我们声明编译后的代码将放置在 ESP32 的内部 RAM (IRAM) 中。否则,代码将放在 Flash 中。ESP32 上的闪存比内部 RAM 慢得多。目的就是加快读取串口中断的时间,使程序运行更快。

3.将外部中断与引脚连接

//  attachInterrupt(Pin,ISR,FALLING); 
attachInterrupt(key,ZD,FALLING);

attachInterrupt(Pin,ISR,FALLING); 这个函数就是把引脚与外部中断连接起来,

第一个参数Pin代表发生外部中断的引脚,第二个参数ISR就是外部中断函数,即引脚电平发生变化后执行的函数,FALLING为下降沿触发,触发方式还有以下几种

LOW 低电平 HIGH 高电平 CHANGE 引脚发送变化 FALLING 下降沿 RISING上升沿

比如当Pin这个引脚低电平时,进入中断函数,那就把FALLING变成LOW。

经过上面三步我们已经吧外部中断配置完成。

4.案例实现,我们设置一个按键,当他按下去瞬间,小灯亮灭反转。

注:按键没有按下去key是高电平,按下后由高电平变为低电平及下降沿。ESP32板子上默认引脚2连接一个小灯,因此直接使用板子上的小灯就行。没有按键可以将引脚4用杜邦线连接3.3V,然后从3.3V拔出插到GND,模拟下降沿

int led = 2;
int key = 4;
void IRAM_ATTR ZD()
{
  digitalWrite(led,!digitalRead(led));
}


void setup() {
  pinMode(led,OUTPUT);
  pinMode(key,INPUT);
  attachInterrupt(key,ZD,FALLING); 
}

void loop() {
  
}

补充,如果想控制更加精确就实现一下硬件消抖。

2.定时器中断

定时器中断顾名思义,就是计数到一定时间触发一次中断,即每隔一段时间触发中断。

定时器中断的配置

1.先声明一个定时器指针,指向空。 指针名字timer,hw_timer_t这个是ESP32里面自己定义的一个指针类型。

hw_timer_t*timer = NULL;

2.定时器中断函数的编写

volatile byte ZT = 0;

void IRAM_ATTR contral_Time0(){
  ZT = !ZT;
  digitalWrite(led,ZT);
}

volatile 关键字防止变量被优化,这个字说明我们需要在中断修改这个变量

IRAM_ATTR 与上面外部中断一样,吧定时器函数放到RAM中,而不是内部Flash,目的就是让CUP更快的读取该函数并运行。

3.定时器初始化

  // 设置定时器0,80预分频器的值,true上升沿计数,false下降沿计数
  timer = timerBegin(0,80,true);
  // timer指针变量 kaiDS触发中断执行的函数,
  timerAttachInterrupt(timer,&contral_Time0,true);
  // timer指针变量 1000 000 触发中断的频率,一秒进入一次中断,true每次触发后自动重置定时器中断
  timerAlarmWrite(timer,1000000,true);
  timerAlarmEnable(timer);  //启用定时器

1.timerBegin(TIMERx,Pre,True

timerBegin函数以对定时器进行初始化,这个函数会返回一个指向hw_timer_t结构类型的指针,timer就是上面第一步声明的空指针,给他初始化timerBegin(TIMERx,Pre,True)

TIMERx表示使用那个定时器,ESP32一共有4个定时器,定时器0,定时器1,定时器2,定时器3

特别注意是从定时器0开始没有定时器4。

Pre是预分频系数(Prescale)ESP32计数器使用的基频信号通常是80 MHz,即80 000 000Hz

这个的意思就是每一秒种定时器计数80 000 000次,预分频系数就是给他分频减小他每秒计数的次数,这里选用80,80 000 000/80等于1 000 000 即一秒计数1000 000次,那么每计数一次就是1us。

第三个参数是计数方式true是向上计数,false是向下计数。一般选择向上计数。

2.  timerAttachInterrupt(timer,&contral_Time0,true)

这个函数的作用就是把定时器与定时器中断函数捆绑在一起,第一个参数就是最上面定义的指针。第二个参数就是中断处理函数的地址,因此要在函数名前面加&号,外部中断传入的是函数名,定时器中断传入的是函数名加取地址符。第三个参数是中断触发类型是边沿,还是电平的标志,边沿的话是true,电平的话是false,一般选择true就是边沿触发。

3. timerAlarmWrite(timer,1000000,true)

这个参数的作用是定时器多长时间进入一次中断。第一个参数是定时器指针,第二个参数表示多久进一次定时器中断,由于第二个参数配置的预分频系数是80,即ESP32一秒计数1000 000次,那么第二个参数写1000 000就代表每隔一秒进入一次定时器中断,如果第二个参数写500 000那么就是每0.5秒进入一次中断。第三个参数设置为true(表示计数器将自动重新加载),即计数到1000 000后就从0开始重新计数。计数到下一个1000 000再次进入到定时器中断。这样就能周期性地产生中断。如果写false,那么定时器计数到1000 000执行一次定时器中断后就不执行定时器中断了。

 4.timerAlarmEnable(timer)   

作用启用定时器

5.补充关于定时器的函数

*timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )

void timerEnd(hw_timer_t *timer)   取消初始化定时器

void timerDetachInterrupt(hw_timer_t *timer) 取消定时器中断

void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload)
alarm_value : 计数上限值,单位:微秒
autoreload : 是否重装载.  

void timerAlarmDisable(hw_timer_t *timer)  失能定时器

bool timerAlarmEnabled(hw_timer_t *timer) 判断定时器是否启动

4.案例实现,我们配置定时器,实现每隔一秒进入定时器中断,然后实现小灯的反转。

hw_timer_t*timer = NULL;
volatile int led =2;
volatile byte ZT = 0;

void IRAM_ATTR contral_Time0(){
  ZT = !ZT;
  digitalWrite(led,ZT);
}

void setup() {
  Serial.begin(115200);
  pinMode(led,OUTPUT);

  // 设置定时器 0是定时器(4个定时器)80预分频器的值,true上升沿计数,false下降沿计数
  timer = timerBegin(0,80,true);
  // timer指针变量 kaiDS触发中断执行的函数,
  timerAttachInterrupt(timer,&contral_Time0,true);
  // timer指针变量 1000 000 触发中断的频率,一秒进入一次中断,true每次触发后自动重置定时器中断
  timerAlarmWrite(timer,1000000,true);
  timerAlarmEnable(timer);  //启用定时器
  
}

void loop() {
  
}

注:在中断里面的变量尽量都用volatile 声明一下,防止被优化。

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值