2011年10月21日 星期五

Visual C# 2010 Serial Port 設定

    最近一下子太多案子都是要 Rs232,所以先寫一個標準的 RS232 設定,好讓所有的系統共用。

   首先,構想是把 RS232 的各項設定值直接放在 Properties.Settings.settings 中 ,所以先在 Visual C# 2010 專案中的 Properties.Settings.settings 中加入:

serial_Port
serial_Baudrate
serial_Parity
serial_Databits
serial_Stopbit

   為了方便,每個變數的型態都是 String,如果是數值變數讀進來時會先用 Int32.TryParse(String, out numValue) 測試 String 是否能轉成 Integer,如果 Parse 可以再執行 ToInt32。

整個程式如後:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private string RxString;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] SerialPorts = SerialPort.GetPortNames();
            foreach (string port in SerialPorts)
            {

            }


        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                serialPort1.PortName = Properties.Settings.Default.serial_Port;
                int numValue;
                if (Int32.TryParse(Properties.Settings.Default.serial_Baudrate, out numValue))
                    serialPort1.BaudRate = Convert.ToInt32(Properties.Settings.Default.serial_Baudrate);
                switch (Properties.Settings.Default.serial_Parity)
                {
                    case "無":
                        serialPort1.Parity = Parity.None;
                        break;
                    case "奇數":
                        serialPort1.Parity = Parity.Odd;
                        break;
                    case "偶數":
                        serialPort1.Parity = Parity.Even;
                        break;
                }

                switch (Properties.Settings.Default.serial_Stopbits)
                {
                    case "0":
                        serialPort1.StopBits = StopBits.None;
                        break;
                    case "1":
                        serialPort1.StopBits = StopBits.One;
                        break;

                    case "2":
                        serialPort1.StopBits = StopBits.Two;
                        break;

                }
                serialPort1.StopBits = StopBits.One;
                try
                {
                    serialPort1.Open();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Port 無法開啟 " + ex.Message);
                }
                finally
                {

                    button1.Text = "關閉";
                }
            }
            else
            {
                try
                {
                    serialPort1.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Port 無法關閉 " + ex.Message);
                }
                finally
                {
                    button1.Text = "開啟";
                }
            }
        }

        private void DisplayText(object sender, EventArgs e)
        {
            richTextBox1.AppendText(RxString);
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string tmpStr;
            char[] tmpChar;
            tmpStr = serialPort1.ReadExisting();
            tmpChar = tmpStr.ToCharArray();
            RxString = "";
            foreach (char letter in tmpChar)
            {
                int value = Convert.ToInt32(letter);
                string hexOut = String.Format("{0:x2}", value) + " ";
                RxString += hexOut;
            }
            this.Invoke(new EventHandler(DisplayText));
        }

        private void button2_Click(object sender, EventArgs e)
        {
            bool test;
            test = SendFc3((byte)0x01, 0x00, 0x16);
        }

        private void GetCRC(byte[] message, ref byte[] CRC)
        {
            //Function expects a modbus message of any length as well as a 2 byte CRC array in which to
            //return the CRC values:

            ushort CRCFull = 0xFFFF;
            byte CRCHigh = 0xFF, CRCLow = 0xFF;
            char CRCLSB;

            for (int i = 0; i < (message.Length) - 2; i++)
            {
                CRCFull = (ushort)(CRCFull ^ message[i]);

                for (int j = 0; j < 8; j++)
                {
                    CRCLSB = (char)(CRCFull & 0x0001);
                    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);

                    if (CRCLSB == 1)
                        CRCFull = (ushort)(CRCFull ^ 0xA001);
                }
            }
            CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
            CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
        }

        private void BuildMessage(byte address, byte type, ushort start, ushort registers, ref byte[] message)
        {
            //Array to receive CRC bytes:
            byte[] CRC = new byte[2];

            message[0] = address;
            message[1] = type;
            message[2] = (byte)(start >> 8);
            message[3] = (byte)start;
            message[4] = (byte)(registers >> 8);
            message[5] = (byte)registers;

            GetCRC(message, ref CRC);
            message[message.Length - 2] = CRC[0];
            message[message.Length - 1] = CRC[1];
        }

        public bool SendFc3(byte address, ushort start, ushort registers)
        {
            //Ensure port is open:
            if (serialPort1.IsOpen)
            {
                //Clear in/out buffers:
                serialPort1.DiscardOutBuffer();
                serialPort1.DiscardInBuffer();
                //Function 3 request is always 8 bytes:
                byte[] message = new byte[8];

                //Build outgoing modbus message:
                BuildMessage(address, (byte)3, start, registers, ref message);
                //Send modbus message to Serial Port:
                try
                {
                    serialPort1.Write(message, 0, message.Length);
                    return true;
                }
                catch (Exception err)
                {
                    MessageBox.Show("Error in read event: " + err.Message);
                    return false;
                }

            }
            else
            {
                MessageBox.Show("Serial port not open");
                return false;
            }

        }

        private void serButton_Click(object sender, EventArgs e)
        {
            Form2 SerialSetup = new Form2();
            SerialSetup.Show();

        }

    }

}

執行畫面: