2014年2月7日 星期五

[C#/winform] RS-232/SerialPort 傳送及接收

1.先從工具箱拉SerialPort元件(要記得程式碼加入System.IO.Ports)

2.點選元件可以調整BaudRate.DataBit.ParityBit.HandShake...等

3.也可以從程式碼中新增: serialPort1 = new SerialPort(COM幾(String), 9600, Parity.None, 8, StopBits.One);

4.如果要抓取電腦現有的COM,可以使用string[] port_name = SerialPort.GetPortName();
可以用foreach() loop + comboBox的add來新增到comboBox裡面

5.讀取部分
           private byte[] Port_read()
        {
            //---------------------------讀取部分---------------------------------//
            int B2R = serialPort1.BytesToRead;//有多少
            byte[] Buffer = new byte[B2R];//new多少byte 陣列
            if (B2R > 0)
            {
                serialPort1.Read(Buffer, 0, B2R);//有多少就讀入多少(共85byte)
            }
            return Buffer;
            //---------------------------讀取部分-End------------------------------//
        }

6.寫入部分
          //---------------------------寫入部分----------------------------------//
            //先檢查有幾個modbus,
            try
            {
                serialPort1.Write(byte陣列, 0, 寫多少byte);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("關閉通訊埠");//關閉通訊埠
            }
            catch (IOException IOE)
            {
                MessageBox.Show(IOE.Message);
                MessageBox.Show("IO錯誤");//IO exception
            }

大致上就完成簡單的通訊程式

其餘比較有用的:

System.Text.Encoding.Default.GetBytes(String); //string轉byte[]

System.Text.Encoding.Default.GetString(byte[]);//byte[]轉String

[C#] Class小記 - 以 CRC 16為例

先看程式碼,如下  

class CRC_16
    {
        public byte CRC_1 { get; set; }
        public byte CRC_2 { get; set; }

        public void CRC16_counter(byte[] data, int CRC_length) //跑兩個  1.送出去產生CRC(length = 6) 產生後 = 8
        {                                                    //        2.接收時驗證CRC(length = 83) 產生後 = 85
            ushort CRCFull = 0xFFFF;
            byte CRChigh = 0xFF, CRClow = 0xFF;
            char CRC_LSB;

            for (int i = 0; i < CRC_length; i++)
            {
                CRCFull = (ushort)(CRCFull ^ data[i]); //指令的第i組數字與CRCFull做XOR

                for (int j = 0; j < 8; j++)//8bit,所以跑八次
                {
                    CRC_LSB = (char)(CRCFull & 0x00000001);//取得最後一個位元的值
                    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF); //右移一位,第一位補0
                    //檢查
                    if (CRC_LSB == 0) //如果右移的值為0
                    {
                        //就把剛剛右移+第一位補零的數值存入暫存(不過已經做了,這邊只是註解)
                    }
                    if (CRC_LSB == 1) // 如果右移的值為1
                    {
                        CRCFull = (ushort)(CRCFull ^ 0xA001);  //跟0xA001去做XOR,存入暫存器
                    }
                }
            }
            //跑完要讓高低register對調
            //CRChigh = (byte)((CRCFull >> 8) & 0xFF); //右移8Bit,也就是變成低位元,跟FF(1111 1111)做& 0還是0 1還是1
            //CRClow = (byte)(CRCFull & 0xFF); //低的變成高的
            CRChigh = (byte)(CRCFull >> 8); //右移8Bit,也就是變成低位元,跟FF(1111 1111)做& 0還是0 1還是1,不用&0xff也可
            CRClow = (byte)CRCFull; //低的變成高的,不用&0xff也可
            if (CRC_length == 6)
            {
                CRC_2 = CRChigh;//現在是低
                CRC_1 = CRClow; //現在是高
            }
            if (CRC_length == 83)
            {
                CRC_2 = CRChigh;//現在是低
                CRC_1 = CRClow; //現在是高
            }
        }
    }

本例Protocol有兩種1.傳送(8byte)2.接收(85byte)

因此先用6byte 算出CRC(最後2byte) = 8 / 83byte 算出CRC(最後2byte) = 85,

用以驗證CRC-16是否正確。

Class部份假如要使用到CRC_1,CRC_2 則需要 這樣呼叫

1.先new好Class
   CRC_16 CRC = new CRC_16();
2.存取Class內部資料
   CRC.CRC_1 ,CRC.CRC_2
3.如果內部將CRC_1宣告成 public static .... ,則呼叫需改為
   namespace名稱.Class名稱.CRC_1