ESPS3-工控拓展板调试记录
·
ESPS3-工控拓展板
一. 单功能测试
1.数字来输出
对于四个继电器 依次输出
// 定义需要控制的GPIO引脚
int gpioPins[] = {4, 5, 6, 7};
int pinCount = 4;
// 用于记录循环次数的变量(可选)
int loopCounter = 0;
void setup() {
// 初始化串口通信,波特率设置为115200(常用调试波特率)
Serial.begin(115200);
// 等待串口连接稳定(对于某些开发板是必要的)
while (!Serial) {
; // 等待串口就绪(仅对原生USB有效,一般可省略)
}
// 打印启动信息
Serial.println("=== ESP32-S3 GPIO 顺序输出测试开始 ===");
Serial.print("将控制 ");
Serial.print(pinCount);
Serial.println(" 个 GPIO 引脚。");
// 将所有引脚初始化为输出模式
for (int i = 0; i < pinCount; i++) {
pinMode(gpioPins[i], OUTPUT);
digitalWrite(gpioPins[i], LOW);
// 日志:记录每个引脚的初始化状态
Serial.print("GPIO ");
Serial.print(gpioPins[i]);
Serial.println(" 已初始化为输出,初始电平 LOW。");
}
Serial.println("初始化完成,开始循环输出。\n");
}
void loop() {
// 增加循环计数,便于观察执行轮次
loopCounter++;
Serial.print("********** 第 ");
Serial.print(loopCounter);
Serial.println(" 轮循环开始 **********");
// 依次控制每个引脚
for (int i = 0; i < pinCount; i++) {
int currentPin = gpioPins[i];
// --- 输出高电平 ---
digitalWrite(currentPin, HIGH);
// 日志:记录引脚及其电平变化(带时间戳,利用 millis())
Serial.print("[Time: ");
Serial.print(millis());
Serial.print(" ms] GPIO ");
Serial.print(currentPin);
Serial.println(" -> HIGH (3.3V)");
// 高电平持续1秒
delay(2000);
// --- 输出低电平 ---
digitalWrite(currentPin, LOW);
// 日志:记录引脚回到低电平
Serial.print("[Time: ");
Serial.print(millis());
Serial.print(" ms] GPIO ");
Serial.print(currentPin);
Serial.println(" -> LOW (0V)");
// 注意:这里没有额外的延时,会立即切换到下一个引脚
// 如果需要观察每个引脚低电平的停留时间,可在此处加一个短延时,但会影响顺序间隔
// delay(100); // 可选:加一个微小间隔便于观察
delay(2000);
}
// 一轮结束,打印换行以便区分
Serial.println("--- 本轮循环结束,立即开始下一轮 ---\n");
// loop() 函数会自然循环,无需额外 delay
}
2.开关量输入
当37 38 39 40四个引脚有24V 输入时,会有对应信号输出。
/*
* ESP32-S3 数字输入调试示例
* 引脚: GPIO 37, 38, 39, 40
* 外部下拉电阻已安装,高电平有效(3.3V = 有输入,0V = 无输入)
* 串口调试信息:实时打印引脚状态变化(上升沿/下降沿)
*/
// 定义输入引脚数组
const int inputPins[] = {37, 38, 39, 40};
const int pinCount = 4;
// 存储每个引脚上一次的状态(初始为 LOW)
int lastState[pinCount] = {LOW, LOW, LOW, LOW};
// 记录启动后的运行时间(用于日志时间戳)
unsigned long startTime = 0;
void setup() {
// 初始化串口,波特率 115200
Serial.begin(115200);
// 等待串口稳定(对于基于USB的开发板可忽略)
while (!Serial) {
; // 等待
}
// 打印启动信息
Serial.println("========================================");
Serial.println(" ESP32-S3 数字输入调试程序");
Serial.println(" 引脚: 37, 38, 39, 40 (外部下拉电阻)");
Serial.println(" 高电平(3.3V) = 有输入,低电平(0V) = 无输入");
Serial.println("========================================\n");
startTime = millis();
// 初始化所有引脚为输入模式(不启用内部上拉/下拉)
for (int i = 0; i < pinCount; i++) {
pinMode(inputPins[i], INPUT);
// 读取初始状态并保存
lastState[i] = digitalRead(inputPins[i]);
// 打印初始状态
Serial.print("[初始化] GPIO ");
Serial.print(inputPins[i]);
Serial.print(" 状态: ");
Serial.println(lastState[i] == HIGH ? "有输入 (HIGH)" : "无输入 (LOW)");
}
Serial.println("\n开始监控引脚状态变化...\n");
}
void loop() {
// 遍历所有引脚
for (int i = 0; i < pinCount; i++) {
int currentPin = inputPins[i];
int currentState = digitalRead(currentPin); // 读取当前电平
// 检测到状态变化(上升沿或下降沿)
if (currentState != lastState[i]) {
// 更新时间戳
unsigned long elapsed = millis() - startTime;
// 打印变化信息
Serial.print("[");
Serial.print(elapsed);
Serial.print(" ms] GPIO ");
Serial.print(currentPin);
Serial.print(" 变化 -> ");
if (currentState == HIGH) {
Serial.println("有输入 (上升沿)");
} else {
Serial.println("无输入 (下降沿)");
}
// 更新该引脚的最后状态
lastState[i] = currentState;
}
}
// 可选的循环周期:为了避免过度占用串口,可增加一个小延时
// 但检测变化是即时的,不加延时能最快捕捉。若需要减轻CPU负载,可加 delay(10)
delay(10); // (可选)
}
3.模拟量 输出 4-20mA
/*
* ESP32-S3 PWM 输出校准版
* 引脚: GPIO1, 14位分辨率, 1000Hz
* 百分比 0~100% 对应 0~20mA (可校准)
* 最大有效PWM值限定为 15047 (根据实测校准)
*/
#define PWM_PIN 1
#define PWM_FREQ 1000
#define PWM_RESOLUTION 14
#define PWM_MAX_HARD ((1 << PWM_RESOLUTION) - 1) // 16383
// 根据您的实测,20mA 对应的 PWM 值(请根据实际电流调整)
#define PWM_MAX_EFFECTIVE 15036 // 100% 占空比对应的 PWM 值
const int PWM_MAX = PWM_MAX_EFFECTIVE; // 程序内部使用的最大值
void setDutyPercent(int percent);
void setDutyRaw(int duty);
void printHelp();
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
analogWriteResolution(PWM_PIN, PWM_RESOLUTION);
analogWriteFrequency(PWM_PIN, PWM_FREQ);
pinMode(PWM_PIN, OUTPUT);
Serial.println("\n========================================");
Serial.println(" ESP32-S3 PWM 输出 (校准版)");
Serial.println("========================================");
Serial.printf(" GPIO 引脚 : %d\n", PWM_PIN);
Serial.printf(" 硬件最大PWM值 : %d\n", PWM_MAX_HARD);
Serial.printf(" 有效最大PWM值 : %d (对应 20mA)\n", PWM_MAX);
Serial.println(" 占空比 0~100% 线性对应 0~20mA");
Serial.println("========================================\n");
Serial.println("命令格式:");
Serial.println(" • 输入 0~100 → 设置百分比");
Serial.println(" • 输入 v 数值 → 直接设置PWM值 (0~PWM_MAX)");
Serial.println(" • 输入 auto → 自动扫描");
Serial.println(" • 输入 help / ? → 显示帮助");
Serial.println();
setDutyPercent(0);
}
void loop() {
if (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.length() == 0) return;
// 调试打印
Serial.print("🔍 原始输入: '");
Serial.print(input);
Serial.println("'");
// 处理 auto(自动扫描)
if (input.equalsIgnoreCase("auto")) {
Serial.println("\n--- 开始自动循环扫描 (5%步进, 每步保持1秒) ---");
for (int p = 0; p <= 100; p += 5) {
setDutyPercent(p);
delay(1000);
}
for (int p = 100; p >= 0; p -= 5) {
setDutyPercent(p);
delay(1000);
}
Serial.println("--- 自动循环结束 ---\n");
printHelp();
return;
}
// 帮助
if (input.equalsIgnoreCase("help") || input.equals("?")) {
printHelp();
return;
}
// 直接数值命令 "v 数值"
if (input.startsWith("v ") || input.startsWith("V ")) {
String numStr = input.substring(2);
numStr.trim();
int raw = numStr.toInt();
if (raw >= 0 && raw <= PWM_MAX) {
setDutyRaw(raw);
} else {
Serial.printf("❌ 无效数值,请输入 0 ~ %d 之间的整数\n", PWM_MAX);
}
return;
}
// 百分比输入
int percent = input.toInt();
if (percent >= 0 && percent <= 100) {
setDutyPercent(percent);
} else {
Serial.println("❌ 无效输入!请使用:0~100(百分比)或 v 数值(PWM值)");
printHelp();
}
}
delay(50);
}
// 百分比 → PWM值 (线性映射,0%→0, 100%→PWM_MAX)
void setDutyPercent(int percent) {
percent = constrain(percent, 0, 100);
int duty = (long)percent * PWM_MAX / 100;
setDutyRaw(duty);
}
// 直接设置PWM值 (限制不超过PWM_MAX)
void setDutyRaw(int duty) {
duty = constrain(duty, 0, PWM_MAX);
analogWrite(PWM_PIN, duty);
unsigned long now = millis();
float percent = (float)duty * 100.0 / PWM_MAX;
float current = (float)duty * 20.0 / PWM_MAX; // 按0~20mA线性计算
Serial.printf("[%lu ms] PWM值: %5d (占空比: %6.2f%%) → 电流: %5.2f mA\n",
now, duty, percent, current);
}
void printHelp() {
Serial.println("----------------------------------------");
Serial.println("命令说明:");
Serial.println(" • 输入 0~100 → 设置百分比");
Serial.printf(" • 输入 v 数值 (0~%d) → 直接设置PWM值\n", PWM_MAX); // 修正点:使用 printf
Serial.println(" • 输入 auto → 自动扫描");
Serial.println(" • 输入 help 或 ? → 显示帮助");
Serial.println("----------------------------------------\n");
}
4.模拟量输入
/*
* ESP32-S3 综合测试程序:PWM输出 (0-20mA) + ADS1115采集 (0-20mA)
* ============================================================
* PWM输出: GPIO1, 14位, 1000Hz, 校准值15036对应20mA
* ADS1115: I2C SDA=GPIO9, SCL=GPIO10, 地址0x48 (ADDR接GND)
* 采样电阻150Ω, 0-3.0V 对应 0-20mA
* 串口命令: 波特率115200
* - 输入 0~100 : 设置PWM占空比百分比
* - 输入 v 数值 : 直接设置PWM计数值 (0~15036)
* - 输入 auto : 自动扫描0→100→0 (步进5%, 间隔1s)
* - 输入 read : 立即读取一次ADS1115并打印
* - 输入 help / ? : 显示帮助
* - 输入(空) : 持续自动打印采集值 (默认)
*/
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
// ===================== PWM 输出配置 =====================
#define PWM_PIN 1
#define PWM_FREQ 1000
#define PWM_RESOLUTION 14
#define PWM_MAX_HARD ((1 << PWM_RESOLUTION) - 1) // 16383
#define PWM_MAX_EFFECTIVE 15036 // 根据校准,此值对应20mA
// ===================== ADS1115 配置 =====================
#define I2C_SDA 9
#define I2C_SCL 10
#define ADS1115_ADDR 0x48 // ADDR接GND
#define ADS1115_GAIN GAIN_ONE // ±4.096V
#define ADS_CHANNEL 0 // 使用A0通道
// ===================== 电压/电流映射 (150Ω) =====================
const float VOLTAGE_MIN = 0.0; // 0mA 对应电压
const float VOLTAGE_MAX = 3.0; // 20mA 对应电压 (20mA * 150Ω)
const float CURRENT_MIN = 0.0;
const float CURRENT_MAX = 20.0;
// ===================== 全局对象 =====================
Adafruit_ADS1115 ads;
int currentPercent = 0; // 当前输出百分比
// ===================== 函数声明 =====================
void setDutyPercent(int percent);
void setDutyRaw(int duty);
void readAndPrintADC();
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max);
void printHelp();
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
// -------- 初始化PWM --------
analogWriteResolution(PWM_PIN, PWM_RESOLUTION);
analogWriteFrequency(PWM_PIN, PWM_FREQ);
pinMode(PWM_PIN, OUTPUT);
setDutyPercent(0); // 初始输出0mA
// -------- 初始化I2C和ADS1115 --------
Wire.begin(I2C_SDA, I2C_SCL);
if (!ads.begin(ADS1115_ADDR, &Wire)) {
Serial.println("❌ 未检测到ADS1115!请检查接线。");
while (1) delay(1000);
}
ads.setGain(ADS1115_GAIN);
// -------- 打印启动信息 --------
Serial.println("\n========================================");
Serial.println(" ESP32-S3 综合测试 (输出+采集)");
Serial.println("========================================");
Serial.printf(" PWM输出: GPIO%d, %dHz, %d位, 20mA对应PWM=%d\n",
PWM_PIN, PWM_FREQ, PWM_RESOLUTION, PWM_MAX_EFFECTIVE);
Serial.printf(" ADS1115: I2C GPIO%d(SDA) & GPIO%d(SCL), 地址0x%02X\n",
I2C_SDA, I2C_SCL, ADS1115_ADDR);
Serial.printf(" 采样电阻: 150Ω, 满量程 %.1fV\n", VOLTAGE_MAX);
Serial.println(" 映射: 0V→0mA, 3.0V→20mA");
Serial.println("========================================\n");
printHelp();
Serial.println("\n开始运行,每秒自动采集并显示...\n");
}
void loop() {
// -------- 处理串口命令 --------
if (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.length() == 0) return;
// 调试打印原始输入(可选)
// Serial.print("🔍 原始输入: '"); Serial.print(input); Serial.println("'");
// -------- 命令: auto (自动扫描) --------
if (input.equalsIgnoreCase("auto")) {
Serial.println("\n--- 开始自动扫描 (5%步进, 间隔1s) ---");
for (int p = 0; p <= 100; p += 5) {
setDutyPercent(p);
delay(1000);
readAndPrintADC(); // 每步采集一次
}
for (int p = 100; p >= 0; p -= 5) {
setDutyPercent(p);
delay(1000);
readAndPrintADC();
}
Serial.println("--- 扫描结束 ---\n");
printHelp();
return;
}
// -------- 命令: read (立即读取) --------
if (input.equalsIgnoreCase("read")) {
readAndPrintADC();
return;
}
// -------- 命令: help / ? --------
if (input.equalsIgnoreCase("help") || input.equals("?")) {
printHelp();
return;
}
// -------- 命令: v 数值 (直接PWM值) --------
if (input.startsWith("v ") || input.startsWith("V ")) {
String numStr = input.substring(2);
numStr.trim();
int raw = numStr.toInt();
if (raw >= 0 && raw <= PWM_MAX_EFFECTIVE) {
setDutyRaw(raw);
Serial.printf("✅ 设置PWM值: %d (约 %.2f%%)\n", raw, (float)raw*100/PWM_MAX_EFFECTIVE);
readAndPrintADC(); // 设置后立即采集显示
} else {
Serial.printf("❌ 无效数值,请输入 0 ~ %d\n", PWM_MAX_EFFECTIVE);
}
return;
}
// -------- 命令: 百分比 (0~100) --------
int percent = input.toInt();
if (percent >= 0 && percent <= 100) {
setDutyPercent(percent);
Serial.printf("✅ 设置占空比: %d%%\n", percent);
readAndPrintADC(); // 设置后立即采集显示
} else {
Serial.println("❌ 无效命令,输入 0~100 或 'help' 查看帮助。");
}
}
// -------- 循环主体:每秒自动采集一次并显示 --------
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 1000) {
lastPrint = millis();
readAndPrintADC(); // 每秒打印一次当前采集值
}
}
// ===================== PWM 设置函数 =====================
void setDutyPercent(int percent) {
percent = constrain(percent, 0, 100);
currentPercent = percent;
int duty = (long)percent * PWM_MAX_EFFECTIVE / 100;
setDutyRaw(duty);
}
void setDutyRaw(int duty) {
duty = constrain(duty, 0, PWM_MAX_EFFECTIVE);
analogWrite(PWM_PIN, duty);
// 可选的调试输出:
// Serial.printf("PWM set to %d\n", duty);
}
// ===================== ADS1115 读取与打印 =====================
void readAndPrintADC() {
int16_t adcValue = ads.readADC_SingleEnded(ADS_CHANNEL);
float voltage = ads.computeVolts(adcValue);
float current = mapFloat(voltage, VOLTAGE_MIN, VOLTAGE_MAX, CURRENT_MIN, CURRENT_MAX);
unsigned long now = millis();
Serial.printf("[%lu ms] ADC=%5d | %.3f V | %5.2f mA (输出设定: %d%%)\n",
now, adcValue, voltage, current, currentPercent);
}
// ===================== 工具函数 =====================
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) {
if (x < in_min) x = in_min;
if (x > in_max) x = in_max;
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void printHelp() {
Serial.println("----------------------------------------");
Serial.println("串口命令说明:");
Serial.println(" 输入 0~100 : 设置PWM占空比百分比");
// 修正下面这一行:使用 printf 而不是 println
Serial.printf(" 输入 v 数值 : 直接设置PWM值 (0~%d)\n", PWM_MAX_EFFECTIVE);
Serial.println(" 输入 auto : 自动扫描0→100→0 (步进5%, 间隔1s)");
Serial.println(" 输入 read : 立即读取一次ADS1115并显示");
Serial.println(" 输入 help 或 ? : 显示此帮助");
Serial.println(" (无命令时) : 每秒自动采集并显示");
Serial.println("----------------------------------------");
}
5.RS485调试
/*
* ESP32-S3 RS485 通信调试代码
*
* 硬件连接:
* - RO (接收) -> GPIO11
* - DI (发送) -> GPIO12
* - RE# & DE -> GPIO15 (短接)
*
* 功能: 程序启动后,会通过RS485每秒发送一条消息,并监听回应。
* 所有通过RS485接收到的数据都会在串口监视器中打印出来。
*/
#include <HardwareSerial.h>
// 定义引脚
#define RS485_RX_PIN 11 // RO 引脚
#define RS485_TX_PIN 12 // DI 引脚
#define RS485_EN_PIN 15 // RE 和 DE 使能引脚 (短接)
// 创建硬件串口实例,使用 UART1
HardwareSerial rs485Serial(1);
void setup() {
// 初始化调试串口 (连接电脑的USB)
Serial.begin(115200);
while (!Serial) {
; // 等待串口连接
}
Serial.println("ESP32-S3 RS485 调试程序启动");
// 初始化使能引脚为输出模式
pinMode(RS485_EN_PIN, OUTPUT);
// 默认设置为接收模式 (RE=DE=LOW)
digitalWrite(RS485_EN_PIN, LOW);
// 初始化 RS485 串口
// 参数: 波特率, 数据格式, RX引脚, TX引脚
rs485Serial.begin(115200, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);
Serial.println("RS485 串口初始化完成,等待数据...");
}
void loop() {
// ----- 1. 发送数据 (切换到发送模式) -----
// 将RE和DE引脚拉高,进入发送模式
digitalWrite(RS485_EN_PIN, HIGH);
// 短暂延迟,确保模式切换稳定
delay(1);
// 发送一条测试消息
rs485Serial.println("Hello from ESP32-S3!");
Serial.println("RS485 已发送: Hello from ESP32-S3!");
// 等待数据发送完成
rs485Serial.flush();
// 发送完毕后,立即切换回接收模式
digitalWrite(RS485_EN_PIN, LOW);
// 短暂延迟,确保模式切换稳定
delay(1);
// ----- 2. 接收数据 (处于接收模式) -----
// 检查是否有数据从RS485总线传来
if (rs485Serial.available()) {
String receivedMessage = "";
// 读取所有可用的数据
while (rs485Serial.available()) {
char c = rs485Serial.read();
receivedMessage += c;
}
// 在串口监视器中打印接收到的数据
Serial.print("RS485 接收到: ");
Serial.println(receivedMessage);
}
// 等待1秒后进行下一轮循环
delay(500);
}
更多推荐



所有评论(0)