采用485通信协议,C#端采用SerialPort类实现数据收发C#与多设备通过485通讯的问题

最近做一个项目,下位机是单片机,上位机程序采用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网络中,只能由一个上位机主动发送信号

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
C#编程中,与三菱PLC通过MC协议进行通信可以通过使用串口通信来实现。以下是一个简单的示例代码,演示了如何使用C#与三菱PLC进行通信: ```csharp using System; using System.IO.Ports; namespace MitsubishiPLCCommunication { class Program { static SerialPort serialPort; static void Main(string[] args) { // 设置串口参数 serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One); serialPort.Open(); // 发送读取数据的命令 byte[] readCommand = { 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0xD5, 0xCA }; serialPort.Write(readCommand, 0, readCommand.Length); // 接收返回的数据 byte[] buffer = new byte[serialPort.BytesToRead]; serialPort.Read(buffer, 0, buffer.Length); // 处理接收到的数据 // TODO: 解析返回的数据 // 关闭串口 serialPort.Close(); } } } ``` 上述代码中,我们首先创建一个`SerialPort`对象,设置串口参数,包括串口号、波特率、校验位、数据位和停止位等。然后,我们发送一个读取数据的命令(示例中为读取一个寄存器的值),通过`serialPort.Write`方法将命令发送给PLC。 接下来,我们通过`serialPort.Read`方法读取PLC返回的数据,并将数据存储在一个缓冲区中。最后,我们可以根据需要解析和处理接收到的数据。 需要注意的是,上述代码中使用的是串口通信方式,你需要根据实际情况修改串口号、波特率和其他参数。此外,还需要根据MC协议的规范编写命令和解析数据的逻辑。 这只是一个简单的示例,实际应用中可能涉及更复杂的通信操作和数据处理。你可以根据自己的需求进行扩展和修改。另外,你可能需要参考三菱电气公司提供的相关文档来了解MC协议的具体规范和命令格式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值