外部中断
一、外部中断简介
单片机最为核心的内容,应该就是中断了吧。相较于其他的单片机而言,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 之一;
二、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超声波测距模块来介绍这个功能。
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
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() ----- 微秒级延时文章来源:https://www.toymoban.com/news/detail-604982.html
三、霍尔传感器
ESP32自带霍尔传感器 , 当有磁场靠近时,会显示正负值文章来源地址https://www.toymoban.com/news/detail-604982.html
hallRead()
到了这里,关于ESP32 Arduino学习篇(二)中断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!