Openluat Air720D 4G DTU主控板 是由合宙开源社区技术专家“稀饭放姜”设计,上海合宙物联网公司推出的一款移动2G/4G 双模DTU产品。今天的学习日记里面,我将尝试使用iRTU配合另一个开源C#客户端UPWs_CS实现PC电脑上用C#客户端与iRTU双向传输数据。
基本功能:
通过开源的C#客户端(UPWs_CS)和iRTU的485端口建立透传连接,可以互相透明传输文本或者二进制数据。
实现原理
- iRTU通过UDP端口连接到远程的UPWS服务器,并发送上线消息
服务地址为 udp://box.miuser.net:7101
2)PC客户端通过UPWs_CS C#客户端 连接到UPWS服务器,并发送上线消息,连接地址同上为:
服务地址为 udp://box.miuser.net:7101
3)电脑客户端接一个USB转UART串口的连接线,再转接一个UART转RS485的连接板连接到iRTU上,并使用串口调试工具打开USB串口
4)通过电脑客户端可以和LLCOM串口调试工具建立起双向的文本命令传输,传输支持中文和英文。
硬件连接方式及IRTU配置方式请参考上一篇文章《稀饭放姜 iRTU 学习日记 (2):实现最基本的一个应用-RS485透传》
文章链接为 https://luatdoc.papapoi.com/647/
iRTU 使用 C#客户端 透传使用方法
运行文末附带的C#连接功能包的执行文件:UPWS_CS.exe
源码为文件包中的UPWS_CS.rar
输入连接地址:box.miuser.net
输入端口号:7101
输入任意10位数字作为ID
输入任意16位数字或英文字母作为密码
ID与MM设置需要与iRTU设置保持一致
点击”打开连接”,即可收到iRTU上行的心跳数据包了
发送方式可以是字符串,或者是二进制数据,通过单选框“字符发送”与“Hex发送”进行选择
举个栗子,比如Hex模式下发送的343536,等效于字符发送模式系下发送“456” 因为ASCII码表中0x34,对应字符“4”
接收的原理相同,您可以通过选择“字符显示功能”,决定以字符串或二进制方式显示接收到的数据包
例子中为了演示清晰,心跳包内容也都做了展示。 您可以通过判断包头类型方式来过滤心跳包显示,源码中有相关的内容叙述。
关键性代码展示
下面我选取部分有趣的代码,并加以简单的原理介绍,文末的文件包中提供完整的C#源码,在VS2019环境中编译使用。
打开连接部分:
private void btn_ConnectUDP_Click(object sender, EventArgs e)
{
if (!isRunning)
{
isRunning = true;
//获取服务器地址
s_server = txt_server.Text;
//获取服务器端口
s_port = txt_port.Text;
//对域名进行解析
IPHostEntry hostEntry = Dns.GetHostEntry((s_server));
//取得解析得到的IP地址
client.ep = new IPEndPoint(hostEntry.AddressList[hostEntry.AddressList.Length - 1], Convert.ToInt32(s_port));
//开始侦听
client.Listening();
//挂载接收消息的处理函数
client.Received += new UdpEventHandler(client_Received);
//判断显示模式,二进制或字符串显示
if (rbnHex.Checked)
{
isHexRead = true;
}
else
{
isHexRead = false;
}
//打开心跳发送时钟
tmr_heartbeat_Tick(sender,e);
}
}
数据包拼接:
public class package
{
public string str;
//生成一个数据包
public package(string ID = "0000000000", string MM = "0000000000000000",string content="",string type="")
{
//数据包头的模板
if (type == "")
{
str = "004932A08";
}else
{
str = "004932" + type + "08";
}
//添加ID和MM字段
str = str + ID;
str = str + MM;
//添加1234为正文引导
str = str + "1234";
//添加要发送的正文
str = str + content;
//添加数据尾05
str = str + "05";
//计算发送包总长,并转化为字符串
int len = str.Length;
string s_len = ("00" + len.ToString()).Substring(0, 4);
//用计算出来的长度替换数据头模板中的长度数据
str = s_len + str.Substring(4, str.Length - 4);
}
}
发送数据部分:
//发送数据
private void btnSend_Click(object sender, EventArgs e)
{
//根据用户选择决定是发送二进制还是文本
if (rad_AscSend.Checked) isHexWrite = false; else isHexWrite = true;
//UDP连接
if (isRunning)
{
//生成一个包
if (!isHexWrite)
{
List<byte> lbuff = new List<byte>();
lbuff = StringToBytes(txt_send.Text).ToList();
//组包
package pkg = new package(txt_ID.Text, txt_MM.Text, BytesToString(lbuff.ToArray()));
string s_out = pkg.str.ToString();
//将要发送的字符串转为字节数据
byte[] bt = Encoding.GetEncoding("GB2312").GetBytes(s_out);
//发送
client.Send(bt, client.ep);
}else
{
List<byte> lbuff = new List<byte>();
//将字符表示的16进制数转化成为字节数据
lbuff = strToToHexByte(txt_send.Text).ToList();
//将字节数据转变成字符串,并组包
package pkg = new package(txt_ID.Text, txt_MM.Text, BytesToString(lbuff.ToArray()));
string s_out = pkg.str.ToString();
//将要发送的字符串转为字节数据
byte[] bt = Encoding.GetEncoding("GB2312").GetBytes(s_out);
client.Send(bt, client.ep);
}
}
else
{
MessageBox.Show("数据传输端口未打开", "错误提示");
return;
}
if (!CheckSendData())
{
MessageBox.Show("请输入要发送的数据!", "错误提示");
return;
}
接收数据部分:
//UDP收到消息后的回调函数
void client_Received(object sender, UdpEventArgs e)
{
IPEndPoint ep = e.Remote as IPEndPoint;
string tmpReceived = Encoding.Default.GetString(e.Received);
//在主线程更新显示信息
this.BeginInvoke(new Action(() =>
{
//决定是否显示发送心跳包的回声
//if (tmpReceived.Substring(6,1)=="C")
{
string content = tmpReceived.Substring(39, tmpReceived.Length - 41);
if (isHexRead == false)
{
//显示接收的数据
txt_rsv.Text += content + "\r\n";
txt_rsv.Select(txt_rsv.TextLength, 0);
txt_rsv.ScrollToCaret();
}
else
{
//以二进制方式显示接收的数据
string RecvDataText = "";
Byte[] ReceivedData = StringToBytes(content);
for (int i = 0; i < ReceivedData.Length; i++)
{
RecvDataText += (ReceivedData[i].ToString("X2") + " ");
}
RecvDataText += "\r\n";
txt_rsv.Text += RecvDataText;
txt_rsv.Select(txt_rsv.TextLength, 0);
txt_rsv.ScrollToCaret();
}
}
//显示原始发送数据
rtb_rsv.Text = rtb_rsv.Text+ "[" +DateTime.Now.ToLongTimeString()+"]" +tmpReceived+ "\r\n" ;
}));
}
常见故障排除
1 程序无法编译,请检查VS版本是否为最新的VS2019
2 发送接收数据不全,错误,请检查ID和MM长度是否正确
3 无接收,无法送,请检查iRTU的ID和MM设置是否完全一致
参考资料
本文所提及的文档及工具资料包:
https://pan.baidu.com/s/15QICk163bI5NCB8M0SSDpA 提取码:a610
本文参考资料如下:
1 iRTU项目开源地址
https://github.com/hotdll/iRTU
2 UPWS服务器项目开源地址
https://github.com/miuser00/UdpPlugWebsocket
3 LLC能跑Lua脚本的串口调试工具项目开源地址
https://github.com/chenxuuu/llcom
技术咨询方式
合宙Luat(稀饭放姜iRTU) QQ群:952343033
本文所述iRTU系列 DTU主控板购买链接
http://m.openluat.com/product/724
谢谢您阅读本文,并祝您开发一切顺利