智驰华芯--雷达液位计(ModBus 通讯协议)--LUA实现

一. 代码分为两部分,使用VScode下载luatIDE可在线调试。

二. ModBus通讯协议 V1.1.5

1. main.lua

a.main函数里提供了几个测试报文,通过设定不同的模拟报文,检测函数的逻辑性和可用性。

PROJECT = "M40协议"
VERSION = "2.0.0"

require "M40"


---------------------1.测试报文read-----------------------
--[[
Demo: 读取当前水位值;data:命令报文
]]
--local data = M40.Read_DATA(defaultadd,ReadCode,WaterLevel,2)
--for i=1,8,1 do
--   print(string.format("%02x",data[i]))
--end
---------------------测试报文-----------------------


---------------------2.测试报文write-----------------------
--[[
Demo: 设定量程值;data:命令报文
]]
--local data = M40.Write_DATA(defaultadd,SWriteCode,Range_Max,0)
--for i=1,8,1 do
--   print(string.format("%02x",data[i]))
--end
---------------------测试报文-----------------------


---------------------3.测试报文cut_data-----------------------
--[[
Demo: 读取数据;Revdata:应答报文
]]
--{(多)双寄存器读取数据}
print("Read value of multiple registers")
local RevData1 = {0x01,0x03,0x04,0x00,0x00,0x27,0xD8,0x99,0xE1}
local Data1 = M40.Cut_data(defaultadd,0x02,RevData1)
print(Data1)
--{(单)单寄存器读取数据}
print("Single register reading")
local RevData2 = {0x01,0x03,0x02,0x25,0xFF,0x99,0xE1}
local Data2 = M40.Cut_data(defaultadd,0x01,RevData2)
print(Data2)
---------------------测试报文-----------------------

 2. M40.lua

a.每个功能的寄存器数量最多是两个,所以读函数分为单次读取和多次读取两个函数实现。故在解析应答报文的函数中,通过判断寄存器数量来截取数据。

b.应答报文错误类型检测:应答报文存在每一位存在固定的信息码,因此通过判断信息码分辨不同错误信息。

c.CRC校验位根据ModBus协议的校验方式实现,这里不多赘述。

M40 = {}

ReadCode   = 0x03          --读寄存器功能码
SWriteCode = 0x06          --单个写寄存器功能码
MWriteCode = 0x10          --连续写寄存器功能码
defaultadd = 0x01          --设备默认地址
------------------寄存器地址---------------------
groundDistance   = 0x00    --空高值寄存器-->num=2
WaterLevel       = 0x02    --水位值寄存器-->num=2
WaterPercent     = 0x04    --水位百分比寄存器-->num=2
Low_position     = 0x08    --低位设置寄存器-->num=2
High_position    = 0x0A    --高位设置寄存器-->num=2
Range_Max        = 0x0D    --量程设置寄存器-->num=2
Range_min        = 0x0F    --盲区设置寄存器-->num=2
distance_offset  = 0x11    --距离偏量寄存器-->num=1
Integration_time = 0x12    --积分时间寄存器-->num=1
X_angle          = 0x15    --X轴与水平面夹角寄存器-->num=1
Y_angle          = 0x16    --Y轴与水平面夹角寄存器-->num=1
Z_angle          = 0x17    --Z轴与水平面夹角寄存器-->num=1
Signal_noise     = 0x1A    --雷达信噪比寄存器-->num=1

Text1_Regis      = 0x1F    --测试寄存器-->num=1  
Text2_Regis      = 0x22    --测试寄存器-->num=1

temperature      = 0x1E    --温度寄存器-->num=1
Regis_Format     = 0x23    --输出单位及格式寄存器-->num=1
Run_time         = 0x24    --运行时间寄存器-->num=1
Sleep_time       = 0x25    --休眠寄存器-->num=1
Equipment_status = 0x26    --设备状态寄存器-->num=1
Modbus_add       = 0x64    --Modbus地址寄存器-->num=1
Modbus_Baud      = 0x65    --Modbus波特率寄存器-->num=1
Modbus_Parity    = 0x66    --Modbus奇偶校验寄存器-->num=1
Birth_year       = 0x67    --设备生产年份寄存器-->num=1
Birth_month      = 0x68    --设备生产月份寄存器-->num=1
Birth_day        = 0x69    --设备生产日期寄存器-->num=1
Device_IME       = 0x6A    --设备序列号寄存器-->num=2
Version          = 0x6C    --设备序列号寄存器-->num=2
------------------寄存器地址---------------------


--[[
函数名: Cut_data
功能  : 从应答报文中获取数据
参数  : deviceAdd(设备地址),RevData(返回报文),RegisNum(寄存器数量)
返回值: info(数据)
]]
function M40.Cut_data(deviceAdd,RegisNum,RevData)
	local ret = M40.Errinfo(deviceAdd,RevData)  --判断应答报文是否正确
	if RegisNum==1 and 1==ret then     --读单个寄存器值的应答报文数据裁剪
		local Hdata = RevData[4] << 8
		local Ldata = RevData[5]
		local Data1 = Hdata | Ldata
		return Data1
	elseif RegisNum==2 and 1==ret then --读两个寄存器值的应答报文数据裁剪
		local HData1 = RevData[4] << 24
		local HData2 = RevData[5] << 16
		local LData1 = RevData[6] << 8
		local LData2 = RevData[7] 
		local Data2 = HData1 | HData2 | LData1 | LData2
		return Data2
	elseif ret == -1 then
		return -1
	end
