用线程是一种方式,也可以用自带的组件是异步的,如果不用组件用API写串口,应该启用两个线程,用作读写。

以下代码是可以用来学习的

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1 mainform;
        public Form2 f;
        private bool show_or_not = true;    //是否显示接收和发送
        private byte[] send = new byte[50];       //要发送的字节
        private byte[] receive = new byte[50];   //要接收的字节 
        private byte sendnum;           //需要发送的数据个数 
        private byte receivenum;           //需要返回的数据个数
        Thread trd;     //开一个线程

        private delegate void DelegateFunciton();

        public Form1()
        {
            InitializeComponent();
        }       

        private void CreateHeadersAndFillListview()
        {
            listView1.Columns.Add("数据大小", 77, HorizontalAlignment.Left); 
            listView1.Columns.Add("数据项名称",140, HorizontalAlignment.Left);
            listView1.Columns.Add("标识编码", 75, HorizontalAlignment.Right); 
        }
        
        private void PaintListView()
        {
            listView1.BeginUpdate();
            listView1.Items.Add("0", "00001234", 0);
            listView1.Items[0].SubItems.Add("正向有功功率");
            listView1.Items[0].SubItems.Add("0x9010");
            listView1.Items.Add("1", "00001234", 0);
            listView1.Items[1].SubItems.Add("费率1正向有功功率");
            listView1.Items[1].SubItems.Add("0x9011");
            listView1.Items.Add("2", "00001234", 0);
            listView1.Items[2].SubItems.Add("费率2正向有功功率");
            listView1.Items[2].SubItems.Add("0x9012");
            listView1.Items.Add("3", "00001234", 0);
            listView1.Items[3].SubItems.Add("费率3正向有功功率");
            listView1.Items[3].SubItems.Add("0x9013");
            listView1.Items.Add("4", "00001234", 0);
            listView1.Items[4].SubItems.Add("费率4正向有功功率");
            listView1.Items[4].SubItems.Add("0x9014");
            listView1.Items.Add("5", "00001234", 0);
            listView1.Items[5].SubItems.Add("反向有功功率");
            listView1.Items[5].SubItems.Add("0x9020");
            listView1.Items.Add("6", "00001234", 0);
            listView1.Items[6].SubItems.Add("费率1反向有功功率");
            listView1.Items[6].SubItems.Add("0x9021");
            listView1.Items.Add("7", "00001234", 0);
            listView1.Items[7].SubItems.Add("费率2反向有功功率");
            listView1.Items[7].SubItems.Add("0x9022");
            listView1.Items.Add("8", "00001234", 0);
            listView1.Items[8].SubItems.Add("费率3反向有功功率");
            listView1.Items[8].SubItems.Add("0x9023");
            listView1.Items.Add("9", "00001234", 0);
            listView1.Items[9].SubItems.Add("费率4反向有功功率");
            listView1.Items[9].SubItems.Add("0x9024");
            listView1.Items.Add("10", "00001234", 0);
            listView1.Items[10].SubItems.Add("反向无功功率");
            listView1.Items[10].SubItems.Add("0x9120");
            listView1.Items.Add("11", "00001234", 0);
            listView1.Items[11].SubItems.Add("费率1反向无功功率");
            listView1.Items[11].SubItems.Add("0x9121");
            listView1.Items.Add("12", "00001234", 0);
            listView1.Items[12].SubItems.Add("费率2反向无功功率");
            listView1.Items[12].SubItems.Add("0x9122");
            listView1.Items.Add("13", "00001234", 0);
            listView1.Items[13].SubItems.Add("费率3反向无功功率");
            listView1.Items[13].SubItems.Add("0x9123");
            listView1.Items.Add("14", "00001234", 0);
            listView1.Items[14].SubItems.Add("费率4反向无功功率");
            listView1.Items[14].SubItems.Add("0x9124");
            listView1.Items.Add("15", "00001234", 0);
            listView1.Items[15].SubItems.Add("瞬时有功功率");
            listView1.Items[15].SubItems.Add("0xB630");
            listView1.Items.Add("16", "00001234", 0);
            listView1.Items[16].SubItems.Add("A相有功功率");
            listView1.Items[16].SubItems.Add("0xB631");
            listView1.Items.Add("17", "00001234", 0);
            listView1.Items[17].SubItems.Add("B相有功功率");
            listView1.Items[17].SubItems.Add("0xB632");
            listView1.Items.Add("18", "00001234", 0);
            listView1.Items[18].SubItems.Add("C相有功功率");
            listView1.Items[18].SubItems.Add("0xB633");
            listView1.Items.Add("19", "00001234", 0);
            listView1.Items[19].SubItems.Add("瞬时无功功率");
            listView1.Items[19].SubItems.Add("0xB640");
            listView1.Items.Add("20", "00001234", 0);
            listView1.Items[20].SubItems.Add("A相无功功率");
            listView1.Items[20].SubItems.Add("0xB641");
            listView1.Items.Add("21", "00001234", 0);
            listView1.Items[21].SubItems.Add("B相无功功率");
            listView1.Items[21].SubItems.Add("0xB642");
            listView1.Items.Add("22", "00001234", 0);
            listView1.Items[22].SubItems.Add("C相无功功率");
            listView1.Items[22].SubItems.Add("0xB643");
            listView1.Items.Add("23", "1234", 0);
            listView1.Items[23].SubItems.Add("A相电压");
            listView1.Items[23].SubItems.Add("0xB611");
            listView1.Items.Add("24", "1234", 0);
            listView1.Items[24].SubItems.Add("B相电压");
            listView1.Items[24].SubItems.Add("0xB612");
            listView1.Items.Add("25", "1234", 0);
            listView1.Items[25].SubItems.Add("C相电压");
            listView1.Items[25].SubItems.Add("0xB613");
            listView1.Items.Add("26", "1234", 0);
            listView1.Items[26].SubItems.Add("A相电流");
            listView1.Items[26].SubItems.Add("0xB621");
            listView1.Items.Add("27", "1234", 0);
            listView1.Items[27].SubItems.Add("B相电流");
            listView1.Items[27].SubItems.Add("0xB622");
            listView1.Items.Add("28", "1234", 0);
            listView1.Items[28].SubItems.Add("C相电流");
            listView1.Items[28].SubItems.Add("0xB623");
            listView1.EndUpdate();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text == "关闭串口")  //关闭串口
            {
                button1.Text = "打开串口";
                serialPort1.DiscardOutBuffer();
                serialPort1.DiscardInBuffer();
                trd.Abort();
                serialPort1.Close();//关闭串口
            }
            else if (button1.Text == "打开串口") //打开串口
            {
                serialPort1.PortName = comboBox1.SelectedItem.ToString();
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text, 10);
                if (comboBox3.SelectedIndex == 0)
                    serialPort1.Parity = System.IO.Ports.Parity.Even;   //偶校验
                else if (comboBox3.SelectedIndex == 1)
                    serialPort1.Parity = System.IO.Ports.Parity.Odd;    //奇校验
                else serialPort1.Parity = System.IO.Ports.Parity.None;  //无校验
                serialPort1.Open();
                serialPort1.DiscardOutBuffer();
                serialPort1.DiscardInBuffer();
                button1.Text = "关闭串口";
                trd = new Thread(new ThreadStart(this.ThreadTask));
                trd.IsBackground = true;
                trd.Start();        //打开线程
            }
        }

        public byte Calculate_Parity(byte[] data, byte num1, byte num2) //num1是FE数量,num2是数组大小,奇偶校验
        {
            byte i;
            byte sum=0;
            for (i = num1; i < num2; i++)
                sum += data[i];
            return sum;
        }

        public Int32 Get_Item_Index(Int16 DI1_0)        //由标识编码得到listview中的item的编号
        {
            Int16 i;
            for (i = 0; (i < listView1.Items.Count) && (Convert.ToInt16(listView1.Items[i].SubItems[2].Text, 16) != DI1_0); i++) ;

            if ((i == listView1.Items.Count) && (Convert.ToInt16(listView1.Items[i-1].SubItems[2].Text, 16) != DI1_0))
            {
                return 10000;//错误   
            }
            else
                return i;
        }

        private void ThreadFunction()
        {
            richTextBox1.Focus();
        }

        private void ThreadTask()       //独立线程
        {
            byte i,FE_num,err;
            UInt16  temp;              
            Int32   temp1;
            Int16 DL745_DI; //DL645标识编码
                            
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
            richTextBox1.BackColor = Color.Black;
            while (true)
            {              
                DelegateFunciton df = new DelegateFunciton(ThreadFunction);
                while (serialPort1.BytesToRead == 0)
                {
                  //richTextBox1.Focus();
                  //comboBox6.Focus();
                  //comboBox6.SelectedIndex = 2;                    
                    this.Invoke(df);
                    Thread.Sleep(50);  //延时50ms
                }
                Thread.Sleep(50);  //延时50ms                 
                FE_num = 0;
                i = 0;
                receivenum = (byte)serialPort1.BytesToRead;
                serialPort1.Read(receive, 0, serialPort1.BytesToRead);
                while (receive[i] == 0xFE)
                    FE_num++;
                err = Calculate_Parity(receive, FE_num, (byte)(receivenum - 2));
                if (err != receive[receivenum - 2]) //奇偶校验错误
                {                    
                    if (show_or_not == true)  //是否显示
                    {
                        richTextBox1.SelectionColor = Color.LawnGreen;
                        richTextBox1.AppendText("奇偶校验错误!\r\n");
                        richTextBox1.SelectionColor = Color.White;
                        richTextBox1.AppendText("接收: ");
                        for (i = 0; i < receivenum; i++)
                        {
                            if (receive[i] < 16)
                                richTextBox1.AppendText("0" + receive[i].ToString("X") + " ");    //按16进制显示
                            else
                                richTextBox1.AppendText(receive[i].ToString("X") + " ");    //按16进制显示
                        }
                        richTextBox1.AppendText("\r\n");
                    }
                    temp = Convert.ToUInt16(label5.Text, 10);
                    temp++;
                    label5.Text = temp.ToString();      //接收加1
                    serialPort1.DiscardOutBuffer(); //窗口清零
                    serialPort1.DiscardInBuffer();

                }
                else//奇偶校验正确
                {
                    if (show_or_not == true)  //是否显示
                    { 
                    richTextBox1.SelectionColor = Color.White;
                    richTextBox1.AppendText("接收: ");
                    for (i = 0; i < receivenum; i++)
                    {
                        if(receive[i]<16)
                            richTextBox1.AppendText("0"+receive[i].ToString("X") + " ");    //按16进制显示
                        else
                            richTextBox1.AppendText(receive[i].ToString("X") + " ");    //按16进制显示
                    }                        
                    richTextBox1.AppendText("\r\n");
                    }                    
                    temp = Convert.ToUInt16(label5.Text, 10);
                    temp++;
                    label5.Text = temp.ToString();      //接收加1
                    DL745_DI = (Int16)receive[11 + FE_num];
                    DL745_DI -= 0x33;
                    DL745_DI <<= 8;
                    DL745_DI += receive[10 + FE_num];
                    DL745_DI -= 0x33;  //解析得到的DL645标识编码
                    temp1 = Get_Item_Index(DL745_DI);   //得到其在listview中对应的位置index
                    if (temp1 != 10000)
                    {
                        send[0] = send[1] = 0xFE;   //发两字节的0xFE
                        for (i = FE_num; i < FE_num + 12; i++)
                            send[i - FE_num + 2] = receive[i];  //发送的相同字节
                        send[10] = 0x81;
                        if (temp1 < 23)    //index在23之前的都是4字节
                        {
                            send[11] += 4;
                            send[14] = Convert.ToByte(listView1.Items[temp1].Text.Substring(6, 2), 16);
                            send[15] = Convert.ToByte(listView1.Items[temp1].Text.Substring(4, 2), 16);
                            send[16] = Convert.ToByte(listView1.Items[temp1].Text.Substring(2, 2), 16);
                            send[17] = Convert.ToByte(listView1.Items[temp1].Text.Substring(0, 2), 16);
                            send[14] += 0x33;
                            send[15] += 0x33;
                            send[16] += 0x33;
                            send[17] += 0x33;
                            send[18] = Calculate_Parity(send, 2, 18);
                            send[19] = 0x16;
                            sendnum = 20;
                        }
                        else  //2字节
                        {
                            send[11] += 2;
                            send[14] = Convert.ToByte(listView1.Items[temp1].Text.Substring(2, 2), 16);
                            send[15] = Convert.ToByte(listView1.Items[temp1].Text.Substring(0, 2), 16);
                            send[14] += 0x33;
                            send[15] += 0x33;
                            send[16] = Calculate_Parity(send, 2, 16);
                            send[17] = 0x16;
                            sendnum = 18;
                        }
                        serialPortSend();//发送                                        
                    }
                    richTextBox1.Focus();
                    
                    }
                    
                
 //               richTextBox1.Select(richTextBox1.TextLength, 0);
 //               richTextBox1.ScrollToCaret();       //richtextbox显示最后一行
            }
        }


        private void listView1_ItemActivate(object sender, EventArgs e)
        {
            int i =new int();
            Form2 f = new Form2();
            f.ShowDialog();   
            if (f.DialogResult == DialogResult.OK)//f2窗口点击OK是要警醒处理的结果
            {
                i = listView1.SelectedItems[0].Index;
                if (i < 23) //index在23之前的都是4字节
                {
                    if (f.datasource.Length > 8)
                        f.datasource = f.datasource.Substring(0, 8);
                    listView1.Items[i].Text = f.datasource.ToString().PadLeft(8, '0');//固定长度一个数值,左边补齐0,直到满8个长
                }
                else
                {
                    if (f.datasource.Length > 4)
                        f.datasource = f.datasource.Substring(0, 4);
                    listView1.Items[i].Text = f.datasource.ToString().PadLeft(4, '0');
                }
            }            
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = System.IO.Ports.SerialPort.GetPortNames();
            byte i = 0;            
            foreach (string port in ports)
            {
                comboBox1.Items.Add(port);
                i++;
            }
            if (i > 0)
            {
                comboBox1.SelectedIndex = 0;
                comboBox2.SelectedIndex = 1;
                comboBox3.SelectedIndex = 0;
                button1.Text = "打开串口";
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                }
                serialPort1.PortName = comboBox1.SelectedItem.ToString();
                //label6.Text = "没有打开串口!";
            }
            comboBox6.SelectedIndex = 0;
            CheckForIllegalCrossThreadCalls = false;        //线程间调用       
            trd = new Thread(new ThreadStart(this.ThreadTask));
            trd.IsBackground = true;
            CreateHeadersAndFillListview();
            PaintListView();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
            label5.Text = "0";
            label6.Text = "0";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (button2.Text == "停止显示")
            {
                show_or_not = false;
                button2.Text = "继续显示";
            }
            else
            {
                show_or_not = true;
                button2.Text = "停止显示";
                richTextBox1.Focus();
            }
        }

        private void serialPortSend()         //串口发送函数
        {
            byte i;
            UInt16 temp;
            try
            {                
                serialPort1.Write(send, 0, sendnum);    // 要发送的数据个数
                if (show_or_not == true)  //是否显示
                { 
                richTextBox1.SelectionColor = Color.Yellow;
                richTextBox1.AppendText("发送: ");
                for (i = 0; i < sendnum; i++)
                {
                    if (send[i] < 16)
                        richTextBox1.AppendText("0"+send[i].ToString("X") + " ");   //16进制显示
                    else
                        richTextBox1.AppendText(send[i].ToString("X") + " ");   //16进制显示
                }
                richTextBox1.AppendText("\r\n");
                }                
                temp = Convert.ToUInt16(label6.Text, 10);
                temp++;
                label6.Text = temp.ToString();
            }
            catch (System.InvalidOperationException e)
            {
                MessageBox.Show("通信接口未打开!", "注意!");
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (serialPort1.IsOpen)
            { 
                serialPort1.DiscardOutBuffer();
                serialPort1.DiscardInBuffer();
                trd.Abort();        //关掉线程
                serialPort1.Close();
            }
            
        }

        private void button7_Click(object sender, EventArgs e)  //串口清零
        {
            if (serialPort1.IsOpen)
            { 
                serialPort1.DiscardOutBuffer();
                serialPort1.DiscardInBuffer();
            }            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
           
            richTextBox1.Focus();       //让其获得焦点,一直显示最后一行
 //           comboBox6.Focus();
            
        }

        private void comboBox1_Click(object sender, EventArgs e)
        {
            //Cursor cr = Cursor.Current;
            //Cursor.Current = Cursors.WaitCursor;            
        }

    }
}