外部中断

一、外部中断简介

单片机最为核心的内容,应该就是中断了吧。相较于其他的单片机而言,ESP32的外部中断是十分强大的,因为其每个引脚均可以设置为外部中断的触发引脚。

ESP32 Arduino 有以下触发方式:

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

二、外部中断函数

1. 开启外部中断 attachInterrupt(pin,function,mode);
attachInterrupt(uint8_t pin, std::function<void ()> intRoutine, int mode)

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

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

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

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



中断触发模式

说明

RISING

上升沿触发

FALLING

下降沿触发

CHANGE

电平变化触发

ONLOW

低电平触发

ONHIGH

高电平触发



举例:

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

void loop()
{
  
}
//中断函数就是当中断被触发后要去执行的函数,该函数不能带有任何参数,且返回类型为空,设置一个外部中断的中断服务函数
2. 关闭引脚中断 detchInterrupt(pin);

无返回值

三、外部配置步骤

步骤:

1.CHUSHIHUA

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

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

完整代码示例:

#include <Arduino.h>

// 定义外部中断的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

二、电容按键函数

(1) 电容输入 touchRead(pin)

返回值 0~255. 触摸强度

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

示例:

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

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

(2)电容输入中断:touchAttachInterrupt(pin, TSR , threshold);

参数:

  • TSR :中断回调函数, 不能带参数, 不能有返回值。
  • threshold:阈值, 达到该阈值会触发此中断

示例:

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

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

void loop()
{
  
}

定时器

一、定时器简介

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

二、定时器函数

(1)timerBegin 初始化(开启)定时器

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);

(2) 取消初始化定时器:timerEnd

void timerEnd(hw_timer_t *timer)

参数:

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

(3) 配置定时器中断 :timerAttachInterrupt

void IRAM_ATTR timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge)

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

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

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

(4)取消定时器中断 :timerDetachInterrupt

void timerDetachInterrupt(hw_timer_t *timer)

参数:

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

(5) 定时器设置:timerAlarmWrite

timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload);

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

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

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

(6) 使能定时器:timerAlarmEnable

timerAlarmEnable(hw_timer_t *timer);

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

(7) 失能定时器 timerAlarmDisable

void timerAlarmDisable(hw_timer_t *timer)

(8) 判断定时器是否启动 timerAlarmEnabled

bool timerAlarmEnabled(hw_timer_t *timer)

三、定时器配置步骤

步骤:

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

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

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

4.使能定时器 timerAlarmEnable()

代码示例(向串口发送1-5,1s为间隔)

#include <Arduino.h>
#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 定时库简介

Ticker 是ESP32自带库

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




ESP32开启外部中断函数touchAttachInterrupt esp32串口中断_学习


二、Ticker 定时库相关函数

1. 定时状态获取 .active();

/**
 * Ticker是否激活状态
 * @return bool true表示ticker启用
 */
bool active();

2. 终止定时器 .detach()

/**
 * 停止Ticker
 */
void detach();

3. once() —— xx秒后只执行一次

/**
 * 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);
}

4. once_ms() —— xx毫秒后只执行一次

/**
 * 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);

5. attach() —— 每隔xx秒周期性执行

和上面一样,只是周期性执行, 需要.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)

6. attach_ms() —— 每隔xx毫秒周期性执行

/**
 * 每隔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超声波测距模块来介绍这个功能。


ESP32开启外部中断函数touchAttachInterrupt esp32串口中断_Powered by 金山文档_02


1.前言:

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

2.HC-SR04模块介绍

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

(1)机器人避障

(2)物体测距

(3)液位检测

(4)公共安防

(5)停车场检测

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

3.电气参数


电气参数

HC-SR04超声波测距模块

工作电压

DC 5V

工作电流

15mA

工作频率

40Hz

最远射程

4米

最近射程

2厘米

测量角度

15度

输入触发信号

10us的TTL脉冲

输出回响信号

输出与射程成正比的TTL电平信号

规格尺寸

40x20x15mm


4.工作原理

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

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

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

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

4.换算单位

(1)us / 58 ——>cm

(2)cm / 148 ——>英寸

5.HC-SR04时序图

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


ESP32开启外部中断函数touchAttachInterrupt esp32串口中断_学习_03


6.ESP32相关函数

pulseIn(pin,state)

pulseIn(pin,state,timeout)

参数:

  • pin : 引脚
  • state : 脉冲类型, 可选高或者低
  • timeout : 超时时间, 默认1秒钟. 单位为微秒, 无符号长整型.

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

示例:

#include <Arduino.h>
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

一、ESP32时间统计函数

1. 开机至今的毫秒数 millis

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

2. 开机至今的微秒数 micros

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

二、 阻塞延时

时间控制函数

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

delay() ----- 毫秒级延时

delayMicroseconds() ----- 微秒级延时

三、霍尔传感器

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

hallRead()