end


--[[
函数名: Errinfo
功能  : 返回应答报文错误信息
参数  : deviceAdd(设备地址),Data(应答报文)
返回值: 返回错误信息码
         01H:非法的功能码     -1
		 02H:非法的数据地址   -2
		 03H:非法的数据值     -3
		 04H:CRC校验错误      -4
		 05H:接收正确         -5
		 06H:接收错误         -6
		 07H:参数错误         -7
]]
function M40.Errinfo(deviceAdd,RevData)
	local flag
	if RevData[1]==deviceAdd then
		if RevData[2]==0x83 or RevData[2]==0x86 or RevData[2]==0x90 then
			if RevData[3] == 0x01 then 	
			   flag=-1
		   elseif RevData[3] == 0x02 then 
			   flag=-2
		   elseif RevData[3] == 0x03 then 
			   flag=-3
		   elseif RevData[3] == 0x04 then 
			   flag=-4
		   elseif RevData[3] == 0x05 then 
		       flag=-5
		   elseif RevData[3] == 0x06 then 
			   flag=-6
		   elseif RevData[3] == 0x07 then 
			   flag=-7   
		    end
		else
			flag=1
		end
	else
		    flag=0
	end
	return flag
end


--[[
函数名: CRC_cal
功能  : 获取命令报文的CRC校验位
参数  : Data(待发送报文(未连接校验位))
返回值: CRCData(校验位数据)
]]

function M40.CRC_cal(Data)
	local DataLen = #Data
	local CRCin = 0xFFFF
    local CRCData = 0
	for j=1,DataLen,1 do
		CRCin = (CRCin ~ Data[j]) & 0xFFFF
		for i=1,8,1 do
			if ((CRCin & 0x0001) > 0) then
				CRCin = CRCin >> 1
                CRCin = (CRCin ~ 0xA001) & 0xFFFF
			else
				CRCin = CRCin >> 1
			end	
		end
	end
    CRCData = (CRCin >> 8) & 0xFF
    CRCData = CRCData | ((CRCin & 0xFF) << 8)
	return CRCData
end


--[[
函数名: Read_DATA
功能  : 读寄存器值
参数  : ADD(设备地址),FuncCode(功能码),RegisAdd(寄存器地址)
        RegisNum(寄存器数量)
返回值: SendData(发送报文)
]]

function M40.Read_DATA(Add,FuncCode,RegisAdd,RegisNum)
	local SendData = {}
	SendData[1] = Add
	SendData[2] = FuncCode
	SendData[3] = 0x00
	SendData[4] = RegisAdd
	SendData[5] = 0x00
	SendData[6] = RegisNum
    local CRC = M40.CRC_cal(SendData)
    SendData[7] = (CRC >> 8) & 0xFF
    SendData[8] = CRC & 0xFF
	return SendData
end

--[[
函数名: Write_DATA
功能  : 单次写寄存器的值
参数  : Add(设备地址),FuncCode(功能码),RegisAdd(寄存器地址),info(数据)
返回值: SendData(命令报文)
]]

function M40.Write_DATA(Add,FuncCode,RegisAdd,info)
	local SendData = {}
	SendData[1] = Add
	SendData[2] = FuncCode
	SendData[3] = 0x00
	SendData[4] = RegisAdd
	SendData[5] = (info >> 8) & 0xFF
	SendData[6] = info & 0xFF
    local CRC = M40.CRC_cal(SendData)
    SendData[7] = (CRC >> 8) & 0xFF
    SendData[8] = CRC & 0xFF
	return SendData
end


--[[
函数名: MWrite_DATA
功能  : 连续写多个寄存器的值(实际操作就是两个寄存器,故信息字节数为四位)
参数  : Add(设备地址),FuncCode(功能码),RegisAdd(寄存器地址)
        RegisNum(寄存器数量),info(数据)
返回值: SendData(命令报文)
]]
function M40.MWrite_DATA(Add,FuncCode,RegisAdd,RegisNum,info)
	local SendData = {}
    SendData[1] = Add
    SendData[2] = FuncCode
    SendData[3] = 0x00
	SendData[4] = RegisAdd
    SendData[5] = (RegisNum >> 8) & 0xFF
    SendData[6] = RegisNum & 0xFF
    SendData[7] = 0x04
    SendData[8] = (info >> 24) & 0xFF 
    SendData[9] = (info >> 16) & 0xFF  
    SendData[10] = (info >> 8) & 0xFF
    SendData[11] =  info & 0xFF 
    local CRC = M40.CRC_cal(SendData)
    SendData[12] = (CRC >> 8) & 0xFF
    SendData[13] = CRC & 0xFF
	return SendData
end


return M40

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值