PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : String über UART ausgeben



ceekay
18.09.2005, 21:13
Hallo,

ich bin gerade dabei mich in C einzuarbeiten. Doch ich komme leider an einer Stelle nicht weiter.
Ich habe es hinbekommen ein Byte über den UART auszugeben. Nun möchte ich gerne einen ganzen String ausgeben. In dem Tutorial von mikrocontroller.net habe ich einen Beispielcode gefunden. Nur leider kann ich diesen nicht nachvollziehen. Es wäre schön wenn jemand mir mal ein Beispiel geben könnte wo alles genau beschrieben ist, so das ich das nachvollziehen kann.

Vielen Dank im Voraus

gruß ceekay

Kjion
18.09.2005, 21:55
Moin,

vielleicht hilft dir ja folgends weiter:
http://www.kreatives-chaos.com/index.php?seite=avr_b

MfG Kjion

ceekay
18.09.2005, 22:40
falls du das "Beispiel zur Ansteuerung des UART" meinst. dann nein.

Denn das hab ich schon verstanden nur ich möchte zum beispiel folgende Bytes nacheinander ausgeben: 'a' 'b' 'c' 'd'
ohne das ich nacheinander jeden Buschstaben manuell in das UDR schreiben muss.
Wie müsste es aussehen wenn diese Bytes nacheinander übertragen werden.

gruß ceekay

ceekay
18.09.2005, 22:43
ah sorry du meintest: Beispiel: "Strings aus dem Flash ausgeben"

sorry hab ich eben erst gesehen. Das sieht gut aus. ich werd mir das morgen mal genau ansehen und denn nochmal konkrete Fragen stellen.
Vielen Dank erstma.

gruß ceekay

ceekay
20.09.2005, 20:14
Hi,
ich habe das Programm von kreatives-chaos.com mal compiliert und auf meinen Controller geladen. Vorher habe ich noch ein paar Dinge angepasst.
baudrate auf 9600 und Systemclock auf 16000000.
Leider funktioniert es nicht. Ich bekomme nur diese Zeichen permanent:

ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ
ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ
ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ ÀÀÀÀÀÀÀÀÀÀÀÀÀÀ

ich hoffe ihr könnt mir helfen.

Vielen Dank schonmal für die Mühen.

gruß ceekay

Kjion
20.09.2005, 21:54
Hört sich nach einem falsch initialisiertem UART an. Hast du BAUD wie im Beispiel als "unsigned long" definiert ??

#define SYSCLK 16000000
#define BAUD 9600UL

Ansonsten sollte das eigentlich funktionieren...

MfG Kjion

PicNick
21.09.2005, 06:49
Für mich schaut das mehr nach Durcheinender von address-of und value
aus (weil die Zeichen alle gleich sind. bei Baudfehlern ist das selten)

Kjion
21.09.2005, 12:42
Hi,

versuch mal folgendes:


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

#define SYSCLK 16000000
#define BAUD 9600UL
#define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)

#define TRUE 1
#define FALSE 0

/* USART initialisieren */
void uart_init(void);

volatile const prog_char *p_string;

/* Zeichenkette im Flashspeicher */
prog_char daten[] = "Hello World!\n";

int main(void)
{
// USART initialisieren
uart_init();

sei();

// Pointer zeigt auf die Daten im Flashspeicher
p_string = daten;

// erstes Byte senden
UDR = pgm_read_byte( p_string++ );

// Interrupt aktivieren
UCSRB |= (1<<UDRIE);

for(;;);
}

void uart_init(void)
{
/* Baudrate einstellen ( Normaler Modus ) */
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x00FF);

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

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

/* Interrupt wird ausgelöst sobald der Sendepuffer leer ist */
SIGNAL(SIG_UART_DATA)
{
char buffer = pgm_read_byte( p_string++ );

/* Wenn nicht das Ende der Zeichenkette erreicht wurde, weiteres Zeichen senden */
if ( buffer != '\0' ) {
UDR = buffer;

} else {
// Interrupt deaktivieren
UCSRB &= ~(1<<UDRIE);
}
}

Warum das andere Beispiel nicht funktioniert weiß ich im Moment auch noch nicht so genau.
Wenn man sich das Assemblerlisting anschaut, dann sieht man, dass er den Pointer p_string nicht neu lädt. Es wird also nach und nach der gesamte Inhalt des Flashspeichers ausgegeben.
Fügt man aber irgendeine Delayroutine hinter die Abfrage ein, so funktioniert auf einmal alles, auch der Pointer wird wieder richtig initialisiert.

Mit Delay:

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

#define SYSCLK 7372800
#define BAUD 9600UL
#define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)

#define TRUE 1
#define FALSE 0

/* USART initialisieren */
void uart_init(void);

