PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART String senden



hacker
20.03.2009, 11:25
Hallo zusammen,

mein Ziel ist es, ein beliebigen String über UART zu senden. Meine ersten C Gehversuche sahen aus wie unten im Code. Jedoch erreicht mich am PC immer nur ein "Ha". Sieht also aus, als passt das was mit dem Speicher nicht? Aber müsste der Pointer nicht einfach immer hochgezählt werden? Den ganzen String durch?

Vielleicht könnt ihr mir helfen.


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

#define BAUD 19200UL
#define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1)

/************************************************** ***********************
Initialisierung vom UART Interface
************************************************** ***********************/
void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);

// Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

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

// Rücksetzen von Receive Complete Flag
UCSRA = (1<<RXC);
}

/************************************************** ***********************
String senden
************************************************** ***********************/
void uart_send(const char *string)
{
do
{
// ... warten bis der Sendepuffer leer ist ...
while (!( UCSRA & (1<<UDRE)))
;

UDR = (const unsigned char)*string;
}
while (*string++);
}

/************************************************** ***********************
UART Empfangs Interrupt ISR
************************************************** ***********************/
ISR(SIG_UART_RECV)
{
unsigned char buffer;

// Daten aus dem Puffer lesen ...
buffer = UDR;
}


void uart_init(void);

void uart_send(const char *string);

uart_send("Hallo!" "\r\n");

Das ist uart.c, uart.h und der Aufruf der Methode in main.c


Danke schonmal für eure Hilfe :)

Grüße,
hacker

Ceos
20.03.2009, 12:29
void uart_send(const char *string)
{
do
{
// ... warten bis der Sendepuffer leer ist ...
while (!( UCSRA & (1<<UDRE)))
;

UDR = (const unsigned char)*string;
}
while (*string++);
}

warum const char *string ? einfach nur char* string reicht doch!

wie empfängst du den string, mitm terminal ?

ausserdem ist deine while bedingung falsch, die ist post-increment, d.h. du übermittelst auf jeden fall noch das stringterminal mit, ausserdem ist fragwürdig was der compiler mit den nicht konkadenierten(hoffentlich war das richtig geschrieben) "Hallo!" "\r\n" macht, da müsste mindestens noch ein + dazwischen, oder gleich das '\r''\n' ans ende der uart_send methode verfrachten ...

zum fehler würd ich jetzt fast vermuten, dass in der schleifenbedingung versucht wird den WERT hinter dem pointer zu inkrementieren (und der ist laut deiner definition "const char* ptr" schreibgeschützt), ich würde sowas immer klammern *(ptr++) bzw. wenn cih den nachfolgenden wert prüfen will *(++ptr)

hacker
20.03.2009, 13:01
Danke für die rasche Antwort. Ich hab den Code nun zu folgendem geändert:


void uart_send(char *string)
{
while (*string)
{
// ... warten bis der Sendepuffer leer ist ...
while (!( UCSRA & (1<<UDRE)))
;

UDR = (unsigned char)*string;

string++;
}

}

Das mit dem "+" Operator hab ich auch mal ausprobiert, jedoch meckert der Compiler dass "+" für "*string" und "*string" nicht geht. Ich hab es aber auch mal so probiert: "uart_send("Hallo!\r\n"); funktioniert auch nicht.

Empfangen tu ich am PC mit einem eigen in Java geschriebenem Programm. Ich hab aber auch schon das Hyperterminal ausprobiert. Ankommen tut ausschließlich "Ha"

Ceos
20.03.2009, 13:15
seltsam, sieht eigentlich vollkommen i.o. aus *grübel*

wo du gesagt hast "selber geschrieben" hab cih schon vermutet dass du vielleicht nur einmal ausliesst und die restlichen bytes im com puffer liegen, aber wenns hyperterminal dasselbe sagt ...

ich machs über den index und mit for schleife
for (int i = 0; i < strlen(text); i++)
{
USART_Transmit(text[i]);
}
USART_Transmit('\r');
USART_Transmit('\n');

USART_Transmit(...) iss auch nur schleife mit warten und ins UDR schreiben


für eher unwahrscheinlich halte ich das alte Quarzproblem, aber dennoch, welchen Quarz benutzt du, ist F_CPU vernünftig eingestellt ?

hacker
20.03.2009, 13:53
Als Quarz benutze ich 16MHz. Mit einem Bascom Programm funktioniert es tadellos. F_CPU steht auch auf 16000000 im MFile. Muss ich sonst noch irgendwas dem Compiler übergeben oder in der IDE einstellen? Ich benutze AVRStudio mit WinAVR. Ich hab es mal probiert zu simulieren/debuggen. In uart_send bleibt er das dritte mal hier


// ... warten bis der Sendepuffer leer ist ...
while (!( UCSRA & (1<<UDRE)))
;

stecken. Das entspricht auch meinem "Ha" ;-) Kann sich das einer erklären, warum er da hängen bleibt?

Grüße,
hacker

