[英]Serial communication with minimal delay
我有一台通過串行通信(即物理或仿真串行端口的 RS-232/RS-422)與外部設備連接的計算機。 它們通過頻繁的數據交換(30Hz)相互通信,但只有小數據包(每個數據包小於 16 字節)。
通信最關鍵的要求是傳輸和接收之間的低延遲或延遲。
數據交換模式類似於握手。 一台主機設備發起通信並不斷在客戶端設備上發送通知。 客戶端設備需要盡快回復來自主機設備的每個通知(這正是需要實現低延遲的地方)。 通知和回復的數據包定義明確; 即數據長度是已知的。 並且基本上不允許數據丟失。
我使用以下常見的 Win API 函數以同步方式進行 I/O 讀/寫:CreateFile、ReadFile、WriteFile
客戶端設備使用 ReadFile 從主機設備讀取數據。 客戶端讀取完長度已知的完整數據包后,使用 WriteFile 將相應的數據包回復給主機設備。 讀和寫總是順序的,沒有並發。
不知何故,通信速度不夠快。 即數據發送和接收之間的時間持續時間太長。 我想這可能是串行端口緩沖或中斷的問題。
這里我總結了一些可能的措施來改善延遲。 請給我一些建議和更正:)
提前致謝!
我通過將通信超時設置為{MAXDWORD,0,0,0,0}
解決了這個問題。
經過多年的努力,在這一天,我終於能夠使用 Microsoft 的 CDC 類 USB UART 驅動程序(USBSER.SYS,現在內置在 Windows 10 中使其真正可用)使我的串行通信終端變得足夠快。
顯然,前面提到的一組值是一個特殊的值,它設置了最小的超時和最小的延遲(至少對於 Microsoft 驅動程序,或者在我看來是這樣)並且如果接收中沒有新字符,也會導致 ReadFile 立即返回緩沖。
這是我的代碼(Visual C++ 2008,項目字符集從“Unicode”更改為“未設置”以避免端口名的 LPCWSTR 類型轉換問題)打開端口:
static HANDLE port=0;
static COMMTIMEOUTS originalTimeouts;
static bool OpenComPort(char* p,int targetSpeed) { // e.g. OpenComPort ("COM7",115200);
char portname[16];
sprintf(portname,"\\\\.\\%s",p);
port=CreateFile(portname,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if(!port) {
printf("COM port is not valid: %s\n",portname);
return false;
}
if(!GetCommTimeouts(port,&originalTimeouts)) {
printf("Cannot get comm timeouts\n");
return false;
}
COMMTIMEOUTS newTimeouts={MAXDWORD,0,0,0,0};
SetCommTimeouts(port,&newTimeouts);
if(!ComSetParams(port,targetSpeed)) {
SetCommTimeouts(port,&originalTimeouts);
CloseHandle(port);
printf("Failed to set COM parameters\n");
return false;
}
printf("Successfully set COM parameters\n");
return true;
}
static bool ComSetParams(HANDLE port,int baud) {
DCB dcb;
memset(&dcb,0,sizeof(dcb));
dcb.DCBlength=sizeof(dcb);
dcb.BaudRate=baud;
dcb.fBinary=1;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
dcb.ByteSize=8;
return SetCommState(port,&dcb)!=0;
}
這是它工作的 USB 跟蹤。 請注意 OUT 事務(輸出字節),然后是 IN 事務(輸入字節),然后是更多 OUT 事務(輸出字節),所有這些都在 3 毫秒內:
最后,如果您正在閱讀本文,您可能有興趣查看我通過 UART 發送和接收字符的函數:
unsigned char outbuf[16384];
unsigned char inbuf[16384];
unsigned char *inLast = inbuf;
unsigned char *inP = inbuf;
unsigned long bytesWritten;
unsigned long bytesReceived;
// Read character from UART and while doing that, send keypresses to UART.
unsigned char vgetc() {
while (inP >= inLast) { //My input buffer is empty, try to read from UART
while (_kbhit()) { //If keyboard input available, send it to UART
outbuf[0] = _getch(); //Get keyboard character
WriteFile(port,outbuf,1,&bytesWritten,NULL); //send keychar to UART
}
ReadFile(port,inbuf,1024,&bytesReceived,NULL);
inP = inbuf;
inLast = &inbuf[bytesReceived];
}
return *inP++;
}
大型傳輸在代碼中的其他地方處理。
最后一點,顯然這是自 1998 年放棄 DOS 以來我設法編寫的第一個快速 UART 代碼。哦,當你玩得開心時,時間會飛逝嗎?
這是我找到相關信息的地方: http : //www.egmont.com.pl/addi-data/instrukcje/standard_driver.pdf
我遇到過類似的串口問題。 就我而言,我解決了降低串行端口延遲的問題。 您可以使用控制面板更改每個端口的延遲(默認設置為 16 毫秒)。 您可以在此處找到該方法: http : //www.chipkin.com/reducing-latency-on-com-ports/
祝你好運!!!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.