最近做一个项目,下位机是单片机,上位机程序采用c# Winform窗体应用程序。采用485通信协议,C#端采用SerialPort类实现数据收发。协议都没有问题,现在有一个情况我不能确定,想请教各位大神帮忙处理一下。
这是一个刷卡放水设备。终端有32台设备,每台设备供用户刷卡,然后进行扣费放水。由于当初采购有问题,购买的射频卡有问题,无法实现直接保存用户金额。所以采用了一个不得已的办法,就是即时通讯。具体的工作流程是这样的:
当用户刷卡时,下位机向上位机发送一个查询指令,上位机收到查询指令,根据卡号到数据库中查询该卡余额,并把结果发送给下位机设备(通过设备号进 行匹配)。下位机设备收到指令后,根据结果,如果余额够,就开始放水。放水成功就再发送一个指令给上位机。上位机收到指令后在数据库中进行扣费操作,本次 通讯过程结束。
现在这些功能都能实现,因为我之前也没搞过485通讯,我想到的不确定因素在于:如果终端有多个用户同时刷卡,我的上位机因为是一对多,所以我不 知道程序会如何反应?是有排队机制呢?还是会丢弃一些数据?或者会不会多个设备同时发送数据过来,上位机收到的数据错位了?请各位大牛不吝指教!!!没有 别的,分数多多奉上!
我的处理机制是这样的:在DataReceived事件中使用了windows消息机制,一旦收到数据,就拼接一下,然后发出消息给对应窗口。为 了功能的实现,我在主窗口中实现了窗口一打开就打开串口,然后接收下位机的指令。部分核心代码如下,请大家帮忙分析分析有没有问题:
sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
string val;
int len;
private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort)sender;
len = port.BytesToRead;
if (len > RecieveBuf.Length)
{
len = RecieveBuf.Length;
}
port.Read(RecieveBuf, 0, len);
val = "";
for (int i = 0; i < RecieveBuf.Length; i++)
{
val += RecieveBuf[i] + ",";
}
if (val.Length > 0)
{
val = val.Substring(0, val.Length - 1);
}
if (ToGetBalanceHandle != null)
{
//指令为2,状态为9代表是充值
if (RecieveBuf[1] == 2 && RecieveBuf[9] == 9)
{
SendMsgToPrg.SendMsgByToHandle(ToGetBalanceHandle, FromHandle, "1", val);
}
}
///发送交易消息给处理交易窗口.使用系统主界面作交易处理窗口,确保每条交易都可记录下来
if (ToTradeHandle != null)
{ //指令为2,状态为0代表是消费
if (RecieveBuf[1] == 2 && RecieveBuf[9] == 0)
{
SendMsgToPrg.SendMsgByToHandle(ToTradeHandle, FromHandle, "2", val);
}
}
}
以上是数据的接收
下面是接收到消费消息的处理过程:
private void DoEventByMsg(int i, String MsgValue)
{
try
{
string temp = MsgValue;
lblDebug.Text = MsgValue + "," + DateTime.Now.ToString();//这是调试,可忽略
switch (i)
{
case 2:
DataConvert.SetByteData(MsgValue.Split(','), data);//解析收到的数据
if (com.CheckValidCode(data)) //检查校验码
{
switch (data[1])//判断命令值
{
case 2://开始交易,查出余额,根据结果给下位机发送指令
lbl2.Text = "接收的查询原始值:" + temp;
if (data[9] == 0)
{
lblCardId.Text = com.GetCardId(data[2], data[3],
data[4], data[5]); //显示卡号,不作解析,直接拼出4个字节
balance = consume.GetBalanceByCardId(com.GetCardId(data[2], data[3],
data[4], data[5]));//根据卡号从数据中取出余额
size = consume.GetSizeByDeviceId(data[8]);//根据设备号取出该设备脉冲值
int flag = 1;
if (balance < 2)
{
flag = 2;//余额不足
}
com.SendData(0x06, "0", 0, data[8], flag, size, 0); //发送指令给下位机
Logger.write(LoggerType.INFO, "已接收到信息,并发送放水指令" +
",发送的值:flag=" + flag);
}
break;
case 6://消费,放水成功,扣费
lbl6.Text = "接收的消费原始值:" + temp;
lblCardId.Text = MsgValue;
if (data[9] == 1)//状态值1
{
ok = consume.Trade(com.GetCardId(data[2], data[3],
data[4], data[5]), 2, "减少", "用户消费", data[8]); //添加消费明细到数据库,并更新余额
if (ok > 0)
{
tsTrade.Text = com.GetCardId(data[2], data[3], data[4], data[5]) +
"消费成功";
}
else
{
tsTrade.Text = com.GetCardId(data[2], data[3], data[4], data[5]) +
"消费失败,请查看日志";
}
}
break;
}
}
else
{
lblInfo.Text = "接收的数据较验码不正确,未作处理";
Logger.write(LoggerType.MESSAGE, "MainForm", "DoEventByMsg",
"接收的数据较验码不正确,未作处理");
}
break;
}
}
catch (Exception ex)
{
Logger.write(LoggerType.EXCEPTION, "MainForm", "DoEventByMsg",
"处理消息时错误:" + ex.Message);
}
}
以上是主要的过程,这个过程执行没有问题。因为终端有32台设备,都是通过串行的方式连接起来,然后通过一个485端口连接到电脑。我不知道当终端32个 人同时刷卡时我的程序会怎么样?DataReceived事件是怎么工作的?我能不能依次读取到每个设备的数据?还有这种机制有没有问题?刷卡会不会延 迟?
因为之前没做过485通讯,这次是和朋友一起做的。他负责下位机编程,但他不会上位机程序。我负责上位机编程,但我不会下位机的各种内容。所以请教各位了,希望能给出示例代码。!!!
不知道理解的是否正确。
有如下问题:
1、每个刷卡设备没有发送设备编号之类的标识码?下位机(单片机)向上位机发送信号时,应该带上每个设备的标识码;
2、上位机多线程处理;上位机接收到下位机发来的信号后,一旦区分出标识码应立即分派给线程去处理;
总体思路是:根据标识码创建多线程处理;如果设备数据还会增加,应考虑线程池。
你扔的代码 没人会看的.. 最多也就是看看你所谓的"需求".
其次 不管你是多少个设备 最终都是通过一个串口线来进行数据的rx tx. 所以跟你带多少个终端 以及你用什么通讯方式是没关系的.
线中只会一个一个的跑数据.
其实 在"一个用户"刷卡的时候 执行你的sp_DataReceived (这个本身就是多线程,别听某些人动不动就分配,又是线程池的)
你会通过协议 (比如长度 比如头尾校验功能码)之类的来查询到 这个"用户".
其实这种模式 就是合法的 对的. 但是可能你会问2个用户同时发送数据的时候怎么办?
这个时候 不是你所关心的问题了..因为我在上面说过 你只有一条线 所以下位机内部自己一定有处理机制.来上行数据.
比如 你的协议是AA-11-22-33-BB 其中AA是头BB是尾. 11-22-33表卡号 5长度组成一个"合法"的数据
这个时候 因为你只有一个串口 假设下位机上行的数据是 AA-11-AA-22........
那么你一定不会知道 这个22是第一个卡号的第二位还是第二个卡号的第一位.
你肉眼看不出来.程序也看不出来..这种情况 只能靠下位机来实现.
也就是 他们发串口的时候 内部有机制. 等待发完在发 或者是其他处理办法.如果他们也是很"随意"的就发出去
你的话 也就只能"随意"的接收..这样的后果就是 数据根本没办法解析.. 所以这不是代码的问题....
485我只用过modbus,一主多从,主机轮询一问一答避免冲突
如果没什么机制,下位机随便往上发可能会有冲突吧?之前有人向我们推荐过can总线,因为可以根据优先级避免总线冲突之类的
具体怎么解决我就不清楚了,坐等老司机
非常感谢各位的回答,2楼兄弟能不能再说得详细一些。因为下位机程序也是我一个朋友写的,如果需要他做什么机制,可以论坛发帖机再说细一些,我来问问他是如何发送的 数据。我大概明白的意思是不是说,下位机在发送数据时会有一个机制,确保这一帧数据是一起发送的。多个设备同时发送的时候也不会乱,是不是这样的呢?
1,先要做网络设计,32个设备要连接32个485串口,不然,一定冲突
2,socket客户端本身就是异步的,每次接收到数据,会建立一个独立的socket实例
<br />在485网络中,只能由一个上位机主动发送信号