PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART avr-gcc, \0x00 zu viel am Ende



ra.graf1988
23.07.2012, 21:45
Hallo zusammen!
Ich habe ein Problem mit dem UART meines RNControl1.4 oder besser gesagt mit der Programmierung.

Mit diesem Wiki Artikel bin ich schon sehr weit gekommen.
http://www.rn-wissen.de/index.php?title=UART_mit_avr-gcc&redirect=no
Die Kommunikation ohne Interrupts funktioniert einwandfrei.

Jetzt habe ich das ganze mit Interrupts probiert, und habe folgendes Problem.
Ich will wie unter:
http://www.rn-wissen.de/index.php?title=UART_mit_avr-gcc&redirect=no#Einen_String_senden
einen String vom µC zum PC senden. Der kommt auch an, leider kommt noch ein \0x00 hinten nach also:

Hallo Welt.
\0x00

Habt ihr eine Vorahnung, an was das liegen könnte, oder muss ich meinen gesamten Code posten?

Gruß

Rainer

ePyx
23.07.2012, 21:53
Ich denke an der do while schleife. Denn der Vergleich mit 0x00 wird erst zum Schluß durchgeführt.



while ( *str )
{
uart_send_char ( *str );
str++;
}


Macht das Gleiche nur, dass der Vergleich im Schleifenkopf stattfindet und damit vor der Übertragung. Des Weiteren werden Strings immer mit einem 0x00 terminiert.

ra.graf1988
23.07.2012, 22:27
Ok verstanden. Das ist also gewollt, dass die 0x00 am Ende kommt.
Könnte mir noch jemand einen Tipp geben, wie ich ein einfaches Echo für einen String mit den Funktionen aus dem oben genannten Artikel erstelle?
Die Funktion uart_getc_wait() und uart_getc_nowait() geben ja nur einen Integer Wert aus... Wie komme ich jetzt da auf einen String?

ePyx
24.07.2012, 05:54
Die Funktion uart_getc_wait() und uart_getc_nowait() geben ja nur einen Integer Wert aus...

Warum sollte das so sein? uint8_t ist das bis auf das Vorzeichen (und damit auch dem Wertebereich) das Gleiche wie ein char. Im Grunde wird so oder so immer nur ein Byte, also ein Zeichen zwischen 0x00 und 0xFF übertragen. Ein Zeichen wird durch die Interpretation daraus (http://www.torsten-horn.de/techdocs/ascii.htm). Bis auf die ersten 30 und die Zeichen größer 127 funzt das ohne Probleme als Echo.

ra.graf1988
24.07.2012, 16:15
ach ja, ok
Wenn ich jetzt


uart_putc(uart_getc_wait());

in meiner Hauptschleife ausführe bekomme ich mein Echo durch einzelne Character.
Aber jetzt wird ja jeder Charakter, wenn er ankommt gleich wieder zurück geschickt.

Wie kann ich denn jetzt die einzelnen Charakter, die ankommen zusammensetzen?
Das mit den Strings in C leuchtet mir noch nicht so ganz ein.


char text2[40] = "";
char x;

do
{
x= uart_getc_wait();
strcat(text2,x);
}
while(x!=-1);

uart_puts(text2);
Das funktioniert auch nicht so ganz...

ePyx
24.07.2012, 16:33
Naja du musst die Zeichen natürlich puffern. Entweder in einem Array oder in einem FIFO (http://www.rn-wissen.de/index.php/FIFO_mit_avr-gcc) (ist eigentlich auch nichts anderes, halt ein Array mit Features). Im Beispiel im Wiki werden ja auch FIFOs benutzt.

Einfach ausgedrückt :
Array anlegen
Ein empfangenes Zeichen in das Array kopieren
Die Position im Array hochzählen

Allerdings würde ich das Ganze dann in der ISR der USART machen und nicht irgendwo in einem Programm.

ra.graf1988
24.07.2012, 17:28
ok, wenn ich die fifo schon dabei hab, dann nutze ich es doch aus:

ISR (USART_RXC_vect){
_inline_fifo_put (&infifo, UDR);


}

char text[] = "Hallo Welt."; char text2[40] = "";
uint8_t x =0;


uart_puts (text);


/*##############Hauptschleife###########*/
while(1)
{
x =0;
do
{
text2[x]= uart_getc_wait();
x++;
}
while(x==5);


uart_puts(text2);
}




return 0;
}
Ich hab mir gedacht ich sende jetzt einfach mal 6 Zeichen. "123456"
Aber nun bekomme ich zurück:
1\0x002\0x003\0x004\0x005\0x006\0x00
\0x00
reiht meine do-while-schleife nicht alle Zeichen aneinander?

außerdem kann ich auch nur 1 Zeichen schicken: "1"
dann kommt zurück:
1\0x00
aber er sollte doch warten bis 6 Zeichen kommen....

ePyx
24.07.2012, 18:01
Ich hab mir gedacht ich sende jetzt einfach mal 6 Zeichen. "123456"


Auch wenn das etwas drastisch klingt, sehr weit hast du dabei nicht gedacht.

Ich würde die Zeichen aus dem FIFO ausgeben und nicht das aktuelle Zeichen was gerade ankommt. Des Weiteren, schmeißt du jedes Zeichen direkt wieder auf den UART, wenn du die Ausgabe abhängig von der Anzahl der Bytes im FIFO machst, wird wohl eher ein Schuh draus.

ra.graf1988
24.07.2012, 20:20
Ist das schon mal besser?



ISR (USART_RXC_vect)
{
_inline_fifo_put (&infifo, UDR);


}



char text2[40] = "23";
uint8_t x =0;


/*##############Hauptschleife###########*/
while(1)
{
if(infifo.count > 0)
{
x =0;
while(infifo.count > 0);
{
text2[x]= _inline_fifo_get(&infifo);
x++;
}
uart_puts(text2);
}
}




return 0;
}
Ich frage ab, ob was in der infifo ist, wenn nein, soll er einen neuen Hauptschleifendurchlauf machen.
Wenn ja, so lange bis die infifo leer ist, die charakter in den String text2 packen
Wenn die infifo nun leer ist, dann wird vom µC an den PC gesendet....

