[英]How do I send bytes to a serial device in C#?
我有一個使用串行(通過USB適配器)與我的PC連接的設備。 我真的很難讓它在C#中很好地發揮。 我知道它工作正常,因為供應商提供的軟件表現得如預期的那樣。 我也知道我能夠使用我的代碼接收數據,這要歸功於一個重復發送“OK”的測試模式。
這是我的代碼:
private SerialPort port;
public SerialConnection()
{
this.port = new SerialPort("COM3", 38400, Parity.None, 8, StopBits.One);
this.port.WriteTimeout = 2000; port.ReadTimeout = 2000;
this.port.Open();
this.port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
public void SendCommand(byte[] command)
{
this.port.Write(command,0,command.Length);
string chars = "";
foreach (byte charbyte in command) chars += (char)charbyte;
Console.WriteLine(" -> " + chars);
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = this.port.ReadLine();
Console.WriteLine(" <- " + data);
}
目前我正在使用另一種測試模式,該模式應該回顯它收到的任何內容。 因此,我用以下字節調用SendCommand:
byte[] {
0x50,
0x69,
0x6E,
0x67
}
但似乎沒有任何東西被送回去。
我不知道下一步該嘗試什么。 有人有什么建議嗎?
對於一個附屬問題,我發布了一些PortMon日志。 我認為它們在這里也可能有用,所以它們在這里:
每個RS-232設備都需要使用某種流量控制機制來通知相對的部分正在進行的通信。 有三種基本機制:
(開始升級)
舊版應用中的初始隊列長度和超時:
1 IOCTL_SERIAL_SET_QUEUE_SIZE InSize: 1024 OutSize: 1024
2 IOCTL_SERIAL_SET_TIMEOUT RI:2000 RM:0 RC:2000 WM:0 WC:2000
而你沒有設置它們。 嘗試使用SerialPort.WriteBufferSize
和SerialPort.ReadBufferSize
設置隊列大小。 同樣使用SerialPort.ReadTimeout
和SerialPort.WriteTimeout
設置超時。
(最后更新)
在您的情況下,遺留應用程序會:
12 IOCTL_SERIAL_CLR_RTS
13 IOCTL_SERIAL_SET_DTR
你做的時候:
12 IOCTL_SERIAL_CLR_RTS
13 IOCTL_SERIAL_CLR_DTR
您沒有設置DTR(數據終端就緒)信號,因此設備不希望串行線路上有任何數據或命令。 因此將SerialPort.DtrEnable
設置為true
。
第二個問題是你不打開握手。 遺留應用程序:
16 IOCTL_SERIAL_SET_HANDFLOW Shake:1 Replace:0 XonLimit:0 XoffLimit:0
18 IOCTL_SERIAL_SET_RTS
…
21 IOCTL_SERIAL_CLR_RTS
你做的時候:
16 IOCTL_SERIAL_SET_HANDFLOW Shake:0 Replace:0 XonLimit:4096 XoffLimit:4096
將SerialPort.Handshake
設置為Handshake.RequestToSend
將其打開。
此外,您似乎經常打開,關閉和重新配置串行端口。 嘗試設置端口,然后在整個會話中使用相同的SerialPort
實例。 不要嘗試重新打開它,因為您將導致重新配置物理端口引腳的狀態。
串行通信不是黑魔法,但它對設置非常敏感,各種設備需要特殊的設置和處理。 適當的命令時序也可能是個問題。
如果您的設備確實有一些技術文檔,請先閱讀兩次,並在第一時間遵守它。 至少應妥善記錄握手模式,命令等。
如果您沒有任何文檔,請嘗試逐個緩解差異。
更新:發送和接收數據。
您寫道,您發送了命令'Ping'
(從十六進制解碼為ASCII)。 但是,您沒有提到發送和命令終止序列。 通常,串行設備期望行結束序列(通常是CR LF)作為命令的終止。 在設備收到包含行結束的完整命令之前,它無法回復。
您正在通過調用ReadLine
來處理數據接收事件 - 但是,在您不能指望完整數據行的位置(即包括行結束以檢測COMlete行)。 您應該檢查提供的事件參數並逐字節讀取輸入。
創建一個包裝類是個好主意,它將提供定制的發送命令,接收響應,發送數據,接收數據功能。 包裝器必須在內部與代碼的其余部分異步工作。 這樣,您將擁有可用的自定義API和良好的串行端口處理。
請注意, SerialPort.NewLine
屬性用於指定行尾序列的外觀。 (在你提到的另一個問題中,你試圖將它設置為特殊字符集。這確實是錯誤的。)
曾經有一段時間我是一個串行通訊英雄(那些是我們沒有vmware的日子,但有兩台486供電的PC和一對直接連接的調制解調器來開發和調試通信應用程序:-)),但我希望這至少有幫助一點點。
最后但並非最不重要的一些常用術語:
您是否嘗試過更改Handshake屬性? 也許設備在接受數據之前需要在控制引腳上進行一些握手。
您應該打開RtsEnable或DtrEnable屬性,設備將忽略您發送的任何內容,也不會在這些信號未在線檢測到您時發回任何內容。 將Handshake屬性設置為RTS應該已經這樣做了。
請注意,ReadLine()方法將阻塞,直到獲取NewLine字符。 你沒有發送一個,所以你也不會回來。 使用Read()將是一個更好的測試。
首先使用已知的工作程序進行一些基本的故障排除,消除接線問題,錯誤的波特率或設備根本不回顯。 使用超級終端或膩子。
湯姆,
我有類似的問題,
我打賭我的賭注是ReadLine()只有在收到\\ r \\ n或者.NET認為是新行的東西后才會返回。
在你的日志中,我沒有看到Winbird報告任何新行字符,我相信APP正在逐字節讀取,而不是等待換行。
因此,您可以向其發送許多字節的數據,並且它將繼續阻塞,直到它收到正確的新行字符。
所以試試SerialPort.Read,一次讀取1個字節給初學者,
public int Read (
byte[] buffer,
int offset,
int count
)
如果這沒有解決它,您可能需要考慮以下內容
我的一些問題通過添加一些Thread.Sleep()來解決,因為我意識到PC的UART速度不夠快,不能正確地通過RS232 / RS485端口電傳輸數據,也可以在打開端口后等待幾毫秒。
我還建議你創建一個單獨的線程來處理串行通信,而不是使用SerialDataReceivedEventHandler,創建一個發送緩沖區,它以正確的增量發送而不阻塞你的應用程序,也讀取數據並將接收到的字節追加到緩沖區,直到你收到了足夠的數據。
您還需要第二個串行設備來捕獲數據,以確保您的C#應用程序正在傳輸正確的數據。
要消除握手問題,只需連接PIN 2,3 + PIN 5(GND)即可進行測試。
希望這可以幫助
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.