2016-09-28 2 views
1

J'essaye d'écrire ma propre bibliothèque pour envoyer des messages de mon UNU Arduino via UART0 à mon ordinateur.Problèmes de réception de chaînes via UART0 sous Arduino UNO

La bibliothèque fonctionne correctement à l'exception de la partie où je souhaite recevoir des chaînes. Le code de la bibliothèque est:

#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); 
    } 
} 

Lors de l'exécution de ce code, PuTTY affiche des jetons et des arrêts aléatoires. Je ne peux plus rien insérer.

+0

"PuTTY montre quelques jetons et arrêts aléatoires" - quels jetons aléatoires? Êtes-vous capable de nous donner la sortie? –

+0

Aussi, essayez d'affiner votre problème si possible, en donnant un [exemple minimal, complet et vérifiable] (http://stackoverflow.com/help/mcve), peut-être par la méthode ** Divide and Conquer ** qui page d'aide suggère. –

+1

"PuTTY affiche des jetons et des arrêts aléatoires" - sonne comme un mauvais réglage du débit en bauds – Gravell

Répondre

2

Je pense que le problème principal que vous avez est que vous n'avez alloué aucun tampon dans lequel stocker les données reçues (comme indiqué dans les commentaires par @WeatherVane). Lorsque vous écrivez une fonction en C qui va renvoyer une chaîne, vous avez deux choix: soit l'appelant fournit un tampon et lui passe un pointeur dans la fonction, soit la fonction alloue le tampon et renvoie un pointeur vers il.

Si la fonction va l'allouer, alors il devra l'allouer sur le tas, en utilisant la fonction malloc. Vous ne pouvez pas utiliser une variable locale dans la fonction, car si vous l'avez fait dès que vous avez quitté la fonction, la variable est hors de portée. En théorie, vous pouvez utiliser une variable statique comme tampon, mais si vous l'avez fait, vous ne pouvez lire qu'une seule chaîne à la fois.

Si l'appelant doit fournir un tampon, il peut alors utiliser une variable locale, une variable statique ou une allocation à partir du tas.

Lorsque le tampon est alloué sur le tas, peu importe qui l'attribue, l'appelant doit le libérer lorsqu'il en a terminé avec la fonction free.

Les systèmes embarqués minimiser généralement l'utilisation de variables attribuées tas - voir this question pour quelques informations sur les raisons pour cela - et vous pourriez être mieux permettre à l'appelant d'allouer la mémoire tampon, comme ceci:

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); 
    ... 
} 

Notez que j'ai défini la fonction UART0_READ pour prendre deux arguments: l'adresse du tampon, et sa longueur. Une autre chose qui manque à votre programme est toute garde contre le débordement de la mémoire tampon.

À l'intérieur de votre routine d'entrée, utilisez l'argument buflen dans par exemple. l'appel à memset, et à l'intérieur de la boucle qui lit les caractères pour quitter tôt si trop de caractères sont lus.

Le tampon est défini comme un tableau de caractères locaux dans la fonction appelante.

Quelques autres notes:

  • Ne pas oublier d'ajouter un zéro, un passé le dernier caractère ajouté au tableau. Cela signifie également que vous devez quitter la boucle après avoir lu les caractères buflen-1, de sorte que vous avez suffisamment d'espace pour le 0.

  • Je ne sais pas pourquoi vous appelez strncpy? Vous semblez copier la chaîne sur elle-même. L'exécution d'un programme avec des pointeurs parasites dans un système d'exploitation en taille réelle entraîne souvent une erreur de segmentation. Les environnements embarqués manquent souvent de la sophistication pour détecter les accès mémoire incorrects, à la place vous pourriez avoir un comportement moins prévisible (comme une poubelle aléatoire sortant du port série).

+0

Belle réponse, a bien couvert les lacunes. – chux

+0

Merci, dès que j'aurai le temps je vais essayer d'appliquer vos commentaires. J'avais l'habitude de 'memset' pour remplir' ReceivedString' avec des zéros. Ensuite, importez tous les caractères de l'entrée, mais 'ReceivedString' devrait être rempli de zéros en raison de la fonction' memset'. Par conséquent, je l'ai copié sur lui-même en supprimant les zéros restants avec 'strncpy'. – TheCoffeeRanger