/*
程序: 中断演示
公众号:孤独的二进制
*/
#include <util/atomic.h> // 用于 demo 4: ATOMIC_BLOCK macro.
#define LEDPIN 6 //LED引脚
#define INTERRUPTPIN 2 //中断引脚
volatile byte ledStatus = LOW; //此变量被中断使用,定义为挥发性变量
volatile int bankBalance = 0; //用于 demo3 和 demo4 账户余额
void setup() {
Serial.begin(9600);
pinMode(LEDPIN, OUTPUT); // 设置引脚为输出模式,以给LED等输出信号电平
pinMode(INTERRUPTPIN, INPUT_PULLUP); //INPUT_PULLUP是指,在默认情况下,给高电平 这是中断引脚
digitalWrite(LEDPIN,LOW); // 一开始把LED引脚写成低电平
// demo 1 : 基本中断使用方法
//attachInterrupt(digitalPinToInterrupt(INTERRUPTPIN),blink,FALLING); //FALLING是检测引脚是否发生由高电平到低电平
// 在setup中注册了中断函数之后,之后每次触发中断都会开启中断函数。哪怕setup函数在esp32初始化之后只执行一次
// demo 2: 中断防止按钮抖动
//attachInterrupt(digitalPinToInterrupt(INTERRUPTPIN),blinkWithDebounce,FALLING);
// 实际上在按钮触发中断时,有可能会发生抖动,就是短时间内按下了多次中断
// demo 3 , demo 4 中断使用的变量长度超过了MCU的总线宽度
// payDay 16 bits > Atmega328P 8 Bits
attachInterrupt(digitalPinToInterrupt(INTERRUPTPIN),payDay,FALLING);
}
void loop() {
digitalWrite(LEDPIN,ledStatus);
// demo 3: 使用 noInterrupts 和 interrupts demo3 调用的中断是给余额加1000元
// noInterrupts(); // 对变量访问打印前,强制性把中断先关闭
// Serial.println(bankBalance);
// interrupts(); //又手动开启中断函数
// demo 4: 使用atomic block 因此除了上述手动关开中断,可以用库里面的原子block函数
// block函数里面的所有变量,都是在运行前,就会关闭所有中断,运行后,再开启
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
Serial.println(bankBalance);
}
}
/*
中断的函数 没有 输入也没有 输出
里面的内容越少越好,最好简化到改一个byte的内容
*/
void blink() {
ledStatus = !ledStatus; //此变量被中断使用,定义为挥发性变量 发生中断时,调用中断函数
}
long debouncing_time = 15; //Debouncing Time in Milliseconds 设置防抖动时间 表示一次中断之后,在时间内不会引起下次中断
volatile unsigned long last_micros;
void blinkWithDebounce() {
if((long)(micros() - last_micros) >= debouncing_time * 1000) {
ledStatus = !ledStatus; //此变量被中断使用,定义为挥发性变量
last_micros = micros();
}
}
// 需要知道,很少用这种在软件中控制防抖动的,一般好的方案还是硬件上加一个RC电路,来防止抖动
void payDay() {
//中断中的赋值类型超过了1个字节
//超过了Atmega328P的总线8位比特
//在其他程序段的使用中,需要关闭中断,或者使用atomic
bankBalance=bankBalance+1000;
}