Archiv verlassen und diese Seite im Standarddesign anzeigen : String über UART ausgeben
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
Moin,
vielleicht hilft dir ja folgends weiter:
http://www.kreatives-chaos.com/index.php?seite=avr_b
MfG Kjion
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
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
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
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
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)
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, 16: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 :-)
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
Hallo,
ja vielen Dank es funktioniert.
echt klasse Forum.
gruß ceekay
P.S.: hab schon bald ne neue Frage
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
prog_char daten[] = { 30,31,..... };
wenn ich mich richtig erinnere
klasse funktioniert.
Ist es auch möglich dort variablen von typ char oder int mit einzubringen?
gruß ceekay
prog_char daten[] = { 'a','b',..... }; // is klar
int integs[] = { -3448, 7350, 48, ..... }; // analog
was halt in den Typ reinpasst
jo ok das versteht ich.
doch kann ich auch zwischen die werte ne variable vom gleichen datentyp zwischenschieben?
gruß ceekay
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
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
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
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?
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
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
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
Achso, kannst du mir noch den Unterschied zwischen:
char bStr[] = {irgentwas};
und
prog_char daten[] = {irgentwas};
erklären ?
gruß ceekay
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
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
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.
hy bist du sicher das du beim erstellen der makefile auch deinen Controller angegeben hast?
jo, hab den atmega162 wie man ja in der Ausgabe auch sieht...ich verstehs nicht, grrrr
hmm ich tippe trotzdem auf die makefile. da er die ganzen registerbezeichnungen nicht kennt.
we sieht dein makefile aus, kannst du es grade mal posten?
ich hoffe ich komme hiermit auf 15 zeichen
ist ja quasi die selbe, nur der MCU anders...
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
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
hast recht da hatte ich gar nicht dran gedacht. dann ist es auch erklärlich....
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.