https://www.cnblogs.com/yangfengwu/p/11087613.html
頁面修改成這樣子
現在看串口發送數據
點擊點亮 發送0xaa 0x55 0x01
我電腦上安裝了虛擬串口軟件,虛擬出來了COM1和COM2,然后COM1發送的數據會發給COM2 COM2發送的數據會發給COM1
大家如果有兩個串口模塊也可以
https://jingyan.baidu.com/article/e3c78d648965303c4c85f535.html
那個按鈕的程序這樣寫
測試一下
現在看串口接收數據
說一下哈,這個是上位機的串口中斷函數,就是只要接收到數據就會進入這個中斷
現在咱讀出來接收的數據,然后顯示在
讀取數據給了好幾個方法
咱就說1個,哈哈哈,其實自己一選擇方法的時候就有中文注釋......
大家注沒注意
現在調用一個函數讀出來,然后顯示出來
ReadExisting() 這個方法就會返回緩沖區里面的所有字節,注意返回的是字符串形式的
調用這個方法就是 serialPort1.ReadExisting(); serialPort1就是咱的
因為咱就是要里面的數據所以
string str = serialPort1.ReadExisting();//讀出來當前緩存里面的所有數據
Invoke((new Action(() =>
{
這里面放要操作的主線程的控件的方法
})));
其實這個方法主要是方便解決一個問題,稍候再說,咱先測試一下哈
說明可以了,現在呢,咱去掉
大家可以點開那個 如何跨線程調用 Windows 窗體控件
大家可以看這個 https://www.cnblogs.com/yangfengwu/p/5761841.html (最好別看,看了就會感覺麻煩)
4.0之后引進了這種方法
對於初學者知道這個就可以了,像C#,C++,JAVA等等這種高級語言哈,因為可以做界面了,,高級語言規定,操作頁面不能在子線程中進行
哪些是子線程呢!..像上面那個串口中斷函數,還有自己創建的任務Thread,,,等等吧
好現在,咱接收16進制,
接收到
0xaa 0x55 0x01
0xaa 0x55 0x00
好,上菜
//串口接收到數據就會進入 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { int len = serialPort1.BytesToRead;//獲取可以讀取的字節數 if (len > 0) { byte[] recvBytes = new byte[len];//創建接收的數組 serialPort1.Read(recvBytes, 0, len);//接收數據 if (recvBytes[0] == 0xaa && recvBytes[1] == 0x55)//判斷數據 { if (recvBytes[2] == 0x01)// { Invoke((new Action(() => { button3.Text = "熄滅"; label5.Text = "點亮"; }))); } else if (recvBytes[2] == 0x00) { Invoke((new Action(() => { button3.Text = "點亮"; label5.Text = "熄滅"; }))); } } } //string str = serialPort1.ReadExisting();//讀出來當前緩存里面的所有數據 //Invoke((new Action(() => //{ // //顯示在文本框里面 // textBox1.AppendText(str); //}))); }
測試
雖然可以了,但是這樣寫不保險...
原因是那個中斷是不定長的數據就進去(受到電腦整體運行狀態的影響),所以呢咱優化下
//串口接收到數據就會進入 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { int len = serialPort1.BytesToRead;//獲取可以讀取的字節數 if (len > 0) { byte[] recvBytes = new byte[len];//創建接收的數組 serialPort1.Read(recvBytes, 0, len);//接收數據 for (int i = 0; i < len; i++)//拷貝數據到UsartReadBuff { UsartReadBuff[i+ UsartReadCnt] = recvBytes[i];//從上次的地方接着填入數據 } UsartReadCnt = UsartReadCnt + len;//記錄上次的數據個數 if (UsartReadCnt >= 3)//接收到可以處理的數據個數 { UsartReadCnt = 0; if (UsartReadBuff[0] == 0xaa && UsartReadBuff[1] == 0x55)//判斷數據 { if (UsartReadBuff[2] == 0x01)// { Invoke((new Action(() => { button3.Text = "熄滅"; label5.Text = "點亮"; }))); } else if (UsartReadBuff[2] == 0x00) { Invoke((new Action(() => { button3.Text = "點亮"; label5.Text = "熄滅"; }))); } } } } //string str = serialPort1.ReadExisting();//讀出來當前緩存里面的所有數據 //Invoke((new Action(() => //{ // //顯示在文本框里面 // textBox1.AppendText(str); //}))); }
自己測試哈
現在說一下
如果接收的是字符串,想顯示出來
如果發過來了16進制 注意哈,發過來的是16進制 假設 00 就是數字0 因為那個文本框顯示的時候是顯示的字符串
所以需要轉成 "00" 發過來0F 需要顯示字符串形式的 "0F"
給大家准備好了
/// <字節數組轉16進制字符串> /// <param name="bytes"></param> /// <returns> String 16進制顯示形式</returns> public static string byteToHexStr(byte[] bytes) { string returnStr = ""; try { if (bytes != null) { for (int i = 0; i < bytes.Length; i++) { returnStr += bytes[i].ToString("X2"); returnStr += " ";//兩個16進制用空格隔開,方便看數據 } } return returnStr; } catch (Exception) { return returnStr; } }
//串口接收到數據就會進入 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { int len = serialPort1.BytesToRead;//獲取可以讀取的字節數 if (len > 0) { byte[] recvBytes = new byte[len];//創建接收的數組 serialPort1.Read(recvBytes, 0, len);//接收數據 Invoke((new Action(() =>//顯示字符串 { textBox1.AppendText("字符串:"+Encoding.Default.GetString(recvBytes)); //顯示在文本框里面 }))); Invoke((new Action(() =>//顯示16進制 { textBox1.AppendText("\r\n16進制:" + byteToHexStr(recvBytes) + "\r\n"); //顯示在文本框里面 }))); for (int i = 0; i < len; i++)//拷貝數據到UsartReadBuff { UsartReadBuff[i+ UsartReadCnt] = recvBytes[i];//從上次的地方接着填入數據 } UsartReadCnt = UsartReadCnt + len;//記錄上次的數據個數 if (UsartReadCnt >= 3)//接收到可以處理的數據個數 { UsartReadCnt = 0; if (UsartReadBuff[0] == 0xaa && UsartReadBuff[1] == 0x55)//判斷數據 { if (UsartReadBuff[2] == 0x01)// { Invoke((new Action(() => { button3.Text = "熄滅"; label5.Text = "點亮"; }))); } else if (UsartReadBuff[2] == 0x00) { Invoke((new Action(() => { button3.Text = "點亮"; label5.Text = "熄滅"; }))); } } } } }
現在看發送
發送就只做字符串發送哈,,,16進制發送后期補上,,大家先吸收吸收現在的....
執行文件
我把16進制發送用到的函數放在這里,后期再回來加上
/// <字符串轉16進制格式,不夠自動前面補零> /// /// </summary> /// <param name="hexString"></param> /// <returns></returns> private static byte[] strToToHexByte(String hexString) { int i; bool Flag = false; hexString = hexString.Replace(" ", "");//清除空格 if ((hexString.Length % 2) != 0) { Flag = true; } if (Flag == true) { byte[] returnBytes = new byte[(hexString.Length + 1) / 2]; try { for (i = 0; i < (hexString.Length - 1) / 2; i++) { returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); } returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16); } catch { for (i = 0; i < returnBytes.Length; i++) { returnBytes[i] = 0; } MessageBox.Show("超過16進制范圍A-F,已初始化為0", "提示"); } return returnBytes; } else { byte[] returnBytes = new byte[(hexString.Length) / 2]; try { for (i = 0; i < returnBytes.Length; i++) { returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); } } catch { for (i = 0; i < returnBytes.Length; i++) { returnBytes[i] = 0; } MessageBox.Show("超過16進制范圍A-F,已初始化為0", "提示"); } return returnBytes; } }
對了,其實上位機串口是有空閑時間中斷的(異常捕獲),只不過,我還沒細研究呢!!!
https://www.cnblogs.com/yangfengwu/p/11094009.html