zoukankan      html  css  js  c++  java
  • 串口通信

    using system.IO.Ports;

    SerialPort类

    1.获取机器的所有串口

    /*获得设备的所有串口*/
    //类SerialPort的静态方法GetPortNames()返回一台设备所有的串口名字
    //如果机器无串口,返回一个空的字符串数组的引用【不是null】
    string[] DevideAllports = SerialPort.GetPortNames();
    if(DevideAllports.Length == 0) {
        Console.WriteLine("本机无串口");
    }
    else {
        foreach (var item in DevideAllports) {
            Console.WriteLine(item);
        }
    }

    2.操纵设备的一个串口

    两台设备之间实现串口通信,二者使用的串口的(1)数据位 (2)停止位  (3)奇偶校验方式 (4)波特率 必须相同。

    //1.创建一个实例
    SerialPort DeciveSp = new SerialPort();
    //2.绑定串口
    DeciveSp.PortName = "COM1";
    //3.设置通信参数
    DeciveSp.DataBits = 8;//设置数据位
    DeciveSp.StopBits = StopBits.One;//设置停止位
    DeciveSp.BaudRate = 9600;//设置波特率
    DeciveSp.Parity = Parity.Even;//设置奇偶校验方式

    3.打开和关闭一个串口

    /*打开串口*/
    if (!DeciveSp.IsOpen) {
        DeciveSp.Open();
    }
    /*关闭串口*/
    if (DeciveSp.IsOpen) {
        DeciveSp.Close();
    }

    4.发送数据

    public void Write (string str);
    public void Write (byte[] buffer, int offset, int count);
    public void Write (char[] buffer, int offset, int count);
    public void WriteLine (string str);

    5.接收数据

    public delegate void SerialDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e);
    
    public event SerialDataReceivedEventHandler DataReceived;
    C#中SerialPort类中DataReceived事件,当机器收到数据时会激发中断处理程序,在辅助线程上引发 DataReceived 事件;
    device.ReceivedBytesThreshold = 1;表示机器串口硬件缓存收到一个字节,就触发DataReceived事件,但是C#并不能保证接收到的每一个字节都会触发一次DataReceived事件。
    所以:
    (1)触发一次,可以使用BytesToRead循环获取缓冲区内接收到的所有数据。
    (2)由于Read()是在辅助线程上执行的,不是在主线程上执行的,所以在DataRecived事件绑定的方法中,必须使用Control.Invoke()方法修改UI;

    应用场景一:通信双方发送的消息不长(低于1024 bits,约512个字符),各个命令的执行必须是互斥的,一发一答的过程不能被其他命令中断。

    class MySerialPort {
        private SerialPort device = new SerialPort();
        private AutoResetEvent waitRsp = new AutoResetEvent(false);
        private object locker = new object(); //用于同步触发串口接收数据的函数
        byte[] bufferReceived = null;//接收缓存
        public MySerialPort() {
            device.ReadBufferSize = 1024;//设置接收缓存的大小,一般容纳下最长消息即可
            device.DataReceived += new SerialDataReceivedEventHandler(device_ReceiveData);
        }
        private void device_ReceiveData(object sender,SerialDataReceivedEventArgs e) {
            if(device.BytesToRead > 0) {
                lock (locker) {
                    if(device.BytesToRead > 0) {
                        while (device.BytesToRead > 0) {
                            bufferReceived = new byte[device.BytesToRead];
                            device.Read(bufferReceived, 0, device.BytesToRead);
                        }
                        waitRsp.Set();  //告诉处理命令的方法,已经收到回复信息,请继续往下执行
                    }
                }
            }
        }
    }

    串口编程注意事项:

    (1)DataReceived事件中,最高效的做法是指缓存数据,然后异步的去分析数据。但是,这样较复杂,在效率要求不是很高的情况下(大多数情况),可以在DataReceived事件中缓存数据后,立刻进行数据完整性检查,有效性检查,分析数据,以及更新界面。但这么做有一个隐患,底层串口操作的效率依赖于数据分析和界面更新,任何一个环节频繁耗时过长,都会造成数据的堆积。文章只假设都不拖时间的情况。

    (2)一答一回的指令可以使用AutoResetEvent在发完数据后,在DataReceived事件中set()来同步

    (3)相互独立的指令交互过程,可以使用Interlocked锁进行同步,这样在用户多个线程调用指令时,也不会发生错误。

    (4)发送指令不能太快,否则可能造成设备处理不及,可以在发送前,判断一下(当前时间 - 上一次收到数据的时间)是否满足设备的响应时长。

    (5)考虑重发问题。

  • 相关阅读:
    OOP、DI、IOC的情爱恩仇录
    NuGet:添加EntityFramework
    DataGrid之DataGridComboBoxColumn,DataGridCheckBoxColumn,DataGridHyperlinkColumn,DataGridTextColumn
    JohnSon:动态创建模块选项卡
    maf实例
    MVVM理解之逐步重构成为MVVM模式,比MVC的独到之处
    我学Unity系列1:Unity和Mef的比较
    微软一站式代码资料
    匿名方法,泛型委托,Lambda表达式
    关于JS表单验证(转)
  • 原文地址:https://www.cnblogs.com/maoshuyi/p/10148827.html
Copyright © 2011-2022 走看看