Arduino PLC(如Arduino Industrial 101)可通过arduino-cli实现命令行编译/上传,替代图形化IDE:
# 安装arduino-cli(Linux/macOS)
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
# 初始化配置
arduino-cli config init
# 安装PLC核心(以Industrial 101为例)
arduino-cli core install arduino:avr
# 编译PLC程序(替换为你的 sketch 路径)
arduino-cli compile --fqbn arduino:avr:industrial101 /path/to/your/sketch
# 上传到PLC(替换串口名,如/dev/ttyUSB0)
arduino-cli upload -p /dev/ttyUSB0 --fqbn arduino:avr:industrial101 /path/to/your/sketch
Termux(安卓终端)中可搭建ESP32开发环境,核心命令:
# 安装依赖
pkg install git python3 py3-pip gcc make libffi openssl
# 安装esptool(烧录工具)
pip3 install esptool
# 克隆ESP-IDF(适配ESP32的版本)
git clone --depth 1 --branch v4.4 https://github.com/espressif/esp-idf.git
# 安装ESP-IDF依赖
cd esp-idf
./install.sh esp32
# 配置环境变量
. ./export.sh
# 烧录固件到ESP32(替换串口名/固件路径,Termux串口通常为/dev/ttyUSB0或/dev/ttyACM0)
esptool.py --port /dev/ttyUSB0 write_flash 0x1000 /path/to/your/esp32_firmware.bin
若需Arduino PLC与ESP32通信,可通过串口/Modbus实现,核心代码片段(Arduino PLC端):
#include < ModbusRTU.h >
ModbusRTU mb;
void setup() {
Serial.begin(9600); // 与ESP32串口波特率一致
mb.begin(&Serial);
mb.slave(1); // 从机地址
}
void loop() {
mb.poll();
// 读取ESP32发送的寄存器数据(示例:读取寄存器0的值)
uint16_t val = mb.Hreg(0);
// 控制PLC输出(示例:根据值控制数字输出)
digitalWrite(13, val > 0 ? HIGH : LOW);
}
ModbusRTU 库(Arduino IDE 或 arduino-cli 均可);modbus_slave 相关依赖(脚本内包含)。#include < ModbusRTU.h >
// 定义Modbus对象
ModbusRTU mb;
// 定义PLC引脚(根据实际型号调整,以Industrial 101为例)
const int PLC_OUTPUT_PIN = 13; // PLC数字输出引脚
const int PLC_INPUT_PIN = 2; // PLC数字输入引脚
void setup() {
// 1. 初始化串口(与ESP32波特率、校验位一致)
Serial.begin(9600, SERIAL_8N1);
while (!Serial) {} // 等待串口就绪
// 2. 初始化Modbus主机
mb.begin(&Serial);
mb.master(); // 配置为Modbus主机
mb.setTimeOut(1000); // 通信超时时间(1秒)
// 3. 初始化PLC引脚
pinMode(PLC_OUTPUT_PIN, OUTPUT);
pinMode(PLC_INPUT_PIN, INPUT);
}
void loop() {
uint16_t esp_data[2]; // 存储从ESP32读取的数据(寄存器0:传感器值,寄存器1:ESP32状态)
uint8_t result; // Modbus通信结果
// 1. 读取ESP32的2个保持寄存器(地址0和1,从机地址1)
result = mb.readHreg(1, 0, 2, esp_data);
if (result == mb.ku8MBSuccess) {
// 读取成功:打印ESP32数据
Serial.print("ESP32 传感器值:");
Serial.println(esp_data[0]);
Serial.print("ESP32 状态:");
Serial.println(esp_data[1] == 1 ? "正常" : "异常");
// 2. 根据ESP32数据控制PLC输出
if (esp_data[0] > 500) { // 示例:传感器值大于500时,PLC输出高电平
digitalWrite(PLC_OUTPUT_PIN, HIGH);
} else {
digitalWrite(PLC_OUTPUT_PIN, LOW);
}
} else {
// 读取失败:打印错误代码
Serial.print("Modbus读取失败,错误代码:");
Serial.println(result);
}
// 3. 读取PLC输入状态,发送给ESP32(写入ESP32的线圈0)
bool plc_input_state = digitalRead(PLC_INPUT_PIN);
result = mb.writeCoil(1, 0, plc_input_state); // 写入ESP32线圈0(从机地址1)
if (result != mb.ku8MBSuccess) {
Serial.print("Modbus写入失败,错误代码:");
Serial.println(result);
}
delay(1000); // 通信间隔(1秒,可调整)
}
# 1. 进入ESP-IDF目录,加载环境变量
cd ~/esp-idf
. ./export.sh
# 2. 创建新的ESP32项目(项目名:esp32_modbus_slave)
idf.py create-project esp32_modbus_slave
cd esp32_modbus_slave
# 3. 配置项目(选择ESP32开发板,如ESP32-WROOM-32)
idf.py set-target esp32
idf.py menuconfig
# (可选)在menuconfig中设置串口波特率(默认9600,需与PLC一致)
# 路径:Component config → Modbus → UART Baud Rate → 9600
#include < stdio.h >
#include < string.h >
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "modbus_slave.h"
// 1. 串口配置(与PLC一致)
#define UART_NUM UART_NUM_0 // ESP32串口0(可替换为UART_NUM_1)
#define BAUD_RATE 9600 // 波特率
#define TX_PIN GPIO_NUM_1 // ESP32 TX引脚(连接PLC RX)
#define RX_PIN GPIO_NUM_3 // ESP32 RX引脚(连接PLC TX)
#define BUF_SIZE (1024) // 串口缓冲区大小
// 2. Modbus从机配置
#define MODBUS_SLAVE_ADDR 1 // 从机地址(需与PLC主机一致)
#define REG_HOLDING_START 0 // 保持寄存器起始地址
#define REG_HOLDING_SIZE 2 // 保持寄存器数量(2个:传感器值、状态)
#define COIL_START 0 // 线圈起始地址
#define COIL_SIZE 1 // 线圈数量(1个:接收PLC输入状态)
// 3. 模拟传感器数据(可替换为实际传感器读取代码)
uint16_t sensor_value = 0;
// 4. Modbus寄存器和线圈存储区
uint16_t holding_regs[REG_HOLDING_SIZE] = {0}; // 保持寄存器(供PLC读取)
bool coils[COIL_SIZE] = {false}; // 线圈(接收PLC写入)
// 串口初始化函数
void uart_init() {
const uart_config_t uart_config = {
.baud_rate = BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
// 配置串口参数
uart_param_config(UART_NUM, &uart_config);
// 设置串口引脚
uart_set_pin(UART_NUM, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
// 安装串口驱动(中断模式)
uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0);
}
// Modbus从机初始化函数
void modbus_slave_init() {
// 1. 初始化Modbus从机(串口0,从机地址1)
modbus_slave_init_port(UART_NUM, MODBUS_SLAVE_ADDR);
// 2. 注册保持寄存器(供PLC读取)
modbus_slave_register_holding_regs(REG_HOLDING_START, REG_HOLDING_SIZE, holding_regs);
// 3. 注册线圈(接收PLC写入)
modbus_slave_register_coils(COIL_START, COIL_SIZE, coils);
// 4. 启动Modbus从机任务
modbus_slave_start_task();
}
// 模拟传感器数据更新任务
void sensor_update_task(void *pvParameters) {
while (1) {
// 模拟传感器值递增(0~1000,循环)
sensor_value = (sensor_value + 10) % 1000;
// 更新保持寄存器(寄存器0:传感器值,寄存器1:状态1=正常)
holding_regs[0] = sensor_value;
holding_regs[1] = 1; // 固定为正常状态,可替换为实际状态判断
vTaskDelay(500 / portTICK_PERIOD_MS); // 500ms更新一次
}
}
// 读取PLC写入的线圈状态任务
void plc_coil_read_task(void *pvParameters) {
while (1) {
// 读取线圈0的状态(PLC输入引脚状态)
bool plc_input = coils[0];
// 打印PLC输入状态
printf("PLC输入状态:%sn", plc_input ? "高电平" : "低电平");
// (可选)根据PLC状态控制ESP32引脚
gpio_set_level(GPIO_NUM_2, plc_input ? 1 : 0); // ESP32引脚2输出对应电平
vTaskDelay(1000 / portTICK_PERIOD_MS); // 1秒读取一次
}
}
void app_main(void) {
// 1. 初始化GPIO(ESP32引脚2,用于响应PLC控制)
gpio_reset_pin(GPIO_NUM_2);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
// 2. 初始化串口和Modbus从机
uart_init();
modbus_slave_init();
// 3. 创建传感器更新和PLC线圈读取任务
xTaskCreate(sensor_update_task, "sensor_task", 2048, NULL, 5, NULL);
xTaskCreate(plc_coil_read_task, "coil_task", 2048, NULL, 5, NULL);
}
# 1. 编译项目
idf.py build
# 2. 烧录固件(替换串口名,Termux中通常为/dev/ttyUSB0或/dev/ttyACM0)
idf.py -p /dev/ttyUSB0 flash monitor
# 烧录成功后,按Ctrl+]退出monitor,ESP32将自动运行程序
idf.py -p /dev/ttyUSB0 monitor,可看到 PLC 输入引脚的状态;sensor_value),观察 PLC 输出引脚是否按条件切换;全部0条评论
快来发表一下你的评论吧 !