sternst
20.03.2009, 13:57
warum const char *string ? einfach nur char* string reicht doch!Der String wird in der Funktion nicht verändert, also ist das const hier genau richtig. Das hat nichts mit "reicht doch" zu tun, sondern mit gutem Programmierstil.


ausserdem ist fragwürdig was der compiler mit den nicht konkadenierten(hoffentlich war das richtig geschrieben) "Hallo!" "\r\n" machtDas ist völlig korrektes C, und macht genau das, was der OP davon erwartet.


da müsste mindestens noch ein + dazwischenC != C++


@ hacker:

Bekommst du nur ein einzelnes "Ha", oder eine unendliche Abfolge davon? Wenn letzteres, tippe ich auf den Watchdog.

hacker
20.03.2009, 13:58
Komisch. Ich hab grad die Interrupts gesperrt. Und siehe da es kommt "Hallo!" an. Aber was hat das mit den Interrupts zu tun?

Ich bekomme mit sei() nur ein einzelnes "Ha".

Ceos
20.03.2009, 14:08
vielleicht hast du einen interrupt enabled, den du im code noch nciht eingebaut hast und dein controller schmiert ab ?!

sternst
20.03.2009, 14:16
vielleicht hast du einen interrupt enabled, den du im code noch nciht eingebaut hast und dein controller schmiert ab ?!
Dann müsste eine unendliche Abfolge von "Ha"s kommen.
Ich tippe eher auf eine Endlosschleife in einer ISR, oder einem versehentlichen Deaktivieren des Uart in einer ISR.

Ceos
20.03.2009, 14:28
stimmt auch wieder ... naja check halt mal die interrupts ^^

hacker
20.03.2009, 14:32
Ich hab bei der uart_init() nun folgenden Code gestrichen. Jetzt funktioniert es.


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

// Rücksetzen von Receive Complete Flag
UCSRA = (1<<RXC);

ISRs hab ich nur eine einzelne die


ISR(SIG_UART_RECV)
{
//unsigned char buffer;

// Daten aus dem Puffer lesen ...
//buffer = UDR;
}

Und da steht nichts drin ;-)

sternst
20.03.2009, 15:06
Ich hab bei der uart_init() nun folgenden Code gestrichen. Jetzt funktioniert es.Nein, daran liegt es sicher nicht.


ISRs hab ich nur eine einzelne die


ISR(SIG_UART_RECV)
{
//unsigned char buffer;

// Daten aus dem Puffer lesen ...
//buffer = UDR;
}

Und da steht nichts drin ;-)Und wie sieht diese ISR denn nun wirklich aus? So wie hier (was Probleme verursacht), oder so wie im ersten Posting?

hacker
20.03.2009, 15:15
Hallo,

die ISR sieht nun aktuell so aus:


ISR(USART_RXC_vect)
{
unsigned char buffer;

// Daten aus dem Puffer lesen ...
buffer = UDR;
}

UDR wird schon gelesen, sonst rennt der Interrupt ja immer wieder an.

Aber es funktioniert immer noch nicht wirklich. Nur wenn ich die Interrupts ausschalte, kommt der ganze String an, sonst immer nur "Ha".

/Edit.

Jetzt geht es nicht mal mehr, wenn ich die Interrupts ausschalte. Aktueller Code:


#include <uart.h>

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


void set_pll_frequency(unsigned short multiplier)
{
unsigned short divider = 1024;
unsigned char mux = 10;

while (divider * multiplier > 2000)
{
divider >>= 1;
mux--;
}

//divider * multiplier -> Zerlegen in die zwei PCF8574 Bytes für PLL und über i2c wegschicken

//mux -> mux ports setzen

}




int main(void)
{
uart_init();

//sei();

uart_send_string("Hallo!" "\r\n");

while (1)
{

}

return 0;
}


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

#define BAUD 19200UL
#define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1)

/************************************************** ***********************
Initialisierung vom UART Interface
************************************************** ***********************/
void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);

// Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

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

// Rücksetzen von Receive Complete Flag
UCSRA = (1<<RXC);
}

/************************************************** ***********************
Zeichen senden
************************************************** ***********************/
void uart_send_char(const unsigned char data)
{
// ... warten bis der Sendepuffer leer ist ...
while (!( UCSRA & (1<<UDRE)))
;

UDR = data;
}

/************************************************** ***********************
String senden
************************************************** ***********************/
void uart_send_string(const char *data)
{
while (*data)
{
uart_send_char(*data);

data++;
}
}

/************************************************** ***********************
UART Empfangs Interrupt ISR
************************************************** ***********************/
ISR(USART_RXC_vect)
{
unsigned char buffer;

// Daten aus dem Puffer lesen ...
buffer = UDR;
}

hacker
20.03.2009, 15:42
Kann es sein, dass man noch was in der IDE oder beim Compiler einstellen muss? Ich fang erst mit C an und falls man dazu noch was einstellen müsste, hab ich es sicherlich nicht oder falsch gemacht. Das ist vielleicht als Fehlerquelle auch nicht auszuschließen?