Arduino学习篇(二)中断

外部中断

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

attachInterrupt(uint8_t pin, std::function intRoutine, int mode)

函数功能:配置初始化外部中断

参数1:pin,外部中断所使用的引脚,ESP32所有引脚均可以配置为外部中断引脚

参数2:外部中断回调函数 ,此处填写函数名即可

参数3:中断触发方式,支持以下触发方式:

举例:

void func1()
{
  Serial.printf("按键中断触发");
  }
void setup()
{
  Serial.begin(9600);
  attachInterrupt(0,func1,FALLING);
}

void loop()
{

}
//中断函数就是当中断被触发后要去执行的函数,该函数不能带有任何参数,且返回类型为空,设置一个外部中断的中断服务函数

无返回值

步骤:

1.CHUSHIHUA

2.绑定中断服务函数 timerAttachInterrupt()

3.设置触发定外部中断的方式 timerAlarmWrite()

完整代码示例:

#include

// 定义外部中断的Mode
// 0: 无中断,读取Touch值
// 1:Touch中断,执行 TouchEvent()
// 2: 外部IO的中断
#define EXT_ISR_MODE 1

void TouchEvent()
{
    Serial.printf("Touch Event.\r\n");
}

void PinIntEvent()
{
    Serial.printf("PinInt Event.\r\n");
}

void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);

#if 1 == EXT_ISR_MODE   // 触摸中断
    // Pin: T0(GPIO4), 函数指针:TouchEvent, 阈值: 40
    touchAttachInterrupt(T0, TouchEvent, 40);

#elif 2 == EXT_ISR_MODE   // 下降沿触发
    pinMode(0, INPUT_PULLUP); //设置引脚0位外部中断引脚
    attachInterrupt(0, PinIntEvent, FALLING);

#endif
}

void loop()
{
    // put your main code here, to run repeatedly:

#if 0 == EXT_ISR_MODE
    Serial.printf("touch:%d\r\n", touchRead(T0));
#endif

    delay(200);
}

电容按键

ESP32专门提供了电容触摸传感器的功能, 共有T0,T2~T9 共 9个touch传感器可用.分别对应引脚4、2、15、13、12、14、27、33、32. 无需设置PinMode

返回值 0~255. 触摸强度

注意: 摸得越瓷实,数值越小

示例:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
   Serial.printf("touch:%d\n",touchRead(4));
}

参数:

  • TSR :中断回调函数, 不能带参数, 不能有返回值。

  • threshold:阈值, 达到该阈值会触发此中断

示例:

void TSR()
{
  Serial.printf("我被按下了!\r\n");
  }

void setup()
{
  Serial.begin(9600);
  touchAttachInterrupt(4, TSR , 20);
}

void loop()
{

}

定时器

ESP32 芯片包含两个定时器组,每组有两个通用定时器。它们都是基于 16 位预分频器和 64 位自动重载功能的向上/向下计数器的 64 位通用定时器

hw_timer_t * IRAM_ATTR timerBegin(uint8_t num, uint16_t divider, bool countUp)
  • num : 定时器编号(0到3,对应全部4个硬件定时器)

  • divider: 预分频器数值(ESP32计数器基频为80M,80分频单位是微秒)

  • countUp: 计数器向上(true)或向下(false)计数的标志

  • 返回值:返回一个计时器结构体指针 hw_timer_t * ,预定义一个指针接收它

示例:

hw_timer_t *timer = NULL;
timer = timerBegin(0, 80, true);
void timerEnd(hw_timer_t *timer)

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )
void IRAM_ATTR timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge)

timer:指向已初始化定时器的指针

(*fn)():中断服务函数的函数指针

edge:表示中断触发类型是边沿(true)还是电平(false)的标志

void timerDetachInterrupt(hw_timer_t *timer)

参数:

  • *timer : 目标定时器 ( 计时器结构体指针 hw_timer_t * )
    timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload);

timer:指向已初始化定时器的指针

alarm_value: 触发中断的计数器值(1000000 us -> 1s)

autoreload:定时器在产生中断时是否重新加载的标志

    timerAlarmEnable(hw_timer_t *timer);

timer:指向已初始化定时器的指针

void timerAlarmDisable(hw_timer_t *timer)
bool timerAlarmEnabled(hw_timer_t *timer)

1.选择定时器并设置合适分频系数和计数模式 (两组四个) timerBegin()

2.绑定中断服务函数 timerAttachInterrupt()

3.设置触发定时器中断的计数器值 timerAlarmWrite()

4.使能定时器 timerAlarmEnable()

#include
#include "../lib/Moter/Moter.h"
#define PMW_EN 0
int interruptCounter = 0;
hw_timer_t *timer = NULL;
// 中断服务函数,为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性
void IRAM_ATTR TimerEvent()
{
    Serial.println(interruptCounter++);
    if (interruptCounter > 5)
    {
        interruptCounter = 1;
    }
}
void setup()
{
    Serial.begin(115200);
#if PMW_EN
    Motor_Init();
#endif
    timer = timerBegin(0, 80, true);
    timerAttachInterrupt(timer, &TimerEvent, true);
    timerAlarmWrite(timer, 1000000, true);
    timerAlarmEnable(timer); //使能定时器
}
void loop()
{
#if PMW_EN
    PWM_SetDuty(200 * interruptCounter, 200 * interruptCounter);
#endif
}

Ticker 定时库