void delay_ms(uint16_t ms);

volatile unsigned char daten_gesendet = TRUE;
volatile const prog_char *p_string;

/* Zeichenkette im Flashspeicher */
prog_char daten[] = "Hello World!\n";

int main(void)
{
// USART initialisieren
uart_init();

sei();

while (1)
{
if (daten_gesendet)
{
// Flag zurücksetzen
daten_gesendet = FALSE;

// Pointer zeigt auf die Daten im Flashspeicher
p_string = daten;

// erstes Byte senden
UDR = pgm_read_byte( p_string++ );

// Interrupt aktivieren
UCSRB |= (1<<UDRIE);
}

delay_ms(1);
}
}

void uart_init(void)
{
/* Baudrate einstellen ( Normaler Modus ) */
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x00FF);

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

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

/* Interrupt wird ausgelöst sobald der Sendepuffer leer ist */
SIGNAL(SIG_UART_DATA)
{
char buffer = pgm_read_byte( p_string++ );

/* Wenn nicht das Ende der Zeichenkette erreicht wurde, weiteres Zeichen senden */
if ( buffer != '\0' ) {
UDR = buffer;

} else {
// Flag setzen, das der String gesendet wurde
daten_gesendet = TRUE;

// Interrupt deaktivieren
UCSRB &= ~(1<<UDRIE);
}
}

/*
* eine kleine Warteschleife ( fürs debugging )
*/
void delay_ms(uint16_t ms)
{
uint16_t zaehler;

while (ms)
{
zaehler = F_CPU / 5000;
while (zaehler)
{
asm volatile ("nop"::);
zaehler--;
}
ms--;
}
}

MfG Kjion

SprinterSB
21.09.2005, 15:12
volatile const prog_char *p_string;
Das mutet etwas seltsam an. Wenn etwas const ist, ist es kaum flüchtig (volatile).
Du meinst wohl eher:

const prog_char * volatile p_string;
p_string ist volatile und das, worauf er zeigt, ist unveränderlich.

Übrigens brauchst du nicht UDR zu schreiben, um das Senden anzustoßen. Da genügt ein UCSRB |= (1<<UDRIE); und man landet in der ISR, sobalt UDR bereit ist. Dort wird dann mit dem 1. Zeichen begonnen und nicht erst mit dem 2.
Spart Platz und ist klarer :-)

Kjion
21.09.2005, 15:24
const prog_char * volatile p_string;
p_string ist volatile und das, worauf er zeigt, ist unveränderlich.

So wars eigentlich auch gemeint. Damit funktioniert es dann natürlich auch.

Wie war das noch, der Computer macht das was man ihm sagt, nicht das was man meint ...


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

#define SYSCLK 7372800
#define BAUD 9600UL
#define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)

#define TRUE 1
#define FALSE 0

// USART initialisieren
void uart_init(void);

volatile unsigned char daten_gesendet = TRUE;
const prog_char* volatile p_string;

// Zeichenkette im Flashspeicher
prog_char daten[] = "Hello World!\n";

int main(void)
{
// USART initialisieren
uart_init();

sei();

while (1)
{
if (daten_gesendet)
{
// Flag zurücksetzen
daten_gesendet = FALSE;

// Pointer zeigt auf die Daten im Flashspeicher
p_string = daten;

/* Interrupt aktivieren, damit wird sofort zur
Interruptroutine gesprungen und das erste Zeichen gesendet. */
UCSRB |= (1<<UDRIE);
}
}
}

void uart_init(void)
{
// Baudrate einstellen ( Normaler Modus )
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x00FF);

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

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

/* Interrupt wird ausgelöst sobald der Sendepuffer leer ist */
SIGNAL(SIG_UART_DATA)
{
char buffer = pgm_read_byte(p_string++);

/* Wenn nicht das Ende der Zeichenkette erreicht wurde,
dann weiteres Zeichen senden */
if ( buffer != '\0' ) {
UDR = buffer;

} else {
// Flag setzen, das der String gesendet wurde
daten_gesendet = TRUE;

// Interrupt deaktivieren
UCSRB &= ~(1<<UDRIE);
}
}


MfG Kjion

ceekay
22.09.2005, 19:21
Hallo,
ja vielen Dank es funktioniert.

echt klasse Forum.

gruß ceekay

P.S.: hab schon bald ne neue Frage

ceekay
03.10.2005, 11:37
hallo, hab doch noch mal ne Frage hierzu:

So lege ich die Zeichenkette im Flash ab:

prog_char daten[] = "Hier steht der Text";

Wie müsste es aussehen wenn ich einzelne Bytes hinschreiben möchte?
Ich habs wie folgt probiert aber ging leider nicht.

