在工業物聯網通信開發中,485 總線與 Modbus 協議的組合應用十分常見。本文以Air780EHV 系列模組為實例,圍繞 LuatOS 開發環境,詳解 485 總線的硬件設計細節,包括其與 UART 的關聯、電平匹配處理及不同防護等級的 TVS 器件選型,同時介紹 LuatOS 輕量化的 exmodbus 擴展庫,并給出該庫實現 Modbus RTU 主站通信的代碼示例與相關文檔查閱渠道。
Air780EHV 系列模組的相關參數說明如下:
該模組可適配多種外設,包含 SPI 串口屏、墨水屏、OLED 單色屏、30 萬像素攝像頭,同時具備 CAN、RJ45 以太網、485、USB、UART、SPI、I2C、PWM、GPIO 等接口。
網絡通信方面,模組支持 TCP/UDP、TCP-SSL/TCP-TLS、FTP、MQTT、HTTP、WebSocket、NTP、Modbus 協議。
模組集成 4G 通信與音頻模塊,可實現語音通話、錄音播放以及 TTS 功能。
工業通信中非常經典的485總線,硬件設計中需要注意的細節,Modbus協議在LuatOS開發中的應用,詳見下文。
一、485總線接口與UART的關系
485總線接口本質上是UART總線接口的一種應用,需要搭配485收發器芯片實現。
二、電平匹配問題
在UART與485收發器芯片的搭配中,最常見需要注意的一個問題是電平匹配。
由于上一章節參考設計中Air780EHV和SP3485都是3.3V的IO電平,所以不再需要分立元器件電平轉換電路或電平轉換芯片。
當雙方電平不一致時,則需要分立元器件電平轉換電路或電平轉換芯片。
常見的分立元器件電平轉換電路如下:
三、485總線接口的TVS防護
工業現場環境復雜,485總線經常面臨靜電、浪涌等威脅,因此接口保護必不可少。
485接口用TVS,常用的型號有SM712系列,如果防護等級要求較高,也可以選擇如下推薦的型號。
ESD等級防護:適用于一般靜電防護場景。型號:應能微ASM712
TVS等級防護:具備2KV 1.2/50uS浪涌能力。型號:應能微SMBJ7.0CAW
TSS等級防護:具備4KV 10/700uS浪涌能力。型號:應能微P0080SA
四、Modbus通信協議
與485總線接口相關的通信協議是Modbus。LuatOS的modbus核心庫,但使用難度較高。而exmodbus擴展庫——在核心庫的基礎上封裝了更簡潔易用的API,降低開發難度,易于開發者集成Modbus通信。
exmodbus最新API文檔詳見資料中心
核心示例持續更新中!
PROJECT = "RTU_MASTER"
VERSION = "001.000.000"
-- 在日志中打印項目名和項目版本號
log.info("main", PROJECT, VERSION)
local exmodbus = require("exmodbus")
-- 使用 Air8000 開發板測試打開這兩個
gpio.setup(16, 1) -- RS485 芯片供電引腳
local rs485_dir_gpio = 17 -- RS485 方向引腳
-- 使用 Air780EPM 開發板測試打開這三個;
-- gpio.setup(1, 1) -- Air780EPM RS485 芯片供電引腳
-- gpio.setup(23, 1) -- Air780EPM vref 腳拉高
-- local rs485_dir_gpio = 24 -- Air780EPM RS485 方向引腳(V1.2 是 25,V1.3 是 24)
-- 創建 RTU 主站配置參數;
-- 說明:創建 RTU 主站時只需要配置如下參數即可;
local create_config = {
-- 串口配置參數;
mode = exmodbus.RTU_MASTER, -- 通信模式
uart_id = 1, -- UART 端口號
baud_rate = 115200, -- 波特率
data_bits = 8, -- 數據位
stop_bits = 1, -- 停止位
parity_bits = uart.None, -- 校驗位
byte_order = uart.LSB, -- 字節順序
rs485_dir_gpio = rs485_dir_gpio, -- RS485 方向引腳
rs485_dir_rx_level = 0, -- RS485 接收方向電平
}
-- 初始化從站 1 數據結構
-- 用于記錄從站 1 保持寄存器 0-1 的值;
local slave1_data = {}
-- 配置讀取從站 1 保持寄存器 0-1 的值;
local read_config = {
raw_request = string.char(
0x01, -- 從站地址
0x03, -- 功能碼:讀取保持寄存器
0x00, 0x00, -- 寄存器起始地址
0x00, 0x02, -- 寄存器數量
0xC4, 0x0B -- CRC16校驗碼
),
timeout = 1000 -- 超時時間 1000 ms
}
-- 創建 RTU 主站實例
local rtu_master = exmodbus.create(create_config)
-- 判斷主站是否創建成功并記錄日志
if not rtu_master then
log.info("exmodbus_test", "rtu_master 創建失敗")
else
log.info("exmodbus_test", "rtu_master 創建成功")
end
-- 讀取從站 1 保持寄存器數據的函數
local function read_slave1_holding_registers()
log.info("exmodbus_test", "開始讀取從站 1 保持寄存器 0-1 的值")
-- 執行讀取操作
local read_result = rtu_master:read(read_config)
-- 根據返回狀態處理結果
if read_result.status == exmodbus.STATUS_SUCCESS then
local resp = read_result.raw_response
-- 特別說明:
-- 接下來的判斷是針對 modbus RTU 標準響應格式的應答原始幀來解析的
-- 在實際項目中,應根據自己項目中的實際應答原始幀格式進行解析
-- 如果實際格式與此處演示的格式不一致,需要修改接下來的解析代碼
-- 1. 檢查總長度:必須為 9 字節(1 地址 + 1 功能碼 + 1 字節數 + 4 數據 + 2 CRC)
if #resp ~= 9 then
log.info("exmodbus_test", "響應長度錯誤,期望 9 字節,實際:", #resp)
return
end
-- 2. 檢查從站地址
if string.byte(resp, 1) ~= 0x01 then
log.info("exmodbus_test", "從站地址不匹配,收到:", string.byte(resp, 1))
return
end
-- 3. 檢查功能碼
local func_code = string.byte(resp, 2)
if func_code == 0x83 then
local exc_code = string.byte(resp, 3)
log.info("exmodbus_test", "從站返回異常響應,異常碼:", exc_code)
return
elseif func_code ~= 0x03 then
log.info("exmodbus_test", "功能碼錯誤,收到:", func_code)
return
end
-- 4. 檢查字節數字段(應為 4)
local byte_count = string.byte(resp, 3)
if byte_count ~= 4 then
log.info("exmodbus_test", "字節數字段錯誤,期望 4,實際:", byte_count)
return
end
-- 5. 校驗CRC
-- 計算前 7 字節的 CRC
local crc_calculated = crypto.crc16_modbus(resp:sub(1, 7))
-- 提取接收到的 CRC
local crc_received = string.unpack("< I2", resp, 8)
-- 比較 CRC
if crc_calculated ~= crc_received then
log.info("exmodbus_test", "CRC 校驗錯誤,計算值:", crc_calculated, ",接收值:", crc_received)
return
end
-- 6. 解析寄存器數據(從第 4 字節開始,大端序)
local data1 = string.unpack(" >I2", resp, 4) -- 寄存器 0,偏移 4
local data2 = string.unpack(" >I2", resp, 6) -- 寄存器 1,偏移 6
-- 7. 記錄數據
slave1_data[0] = data1
slave1_data[1] = data2
-- 8. 記錄日志
log.info("exmodbus_test", "成功讀取到從站 1 保持寄存器 0-1 的值,寄存器 0 數值為", slave1_data[0], ",寄存器 1 數值為", slave1_data[1])
elseif read_result.status == exmodbus.STATUS_TIMEOUT then
log.info("exmodbus_test", "未收到從站 1 的響應(超時)")
end
end
-- 定時任務函數:每 2 秒調用一次讀取函數
local function task()
while true do
if rtu_master then
-- 每 2 秒調用一次讀取函數
read_slave1_holding_registers()
else
log.info("exmodbus_test", "rtu_master 未創建,無法執行 read_slave1_holding_registers()")
end
sys.wait(2000)
end
end
-- 初始化任務
sys.taskInit(task)
-- 用戶代碼已結束---------------------------------------------
-- 結尾總是這一句
sys.run()
-- sys.run()之后后面不要加任何語句!!!!
以上為 485 總線硬件設計核心要點及 LuatOS 環境下 Modbus 協議應用的相關分享,內容涵蓋 485 總線與 UART 的關系、電平匹配、TVS 防護以及 exmodbus 擴展庫的優化內容,相關實操內容可供工程技術人員參考,用于解決實際應用中的相關問題。
審核編輯 黃宇
-
總線
+關注
關注
10文章
3047瀏覽量
91750 -
硬件設計
+關注
關注
18文章
471瀏覽量
45655 -
LuatOS
+關注
關注
0文章
162瀏覽量
2724
發布評論請先 登錄
485 總線硬件設計:電平匹配、TVS 防護與 Modbus 庫應用
LuatOS exgnss擴展庫實戰進階:GNSS功能開發全流程!
LuatOS MCU核心庫全接觸:新手操作與功能測試攻略!
USB設計操作指南:硬件關鍵與LuatOS API開發技巧!
LuatOS AGPS 輔助定位開發實戰教程
零基礎學習LuatOS編程:快速上手開發實戰教程!
快速入門——LuatOS:sys庫多任務管理實戰攻略!
全棧開發進階指南:LuatOS-log庫從入門到實戰!
解鎖LuatOS-log庫:全棧工程師的日志管理實戰課!
LuatOS:485 總線硬件設計要點與 exmodbus 庫開發實戰
評論