跳到主要内容

4G通信(TCP/UDP/MQTT)

注意:本例程使用的 4G 模块为 SB-C17(EC800 4G 模块),ML302 4G 模块由于停产这里并不推荐使用。

C2M模块本身不带4G功能,需要在开发板的4G双排针插槽上插一个外扩的4G模块。本教程提供了三个范例基于4G模块,分别示范了基于4G Cat1的TCP,UDP,MQTT的编程方法。开发者在开发这三种通信的时候可以参考下面提供的范例加以修改即可。 4G通信的代码和WiFi非常类似,所以开发者在看下面的代码会发现和之前看过的WiFi代码很相似。

C2DevKit

[toc]

一、TCP通信范例

ShineBlink C2基于4G模块的TCP开发极为简单,只涉及4个API:

  • LIB_Cat1TcpUdpConfig
  • LIB_Cat1TcpUdpRecv
  • LIB_Cat1TcpUdpSend
  • LIB_Cat1StatusQuery

以下代码实现了TCP Client方式和远端server服务器建立TCP通信。每隔3秒向服务器发送一包数据。并一直监测服务器是否下发数据,如果收到数据则开发板上的黄色LED灯闪烁一下,且如果数据合法绿色LED灯闪烁一下。并且一直监测4G模块是否入网,如果正常入网则红灯亮,否则红灯灭。

源码(ML302,已停产)

server_addr = "47.92.146.210" --这里也可以写服务器域名,比如"abc.com"等
server_port = 8888
--初始化4G TCP模式
LIB_Cat1TcpUdpConfig("UART0","D5","HIGH","D6","HIGH",server_addr,server_port,0,"TCP","NO_GPS")
--使能10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")
timer0 = 0
timer1 = 0
--定义10毫秒定时器回调函数
function LIB_10msTimerCallback()
timer0 = timer0 + 10
timer1 = timer1 + 10
end
--配置红色LED的GPIO为输出(D0)
LIB_GpioOutputConfig("D0","STANDARD")
--配置黄色LED的GPIO为输出(D8)
LIB_GpioOutputConfig("D8","STANDARD")
--配置绿色LED的GPIO为输出(D9)
LIB_GpioOutputConfig("D9","STANDARD")
--开始大循环
while(GC(1) == true)
do
--示例1:接收
--查询是否收到远端tcp server下发的数据
recv_flag,recv_tab = LIB_Cat1TcpUdpRecv()
if recv_flag == 1 then
--只要收到数据就闪烁一下黄色LED
LIB_GpioToggle("D8")
--判断接收到的数据是否合法,合法就闪烁一下绿色LED
--如果收到的数据包第1个字节为0x01,第5个字节为0x05,且数据包个数为5个就合法
if recv_tab[1] == 0x01 and recv_tab[5] == 0x05 and #recv_tab == 5 then
LIB_GpioToggle("D9")
end
end

--示例2:发送
--每隔三秒向服务器发送一包5字节数据,比如01 02 AA FF 05
if timer0 >= 3000 then
timer0 = 0
SendTab = {}
SendTab[1] = 0x01
SendTab[2] = 0x02
SendTab[3] = 0xAA
SendTab[4] = 0xFF
SendTab[5] = 0x05
--发送数据
LIB_Cat1TcpUdpSend(SendTab)
end

--示例3:4G状态判断
--每隔一秒读取一次4G状态信息
if timer1 >= 1000 then
timer1 = 0
State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
if State == "Connected" then
LIB_GpioWrite("D0", 0) --4G模块已和服务器建立连接,红灯亮
else
LIB_GpioWrite("D0", 1) --4G模块未和服务器建立连接,红灯灭
end
end
end

源码(EC800,推荐)

server_addr = "47.92.146.210" --这里也可以写服务器域名,比如"abc.com"等
server_port = 8888
--初始化4G TCP模式
LIB_Cat1TcpUdpEC800Config("UART0","D5","HIGH","D6","HIGH",server_addr,server_port,0,"TCP","NO_GPS")
--使能10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")
timer0 = 0
timer1 = 0
--定义10毫秒定时器回调函数
function LIB_10msTimerCallback()
timer0 = timer0 + 10
timer1 = timer1 + 10
end
--配置红色LED的GPIO为输出(D0)
LIB_GpioOutputConfig("D0","STANDARD")
--配置黄色LED的GPIO为输出(D8)
LIB_GpioOutputConfig("D8","STANDARD")
--配置绿色LED的GPIO为输出(D9)
LIB_GpioOutputConfig("D9","STANDARD")
--开始大循环
while(GC(1) == true)
do
--示例1:接收
--查询是否收到远端tcp server下发的数据
recv_flag,recv_tab = LIB_Cat1TcpUdpEC800Recv()
if recv_flag == 1 then
--只要收到数据就闪烁一下黄色LED
LIB_GpioToggle("D8")
--判断接收到的数据是否合法,合法就闪烁一下绿色LED
--如果收到的数据包第1个字节为0x01,第5个字节为0x05,且数据包个数为5个就合法
if recv_tab[1] == 0x01 and recv_tab[5] == 0x05 and #recv_tab == 5 then
LIB_GpioToggle("D9")
end
end