prog_char daten[] = 30,31;

wie müsste das vom syntax her aussehen?

gruß ceekay

PicNick
03.10.2005, 12:29
prog_char daten[] = { 30,31,..... };

wenn ich mich richtig erinnere

ceekay
03.10.2005, 13:12
klasse funktioniert.

Ist es auch möglich dort variablen von typ char oder int mit einzubringen?

gruß ceekay

PicNick
03.10.2005, 13:21
prog_char daten[] = { 'a','b',..... }; // is klar

int integs[] = { -3448, 7350, 48, ..... }; // analog

was halt in den Typ reinpasst

ceekay
03.10.2005, 13:45
jo ok das versteht ich.

doch kann ich auch zwischen die werte ne variable vom gleichen datentyp zwischenschieben?

gruß ceekay

PicNick
03.10.2005, 14:00
prog_char daten[] = { 'a','b',37,13,.. };
sowas kannst du natürlich mischen, da die Angaben
'a' = 65 = 0x41 für den C ja dasselbe sind
das ist auch bei integern und was du willst so.
uint32_t = 'z' ist völlig ok.

Was anderes ist es eigentlich nur mit doppel-hochkomma " " , denn das ist ein String mit null-terminator

ceekay
03.10.2005, 15:58
ich meine kann ich folgendes machen:

char variable_x;

prog_char daten[] = {65,66,variable_x,67};

So das ich einen festen Teil aus Werten habe aber auch mal einen Variablen.

wenn ich das nämlich so mache dann bekomme ich die Fehlermeldung:
error: initializer element is not constant


gruß ceekay

PicNick
03.10.2005, 16:03
Beim GCC/WinAVR kann ich's jetzt garnicht sagen. Aber beim VC++ ist das kein Problem. versuch's einfach.

Nur, in deinem Beispiel ist die Variable undefinierten Inhalts. d.h. es steht dann IRGENDWAS drin

char bCH = 65;
char bStr[] = { 1,2,bCH, 78};

geht jedenfalls

ceekay
03.10.2005, 16:06
wie gesagt es geht leider nicht.
Fehlermeldung: error: initializer element is not constant

wie kann ich das denn sonst anstellen? Gibts da noch ne andere Möglichkeit?

ceekay
03.10.2005, 16:13
dein Beispiel

char bCH = 65;
char bStr[] = { 1,2,bCH, 78};

geht bei mir nicht. gleiche Fehlermeldung wie oben.

Hast du das mit winavr getestet?

gruß ceekay

PicNick
03.10.2005, 16:21
oje, das liegt am Compiler, er will einen konstanten wert haben. naja.

Alternative:

char bCH = 65;
char bStr[] = { 1,2, 0 , 78}; // nur platzhalten

bStr[2] = bCH; // jetzt muß er aber können

bei vielen Werten ist das natürlich mühsam

leider

ceekay
03.10.2005, 16:23
nein sind nicht viele Werte ist nur ein Integer den ich in 2 char aufteile. Der Rest sind Konstanten.
Dann will ichs mal testen.

gruß ceekay

ceekay
03.10.2005, 16:27
Achso, kannst du mir noch den Unterschied zwischen:

char bStr[] = {irgentwas};

und

prog_char daten[] = {irgentwas};

erklären ?

gruß ceekay

ceekay
03.10.2005, 16:38
Also ich hab jetzt folgendes:

char pwm_wert_motor_fuer_uebertragung_low;
char pwm_wert_motor_fuer_uebertragung_high;

char daten[14] = {2,66,0,0,0,0,0,0,0,1,0,0,3,4,23};

und dann schreibe ich in der main();
{
daten[10] = pwm_wert_motor_fuer_uebertragung_high;
daten[11] = pwm_wert_motor_fuer_uebertragung_low;
}

wie kann ich diesen String jetzt wieder auslesen?


p_string = daten;

UDR = pgm_read_byte( p_string++ );

gruß ceekay

ceekay
03.10.2005, 19:08
ok jetzt funktioniert alles.
Ich hätte mich vorher erstmal mit zeiger und arrays auseinandersetzen.
da das arry ja jetzt nicht mehr im flash steht funktionierte natürlich "pgm_read_byte" nicht mehr

Vielen Dank für eure Hilfe

gruß ceekay

mpetz
03.10.2005, 20:27
hab kijons code genommen:


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

#define SYSCLK 7372800
#define BAUD 9600UL
#define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)

#define TRUE 1
#define FALSE 0

// USART initialisieren
void uart_init(void);

volatile unsigned char daten_gesendet = TRUE;
const prog_char* volatile p_string;

// Zeichenkette im Flashspeicher
prog_char daten[] = "Hello World!\n";

