![](/img/trans.png)
[英]How can I flush/empty my UART(RX) each time before I receive a new message?
[英]Why do I receive characters at an offset in the buffer when using ReadFile()?
我正在嘗試編寫 win 控制台,它將通過 UART 與我的 ATMega2560 板進行通信。 現在它應該將保存在stringToSend
中的字符串發送到 MCU,該 MCU 應該發送回 PC。 MCU發送過來的字符串要保存在receivedString
中,然后寫入win控制台window。
它現在所做的是,在我將字符串發送到 MCU 之后它會返回,但在控制台上我看到在回顯字符串之前出現意外的“╠”字符序列,就像這樣:
你發送:
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠已發送測試字符串!
編輯:如果BUFFER_SIZE
是常量,字符數是一致的,但它隨着BUFFER_SIZE
:
BUFFER_SIZE = 124
那么有132個這樣的字符BUFFER_SIZE = 1024
那么有1032個這樣的字符BUFFER_SIZE = 1
那么有9個這樣的字符receivedString
時, stringToSend
中的字符串不存在,但它會出現在控制台中。#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <tchar.h>
#include <windows.h>
#define BUFFER_SIZE 124
// This is code from microsoft website which I just transfered into function
HANDLE SerialCommSetup(TCHAR* comName, DWORD baudRate, BYTE byteSize, BYTE parity, BYTE stopBits )
{
DCB dcb;
BOOL fSuccess;
TCHAR* pcCommPort = comName; // Most systems have a COM1 port
COMMTIMEOUTS timeouts = { 0 };
// Open a handle to the specified com port.
HANDLE hCom = CreateFile( pcCommPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if( hCom == INVALID_HANDLE_VALUE )
{
printf( "CreateFile failed with error %d.\n", GetLastError() );
return hCom;
}
// Initialize the DCB structure.
SecureZeroMemory( &dcb, sizeof( DCB ) );
dcb.DCBlength = sizeof( DCB );
// Build on the current configuration by first retrieving all current settings.
fSuccess = GetCommState( hCom, &dcb );
if( !fSuccess )
{
printf( "GetCommState failed with error %d.\n", GetLastError() );
return hCom;
}
// Fill in some DCB values and set the com state:
dcb.BaudRate = baudRate; // baud rate
dcb.ByteSize = byteSize; // data size, xmit and rcv
dcb.Parity = parity; // parity bit
dcb.StopBits = stopBits; // stop bit
fSuccess = SetCommState( hCom, &dcb );
if( !fSuccess )
{
printf( "SetCommState failed with error %d.\n", GetLastError() );
return hCom;
}
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if( SetCommTimeouts( hCom, &timeouts ) == 0 )
{
fprintf( stderr, "Error setting timeouts\n" );
CloseHandle( hCom );
return hCom;
}
// Get the comm config again.
fSuccess = GetCommState( hCom, &dcb );
if( !fSuccess )
{
printf( "GetCommState failed with error %d.\n", GetLastError() );
return hCom;
}
_tprintf( TEXT( "\nSerial port %s successfully reconfigured.\n" ), pcCommPort );
return hCom;
}
int main( void )
{
char stringToSend[] = "Sended test string!\0";
char receivedString[BUFFER_SIZE];
TCHAR wroteCom[5]; // Variable for name of port where the MCU is connected (find it in device manager or avrdude)
// Enter on which port you have connected the MCU to your PC (COM0 - COM9) - mine is on COM3
printf( "Enter COM name: " );
if( !scanf( "%ls", wroteCom ) )
return -1;
if( !wroteCom )
return -2;
wroteCom[4] = '\0';
/* Serial communication inicialization with parameters:
* - Port: (which you typed)
* - Baud rate: 9600
* - Data bits: 8
* - Parity: NONE
* - Stop bits: 1
*/
HANDLE mainCom = SerialCommSetup( wroteCom, CBR_9600, 8, NOPARITY, 1 );
if( !mainCom )
return 1;
// Send string to MCU
if( !WriteFile( mainCom, stringToSend, sizeof( stringToSend ), NULL, NULL ) )
{
CloseHandle( mainCom );
return 2;
}
// Receive string from MCU and write it into console
if( !ReadFile( mainCom, receivedString, sizeof( stringToSend ), NULL, NULL ) )
{
CloseHandle( mainCom );
return 3;
}
printf( "\nYou sent: \n\n%s\n\n", receivedString );
CloseHandle( mainCom );
return 0;
}
#define F_CPU 16000000 // Set the clock speed
#define BAUD_RATE 9600 // Set the baud rate
#define MYUBRR F_CPU/16/BAUD_RATE-1 // Calculate the value for UBRR0 - from datasheet
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int newString = 0;
unsigned int index = 0;
char receivedString[1024];
// USART init - from datasheet
void USART_Init( unsigned int ubrr)
{
/* Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 1stop bit */
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
} // USART_Init
// USART receiving - from datasheet
unsigned char USART_Receive( void )
{
/* Wait for data to be received */
while ( !(UCSR0A & (1<<RXC0)) )
;
/* Get and return received data from buffer */
return UDR0;
}
// USART sending - from datasheet
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = data;
}
void SendString(char* stringToSend)
{
for(unsigned int index = 0; stringToSend[index] != '\0'; index++)
USART_Transmit(stringToSend[index]);
USART_Transmit('\0');
}
ISR(USART0_RX_vect) //
{
char c = USART_Receive();
if( c == '\n' || c == '\0'|| index >= 1023)
{
receivedString[index] = '\0';
index = 0;
newString = 1; // Indication of receiving whole string
}
else
receivedString[index++] = c;
}
int main(void)
{
USART_Init(MYUBRR);
sei(); // Enable interrupts
UCSR0B |= (1<<RXCIE0); // Enable complete interrupt
while (1)
{
if(newString == 1)
{
newString = 0;
SendString(receivedString);
}
}
}
我真的很感激任何幫助,即使是重構/其他編碼技巧。
output:
ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc >ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc ffffffcc 53 65 6e 64 65 64 20 74 65 73 74 20 73 74 72 69 6e 67 21
這些字符的數量始終為
BUFFER_SIZE + 8
,十進制字符表示為-52
WriteFile()
和ReadFile()
並且問題不存在(但它肯定會導致一些問題,因為文檔說最后兩個參數不能同時為 NULL)。ReadFile()
應該總是在事件發生之后出現,並且 function WaitCommEvent()
會捕獲它。 事件類型由SetCommMask(mainCom, EV_RXCHAR)
設置,因此當輸入緩沖區中有字符時會發生(有 function SetCommMask()的文檔)。 此解決方案顯示錯誤是由不發送數據的板引起的,因為WaitCommEvent()
將在無限循環中等待接收數據。 但是,如果不使用WaitCommEvent()
,發送的數據似乎由某種 memory 保存並從那里讀取,所以即使板子不發送它們,它們也會被打印出來(我真的不明白為什么)。 真正解決這個問題的方法很簡單,就是每次我啟動 windows 時重新連接電路板(重新連接后即使使用WaitCommEvent()
也能正常工作)這讓我陷入了完全不同的問題,如果 windows 在啟動時向 USB 端口發送了一些奇怪的東西所以它弄亂董事會,但這是另一個話題。 這也可能是由 windows 在啟動時使用不同的通信參數(如波特率等)引起的。 但那是另一個/不同的問題。 ReadFile()
不會從串行設備讀取任何字節,因為您錯誤地調用了最后兩個參數設置為NULL
。 但是, ReadFile()
沒有返回FALSE
。
填充到receivedString
中的值 0xCC(打印符號擴展為 0xFFFFFFCC)用作調試輔助。
您的 PC 編譯器顯然將變量receivedString
定位在堆棧中變量stringToSend
之前。 額外的字節很可能是金絲雀字。
當您現在打印receivedString
時, function printf
掃描 memory 直到它找到一個終止'\0'
。 這是在stringToSend
的內容被額外掃描並復制到 output之后的情況。所以您看到的不是ReadFile()
收到的,而是stringToSend
的現有字符,這恰好是您期望收到的。
這可視化了 memory 的情況:
(低地址)... | receivedString |
填充 | stringToSend |
...(更高地址) |
---|---|---|---|---|
0xCC, 0xCC, ... 0xCC | 0xCC, ... 0xCC | 'S', 'e', ... ',', '\0' |
你該怎么辦?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.