为什么要使用中断?

外部中断是单片机实时地处理外部事件的一种内部机制。当外部事件发生后,单片机判断外部事件是否符合条件,如果符合外部中断条件,则停止CPU正在执行的程序,转而进行中断事件的处理;中断处理完毕后,又返回被中断的程序处,继续执行。

在项目过程中遇到一个,首先初始化一个端口作为中断服务

#define borrow_gpio_in  21

然后设置端口为输入,并且下拉电阻,因为我们用3.3v电压作为信号

pinMode(borrow_gpio_in, INPUT_PULLDOWN);

随后设置中断监听方式和回调函数,这里函数必须是静态函数

attachInterrupt(digitalPinToInterrupt(borrow_gpio_in), _lock_borrow, CHANGE );

官方文档建议加上这个函数digitalPinToInterrupt,可能是因为判断某些IO口不支持中断,这里我们使用CHANGE作为监听方式,查看源码可以看到还有其他方式:

具体可以查阅文档

其实到这里我们只需要写一个_lock_borrow的静态函数就可以了

void BookCase::_lock_borrow (){

     noInterrupts();

     if(BC.lock_borrow == digitalRead(borrow_gpio_in))
         return;

     BC.lock_borrow = digitalRead(borrow_gpio_in);

     //通知服务器 锁状态变化
     DynamicJsonDocument doc(256);

     /*此处隐去部分逻辑代码*/

     MQTT::pub_message(doc);

     delayMicroseconds(100000);

     interrupts ();
 }

重点是 noInterrupts(); interrupts (); 这两个函数,为什么我要在这里加上去,因为中断有可能干扰,在触发时连续发了几次状态改变,我们只需要拿第一改变的状态值就可以了,还有delayMicroseconds()这个函数,为什么不用delay(),更直接呢?原因在这里,官方有解释:

Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. millis() relies on interrupts to count, so it will never increment inside an ISR. Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal.

请细品,然后还有不明白的,看这里:

For more information on interrupts, see

Last modification:March 15th, 2020 at 08:13 pm
如果觉得我的文章对你有用,打赏杯咖啡吧