網站首頁 編程語言 正文
一、前導知識
串行口是計算機的標準接口,現在的PC機(個人電腦)一般至少有兩個串行口COM1和COM2。串行口應用廣泛,在數據通信、計算機網絡以及分布式工業控制系統中,經常采用串行通信來交換數據和信息
電氣標準及協議來分包括RS-232-C、RS-422、RS485、USB(Universal Serial Bus)等
實現串口通信的必要設置
串口通信最重要的參數是波特率、數據位、停止位和奇偶校驗。
對于兩個進行通行的端口,這些參數必須匹配:
波特率
這是一個衡量通信速度的參數。它表示**每秒鐘傳送的bit的個數**。例如300波特表示每秒鐘發送300個bit,波特率和距離成反比。高波特率常常用于放置的很近的儀器間的通信,典型的例子就是GPIB設備的通信
數據位
這是衡量通信中實際數據位的參數。當計算機發送一個信息包,實際的數據不會是8位的,標準的值是5、7和8位,如何設置取決于你想傳送的信息。比如,標準的ASCII碼是0~127(7位)。擴展的ASCII碼是0~255(8位)。如果數據使用簡單的文本(標準 ASCII碼),那么每個數據包使用7位數據。每個包是指一個字節,包括開始/停止位,數據位和奇偶校驗位。由于實際數據位取決于通信協議的選取,術語“包”指任何通信的情況。
停止位
用于表示單個包的最后一位。典型的值為1,1.5和2位。由于數據是在傳輸線上定時的,并且每一個設備有其自己的時鐘,很可能在通信中兩臺設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,并且提供計算機校正時鐘同步的機會。適用于停止位的位數越多,不同時鐘同步的容忍程度越大,但是數據傳輸率同時也越慢
奇偶校驗位
?在串口通信中一種簡單的檢錯方式。有四種檢錯方式:偶、奇、高和低。當然沒有校驗位也是可以的。對于偶和奇校驗的情況,串口會設置校驗位(數據位后面的一位),用一個值確保傳輸的數據有偶個或者奇個邏輯高位。例如,如果數據是011,那么對于偶校驗,校驗位為0,保證邏輯高的位數是偶數個。如果是奇校驗,校驗位位1,這樣就有3個邏輯高位。高位和低位不真正的檢查數據,簡單置位邏輯高或者邏輯低校驗。這樣使得接收設備能夠知道一個位的狀態,有機會判斷是否有噪聲干擾了通信或者是否傳輸和接收數據是否不同步
二、實驗
我們將通過模擬串口通信,在pc機上進行兩個串口(COM1、COM2)的交互
需要用到的軟件:
Launch Virtual Serial Port Driver Pro:虛擬串口。使用它來模擬兩個串口的連接
繪制窗口
?代碼實現
1.使用SerialPort控制串口
private SerialPort sp1 = new SerialPort();
2.打開串口
private void button2_Click(object sender, EventArgs e)
{
if (!sp1.IsOpen)
{
try
{
//串口號
sp1.PortName = "COM1";
//波特率
sp1.BaudRate = 115200;
//數據位
sp1.DataBits = 8;
//停止位
sp1.StopBits = StopBits.One;
//奇偶校驗位
sp1.Parity = Parity.Even;
//DataReceived事件發送前,內部緩沖區里的字符數
sp1.ReceivedBytesThreshold = 1;
sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;
// Control.CheckForIllegalCrossThreadCalls = false;
//表示將處理 System.IO.Ports.SerialPort 對象的數據接收事件的方法。
sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);
//打開串口
sp1.Open();
MessageBox.Show("COM1打開成功!");
}
catch (Exception ex)
{
MessageBox.Show("COM1打開失??!");
}
}
else
{
MessageBox.Show("COM1打開成功!");
}
}
3.關閉串口
private void button3_Click(object sender, EventArgs e)
{
if (sp1.IsOpen)
{
sp1.Close();
MessageBox.Show("COM1關閉成功!");
}
}
串口2的打開和關閉同理串口1實現
4.發送
private void button1_Click(object sender, EventArgs e)
{
if (sp1.IsOpen)
{
if (!string.IsNullOrEmpty(this.textBox1.Text))
{
sp1.WriteLine(this.textBox1.Text+"\r\n");
}
else
{
MessageBox.Show("發送數據為空");
}
}
else
{
MessageBox.Show("COM1未打開!");
}
}
5.接收
StringBuilder builder1 = new StringBuilder();
//在接收到了ReceivedBytesThreshold設置的字符個數或接收到了文件結束字符并將其放入了輸入緩沖區時被觸發
public void sp1_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine("接收中...");
int n = sp1.BytesToRead; //先記錄下來,避免某種原因,人為的原因,操作幾次之間時間長,緩存不一致
byte[] buf = new byte[n]; //聲明一個臨時數組存儲當前來的串口數據
sp1.Read(buf, 0, n); //讀取緩沖數據
builder1.Remove(0, builder1.Length); //清除字符串構造器的內容
builder1.Append(Encoding.ASCII.GetString(buf));
string comdata = builder1.ToString();
Console.WriteLine("data: + " + comdata);
this.Invoke(settextevent,comdata);
}
這里僅僅實現了一般的接收方式,并不嚴謹和健壯
測試
使用軟件模擬串口連接
?打開兩個程序
?在一程序中打開串口1,在二程序中打開串口2,發送消息
在一程序中輸入字符"hello,HanHanCheng!",發現在二程序中接收到,同樣,在二程序中輸入,在一中也能收到
?三、總結
1.由于是異步線程接收,在接收中需要使用委托來跨線程調用組件
public delegate void settext(string text);
public event settext settextevent;
public void set(string text)
{
this.textBox2.Text = text;
}
//再注冊
settextevent += set;
2.DataReceived事件觸發條件需要注意,可能在實現時,無法觸發導致無法接收。
觸發條件是:在接收到了ReceivedBytesThreshold設置的字符個數或接收到了文件結束字符并將其放入了輸入緩沖區時被觸發
四、附件完整代碼
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 Training_USBCOM
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
settextevent += set;
}
private SerialPort sp1 = new SerialPort();
StringBuilder builder = new StringBuilder();
private void button1_Click(object sender, EventArgs e)
{
if (sp1.IsOpen)
{
if (!string.IsNullOrEmpty(this.textBox1.Text))
{
sp1.WriteLine(this.textBox1.Text+"\r\n");
}
else
{
MessageBox.Show("發送數據為空");
}
}
else
{
MessageBox.Show("COM1未打開!");
}
}
public delegate void settext(string text);
public event settext settextevent;
public void set(string text)
{
this.textBox2.Text = text;
}
StringBuilder builder1 = new StringBuilder();
//在接收到了ReceivedBytesThreshold設置的字符個數或接收到了文件結束字符并將其放入了輸入緩沖區時被觸發
public void sp1_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine("接收中...");
int n = sp1.BytesToRead; //先記錄下來,避免某種原因,人為的原因,操作幾次之間時間長,緩存不一致
byte[] buf = new byte[n]; //聲明一個臨時數組存儲當前來的串口數據
sp1.Read(buf, 0, n); //讀取緩沖數據
builder1.Remove(0, builder1.Length); //清除字符串構造器的內容
builder1.Append(Encoding.ASCII.GetString(buf));
string comdata = builder1.ToString();
Console.WriteLine("data: + " + comdata);
this.Invoke(settextevent,comdata);
}
private void button2_Click(object sender, EventArgs e)
{
if (!sp1.IsOpen)
{
try
{
//串口號
sp1.PortName = "COM1";
//波特率
sp1.BaudRate = 115200;
//數據位
sp1.DataBits = 8;
//停止位
sp1.StopBits = StopBits.One;
//奇偶校驗位
sp1.Parity = Parity.Even;
//DataReceived事件發送前,內部緩沖區里的字符數
sp1.ReceivedBytesThreshold = 1;
sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;
// Control.CheckForIllegalCrossThreadCalls = false;
//表示將處理 System.IO.Ports.SerialPort 對象的數據接收事件的方法。
sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);
//打開串口
sp1.Open();
MessageBox.Show("COM1打開成功!");
}
catch (Exception ex)
{
MessageBox.Show("COM1打開失??!");
}
}
else
{
MessageBox.Show("COM1打開成功!");
}
}
private void button3_Click(object sender, EventArgs e)
{
if (sp1.IsOpen)
{
sp1.Close();
MessageBox.Show("COM1關閉成功!");
}
}
private void button5_Click(object sender, EventArgs e)
{
if (!sp1.IsOpen)
{
try
{
//串口號
sp1.PortName = "COM2";
//波特率
sp1.BaudRate = 115200;
//數據位
sp1.DataBits = 8;
//停止位
sp1.StopBits = StopBits.One;
//奇偶校驗位
sp1.Parity = Parity.Even;
sp1.ReceivedBytesThreshold = 1;
sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;
Control.CheckForIllegalCrossThreadCalls = false;
//表示將處理 System.IO.Ports.SerialPort 對象的數據接收事件的方法。
sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);
//打開串口
sp1.Open();
MessageBox.Show("COM2打開成功!");
}
catch (Exception ex)
{
MessageBox.Show("COM2打開失??!");
}
}
else
{
MessageBox.Show("COM2打開成功!");
}
}
private void button4_Click(object sender, EventArgs e)
{
if (sp1.IsOpen)
{
sp1.Close();
MessageBox.Show("COM2關閉成功!");
}
}
}
}
原文鏈接:https://blog.csdn.net/hey_lie/article/details/120194909
相關推薦
- 2022-03-25 centos系統安裝Kubernetes集群步驟_Linux
- 2022-04-07 怎么減少本地調試tomcat重啟次數你知道嗎_Tomcat
- 2023-11-21 高階函數HoF:用filter()方法編寫一個素數生成函數primes()
- 2023-12-08 antd 表單校驗問題
- 2022-06-11 .Net項目在Docker容器中開發部署_實用技巧
- 2022-11-21 Python?Flask框架開發之運用SocketIO實現WebSSH方法詳解_python
- 2022-12-04 Android性能優化死鎖監控知識點詳解_Android
- 2022-07-26 二分搜索防止整形溢出
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支