吵吵   2014-06-14  阅读:7,444

老实讲,自从用上了c#之后,就再也没有心思去折腾delphi了,从开发速度来讲,c#要用的顺手的多,最起码两点:不用在开头写函数声明,局部变量也不用在函数头声明。抛弃这些东西,强大的LIST链表用的是相当的爽。

前些年觉得,技术进步太快,你只需要专注你自己的东西就ok了,现在看来倒是未必了。开发语言是一种工具,人家用的是大炮了,你还在用手枪,迟早就是躲不开被淘汰的命运。

抛弃存量,寻找增量,是在互联网时代存活下去的定律。编程语言在进化,人也在进化。

com口的通信,要不就用windows自带的API去写,然后用多线程进行异步分装,这个可以参考:

多线程串口异步通信类TSerialPort

在c#中,我们终于发现事情变得非常简单,用serialport控件就行了,在窗口上,拉上这个控件,然后写上DataReceived事件就行了,具体可以参考微软的例子:

using System;
using System.IO.Ports;

class PortDataReceived
{
    public static void Main()
    {
        SerialPort mySerialPort = new SerialPort("COM1");

        mySerialPort.BaudRate = 9600;
        mySerialPort.Parity = Parity.None;
        mySerialPort.StopBits = StopBits.One;
        mySerialPort.DataBits = 8;
        mySerialPort.Handshake = Handshake.None;

        mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

        mySerialPort.Open();

        Console.WriteLine("Press any key to continue...");
        Console.WriteLine();
        Console.ReadKey();
        mySerialPort.Close();
    }

    private static void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        string indata = sp.ReadExisting();
        Console.WriteLine("Data Received:");
        Console.Write(indata);
    }
}

上面的例子是控制台程序的,如果我们做的是winform呢?在DataReceived事件中直接将数据输入到文本框是行不通的,因为UI是一个独立的线程,要跨线程操作,需要用到委托:

public delegate void MyInvoke(string str);

private void AddReceiveText(string str)
        {
            if (tbReceive.InvokeRequired)
            {
                MyInvoke _myInvoke = new MyInvoke(AddReceiveText);
                this.Invoke(_myInvoke, new object[] { str });
            }
            else
            {
                if (this.tbReceive.Text != "")
                {

                    this.tbReceive.Text = this.tbReceive.Text + "\r\n" + str;
                }
                else
                {
                    this.tbReceive.Text = str;
                }
            }
        }

从这里就可以看得出来,微软封装的serialport异步类,依旧是使用多线程来封装的,至于原理么,大概应该和前文我写的那篇文章差不多。

编码问题

原来困扰我们的ASCII和Unicode编码的问题,在c#时代因为Encoding类的出现变得十分简单,直接用相关的函数直接转码就可以了。

VS默认的编码格式是unicode的,也就是双字节的,而ASCII依旧是单字节的。在串口通讯中,大部分时候都是用ASCII编码格式来传输数据的,因此发送内容就应该这么写:

byte[] btSend = Encoding.ASCII.GetBytes(tbSend.Text);
serialPort.Write(btSend, 0, btSend.Length);

很轻松把Unicode编码的文本转化为了ASCII编码的字节数组!

当然,收到数据怎么办呢?那还不简单,再转一次呗:

Encoding.ASCII.GetString(bytes)

在LIS的串口通信中,大部分时候用的还是ASCII编码,比如发送ACK信号:
public void SendACK()
{
if (this.IsOpen)
{
byte[] btACK = new byte[1];
btACK[0] = 6;
this.Write(btACK, 0, btACK.Length);
}
}

至于ACK为什么是6,你去查ASCII码表就知道了。

有些时候,我们需要用com口来传输文本数据,比如中文,这个时候你用ASCII去读取发现还是全部都是?????,为啥啊?因为还有一种格式叫做GB2313.
Encoding chs = Encoding.GetEncoding(“gb2312”);
用这种格式去读取中文,就不会乱码了。

接下来会写一个LIS串口通信协议的分析程序,慢慢来吧。

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

一条回应:“c#的串口通讯”

  1. 屠龙说道:

    其实我想说的是:c#是什么呀

发表评论

电子邮件地址不会被公开。 必填项已用*标注