Ticker 是ESP32自带库
注意: 不建议使用Ticker回调函数来阻塞IO操作(网络、串口、文件);可以在Ticker回调函数中设置一个标记,在loop函数中检测这个标记;
对于arg,必须是 char, short, int, float, void , char之一;

/**
 * Ticker是否激活状态
 * @return bool true表示ticker启用
 */
bool active();
/**
 * 停止Ticker
 */
void detach();
/**
 * xx秒后只执行一次
 * @param seconds 秒数
 * @param callback 回调函数
 */
void once(float seconds, callback_function_t callback);

/**
 * xx秒后只执行一次
 * @param seconds 秒数
 * @param callback 回调函数
 * @param arg 回调函数的参数
 */
void once(float seconds, void (*callback)(TArg), TArg arg)

示例: 一个传参,一个不传参

#include "Arduino.h"
#include "Ticker.h"

Ticker t1;
Ticker t2;

void func1()
{
  Serial.println("我是t1的回调,我没参数");
}
void func1(int a)
{
  Serial.print("我是t2的回调,我的参数是:");
  Serial.println(a);
}

void setup()
{
  Serial.begin(115200);
  if (1)
  {
    t1.once(10, func1);
    t2.once(20, func1, 8);
    //t1 t2 方法名都叫func1, 但其实是不同的方法, 这涉及到一个方法重载的概念
  }
}

void loop()
{
  Serial.println("我来证明我没被阻塞,也没法阻塞Ticker");
  delay(2700);
}
/**
 * xx毫秒后只执行一次
 * @param seconds 秒数
 * @param callback 回调函数
 */
void once_ms(float seconds, callback_function_t callback)

/**
 * xx毫秒后只执行一次
 * @param seconds 秒数
 * @param callback 回调函数
 * @param arg 回调函数的参数
 */
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg);

和上面一样,只是周期性执行, 需要.detach()结束运行

/**
 * 每隔xx秒周期性执行
 * @param seconds 秒数
 * @param callback 回调函数
 */
void attach(float seconds, callback_function_t callback);

/**
 * 每隔xx秒周期性执行
 * @param seconds 秒数
 * @param callback 回调函数
 * @param arg 回调函数的参数
 */
void attach(float seconds, void (*callback)(TArg), TArg arg)
/**
 * 每隔xx毫秒周期性执行
 * @param seconds 秒数
 * @param callback 回调函数
 */
void attach_ms(float seconds, callback_function_t callback);

/**
 * 每隔xx毫秒周期性执行
 * @param seconds 秒数
 * @param callback 回调函数
 * @param arg 回调函数的参数
 */
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)

引脚脉冲信号检测

我们的ESP32自带能检测引脚脉冲宽度的功能,也就是检测高电平的时间。

这里我们以HC-SR04超声波测距模块来介绍这个功能。

众所周知传感器(transducer/sensor)是一种检测装置,能感受到被测量的信息,并能将感受到的信息,按一定规律变换成为电信号或其他所需形式的信息输出,以满足信息的传输、处理、存储、显示、记录和控制等要求。传感器在生活中无处不在,小到温湿度传感器测量温湿度,大到当今最火热的领域——物联网IoT,传感器总是发挥着重要的作用。而学习传感器也尤为重要,特别是在电子设计中。

HC-SR04模块性能稳定,测度距离精确,模块高精度,盲区小。在日常生活中,以下地方都可应用超声波测距模块:

(1)机器人避障

(2)物体测距

(3)液位检测

(4)公共安防

(5)停车场检测

(6)电子设计中的避障智能车也正是应用到了此模块,才能达到避开障碍的功能。

第一步:通过IO口给Trig接口周期不小于10us的脉冲信号。

第二步:HC-SR04接收到单片机发来的脉冲信号后自动发送8个频率为4KHz的方波,自动检测是否有信号返回。

第三步:若有信号返回,则通过Echo接口向单片机相连的IO口发送一个高电平,高电平持续时间就是超声波从发射到返回的总时间。

假设高电平持续时间为T,声速为v(一般为340m/s),那么测到的距离S=(T*v)/2。

(1)us / 58 ——>cm

(2)cm / 148 ——>英寸

板上接线方式:VCC、trig(控制端)、 echo(接收端)、 out(空脚)、 GND

pulseIn(pin,state)

pulseIn(pin,state,timeout)

参数:

  • pin : 引脚

  • state : 脉冲类型, 可选高或者低

  • timeout : 超时时间, 默认1秒钟. 单位为微秒, 无符号长整型.

返回值: 脉冲宽度, 单位微秒, 数据类型为无符号长整型. 如果超时返回0

示例:

#include
int distance = 0;
void setup()
{
  Serial.begin(115200);
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
}

void loop()
{
  digitalWrite(4, HIGH);
  delayMicroseconds(20);
  digitalWrite(4, LOW);
  distance = pulseIn(18,HIGH)/58;
  Serial.printf("当前距离是:%d cm",distance);
  delay(1000);
}

ESP32其他APi

millis() 返回值是unsigned long 类型, 大约50天溢出一次

micros() 返回值是unsigned long 类型, 大约70分钟溢出一次

时间控制函数

由于我们接下来的实验程序很多都用到延时函数,那么这里就介绍几个:

delay() —– 毫秒级延时

delayMicroseconds() —– 微秒级延时

ESP32自带霍尔传感器 , 当有磁场靠近时,会显示正负值

hallRead()

Original: https://blog.csdn.net/DOF526570/article/details/128699173
Author: ODF..
Title: Arduino学习篇(二)中断

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/812618/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球