提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
开发 EPS32基础篇
前言
提示:以下是本篇文章正文内容,下面案例可供参考
一、GPIO输入输出
- 输入模式 (INPUT):当将 pinMode(pin, INPUT)
设置为输入模式时,该引脚允许从外部电路读取电平信号(高或低),例如连接到按钮、传感器等。 - 输出模式 (OUTPUT):通过 pinMode(pin,
OUTPUT),你可以控制这个引脚作为通用的输出口,可以驱动LED或其他电子元件。 - 模拟输入模式 (ANALOGIN):如果你想要将该引脚作为一个ADC(模拟数字转换器)使用,获取电压值而不是简单的二进制状态,可以使用
pinMode(pin, ANALOGIN)。
GPIO可设置一下4种状态
c
// 设置引脚2为输入模式
pinMode(2, INPUT);
// 设置引脚3为输出模式
pinMode(3, OUTPUT);
// 设置引脚4为输入上拉模式(假设Arduino板支持)
pinMode(4, INPUT_PULLUP);
// 设置引脚4为输入下拉模式(假设Arduino板支持)
pinMode(4, INPUT_PULLDOWN);
代码示例:检测按键,按下时:LED亮,松开时,LED灭
c
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函数 是一种非常有用的缓动函数,它可以在多种应用场景中产生平滑、自然的动画效果;
示例代码:呼吸灯
c
#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:当外部中断引脚处于高电平时触发中断。
代码示例:下降沿检测,计数
c
// 定义外部中断引脚
#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检测
cpp
#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秒
}
五、定时器
代码示例:定时器
c
#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=250kHz
timerAttachInterrupt(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读取一次温湿度
c
#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=250kHz
timerAttachInterrupt(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 屏幕
cpp
#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=250kHz
timerAttachInterrupt(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();
}