0%

ESP32的外部中断和编码器的示例

说明

这次主要是记录ESP32的外部中断的相关内容,并且刚刚调试好了编码器,也做一个小小的分享!
按照惯例,先介绍一下环境吧:
硬件:TTGO T-Display ESP32带1.14LCD的小开发板 + 编码器
软件:VSCode + PlatformIO IDE(其实就是Arduino环境)

程序详解

下面就一具体的功能实现来讲解使用外部中断调试编码器。首先还是简单介绍一下编码器吧,编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺。按照读出方式编码器可以分为接触式和非接触式两种;按照工作原理编码器可分为增量式和绝对式两类。增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。

我们直接上淘宝搜索,看具体的实物我觉得会看的更加清楚。然后开始看具体的程序了,首先定义引脚和一些需要用到的变量:

1
2
3
4
5
6
7
8
//定义引脚连接
int CLK = 12; //CLK->D2
int DT = 13; //DT->D3
int SW = 15; //SW->D4

const int Int_Pin = digitalPinToInterrupt(CLK);// Interrupt 0 在 pin 2 上
int count = 0;//计数值
int lastCLK = 0;//CLK历史值

其次是中断处理函数,就是我们在出发外部中断时需要用到的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
//中断处理函数
void ClockChanged()
{
// Serial.println("a");
int clkValue = digitalRead(CLK); //读取CLK引脚的电平
int dtValue = digitalRead(DT); //读取DT引脚的电平
if (lastCLK != clkValue) {
lastCLK = clkValue;
count += (clkValue != dtValue ? 1 : -1);//CLK和DT不一致时+1,否则-1
Serial.print("count:");
Serial.println(count);
}
}

其次是初始化的函数,其中外部中断的初始化函数attachInterrupt()也在里面。接下来,由于将使用外部引脚中断,需要将先前声明的引脚编号配置为输入引脚。为此,调用pinMode函数,将引脚编号和操作模式作为参数传递。pinMode(interruptPin, INPUT_PULLUP);

接下来,通过调用attachInterrupt函数将中断附加到引脚。作为首个参数,将调用结果传递给digitalPinToInterrupt函数,该函数将使用的引脚编号转换为相应的内部中断编号。接下来,我们传递中断处理函数,换而言之,当指定引脚上出现中断时,该函数将予以执行。我们将其称为handleInterruptand,稍后再指定其代码。最后我们传递中断模式,它基本指定了在引脚输入信号中哪种类型变化触发了中断。直接F12查看模式,会发现一共有七种模式,具体如下:

1
2
3
4
5
6
7
8
//Interrupt Modes
#define RISING 0x01
#define FALLING 0x02
#define CHANGE 0x03
#define ONLOW 0x04
#define ONHIGH 0x05
#define ONLOW_WE 0x0C
#define ONHIGH_WE 0x0D

然后下面是具体的初始化函数,如下:

1
2
3
4
5
6
7
8
9
void setup()
{
// pinMode(SW, INPUT);
// digitalWrite(SW, HIGH);
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
attachInterrupt(digitalPinToInterrupt(CLK), ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
Serial.begin(115200);
}

最后的主循环里面就很简单了,一秒打印一次count就可以了,具体如下所示:

1
2
3
4
5
6
7
8
9
10
void loop()
{
// if (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零
// {
// count = 0;
Serial.print("count:");
Serial.println(count);
delay(1000);
// }
}

总结

最后把代码整合一下吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <Arduino.h>

//定义引脚连接
int CLK = 12;//CLK->D2
int DT = 13;//DT->D3
int SW = 15;//SW->D4

const int Int_Pin = digitalPinToInterrupt(CLK);// Interrupt 0 在 pin 2 上
int count = 0;//计数值
int lastCLK = 0;//CLK历史值

//中断处理函数
void ClockChanged()
{
// Serial.println("a");
int clkValue = digitalRead(CLK);//读取CLK引脚的电平
int dtValue = digitalRead(DT);//读取DT引脚的电平
if (lastCLK != clkValue)
{
lastCLK = clkValue;
count += (clkValue != dtValue ? 1 : -1);//CLK和DT不一致时+1,否则-1
Serial.print("count:");
Serial.println(count);
}
}

void setup()
{
// pinMode(SW, INPUT);
// digitalWrite(SW, HIGH);
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
attachInterrupt(digitalPinToInterrupt(CLK), ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发
Serial.begin(115200);
}

void loop()
{
// if (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零
// {
// count = 0;
Serial.print("count:");
Serial.println(count);
delay(1000);
// }
}

ESP32使用外部中断的话还是挺方便的,初始化的设计也是很容易,我写的东西可能如果是有用过相应的硬件来找一下方向应该还是比较容易看懂的,希望以后可能慢慢分享一些内容。

-------------本文结束感谢您的阅读-------------