2016-09-28 47 views
1

我想寫我自己的庫,通過UART0發送消息從我的Arduino UNO到我的電腦。Arduino通過UART0接收字符串的問題UNO

除了我想要接收字符串的部分以外,庫成功工作。該庫的代碼是:

#define F_CPU 16000000 

#define EVEN_P 0 
#define ODD_P 1 

#define BAUD_RATE 57600 

#include <avr/io.h> 
#include <math.h> 
#include <avr/io.h> 
#include <string.h> 
#include <util/delay.h> 

// Initialize UART0 communication 
void UART0_Init_Custom(unsigned long BaudRate, char AsyncDoubleSpeed, char DataSizeInBits, char ParityEVENorODD, char StopBits) 
{ 
    uint16_t UBBR_Value = lrint (F_CPU/16/BaudRate - 1); // maybe 16L?? 

    // Setting the U2X bit to 1 for double speed asynchronous (default = 0, normal speed) 
    if (AsyncDoubleSpeed == 1) UCSR0A = (1 << U2X0); 

    // Upper part of the baud number (bits 8 to 11) 
    UBRR0H = (unsigned char)(UBBR_Value >> 8); 
    // Rest of the baud number 
    UBRR0L = (unsigned char)(UBBR_Value); 

    // Enable the receiver and transmitter 
    UCSR0B = (1 << RXEN0) | (1 << TXEN0); 

    // Set 2 stop bits (default = 1) 
    if (StopBits == 2) UCSR0C = (1 << USBS0); 

    // Set parity 
    if (ParityEVENorODD == EVEN_P) UCSR0C |= (1 << UPM01); 
    if (ParityEVENorODD == ODD_P) UCSR0C |= (3 << UPM00); 

    // Set data length (default = 5 bits) 
    if (DataSizeInBits == 6) UCSR0C |= (1 << UCSZ00); // 6-bit 
    if (DataSizeInBits == 7) UCSR0C |= (2 << UCSZ00); // 7-bit 
    if (DataSizeInBits == 8) UCSR0C |= (3 << UCSZ00); // 8-bit 
    if (DataSizeInBits == 9) UCSR0C |= (7 << UCSZ00); // 9-bit 
} 

void UART0_Init(unsigned long BaudRate) 
{ 
    if (BaudRate == 115200) 
    { 
     UART0_Init_Custom((BaudRate/2),1,8,0,2); 
    } 
    else 
    { 
     UART0_Init_Custom(BaudRate,0,8,0,2); 
    } 
} 

// Receive Data UART0 
char UART0_GET(void) 
{ 
    while (!(UCSR0A & (1 << RXC0))); 
    return UDR0; 
} 

// Transmit Data UART0 
void UART0_PUT(char data) 
{ 
    while (!(UCSR0A & (1 << UDRE0))); 
    UDR0 = data; 
} 

// Transmit Data-String UART0 
void UART0_PRINT(char* String) 
{ 
    while(*String) 
    { 
     UART0_PUT(*String++); 
    } 
} 

// Receive Data-String UART0 
char* UART0_READ(void) 
{ 
    char* ReceivedString; 
    char ReceivedBit; 
    int StringBit = 0; 
    memset(&ReceivedString,0,sizeof(ReceivedString)); 
    while ((ReceivedBit=UART0_GET())!=13) 
    { 
     UART0_PUT(ReceivedBit); 
     ReceivedString[StringBit] = ReceivedBit; 
     StringBit++; 
    } 
    ReceivedString[StringBit] = 13; 
    ReceivedString[StringBit++] = 10; 
    UART0_PUT(10); 
    strncpy(ReceivedString, ReceivedString, StringBit+1); 
    return(ReceivedString); 
} 

char* Input; 
int main(void) 
{ 
    UART0_Init(BAUD_RATE); 
    UART0_PRINT((char*)"Give a message and I will return it\r\n"); 
    while(1) 
    { 
     Input = UART0_READ(); 
     UART0_PRINT((char*)"The message was:"); 
     UART0_PRINT(Input); 
    } 
} 

運行此代碼時,PuTTY會顯示一些隨機令牌並停止。我不能再插入任何東西了。

+0

「PuTTY顯示一些隨機標記並停止」 - 哪個隨機標記?你能給我們輸出嗎? –

+0

此外,儘可能縮小您的問題,給出[最小化,完整和可驗證的示例](http://stackoverflow.com/help/mcve),也許通過** Divide and conquer **方法幫助頁面建議。 –

+1

「PuTTY顯示一些隨機令牌並停止」 - 聽起來像波特率設置錯誤 – Gravell

回答

2

我認爲你的主要問題是你沒有分配任何緩衝區來存儲接收到的數據(正如在@WeatherVane的評論中指出的那樣)。

在C函數中寫一個要返回字符串的函數時,有兩種選擇:調用者提供一個緩衝區並將指針傳遞給該函數,或者函數分配緩衝區並返回一個指向它。

如果函數要分配它,那麼它將不得不使用malloc函數在堆上分配它。你不能在函數中使用局部變量,因爲如果你一旦退出函數,那麼變量超出了範圍。理論上你可以使用一個靜態變量作爲緩衝區,但是如果你這樣做了,你一次只能讀一個字符串。

如果調用者要提供緩衝區,那麼它可以使用局部變量,靜態變量或從堆中分配。

緩衝區在堆上分配時,不管是誰分配緩衝區,調用者必須使用free函數釋放緩衝區。一般

嵌入式系統儘量減少使用堆分配變量 - 見this question有關原因是一些信息 - 所以你可能會更好,以允許呼叫者分配緩衝區,就像這樣:

void UART0_READ(char* buffer, int buflen) 
{ 
// ... here goes code to read into buffer 
} 

#define BUFSIZE 100 

int main(void) 
{ 
    char input[BUFSIZE]; 
    UART0_READ(input, BUFSIZE); 
    ... 
} 

請注意,我將UART0_READ函數定義爲兩個參數:緩衝區的地址和長度。你的程序缺少的另一件事是防止緩衝區溢出。

在你的輸入例程中,使用例如buflen參數。對memset的調用,以及在讀取太多字符時讀取字符以提前退出的循環內部。

緩衝區被定義爲調用函數中的本地字符數組。

其他一些注意事項:

  • 不要忘記加一個零,一個過去的最後一個字符添加到陣列中。這也意味着您必須在讀取buflen-1字符後退出循環,因此您有足夠的空間用於0.

  • 我不確定爲什麼要撥打strncpy?你似乎正在將字符串複製到自己身上。

  • 在全尺寸操作系統中運行帶有雜散指針的程序通常會導致段錯誤。嵌入式環境往往缺乏檢測不正確內存訪問的複雜性,相反,您可能會得到較少的可預測行爲(例如從串口出來的隨機垃圾)。

+0

好的答案,很好地覆蓋了短缺。 – chux

+0

謝謝,只要我有空,我會嘗試應用您的反饋。 我用'memset'來填充'ReceivedString'爲零。 然後導入輸入中的所有字符,但由於memset函數,'ReceivedString'應該填滿零。因此,我將它複製到自身上,用'strncpy'刪除剩餘的零。 – TheCoffeeRanger