Das sind meine Überlegungen, leider tut sich nichts.

Danke schon mal für deine Geduld...

ePyx
24.07.2012, 20:27
ISR (USART_RXC_vect)
{
_inline_fifo_put (&infifo, UDR);
}



char text2[40] = "23";
uint8_t x =0;


/*##############Hauptschleife###########*/
while(1)
{
// Nach 6 Zeichen wird der Inhalt des FIFOs zurückgeschickt.
if(infifo.count == 6)
{
char ch;
while(infifo.count > 0);
{
ch = fifo_get_wait (&infifo);
uart_putc(ch);
}
}
}




return 0;
}

Probiere es mal so.

ra.graf1988
24.07.2012, 20:38
hm ich hab das jetzt mal so probiert, aber es kommt nichts zurück.

ePyx
24.07.2012, 20:45
Aber du hast die Interrupts aktiviert und die Übertragung via Interrupt funktioniert auch?

ra.graf1988
24.07.2012, 20:53
Ja sollte alles funktionieren. Das ist mein Code:



/*### Includes ###*/#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include "BTControlled_v1.0.h"
#include "uart.h"

/*############### ISR ###########################*/

// Empfangene Zeichen werden in die Eingangs-FIFO gespeichert und warten dort
ISR (USART_RXC_vect)
{
_inline_fifo_put (&infifo, UDR);
}

// Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
// Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA-IRQ getriggert
// Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
ISR (USART_UDRE_vect)
{
if (outfifo.count > 0)
UDR = _inline_fifo_get (&outfifo);
else
UCSRB &= ~(1 << UDRIE);
}


/*############## Main ############################*/

int main(void)
{
/*##########Initialisierungsphase############*/

//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
DDRA |= 0x00; //00000000 -> alle Analogports als Eingänge
DDRB |= 0x03; //00000011 -> PORTB.0 und PORTB.1 sind Kanäle des rechten Motors
DDRC |= 0xFF; //11111111 -> PORTC.6 und PORTC.7 sind Kanäle des linken Motors, Rest sind LEDs für Lauflicht
DDRD |= 0xB0; //10110000 -> PORTD.4 ist PWM-Kanal des linken Motors, PORTD.5 des rechten

setportcon(0); setportcon(1); setportcon(2); setportcon(3); setportcon(4); setportcon(5); //LEDs ausschalten
setportdoff(7); //Speaker aus
init_timer1(); //Initialisierung Timer für PWM


uart_init(); //UART initialisieren
sei();

char text[] = "Hallo Welt.";
char text2[40] = "23";

uart_puts (text);

/*##############Hauptschleife###########*/
while(1)
{


if(infifo.count == 6)
{
char ch;
while(infifo.count > 0);
{
ch = fifo_get_wait(&infifo);
uart_putc(ch);
}
}
}




return 0;
}




Nach dem Reset wird auch vom µC auf den PC übertragen:

Hallo Welt.\0x00

dann sende ich an den µC vom PC aus z.B. 1234567
aber es kommt nichts zurück

ePyx
24.07.2012, 20:56
Initialisierst du das FIFO nicht ?

fifo_init (&fifo, buffer, BUF_SIZE);

ra.graf1988
24.07.2012, 21:07
das mache ich in uart.h:
unter uart_init():

/* * uart.h
*
* Created on: 12.05.2012
* Author: rainer
*/


#ifndef UART_H_
#define UART_H_