--示例2:发送
--每隔三秒向服务器发送一包5字节数据,比如01 02 AA FF 05
if timer0 >= 3000 then
timer0 = 0
SendTab = {}
SendTab[1] = 0x01
SendTab[2] = 0x02
SendTab[3] = 0xAA
SendTab[4] = 0xFF
SendTab[5] = 0x05
--发送数据
LIB_Cat1TcpUdpEC800Send(SendTab)
end

--示例3:4G状态判断
--每隔一秒读取一次4G状态信息
if timer1 >= 1000 then
timer1 = 0
State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
if State == "Connected" then
LIB_GpioWrite("D0", 0) --4G模块已和服务器建立连接,红灯亮
else
LIB_GpioWrite("D0", 1) --4G模块未和服务器建立连接,红灯灭
end
end
end

关于上面代码中 Config 函数初始化函数的解释:

--设置Cat1模块占用TX0、RX0、D5、D6引脚
--tcp服务器IP:"47.92.146.210" 端口号:8888
--心跳包间隔时间0秒(不使用心跳机制)。如果需要使用请在ApiDoc文档中查阅关于LIB_Cat1TcpUdpConfig函数的p8参数详细介绍
--TCP Client模式,如果要使用UDP,将"TCP"改成"UDP"即可
--不开启GPS功能,如果需要使用请在ApiDoc文档中查阅关于LIB_Cat1TcpUdpConfig函数的p10参数详细介绍
LIB_Cat1TcpUdpConfig("UART0","D5","HIGH","D6","HIGH",server_addr,server_port,0,"TCP","NO_GPS")

注意1:上面的代码用到了开发板上的红色LED来指示4G是否连上服务器,所以别忘了将开发板上的跳线帽跳至“LED”。

注意2:上面代码中用到的"47.92.146.210"的8888端口是一个实际存在的TCP测试服务器,向它发送什么就会返回什么,开发者如果没有自己的TCP服务器的话可以用它作为测试,但这里不保证该服务器一直能用。

二、UDP通信范例

UDP通信和TCP通信代码几乎一模一样,开发者只需将上面的TCP范例代码中 Config 函数中的参数"TCP"改成"UDP"即可。

由于没有现成的UDP测试服务器,所以需要开发者自己想办法搭建一个UDP远程测试服务器。

三、MQTT通信范例

基于ShineBlink C2的MQTT开发极为简单,只涉及4个API库函数:

ML307(已停产,不推荐):

  • LIB_Cat1MqttML302Config
  • LIB_Cat1MqttML302RecvSub
  • LIB_Cat1MqttML302SendPub
  • LIB_Cat1StatusQuery

EC800(推荐):

  • LIB_Cat1MqttEC800Config
  • LIB_Cat1MqttEC800RecvSub
  • LIB_Cat1MqttEC800SendPub
  • LIB_Cat1StatusQuery

注意:

以下代码使用了 ML307 的 API 库函数代码作为演示,开发者只需换成 EC800 的函数即可。


本例程里的代码示范了如何以MQTT方式接入中国移动OneNet云平台,并和云平台实现数据收发交互。以OneNet接入作为参考,开发者完全可以参考下面范例代码并加以修改后即可接入自己想接入的MQTT服务端。

对于接入任何MQTT服务端来说不管是OneNet、阿里云、华为云还是您自己的MQTT服务端,接入的时候您需要考虑的工作都基本类似,平台的地址和端口号,如何按照平台的规则来满足MQTT接入时候的三要素,以及和服务端进行数据收发涉及到的接收topic发送topic

(1)平台地址和端口号

--MQTT服务器地址(适用于ONE NET平台)
server_addr = "183.230.40.96" --也可以写成"mqtts.heclouds.com"
server_port = 1883

(2)三要素:

--MQTT 连接参数(适用于ONE NET平台)
mqtt_con_clientID = "TestDevice001"
mqtt_con_username = "353255"
mqtt_con_password = "version=2018-10-31&res=products%2F353255%2Fdevices%2FTestDevice001&et=1893427200&method=md5&sign=%2F5RJwGwytPWvVDB04K7rnw%3D%3D"

(3)接收topic和发送topic

--MQTT topic相关参数(适用于ONE NET平台)
mqtt_sub_topic = "$sys/353255/TestDevice001/cmd/request/+"--订阅,用来接收服务器数据
mqtt_pub_topic = "$sys/353255/TestDevice001/dp/post/json" --发布,用来向服务器发送数据

MQTT接入OneNet完整示范代码

