2016-09-28 15 views
1

Arduino UNOからUART0経由でコンピュータにメッセージを送信するための独自のライブラリを作成しようとしています。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)を、おそらく**分割と征服の方法**で試してくださいヘルプページが示唆している。 –

+1

"PuTTYはいくつかのランダムなトークンと停止を表示します" - 間違ったボーレート設定のような音 – Gravell

答えて

2

主な問題は、受信したデータを格納するバッファを割り当てていないことです(@WeatherVaneのコメントで指摘されているように)。

文字列を返す関数を書くときには、呼び出し元がバッファを提供し、そのポインタを関数に渡すか、関数がバッファを割り当ててポインタを返すかの2つの選択肢があります。それ。

関数が割り当てようとしている場合は、malloc関数を使用して、関数をヒープに割り当てる必要があります。関数内でローカル変数を使用することはできませんでした。なぜなら、関数を終了するとすぐに変数が有効範​​囲外になるからです。理論的には、静的変数をバッファーとして使うこともできますが、そうした場合は一度に1つの文字列しか読み込めません。

呼び出し元がバッファを提供する場合は、ローカル変数、静的変数、またはヒープからの割り当てを使用できます。

バッファがヒープ上に割り当てられている場合、呼び出し元は誰に割り当てても、終了時に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関数は、バッファのアドレスと長さという2つの引数をとるように定義しました。あなたのプログラムに欠けているもう一つのことは、バッファオーバーフローに対するガードです。

入力ルーチンの中で、たとえばbuflen引数を使用します。 memsetへの呼び出し、およびあまりにも多くの文字が読み込まれると早く終了する文字を読み込むループの内部で行われます。

バッファは、呼び出し側関数のローカル文字配列として定義されます。

他のいくつかの注意事項:

  • がゼロを追加することを忘れないでください、最後の文字過去1は、アレイに追加。これはまた、buflen-1文字を読んだ後にループを終了しなければならないことを意味します。

  • なぜstrncpyに電話しているのですか?文字列を自分自身にコピーしているようです。

  • フルサイズのOSで迷惑ポインタを含むプログラムを実行すると、segfaultが発生することがよくあります。組み込み環境では、不正なメモリアクセスを検出するための洗練さが欠けていることが多いため、予期しない動作(シリアルポートから出るランダムなゴミなど)が発生する可能性があります。

+0

ニースの答えは、短絡をうまくカバーしました。 – chux

+0

ありがとうございます、私はあなたのフィードバックを適用しようとします時間を持ってすぐに。 私は 'memset'を使って' ReceivedString'にゼロを埋めました。 その後、すべての文字を入力からインポートしますが、 'ReceivedString'は' memset'関数のためにゼロでいっぱいになるはずです。したがって、それを 'strncpy'で残りのゼロを削除してコピーしました。 – TheCoffeeRanger

関連する問題