#include <avr/io.h>
#include <avr/interrupt.h>
#include "fifo.h" // erklärt im Artikel "FIFO mit avr-gcc"


// FIFO-Objekte und Puffer für die Ein- und Ausgabe


#define BUFSIZE_IN 0x40
uint8_t inbuf[BUFSIZE_IN];
fifo_t infifo;


#define BUFSIZE_OUT 0x40
uint8_t outbuf[BUFSIZE_OUT];
fifo_t outfifo;


//Variable zum Dummy auslesen
uint8_t dummy;


void uart_init (void)
{
uint8_t sreg = SREG;




UBRRH = 0; //Highbyte ist 0
UBRRL = 51; //Lowbyte ist 103 (dezimal)
//-> (Frequenz_in_Hz / (Baudrate * 16)) - 1 <- Quarzfrequenz = 16*1000*1000 Hz!!!!


// Interrupts kurz deaktivieren
cli();


// UART Receiver und Transmitter anschalten, Receive-Interrupt aktivieren
// Data mode 8N1, asynchron
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);


// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
do
{
// UDR auslesen (Wert wird nicht verwendet)
dummy = UDR;
}
while (UCSRA & (1 << RXC));


// Rücksetzen von Receive und Transmit Complete-Flags
UCSRA = (1 << RXC) | (1 << TXC);


// Global Interrupt-Flag wieder herstellen
SREG = sreg;


// FIFOs für Ein- und Ausgabe initialisieren
fifo_init (&infifo, inbuf, BUFSIZE_IN);
fifo_init (&outfifo, outbuf, BUFSIZE_OUT);
}




int uart_putc (const uint8_t c)
{
int ret = fifo_put (&outfifo, c);


UCSRB |= (1 << UDRIE);


return ret;
}


int uart_getc_nowait (void)
{
return fifo_get_nowait (&infifo);
}


uint8_t uart_getc_wait (void)
{
return fifo_get_wait (&infifo);
}


// Einen 0-terminierten String übertragen.
void uart_puts (const char *s)
{
do
{
uart_putc (*s);
}
while (*s++);
}


#endif /* UART_H_ */




hier noch fifo.h:

/* * fifo.h
*
* Created on: 12.05.2012
* Author: rainer
*/


#ifndef FIFO_H_
#define FIFO_H_


#include <avr/io.h>
#include <avr/interrupt.h>


typedef struct
{
uint8_t volatile count; // # Zeichen im Puffer
uint8_t size; // Puffer-Größe
uint8_t *pread; // Lesezeiger
uint8_t *pwrite; // Schreibzeiger
uint8_t read2end, write2end; // # Zeichen bis zum Überlauf Lese-/Schreibzeiger
} fifo_t;


extern void fifo_init (fifo_t*, uint8_t* buf, const uint8_t size);
extern uint8_t fifo_put (fifo_t*, const uint8_t data);
extern uint8_t fifo_get_wait (fifo_t*);
extern int fifo_get_nowait (fifo_t*);


static inline uint8_t
_inline_fifo_put (fifo_t *f, const uint8_t data)
{
if (f->count >= f->size)
return 0;


uint8_t * pwrite = f->pwrite;


*(pwrite++) = data;


uint8_t write2end = f->write2end;


if (--write2end == 0)
{
write2end = f->size;
pwrite -= write2end;
}


f->write2end = write2end;
f->pwrite = pwrite;


uint8_t sreg = SREG;
cli();
f->count++;
SREG = sreg;


return 1;
}


static inline uint8_t
_inline_fifo_get (fifo_t *f)
{
uint8_t *pread = f->pread;
uint8_t data = *(pread++);
uint8_t read2end = f->read2end;


if (--read2end == 0)
{
read2end = f->size;
pread -= read2end;
}


f->pread = pread;
f->read2end = read2end;


uint8_t sreg = SREG;
cli();
f->count--;
SREG = sreg;


return data;
}




void fifo_init (fifo_t *f, uint8_t *buffer, const uint8_t size)
{
f->count = 0;
f->pread = f->pwrite = buffer;
f->read2end = f->write2end = f->size = size;
}


uint8_t fifo_put (fifo_t *f, const uint8_t data)
{
return _inline_fifo_put (f, data);
}


uint8_t fifo_get_wait (fifo_t *f)
{
while (!f->count);


return _inline_fifo_get (f);
}


int fifo_get_nowait (fifo_t *f)
{
if (!f->count) return -1;


return (int) _inline_fifo_get (f);
}






#endif /* FIFO_H_ */

ePyx
24.07.2012, 23:08
Das Einzige was mir noch sinnvoll vorkommen würde, wäre das nichts in das FIFO gelangt. Also sprich bei der ISR für den Empfang. Sonst fällt mir auf die Schnelle auch nichts mehr ein.