跳到主要内容

4G远程模拟量采集

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

ShineBlink C2M模组支持四路AD电压采集(A0~A3),在C2 DevKit开发板上A0用于模拟旋钮,A1用于光敏传感器,A2和A3引脚则通过外部扩展排针引出。

注意:ShineBlink C2 的AD电压采集器虽然能够最大输入3.3V电压,但高于2.6V的电压都将作为2.6V,今后在设计中需要注意到。

一、实现的功能描述

在开发板上通过OLED屏幕显示A0~A3这四路电压值,并将四路电压值每隔3秒通过TCP连接上传给远程服务器。

本例程的通信是基于TCP方式,如果希望改成UDP、MQTT方式,或者更多详细细节,可以参考前面的

《4G通信(TCP/UDP/MQTT)》教程。

二、本实验教学目的

掌握基于ShineBlink的:

  • 4G TCP通信

  • 四路AD电压采集(A0~A3)

  • OLED屏幕显示(OLED占用SCL1和SDA1引脚)

三、本实验涉及的模块

4G模块,A0~A3、以及OLED屏幕在开发板上的位置如下:

C2DevKit

四、完整源代码

源码(ML302,已停产)

UID = LIB_GetSysUniID() --也可以自己定义,比如UID = "001"
--配置USB接口为USB CDC虚拟串口模式,这样print打印就可以在电脑串口调试终端查看了
LIB_UsbConfig("CDC")
--配置绿色LED的GPIO为输出(D9)
LIB_GpioOutputConfig("D9","STANDARD")
--配置A0-A3这四个通道同时开始工作,当每个通道采集满20个点时缓存满,每个点的采集时间间隔为10ms
LIB_ADConfig(20,10000)
--设置0.96寸oled模块占用SCL1和SDA1引脚
LIB_0_96_OledConfig("IIC1")
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
A0V = 0.00
A1V = 0.00
A2V = 0.00
A3V = 0.00
--开始大循环
while(GC(1) == true)
do
--每隔3秒向服务器上传一串json字符串,包含C2M自身唯一ID,以及4路电压值
if timer0 >= 3000 then
timer0 = 0
json_str = string.format("{\"id\":%s, \"A0\":%.2f, \"A1\":%.2f, \"A2\":%.2f, \"A3\":%.2f}", UID, A0V, A1V, A2V, A3V)
--TCP发送时需要将字符串转换成table数组才能发送
LIB_Cat1TcpUdpSend(LIB_StrToTab(json_str))
end
--查询是否收到远端tcp server下发的数据,如果收到就打印出数据具体内容用于调试
recv_flag,recv_tab = LIB_Cat1TcpUdpRecv()
if recv_flag == 1 then
print(LIB_TabToStr(recv_tab))
end
--每隔一秒读取一次4G状态信息
if timer1 >= 1000 then
timer1 = 0
State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
if State == "Connected" then
LIB_GpioWrite("D9", 0) --4G模块已和服务器建立连接,绿灯亮
else
LIB_GpioWrite("D9", 1) --4G模块未和服务器建立连接,绿灯灭
end
end
--系统每200ms自动采集满A0通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A0")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A0通道(模拟旋钮输出)的电压
LIB_0_96_OledPuts("1","1",string.format("A0:%.2fv", VOL))
A0V = VOL
end
--系统每200ms自动采集满A1通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A1")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A1通道(光敏感应传感器)的电压
LIB_0_96_OledPuts("2","1",string.format("A1:%.2fv", VOL))
A1V = VOL
end
--系统每200ms自动采集满A2通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A2")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A2通道(外部扩展排针引出)的电压
LIB_0_96_OledPuts("3","1",string.format("A2:%.2fv", VOL))
A2V = VOL
end
--系统每200ms自动采集满A3通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A3")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A3通道(外部扩展排针引出)的电压
LIB_0_96_OledPuts("4","1",string.format("A3:%.2fv", VOL))
A3V = VOL
end
end

源码(EC800,推荐)