int main(void)
{
// USART initialisieren
uart_init();

sei();

while (1)
{
if (daten_gesendet)
{
// Flag zurücksetzen
daten_gesendet = FALSE;

// Pointer zeigt auf die Daten im Flashspeicher
p_string = daten;

/* Interrupt aktivieren, damit wird sofort zur
Interruptroutine gesprungen und das erste Zeichen gesendet. */
UCSRB |= (1<<UDRIE);
}
}
}

void uart_init(void)
{
// Baudrate einstellen ( Normaler Modus )
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) (UBRR_BAUD & 0x00FF);

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

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

/* Interrupt wird ausgelöst sobald der Sendepuffer leer ist */
SIGNAL(SIG_UART_DATA)
{
char buffer = pgm_read_byte(p_string++);

/* Wenn nicht das Ende der Zeichenkette erreicht wurde,
dann weiteres Zeichen senden */
if ( buffer != '\0' ) {
UDR = buffer;

} else {
// Flag setzen, das der String gesendet wurde
daten_gesendet = TRUE;

// Interrupt deaktivieren
UCSRB &= ~(1<<UDRIE);
}
}

bekomme dann aber beim kompilieren immer folgende fehlermeldung:


Z:\AVRDevel\Test>make

-------- begin --------
avr-gcc (GCC) 3.4.3
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Compiling: Test.c
avr-gcc -c -mmcu=atmega162 -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char
-funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-
adhlns=Test.lst -std=gnu99 -MD -MP -MF .dep/Test.o.d Test.c -o Test.o
Test.c: In function `main':
Test.c:41: error: `UCSRB' undeclared (first use in this function)
Test.c:41: error: (Each undeclared identifier is reported only once
Test.c:41: error: for each function it appears in.)
Test.c:41: error: `UDRIE' undeclared (first use in this function)
Test.c: In function `uart_init':
Test.c:49: error: `UBRRH' undeclared (first use in this function)
Test.c:50: error: `UBRRL' undeclared (first use in this function)
Test.c:53: error: `UCSRB' undeclared (first use in this function)
Test.c:53: error: `RXEN' undeclared (first use in this function)
Test.c:53: error: `TXEN' undeclared (first use in this function)
Test.c:56: error: `UCSRC' undeclared (first use in this function)
Test.c:56: error: `URSEL' undeclared (first use in this function)
Test.c:56: error: `UCSZ1' undeclared (first use in this function)
Test.c:56: error: `UCSZ0' undeclared (first use in this function)
Test.c: At top level:
Test.c:60: warning: `SIG_UART_DATA' appears to be a misspelled signal handler
Test.c: In function `SIG_UART_DATA':
Test.c:67: error: `UDR' undeclared (first use in this function)
Test.c:74: error: `UCSRB' undeclared (first use in this function)
Test.c:74: error: `UDRIE' undeclared (first use in this function)
make: *** [Test.o] Error 1

Woran liegt das jetzt, das erste Beispiel bei dem ich auf ein Regsiter zugefriffen hab ging noch?

das Makefile hab ich übrigens mit MFile erstellt.

ceekay
03.10.2005, 20:34
hy bist du sicher das du beim erstellen der makefile auch deinen Controller angegeben hast?

mpetz
03.10.2005, 20:38
jo, hab den atmega162 wie man ja in der Ausgabe auch sieht...ich verstehs nicht, grrrr

ceekay
03.10.2005, 20:44
hmm ich tippe trotzdem auf die makefile. da er die ganzen registerbezeichnungen nicht kennt.

mpetz
03.10.2005, 21:05
we sieht dein makefile aus, kannst du es grade mal posten?

ceekay
03.10.2005, 21:23
ich hoffe ich komme hiermit auf 15 zeichen

mpetz
03.10.2005, 21:34
ist ja quasi die selbe, nur der MCU anders...

cavegn
04.10.2005, 06:40
hi


Achso, kannst du mir noch den Unterschied zwischen:

char bStr[] = {irgentwas};

und

prog_char daten[] = {irgentwas};

erklären ?

gruß ceekay

Beim ersten Beispiel werden die Daten im RAM abgelegt, im zweitem (mit prog_char) sind sie im Flash => es wird weniger RAM benötigt.

Daten, die im Flash liegen, haben einfach die Eigenschaft, dass sie vom Programm nicht verändert weden können.

cu

chris

mpetz
04.10.2005, 21:00
wollte nur mal sagen, woran es lag. da ich den atmega162 verwende, mit 2 uart ports ist die bezeichnung der uart variablen anders, also z.B. statt UBRRH ist es dann UBRR1H

ceekay
04.10.2005, 21:42
hast recht da hatte ich gar nicht dran gedacht. dann ist es auch erklärlich....