以下代码是按照OneNet平台接入规则实现,并每隔5秒向平台发送一串包含虚拟温度湿度数据的json字符串,同时一直监测平台是否下发json cmd字符串,如果收到平台下发的json cmd字符串则解析出关心的数据比如此例中的"LED"控制指令。

--MQTT服务器地址(适用于ONE NET平台)
server_addr = "mqtts.heclouds.com" --中移物联网MQTT接入服务域名/ip地址
server_port = 1883
--MQTT 连接参数(适用于ONE NET平台)
mqtt_con_clientID = "TestDevice002"
mqtt_con_username = "353255"
mqtt_con_password = "version=2018-10-31&res=products%2F353255%2Fdevices%2FTestDevice002&et=1893427200&method=md5&sign=VNzqoi1o%2BSaqUOogFzUb6Q%3D%3D"
--MQTT topic相关参数(适用于ONE NET平台)
mqtt_sub_topic = "$sys/353255/TestDevice002/cmd/request/+"--订阅用
mqtt_pub_topic = "$sys/353255/TestDevice002/dp/post/json" --发布用
--设置m5311 NB模块占用TX0、RX0、D5、D6引脚,MQTT模式,KeepAlive周期180秒,不开启GPS功能
LIB_Cat1MqttML302Config("UART0","D5","HIGH","D6","HIGH",server_addr,server_port,mqtt_con_clientID,mqtt_con_username,mqtt_con_password,180,mqtt_sub_topic,"QOS0","NO_GPS")
--配置D9为普通输出,控制LED2
LIB_GpioOutputConfig("D9","STANDARD")
--使能系统10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")
--变量初始化
cnt_10ms = 0--作为计时器用
cnt1_10ms = 0--作为计时器用
pub_id = 0
temprature = 0.00--用该变量模拟温度数据
humidity = 0.00--用该变量模拟湿度数据
--定义10ms中断回调函数
function LIB_10msTimerCallback()
cnt_10ms = cnt_10ms + 1
cnt1_10ms = cnt1_10ms + 1
temprature = temprature + 0.1--模拟温度动态变化
if temprature >= 60 then
temprature = 0
end
humidity = humidity + 0.2--模拟湿度动态变化
if humidity >= 100 then
humidity = 0
end
end
--开始大循环
while(GC(1) == true)
do
--查询是否收到服务器下发的cmd数据(已订阅的"$sys/353255/TestDevice002/cmd/request/+")
recv_flag,topic,data = LIB_Cat1MqttML302RecvSub()
if recv_flag == 1 then
--根据json路径"$.LED"解析服务器下发的json文本,并执行LED亮灭操作
Json_Val = LIB_JsonParse(data, "$.LED")
--服务器下发的是"{"LED":0}"
if Json_Val == "0" then
LIB_GpioWrite("D9",1) --LED2灭
--服务器下发的是"{"LED":1}"
elseif Json_Val == "1" then
LIB_GpioWrite("D9",0) --LED2亮
--服务器下发的是"{"LED":2}"
elseif Json_Val == "2" then
LIB_GpioToggle("D9") --LED2亮灭切换
else
LIB_GpioWrite("D9",1) --LED2灭
end
--根据收到的topic中的cmdid应答服务器,
--将收到的topic中"request"替换成"response"后作为应答topic发给服务器
topic = string.gsub(topic,"request","response")
--应答服务器的内容可自定义,这里为"Got it!"
LIB_Cat1MqttML302SendPub("QOS0", topic, "Got it!")
end
--每5秒发送温湿度度数据给server
if cnt_10ms >= 500 then
cnt_10ms = 0
pub_id = pub_id + 1
--以下请不要看花眼了,这也是按照ML302模组的要求来做的(双引号前面要加转义符号),实际发送字符串例子如下:
--"{\"id\":44, \"dp\":{\"temperatrue\":[{\"v\": 36.40,}], \"humidity\":[{\"v\":91.40,}]}}"
json_str = string.format("{\\\"id\\\":%d, \\\"dp\\\":{\\\"temperatrue\\\":[{\\\"v\\\": %.2f,}], \\\"humidity\\\":[{\\\"v\\\":%.2f,}]}}", pub_id, temprature, humidity)
--注意json_str的总长度不要超过150字节
LIB_Cat1MqttML302SendPub("QOS0", mqtt_pub_topic, json_str) --publish
end
--每12秒打印一次4G模组信息(包含sim卡)
--注意:这里只是为了演示如何获取模组信息,实际应用中您可以根据您的需求查询即可,不需要一直查询
if cnt1_10ms >= 1200 then --12000ms
cnt1_10ms = 0
State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
print(string.format("module State: %s", State))
print(string.format("module IMSI: %s", IMSI))
print(string.format("module ICCID: %s", ICCID))
print(string.format("module CSQ: %d ", CSQ))
end
end

接入OneNet之后可以在数据看板中看到我们的温度和湿度数据如下图:

result3

也可以通过后台向开发板发送json命令字符串,控制开发板灯的亮灭:

result6