UID = LIB_GetSysUniID() --也可以自己定义,比如UID = "001"
--配置USB接口为USB CDC虚拟串口模式,这样print打印就可以在电脑串口调试终端查看了
LIB_UsbConfig("CDC")
--配置绿色LED的GPIO为输出(D9)
LIB_GpioOutputConfig("D9","STANDARD")
--配置A0-A3这四个通道同时开始工作,当每个通道采集满20个点时缓存满,每个点的采集时间间隔为10ms
LIB_ADConfig(20,10000)
--设置0.96寸oled模块占用SCL1和SDA1引脚
LIB_0_96_OledConfig("IIC1")
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
A0V = 0.00
A1V = 0.00
A2V = 0.00
A3V = 0.00
--开始大循环
while(GC(1) == true)
do
--每隔3秒向服务器上传一串json字符串,包含C2M自身唯一ID,以及4路电压值
if timer0 >= 3000 then
timer0 = 0
json_str = string.format("{\"id\":%s, \"A0\":%.2f, \"A1\":%.2f, \"A2\":%.2f, \"A3\":%.2f}", UID, A0V, A1V, A2V, A3V)
--TCP发送时需要将字符串转换成table数组才能发送
LIB_Cat1TcpUdpEC800Send(LIB_StrToTab(json_str))
end
--查询是否收到远端tcp server下发的数据,如果收到就打印出数据具体内容用于调试
recv_flag,recv_tab = LIB_Cat1TcpUdpEC800Recv()
if recv_flag == 1 then
print(LIB_TabToStr(recv_tab))
end
--每隔一秒读取一次4G状态信息
if timer1 >= 1000 then
timer1 = 0
State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
if State == "Connected" then
LIB_GpioWrite("D9", 0) --4G模块已和服务器建立连接,绿灯亮
else
LIB_GpioWrite("D9", 1) --4G模块未和服务器建立连接,绿灯灭
end
end
--系统每200ms自动采集满A0通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A0")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A0通道(模拟旋钮输出)的电压
LIB_0_96_OledPuts("1","1",string.format("A0:%.2fv", VOL))
A0V = VOL
end
--系统每200ms自动采集满A1通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A1")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A1通道(光敏感应传感器)的电压
LIB_0_96_OledPuts("2","1",string.format("A1:%.2fv", VOL))
A1V = VOL
end
--系统每200ms自动采集满A2通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A2")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A2通道(外部扩展排针引出)的电压
LIB_0_96_OledPuts("3","1",string.format("A2:%.2fv", VOL))
A2V = VOL
end
--系统每200ms自动采集满A3通道的20个点电压
An_full_flag, An_tab = LIB_ADCheckBufFull("A3")
if An_full_flag == 1 then
SUM = 0
for i = 1, #An_tab do --此处#An_tab的值是20,表示An_tab表内的元素个数
SUM = SUM + An_tab[i]
end
AVER = SUM / #An_tab
VOL=AVER*3.6/4096.0--求20个点的平均值以及对应的实际电压值
--OLED屏幕显示A3通道(外部扩展排针引出)的电压
LIB_0_96_OledPuts("4","1",string.format("A3:%.2fv", VOL))
A3V = VOL
end
end

**注意:**上面代码中每隔3秒中将开发板自身的设备 UID 发送给TCP服务器的用意是帮助服务器识别当前开发板的身份,因为在很多TCP/UDP通信场景中是无法通过IP地址来识别Client身份的。

  • UID可以通过LIB_GetSysUniID()函数获取到每个C2M模块的唯一UID用来帮助服务器识别硬件的身份,这样可以保证设备身份的唯一性:
--以下代码会给 UID 赋予一个9字节的唯一ID字符串,例如"0AB95E15E803F78402"
UID= LIB_GetSysUniID()
  • UID也可以由开发者自己定义,如果设备数量不多的话
UID = "001"

开发者可以通过在产品量产的过程中通过UART串口将UID批量打印出来贴在产品外壳上面,shineblink.com官网技术文档中有如何通过热敏打印机批量自动化打印每个设备唯一二维码标签的教程,感兴趣请查阅。

五、实验现象

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

所以利用这个服务器,我们可以测试TCP数据是否发送到服务器,并接收服务器原封不动返回的数据,再通过开发板的USB虚拟串口,我们就可以在电脑端的串口调试助手上看到服务区回传的数据了(和我们发送给服务器的数据一模一样)。

将代码复制到开发板的虚拟TF卡中开始运行后,我们就可以在OLED屏幕显示当前的四路电压值。然后我们在电脑端打开《串口调试助手》工具,就可以看到服务器回传的数据了,如下图:

pic1

pic2