ESP32+Mqtt+Node.js+Vue3 做工控界面
·
1.主机安装 mosquitto
作为mqtt的服务端,转发消息
https://mosquitto.org/download/
2.EPS32端的代码
注意配置WIFI, mqtt_server 是安装了mosquitto,同局域网下的主机ip
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_ADS1X15.h>
#include <Wire.h>
#include <ArduinoJson.h>
// -------------------- 用户配置(必改) --------------------
const char* ssid = "TSK";
const char* password = "tsk_251010";
const char* mqtt_server = "192.168.234.34";
const int mqtt_port = 1883;
// -------------------- MQTT 主题 --------------------
const char* status_topic = "esp32/status";
const char* control_topic = "esp32/control";
// -------------------- 引脚定义 --------------------
// 数字输入 (外部下拉,高电平有效)
const int DI_PINS[4] = {40, 39, 38, 37};
// 数字输出
const int DO_PINS[4] = {7, 15, 16, 17};
// PWM 输出
const int PWM_PINS[4] = {47, 21, 20, 19};
const int PWM_FREQ = 1000;
const int PWM_RESOLUTION = 14;
const int PWM_MAX_VALUE = (1 << PWM_RESOLUTION) - 1; // 16383
// I2C (ADS1115)
#define I2C_SDA 9
#define I2C_SCL 10
#define LED_BUILTIN 13
// -------------------- 全局对象 --------------------
WiFiClient espClient;
PubSubClient client(espClient);
Adafruit_ADS1115 ads;
// -------------------- 状态变量 --------------------
bool diState[4] = {0};
bool lastDIState[4] = {0}; // 用于边沿检测
bool doState[4] = {0};
float aiValue[4] = {0.0};
int pwmPercent[4] = {0};
// -------------------- 前向声明 --------------------
void setupWiFi();
void reconnectMQTT();
void callback(char* topic, byte* payload, unsigned int length);
void readInputs();
void publishStatus();
void handleControl(JsonDocument& doc);
void setPWMDuty(int index, int percent);
// ==================== 初始化 ====================
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("\n=== ESP32 PLC 4444 启动 ===");
// ----- 配置 GPIO -----
Serial.println("初始化数字输入 (外部下拉, 高电平有效)");
for (int i = 0; i < 4; i++) {
pinMode(DI_PINS[i], INPUT); // 外部下拉,无需内部上拉
diState[i] = digitalRead(DI_PINS[i]);
lastDIState[i] = diState[i];
Serial.printf(" DI%d (GPIO%d) 初始状态: %d\n", i+1, DI_PINS[i], diState[i]);
}
Serial.println("初始化数字输出 (初始LOW)");
for (int i = 0; i < 4; i++) {
pinMode(DO_PINS[i], OUTPUT);
digitalWrite(DO_PINS[i], LOW);
doState[i] = 0;
Serial.printf(" DO%d (GPIO%d) -> LOW\n", i+1, DO_PINS[i]);
}
Serial.println("初始化 PWM 输出");
for (int i = 0; i < 4; i++) {
pinMode(PWM_PINS[i], OUTPUT);
analogWriteResolution(PWM_PINS[i], PWM_RESOLUTION);
analogWriteFrequency(PWM_PINS[i], PWM_FREQ);
analogWrite(PWM_PINS[i], 0);
Serial.printf(" PWM%d (GPIO%d) -> 0%%\n", i+1, PWM_PINS[i]);
}
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// ----- I2C & ADS1115 -----
Wire.begin(I2C_SDA, I2C_SCL);
if (!ads.begin()) {
Serial.println("❌ ADS1115 初始化失败,请检查接线");
while (1) delay(1000);
}
ads.setGain(GAIN_ONE);
Serial.println("✅ ADS1115 初始化成功");
// ----- WiFi & MQTT -----
setupWiFi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
Serial.println("✅ 系统就绪\n");
}
// ==================== WiFi 连接 ====================
void setupWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("📶 连接 WiFi");
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 30) {
delay(500);
Serial.print(".");
retry++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✅ WiFi 已连接,IP: " + WiFi.localIP().toString());
} else {
Serial.println("\n❌ WiFi 连接失败,请检查 SSID/密码");
}
}
// ==================== MQTT 重连 ====================
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("🔄 尝试连接 MQTT...");
if (client.connect("ESP32_PLC_4444")) {
Serial.println("✅ 已连接");
client.subscribe(control_topic);
digitalWrite(LED_BUILTIN, HIGH);
} else {
Serial.print("❌ 失败, rc=");
Serial.print(client.state());
Serial.println(",5秒后重试");
digitalWrite(LED_BUILTIN, LOW);
delay(5000);
}
}
}
// ==================== MQTT 回调 ====================
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("📨 收到指令 [");
Serial.print(topic);
Serial.print("] ");
for (unsigned int i = 0; i < length; i++) Serial.print((char)payload[i]);
Serial.println();
DynamicJsonDocument doc(256);
DeserializationError error = deserializeJson(doc, payload, length);
if (error) {
Serial.print("❌ JSON 解析失败: ");
Serial.println(error.c_str());
return;
}
handleControl(doc);
}
// ==================== 控制处理 ====================
void handleControl(JsonDocument& doc) {
bool updateDO = false, updatePWM = false;
if (doc.containsKey("do")) {
JsonArray arr = doc["do"].as<JsonArray>();
if (arr.size() == 4) {
for (int i = 0; i < 4; i++) {
doState[i] = arr[i].as<bool>();
digitalWrite(DO_PINS[i], doState[i] ? HIGH : LOW);
}
updateDO = true;
} else {
Serial.println("⚠️ do 数组长度必须为 4");
}
}
if (doc.containsKey("pwm")) {
JsonArray arr = doc["pwm"].as<JsonArray>();
if (arr.size() == 4) {
for (int i = 0; i < 4; i++) {
int p = arr[i].as<int>();
p = constrain(p, 0, 100);
pwmPercent[i] = p;
setPWMDuty(i, p);
}
updatePWM = true;
} else {
Serial.println("⚠️ pwm 数组长度必须为 4");
}
}
if (updateDO || updatePWM) {
publishStatus(); // 立即反馈
}
}
// ==================== PWM 设置 ====================
void setPWMDuty(int index, int percent) {
int raw = map(percent, 0, 100, 0, PWM_MAX_VALUE);
analogWrite(PWM_PINS[index], raw);
}
// ==================== 读取输入 ====================
void readInputs() {
// 数字输入:直接读取,高电平为1,低电平为0
for (int i = 0; i < 4; i++) {
diState[i] = digitalRead(DI_PINS[i]);
}
// 模拟量
for (int i = 0; i < 4; i++) {
int16_t raw = ads.readADC_SingleEnded(i);
float voltage = raw * 4.096 / 32767.0;
float current = voltage / 150.0 * 1000.0;
current = constrain(current, 0.0, 20.0);
aiValue[i] = current;
}
}
// ==================== 发布状态 ====================
void publishStatus() {
DynamicJsonDocument doc(256);
JsonArray di = doc.createNestedArray("di");
JsonArray ai = doc.createNestedArray("ai");
JsonArray doArr = doc.createNestedArray("do");
JsonArray pwmArr = doc.createNestedArray("pwm");
for (int i = 0; i < 4; i++) {
di.add(diState[i] ? 1 : 0);
ai.add(aiValue[i]);
doArr.add(doState[i] ? 1 : 0);
pwmArr.add(pwmPercent[i]);
}
String jsonStr;
serializeJson(doc, jsonStr);
if (client.publish(status_topic, jsonStr.c_str())) {
Serial.println("📤 发布状态: " + jsonStr);
} else {
Serial.println("❌ 发布失败");
}
}
// ==================== 主循环 ====================
void loop() {
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
// 读取所有输入
readInputs();
// 检测DI边沿变化
bool diChanged = false;
for (int i = 0; i < 4; i++) {
if (diState[i] != lastDIState[i]) {
diChanged = true;
Serial.printf("[DI变化] GPIO%d %d -> %d\n", DI_PINS[i], lastDIState[i], diState[i]);
lastDIState[i] = diState[i];
}
}
// 如果DI有变化,立即发布
if (diChanged) {
publishStatus();
}
// 每秒定时发布全量状态(确保模拟量定期上报)
static unsigned long lastPublish = 0;
if (millis() - lastPublish >= 1000) {
lastPublish = millis();
publishStatus();
}
delay(10); // 微小延时,减轻CPU负载
}
表示正在运行的状态

3.在电脑端查看
在电脑端查看:使用MQTTX
https://mqttx.app/zh/web

更多推荐

所有评论(0)