提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
开发 EPS32基础篇
- 前言
- 一、GPIO输入输出
- GPIO可设置一下4种状态
- 代码示例:检测按键,按下时:LED亮,松开时,LED灭
- 二、PWM输出
- 示例代码:呼吸灯
- 三、外部中断
- 中断触发模式列举:attachInterrupt();函数
- 代码示例:下降沿检测,计数
- 四、ADC
- 代码示例:ADC检测
- 五、定时器
- 代码示例:定时器
- 六、DHT11
- 代码示例:250ms读取一次温湿度
- 七、u8g2驱动SSD1306 屏幕
前言
提示:以下是本篇文章正文内容,下面案例可供参考
一、GPIO输入输出
- 输入模式 (INPUT):当将 pinMode(pin, INPUT)
设置为输入模式时,该引脚允许从外部电路读取电平信号(高或低),例如连接到按钮、传感器等。 - 输出模式 (OUTPUT):通过 pinMode(pin,
OUTPUT),你可以控制这个引脚作为通用的输出口,可以驱动LED或其他电子元件。 - 模拟输入模式 (ANALOGIN):如果你想要将该引脚作为一个ADC(模拟数字转换器)使用,获取电压值而不是简单的二进制状态,可以使用
pinMode(pin, ANALOGIN)。
GPIO可设置一下4种状态
// 设置引脚2为输入模式
pinMode(2, INPUT);// 设置引脚3为输出模式
pinMode(3, OUTPUT);// 设置引脚4为输入上拉模式(假设Arduino板支持)
pinMode(4, INPUT_PULLUP);
// 设置引脚4为输入下拉模式(假设Arduino板支持)
pinMode(4, INPUT_PULLDOWN);
代码示例:检测按键,按下时:LED亮,松开时,LED灭
const int buttonPin = 2; // 定义按键连接的引脚
int ledPin = 13; // LED灯连接的引脚void setup() {// 初始化串口通信,以便在串口监视器中查看输出Serial.begin(9600);// 设置按键引脚为输入模式pinMode(buttonPin, INPUT_PULLUP);// 设置LED引脚为输出模式pinMode(ledPin, OUTPUT);
}void loop() {// 读取按键状态int buttonState = digitalRead(buttonPin);// 在串口监视器中输出按键状态if (buttonState == HIGH) {Serial.println("Button is NOT pressed");digitalWrite(ledPin, LOW); // 熄灭LED灯} else {Serial.println("Button is pressed");digitalWrite(ledPin, HIGH); // 点亮LED灯}// 为了避免串口输出过快,添加一个小延迟delay(100);
}
二、PWM输出
基本概念和工作原理
PWM(脉宽调制)是一种用于控制电子设备亮度、音量等特性的技术。在Arduino ESP32中,PWM输出功能用于控制LED灯的亮度,或者驱动电机等。它通过在一定时间内改变高电平(通电)和低电平(断电)的时间比例,来控制设备的亮度或工作状态。
- 初始化PWM通道
-------初始化PWM通道包括选择通道和设置相关参数。使用ledcSetup()函数来设置PWM通道的频率和分辨率。例如,要设置LEDC通道0的频率为1000Hz,分辨率为8位,可以调用ledcSetup(0, 1000, 8);。(有两种分辨率设置8位和10位) - 绑定PWM通道到具体引脚
------将初始化后的PWM通道绑定到具体的GPIO引脚,需要使用ledcAttachPin()函数。该函数接受两个参数:要绑定的引脚编号和PWM通道编号。例如,要将引脚2绑定到LEDC通道0,可以调用ledcAttachPin(2, 0);。 - 设置PWM的占空比
------设置PWM的占空比,可以使用ledcWrite()函数。该函数接受两个参数:PWM通道的编号和要设置的占空比数值。例如,要将LEDC通道0的占空比设置为50%,可以调用ledcWrite(0, 128);,因为8位分辨率的PWM信号的占空比取值范围为0到255,所以128代表50%的占空比。
easeInOutQuad函数 是一种非常有用的缓动函数,它可以在多种应用场景中产生平滑、自然的动画效果;
示例代码:呼吸灯
#define LED_PIN 14 // LED连接的引脚
#define LEDC_CHANNEL 0 // PWM通道
#define LEDC_FREQ 1000 // PWM频率
#define LEDC_RESOLUTION 8 // 分辨率// 缓动函数
float easeInOutQuad(float t) {if (t < 0.5) return 2 * t * t;else return -1 + (4 - 2 * t) * t;
}void setup() {// 初始化PWM通道ledcSetup(LEDC_CHANNEL, LEDC_FREQ, LEDC_RESOLUTION);// 将LED引脚绑定到PWM通道ledcAttachPin(LED_PIN, LEDC_CHANNEL);
}void loop() {// LED亮度渐增for (int i = 0; i <= 255; i++) {float t = i / 255.0;int dutyCycle = easeInOutQuad(t) * 255;ledcWrite(LEDC_CHANNEL, dutyCycle); // 设置PWM的占空比delay(10); // 延时10毫秒(根据需要调整)}// LED亮度渐减for (int i = 255; i >= 0; i--) {float t = i / 255.0;int dutyCycle = easeInOutQuad(t) * 255;ledcWrite(LEDC_CHANNEL, dutyCycle); // 设置PWM的占空比delay(10); // 延时10毫秒(根据需要调整)}
}
三、外部中断
ESP32的所有GPIO引脚(除了34-39之外)都可以被配置为中断引脚。
中断触发模式列举:attachInterrupt();函数
- CHANGE:当外部中断引脚的电平发生变化时触发中断,无论是从低到高还是从高到低。
- RISING:当外部中断引脚从低电平变为高电平时触发中断。上升沿
- FALLING:当外部中断引脚从高电平变为低电平时触发中断。下降沿
- ONLOW:当外部中断引脚处于低电平时触发中断。
- ONHIGH:当外部中断引脚处于高电平时触发中断。
代码示例:下降沿检测,计数
// 定义外部中断引脚
#define INTERRUPTION_PIN 14
// 定义用于计数的变量
volatile int count = 0;// 中断服务程序
void IRAM_ATTR handleInterrupt() {// 增加计数count++;
}void setup() {// 初始化串口通信,用于调试Serial.begin(115200);// 配置外部中断引脚为输入模式pinMode(INTERRUPTION_PIN, INPUT_PULLUP);// 确保在attachInterrupt之前,引脚4处于高电平状态digitalWrite(INTERRUPTION_PIN, HIGH);delay(1); // 短暂延时,确保引脚状态稳定// 附加中断服务程序到外部中断引脚attachInterrupt(digitalPinToInterrupt(INTERRUPTION_PIN), handleInterrupt, FALLING);// 输出初始计数Serial.println("Initial count: " + String(count));
}void loop() {// 延时一段时间,然后输出当前计数delay(1000);Serial.println("Current count: " + String(count));
}
四、ADC
使用注意事项:
ESP32的ADC驱动程序API支持ADC1和ADC2。
ADC1有8个通道,连接到GPIO 32-39。
ADC2有10个通道,连接到GPIO 0, 2, 4, 12-15和25-27。但请注意,ADC2与Wi-Fi模块共享资源,因此在使用ADC2时需要注意Wi-Fi状态。
高精度:采用12位分辨率,可以提供较为精确的转换结果。
多通道支持:支持18个模拟输入管脚,满足多种应用场景的需求。
低功耗:部分控制器支持Deep-sleep模式下的低功耗运行。
灵活配置:可配置多种分辨率(如12位、11位、10位、9位)
代码示例:ADC检测
#include <Arduino.h>const int analogPin = 35; // 定义模拟输入引脚void setup() {Serial.begin(9600); // 初始化串口通信pinMode(analogPin, INPUT); // 设置模拟输入引脚为输入模式analogReadResolution(12); // 设置ADC分辨率为13位analogSetAttenuation(ADC_11db); // 设置ADC衰减倍数为11dB
}void loop() {int sensorValue = analogRead(analogPin); // 读取模拟输入值Serial.println(sensorValue); // 打印读取的ADC值delay(1000); // 延迟1秒
}
五、定时器
代码示例:定时器
#define LED_PIN 12 // GPIO2,通常内建LED在ESP32上// 创建定时器句柄
hw_timer_t * timer = NULL;// 定义一个标志位用于指示是否要处理定时器事件
volatile bool timerFlag = false;void IRAM_ATTR onTimer() {// 这是定时器中断服务程序 (ISR)timerFlag = true;
}void setup() {Serial.begin(115200);pinMode(LED_PIN, OUTPUT); // 设置LED引脚为输出模式digitalWrite(LED_PIN, LOW); // 初始状态关闭LED// 设置定时器timer = timerBegin(0, 80, true); // 分频因子80意味着定时器计数频率为20MHz/80=250kHztimerAttachInterrupt(timer, &onTimer, true); // 将ISR关联到定时器timerAlarmWrite(timer, 250000, true); // 每250000微秒(即每秒)产生一次中断timerAlarmEnable(timer); // 启用定时器报警
}void loop() {if (timerFlag) {// 处理定时器事件static bool ledState = false;ledState = !ledState; // 反转LED状态digitalWrite(LED_PIN, ledState);Serial.println("Timer triggered!");timerFlag = false; // 重置标志位}
}
六、DHT11
代码示例:250ms读取一次温湿度
#include "DHT.h" // 包含DHT库#define LED_PIN 14 // GPIO12,通常内建LED在ESP32上
#define DHTPIN 4 // DHT11连接到GPIO4
#define DHTTYPE DHT11 // 使用DHT 11// 创建定时器句柄
hw_timer_t * timer = NULL;// 定义一个标志位用于指示是否要处理定时器事件
volatile bool timerFlag = false;// 创建DHT对象
DHT dht(DHTPIN, DHTTYPE);void IRAM_ATTR onTimer() {// 这是定时器中断服务程序 (ISR)timerFlag = true;
}void setup() {Serial.begin(115200);pinMode(LED_PIN, OUTPUT); // 设置LED引脚为输出模式digitalWrite(LED_PIN, LOW); // 初始状态关闭LED// 初始化DHT传感器dht.begin();// 设置定时器timer = timerBegin(0, 80, true); // 分频因子80意味着定时器计数频率为20MHz/80=250kHztimerAttachInterrupt(timer, &onTimer, true); // 将ISR关联到定时器timerAlarmWrite(timer, 250000, true); // 每250000微秒(即每秒)产生一次中断timerAlarmEnable(timer); // 启用定时器报警
}void loop() {if (timerFlag) {// 处理定时器事件static bool ledState = false;ledState = !ledState; // 反转LED状态digitalWrite(LED_PIN, ledState);// 读取温度和湿度float humidity = dht.readHumidity();float temperature = dht.readTemperature();// 检查是否成功读取if (isnan(humidity) || isnan(temperature)) {Serial.println("Failed to read from DHT sensor!");} else {// 打印结果Serial.print("Humidity: ");Serial.print(humidity);Serial.print("% Temperature: ");Serial.print(temperature);Serial.println("°C");}Serial.println("Timer triggered!");timerFlag = false; // 重置标志位}
}
实验现象
七、u8g2驱动SSD1306 屏幕
#include <Wire.h>
#include <U8g2lib.h>
#include "DHT.h"// DHT传感器配置
#define DHTPIN 4 // DHT11连接到GPIO4
#define DHTTYPE DHT11 // 使用DHT 11
// 定义OLED的宽度和高度
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64// 定义I2C地址和引脚
#define OLED_SDA_PIN 21
#define OLED_SCL_PIN 22
#define OLED_I2C_ADDRESS 0x3C // SSD1306 I2C 地址,默认为0x3C或0x3D// 创建对象
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ OLED_SCL_PIN, /* data=*/ OLED_SDA_PIN, /* reset=*/ U8X8_PIN_NONE);DHT dht(DHTPIN, DHTTYPE);// 创建定时器句柄
hw_timer_t * timer = NULL;
bool timerFlag500ms = false;
void IRAM_ATTR onTimer() {// 这是定时器中断服务程序 (ISR)timerFlag500ms = true;
}
//函数声明
void DISPLAY_Refresh();void setup() {Serial.begin(115200);// 初始化U8g2库u8g2.begin();u8g2.enableUTF8Print(); // 启用UTF-8支持// 初始化DHT传感器dht.begin();// 设置默认字体大小u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 使用支持中文的字体// 设置定时器timer = timerBegin(0, 80, true); // 分频因子80意味着定时器计数频率为20MHz/80=250kHztimerAttachInterrupt(timer, &onTimer, true); // 将ISR关联到定时器timerAlarmWrite(timer, 50000, true); // 每250000微秒(即每秒)产生一次中断timerAlarmEnable(timer); // 启用定时器报警
}void loop() {if( timerFlag500ms == true){timerFlag500ms = false;DISPLAY_Refresh();}
}
//刷新屏幕显示
void DISPLAY_Refresh()
{// 处理定时器事件// 读取温度和湿度float humidity = dht.readHumidity();float temperature = dht.readTemperature();// 清除屏幕缓冲区u8g2.clearBuffer();// 设置光标位置并打印中文字符u8g2.setCursor(0, 20);u8g2.print("温度:"); // 中文文本u8g2.setCursor(30, 20);u8g2.print( temperature);u8g2.print("℃");u8g2.setCursor(0, 40);u8g2.print("湿度:"); // 中文文本u8g2.setCursor(30, 40);u8g2.print( humidity);u8g2.print("%");// 设置光标位置并打印英文字符u8g2.setCursor(0, 60);u8g2.print("Hello, World!");// 将缓冲区内容发送到显示屏u8g2.sendBuffer();
}