简介:
该设备是一款基于《ShineBlink 低代码核心模组》开发的《WiFi和RS485甲醛监测器》设备,可实现采集环境中甲醛浓度的功能,并可将数据结果显示在 OLED 屏幕,以及通过 WiFi 或 RS485 Modbus RTU 通信协议发送给远端服务器。并可通过 ShineBlink 免开发云+小程序用户无需开发云和小程序即可拥有一个小程序远程读取传感器数据。
功能:
- 支持环境甲醛浓度采集
- 支持 OLED 屏幕显示
- 支持 RS485 Modbus RTU 通信
- 支持 WiFi 通信
- 支持 TCP + Json 接入云端
- 支持 MQTT + Json 接入云端
- 支持 ShineBlink 免开发云+小程序
应用领域:
-
智能家居
-
环保监测
开源资料地址:
FlexLua SmartSensor: 本仓库包含各种4G/Lora/WiFi/RS485 Modbus远程采集传感器数据的项目。
----------------------配置信息开始----------------------
--Part1: 系统配置
SysMode = 3 --0:WiFi_TCP, 1:WiFi_Mqtt, 2:WiFi_ShineBlinkCloud, 3:NoCloud
SysWorkInterval = 1 --单位秒,系统采集传感器并发送数据的间隔周期。
--SysMyID可任意设定,用作设备的唯一标识,
--也可以用LIB_GetSysUniID()函数获取的芯片唯一ID,形如"761A6617E803F78402"
SysMyID = "Test01" -- SysMyID = LIB_GetSysUniID()
sysWiFiName = "abc123"--你的WiFi账号(SysMode=0,1,2时才有用)
sysWiFiPassword = "mima123456"--你的WiFi密码(SysMode=0,1,2时才有用)
--Part2: Tcp参数(SysMode=0时才有用)
TcpServerIp = "122.114.122.174" --需要连接的服务器IP地址
TcpServerPort = 43106 --需要连接的服务器端口号
--Part3: MQTT参数(SysMode=1时才有用)
MqttServerAddr = "mqtt.ctwing.cn" --天翼云MQTT服务器ip地址或域名
MqttServerPort = 1883 --MQTT服务器端口号
MqttClientID = "15589964DTU01" --产品ID"15589964" + 设备编号"DTU01"
MqttUserName = "ShineBlink" --建议填写为用户自己的天翼物联网平台(AIoT)用户名
MqttPassword = "lMmugH2yURmY2uJqkNby-zQHGJ67ngjMAYR6kkGQmko" --采用的一型一密,特征串
MqttSubTopic = "device_control"--订阅用,用于接收服务器下发的数据
MqttPubTopic = "$device_send" --发布用,用于向服务器发送数据
--Part4: Modbus Slave RS485 通讯配置
MbAddr = 0x01 --Modbus rtu slave本机地址, 1~250
MbBaudRate = "BAUDRATE_4800" --485总线的通信速率
--Part5: 传感器相关的配置
UI = "[1_CH2O_ppb_0_5000]" --UI必须和SensorStrFormat一致
SensorStrFormat = "\"CH2O\":%d"
SensorHeatTime = 2 --读取传感器前需等待传感器等待预热2秒
SensorStrInvalid = string.format(SensorStrFormat, 0) --默认非法值
Ch2oGlobalVal = 0 --甲醛浓度全局变量
----------------------配置信息结束----------------------
--初始化 Uart 甲醛传感器和 IIc Oled 屏幕
function IIcInit()
--设置甲醛传感器占用TX0和RX0引脚
LIB_ZE08KConfig("UART0")
--设置0.96寸oled模块占用SCL1和SDA1引脚
LIB_0_96_OledConfig("IIC1")
end
--定义通读取传感器数值函数,并通过Oled屏幕显示
function GetSensorValue()
local res,str
--查询传感器是否出数
ch2o_flag, val = LIB_ZE08KGetCH2O()
--如果传感器有新的数据产生
if ch2o_flag == 1 then
res = 1
Ch2oGlobalVal = val
--在oled的第一行显示甲醛浓度
LIB_0_96_OledPuts("1","1"," ") --清空行
LIB_0_96_OledPuts("1","1",string.format("CH2O:%d ppb", Ch2oGlobalVal))
--模拟TF卡LOG.TXT和PC串口终端打印
print(string.format("CH2O: %d", Ch2oGlobalVal))
else
res = 0
print("Sensor unconnected!")
end
if res == 1 then
str = string.format(SensorStrFormat, Ch2oGlobalVal)
else
str = SensorStrInvalid
end
return res,str
end
--支持主机通过Modbus RTU协议向本机获取传感器数据
function ModbusRtuSlaveProcess()
local sdata = {}
local RegStartAddr
local RegNum
--查询是否收到Modbus主机发来的消息
flag, data = LIB_Uart1Recv()
if flag == 1 then
--判断消息是不是发给本机,是本机的才理会
if data[1] == MbAddr then --MbAddr是Modbus本机地址
print("Rx:"..LIB_HexTabToHexStr(data))
--判断Modbus功能码
if data[2] == 0x03 then --0x03 读多个保持寄存器
--定义地址为1000的寄存器存放甲醛浓度值,整数,单位 ppb
--定义地址为1001的寄存器保留使用,存放恒定0值,
RegStartAddr = data[3] << 8 | data[4]
RegNum = data[5] << 8 | data[6]
print(string.format("StartAddr:%d,Num:%d",RegStartAddr,RegNum))
if RegStartAddr == 1000 and RegNum == 2 then
sdata[1] = data[1] --本机地址
sdata[2] = data[2] --功能码
sdata[3] = 4 --数据域字节数: 2个寄存器一共4字节
sdata[4] = Ch2oGlobalVal >> 8
sdata[5] = Ch2oGlobalVal & 0x00ff
sdata[6] = 0 >> 8
sdata[7] = 0 & 0x00ff
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[8] = CRC & 0x00ff --低位在前
sdata[9] = CRC >> 8 --高位在后
print("Tx:"..LIB_HexTabToHexStr(sdata))
--回复数据
LIB_Uart1BlockSend(sdata)
else
print("Invalid modbus addr or num")
--回复异常消息(非法数据地址)
sdata[1] = data[1] --本机地址
sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
sdata[3] = 0x02 --异常码0x02表示设备不支持此数据地址
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[4] = CRC & 0x00ff --低位在前
sdata[5] = CRC >> 8 --高位在后
LIB_Uart1BlockSend(sdata)
end
else
--回复异常消息(非法功能码)
sdata[1] = data[1] --本机地址
sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
sdata[3] = 0x01 --异常码0x01表示设备不支持此功能码
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[4] = CRC & 0x00ff --低位在前
sdata[5] = CRC >> 8 --高位在后
LIB_Uart1BlockSend(sdata)
end
end
end
end
--定义10毫秒定时器的回调函数,函数名字必须是LIB_10msTimerCallback
function LIB_10msTimerCallback()
timer_ms = timer_ms + 10
timer1_ms = timer1_ms + 10
timer_cnt = timer_cnt + 10
LIB_GpioToggle("D11") --喂硬件看门狗
--每隔0.5秒根据WiFi状态更新LED灯亮灭
if timer_ms >= 500 then
timer_ms = 0
r1,r2,r3,ApCon=LIB_GetC2KeyDbgInfo()
if ApCon == 0 then --WiFi未连上路由器
LIB_GpioWrite("D0",1) --电路班上的绿色Led灭
LIB_0_96_OledPuts("4","1"," WiFi Unconnect ")
elseif ApCon == 1 then --WiFi已连上路由器
LIB_GpioWrite("D0",0) --电路板上的绿色Led亮
LIB_0_96_OledPuts("4","1"," WiFi Connected ")
else
LIB_GpioWrite("D0",1)
LIB_0_96_OledPuts("4","1"," WiFi Unconnect ")
end
end
--Modbus通信
ModbusRtuSlaveProcess()
end
--延时N秒函数
function DelayS(N)
timer1_ms = 0
target_ms = N*1000
while timer1_ms <= target_ms do
end
end
---------------------系统初始化开始-----------------------
--LIB_SystemLogEnable() --需要看详细log.txt日志时才用
--配置D0为普通GPIO输出,控制L绿色ED
LIB_GpioOutputConfig("D0","STANDARD")
LIB_GpioWrite("D0",1) --一上电Led灯默认不亮
--配置D11为普通输出,控制看门狗
LIB_GpioOutputConfig("D11","STANDARD")
--初始化IIc传感器和Oled屏幕
IIcInit()
--配置Uart1开始工作,并且D8引脚作为自动切换485收发芯片的引脚
--当用LIB_Uart1BlockSend发送时,D8会自动变成低电平,发送完后会立刻变成高电平
LIB_Uart1Rs485Config(MbBaudRate,"D8")
if SysMode == 0 then --WiFi_TCP
--设置内部WiFi以TCP Client模式工作,配置服务器地址,端口号,心跳包间隔时间0秒(不使用心跳机制)。
LIB_IntWifiTcpConfig(sysWiFiName,sysWiFiPassword,TcpServerIp,TcpServerPort,0)
elseif SysMode == 1 then --WiFi Mqtt
--初始化C2芯片内部的WIFI以MQTT Client方式工作,并配置其详细工作参数,具体参数介绍可参考API文档
LIB_MQTTC2Config(sysWiFiName,sysWiFiPassword,MqttServerAddr,MqttServerPort,0,MqttClientID,MqttUserName,MqttPassword,60,MqttSubTopic,"QOS0")
elseif SysMode == 2 then --WiFi ShineBlink Cloud
--设置内部WiFi连接ShineBlink Clould云
LIB_CloudConfig("S0", "WIFI_C2", 0, "SBK_01", UI, sysWiFiName, sysWiFiPassword)
end
--使能系统10毫秒定时器开始工作
timer_ms = 0
timer1_ms = 0
timer_cnt = 0
LIB_10msTimerConfig("ENABLE")
---------------------系统初始化结束-----------------------
--开始大循环
while(GC(1) == true)
do
--------------步骤(一)通过RS485 Modbus RTU协议读取传感器的值-----------------
DelayS(SensorHeatTime) --读取传感器前的预热时间(秒)
SensorStr = nil
result,str = GetSensorValue()
if result == 1 then
--获取传感器json对象字符串
SensorStr = str
end
--------------步骤(二)构造需要发送的Json字符串---------------------------
JsonStr = string.format("{\"Uid\":\"%s\"", SysMyID)
if SensorStr ~= nil then
JsonStr = JsonStr..","..SensorStr
JsonStrForShineBlinkCloud = "{"..SensorStr.."}"
else
JsonStrForShineBlinkCloud = "{"..SensorStrInvalid.."}"
end
JsonStr = JsonStr.."}"
--最终合成JsonStr字符串形如:
--{"Uid":"Test01","Temperature":25.2, "Humidity":76.7}
print("JsonStr:"..JsonStr)
print("SbcJsonStr:"..JsonStrForShineBlinkCloud)
--------------步骤(三)通过WiFi向远端服务器发送数据-----------------
Connect = 0
--前三种工作模式都需要判断WiFi建立连接后才能发送
if SysMode <= 2 then
timer_cnt = 0
while(timer_cnt < 20000)--最多等待20秒
do
r1,r2,r3,ApCon=LIB_GetC2KeyDbgInfo()
if ApCon == 1 then
timer_cnt = 20000 --既然可以发送wifi数据了,就赶紧退出循环
Connect = 1
end
end
else
Connect = 1
end
if Connect == 1 then
if SysMode == 0 then --wifi TCP 发送Json传感器数据
LIB_IntWifiTcpSend(LIB_StrToTab(JsonStr))
elseif SysMode == 1 then --wifi Mqtt 发送Json传感器数据
LIB_MqttC2SendPub("QOS0", MqttPubTopic, JsonStr)
elseif SysMode == 2 then --wifi 向ShineBlink云发送Json传感器数据
LIB_CloudSend(JsonStrForShineBlinkCloud)
end
end
--------------步骤(四)延时SysWorkInterval秒后重新执行本循环-----------------
DelayS(SysWorkInterval)
end