PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Usart programmierung



DanielSan
06.02.2006, 18:18
Hi,

Ich möchte mit meinem Atmega128 daten zum Pc senden und zwar über die rs232 schnitte.

Jetzt habe ich im Datenblatt nachgelesen wie das geht und diese Source samples in mein Programm eingebaut aber ständig kommt beim compilieren das die usart variablen "first use in this function" sind. kann mir da jemand weiterhelfen? ich habe als include dateien avr/io.h und string.h.

mein code sieht also so aus:




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

void USART_Init (unsigned int baud)
{
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
/* Enable reciever and transmitter */
UCSRB = (1<<RXEN)|(1<<Txen);
/* Set frame format: 8data, 2stop bit*/
UCSRC = (1<<USBS)|(3<<UCSZ0=;
}



void USART_Transmit (unsigned char data)
{
/* Wait for empty transmit buffer */
while(!(UCSRA & (1<<UDRE)))
;
/* Put data into buffer, sends the data '/
UDR = data;
}


unsigned char USART_Recieve(void)
{
/* Wait for data to be recieved */
while (!(UCSRA & (1<<RXC)))
;
/* Get and return recieved data from buffer */
return UDR;
}

Danke schonmal für eure hilfreichen Antworten ;)

MFG DanielSan

ogni42
06.02.2006, 18:28
Hast Du den Prozessortyp im makefile richtig gesetzt? Ansonsten werden die #defines in io.h nicht richtig abgearbeitet.

DanielSan
07.02.2006, 10:15
Ich programmiere ihn mit avr studio. Das Problem tritt ja schon beim compilieren auf, nicht erst wenn ich das prog im prozessor habe.

MFG

ogni42
07.02.2006, 10:31
Wenn Du den Prozessortyp (auch im AVR-Studio) nicht richtig setzt, werden die #defines in io.h bei der Auswertung nicht zum richtigen Ergebnis führen:


#elif defined (__AVR_ATmega128__)

Dann bekommst Du die Fehlermeldung.

DanielSan
07.02.2006, 10:49
Also in meiner configuration steht das ich den mega128 mit 16Mhz eingestellt habe. Und als fehlermeldungkommt:




rm -rf usart.o usart.elf dep/ usart.hex usart.eep
Build succeeded with 0 Warnings...
avr-gcc -mmcu=atmega128 -Wall -gdwarf-2 -DF_CPU=16000000 -O0 -fsigned-char -Wp,-M,-MP,-MT,usart.o,-MF,dep/usart.o.d -c ../usart.c
../usart.c: In function `__vector_1':
../usart.c:45: error: `GICR' undeclared (first use in this function)
../usart.c:45: error: (Each undeclared identifier is reported only once
../usart.c:45: error: for each function it appears in.)
../usart.c: In function `__vector_16':
../usart.c:102: error: `GIFR' undeclared (first use in this function)
../usart.c:103: error: `GICR' undeclared (first use in this function)
../usart.c: In function `main':
../usart.c:181: error: `UCSRA' undeclared (first use in this function)
../usart.c:182: error: `UCSRB' undeclared (first use in this function)
../usart.c:189: error: `GIFR' undeclared (first use in this function)
../usart.c:190: error: `GICR' undeclared (first use in this function)
make: *** [usart.o] Error 1
Build failed with 9 errors and 0 warnings...





Ich hoffe das hilft dir weiter um mir zu helfen ;)

MFG DanielSan[/img]

ogni42
07.02.2006, 11:00
kann er ja auch nicht finden, weil der Mega 128 die Register nicht besitzt. Wie kommt man darauf:

In der Installation des WinAVR unter
avr\include\avr\iom128.h nachschauen und nach den Namen suchen: Kein Treffer.

Warum ist das so?
Der 128 hat zwei serielle Schnittstellen, damit heissen die seriellen Register: UCSR0A und UCSR0B bzw. UCSR1A und UCSR1B, etc.

GICR und GIFR scheinen Interruptregister zu sein. Auf jeden Fall ist der Code den Du da hast nicht für den Mega128 geschrieben worden. Welche Bedeutung die Register haben musst Du im Datenblatt des Chips nachlesen , für den der Code ursprünglich war und dann durch die entsprechenden Register - sofern vorhanden - des 128 ersetzen.

DanielSan
07.02.2006, 11:13
ok diese programm ist für den mega128 zumindest habe ich diesen code aus dem datenblatt des mega128.



#include <inttypes.h>
#include <avr/io.h>
#include <avr/signal.h>
#include <string.h>

void USART_Init (unsigned int baud)
{
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
/* Enable reciever and transmitter */
UCSRB = (1<<RXEN)|(1<<Txen);
/* Set frame format: 8data, 2stop bit*/
UCSRC = (1<<USBS)|(3<<UCSZ0=;
}



void USART_Transmit (unsigned char data)
{
/* Wait for empty transmit buffer */
while(!(UCSRA & (1<<UDRE)))
;
/* Put data into buffer, sends the data '/
UDR = data;
}


unsigned char USART_Recieve(void)
{
/* Wait for data to be recieved */
while (!(UCSRA & (1<<RXC)))
;
/* Get and return recieved data from buffer */
return UDR;
}



und wenn ich das compile kommen folgende fehlermeldungen:

Build started 7.2.2006 at 11:14:26
avr-gcc -mmcu=atmega128 -Wall -gdwarf-2 -DF_CPU=16000000 -O0 -fsigned-char -Wp,-M,-MP,-MT,usart.o,-MF,dep/usart.o.d -c ../usart.c
../usart.c: In function `USART_Init':
../usart.c:11: error: `UBRRH' undeclared (first use in this function)
../usart.c:11: error: (Each undeclared identifier is reported only once
../usart.c:11: error: for each function it appears in.)
../usart.c:12: error: `UBRRL' undeclared (first use in this function)
../usart.c:14: error: `UCSRB' undeclared (first use in this function)
../usart.c:14: error: `Txen' undeclared (first use in this function)
../usart.c:16: error: `UCSRC' undeclared (first use in this function)
../usart.c:16: error: parse error before ';' token
../usart.c:34: error: `UCSRA' undeclared (first use in this function)
../usart.c:37: error: `UDR' undeclared (first use in this function)
../usart.c:37: warning: `return' with a value, in function returning void
make: *** [usart.o] Error 1
Build failed with 10 errors and 1 warnings...


MFG Danielsan

ogni42
07.02.2006, 11:20
Die Beispiele im Datenblatt passen nicht immer zum Chip. Ist ein altbekanntes Problem. Die richtigen Namen für die Register findest Du in den entsprechenden Abschnitten des Datenblatts (nicht in den Codebeispielen).

Du wirst also nicht um eine Anpassung des Codes kommen. Im Zweifelsfall immer in den Header-Dateien nachschauen.

Thorsten
07.02.2006, 11:22
Hi,



../usart.c:11: error: `UBRRH1' undeclared (first use in this function)
hab grad mal durch die iom128.h gegrept, gibts nicht wegen der zwei
Uarts heißt's da:
UBRR1H oder UBRR0H
das gleiche für UCSRB:
#define UCSR0B _SFR_IO8(0x0A)
#define UCSR1B _SFR_MEM8(0x9A)
jeweils für Uart0 und 1

Txen: ist eine Konstante wird also groß geschrieben: TXEN.

Schau dir mal die iom128.h an.


mfg
Thorsten

DanielSan
07.02.2006, 11:36
Mh ok das hat mich schon weitergebracht jetzt habe ichs geschafft die fehlermeldungen auf das hier zu reduzieren:

Build started 7.2.2006 at 11:37:42
avr-gcc -mmcu=atmega128 -Wall -gdwarf-2 -DF_CPU=16000000 -O0 -fsigned-char -Wp,-M,-MP,-MT,usart.o,-MF,dep/usart.o.d -c ../usart.c
../usart.c: In function `USART_Transmit':
../usart.c:36: warning: `return' with a value, in function returning void
avr-gcc -mmcu=atmega128 usart.o -o usart.elf
C:/WinAVR/bin/../lib/gcc/avr/3.4.3/../../../../avr/lib/avr5/crtm128.o(.init9+0x0): undefined reference to `main'
make: *** [usart.elf] Error 1
Build failed with 1 errors and 1 warnings...


Also ist ja nur noch hier irgendwas falsch:

C:/WinAVR/bin/../lib/gcc/avr/3.4.3/../../../../avr/lib/avr5/crtm128.o(.init9+0x0): undefined reference to `main'


ich kenne mich leider nicht genug aus um zu verstehen was da falsch ist.

MFG Danielsan

ogni42
07.02.2006, 11:44
Zeig doch mal den ganzen Code.

Thorsten
07.02.2006, 11:45
Hi,

Hast du eine main Funktion?
Am besten du postest mal deinen Code, nur mit der
Fehlermeldung ist es schwer was zu sagen.

mfg
Thorsten

DanielSan
07.02.2006, 11:49
Oh oh ich befürchte schlimmes ;)



#include <inttypes.h>
#include <avr/io.h>
#include <avr/signal.h>
#include <string.h>

void USART_Init (unsigned int baud)
{
/* Set baud rate */
UBRR0H = (unsigned char)(baud>>8);
UBRR0L = (unsigned char)baud;
/* Enable reciever and transmitter */
UCSR0B = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit*/
UCSR0C = (1<<USBS)|(3<<UCSZ0);
}



void USART_Transmit (unsigned char data)
{
/* Wait for empty transmit buffer */
while(!(UCSR0A & (1<<UDRE)))
;
/* Put data into buffer, sends the data */
UDR0 = data;
}


unsigned char USART_Recieve(void)
{
/* Wait for data to be recieved */
while (!(UCSR0A & (1<<RXC)))
;
/* Get and return recieved data from buffer */
return UDR0;
}


das ist mein ganzer code. Ich wette jetzt wirds peinlich für mich 8-[

MFG

ogni42
07.02.2006, 11:58
Da Du es selbst bemerkt hat hält sich die Peinlichkeit in Grenzen :)

int main(void)
{
// mach irgendwas

return 1
}

DanielSan
07.02.2006, 12:06
also in die main könnte ich doch schreiben, das er immer "Hallo" sendet oder?
Wie müsste der Code dazu aussehen? Muss ich dann eine function haben mit der ich ganze strings anstatt einzelner zeichen senden kann? zb. so:


void send_string(char wort[])
{
unsigned int index=0;
while(wort[index] != '\0')
{
sendTxd1(wort[index]);
index++;
}
return;
}



um dann mit
send_string("Hallo");


Hallo zu senden.


MFG

michaelb
07.02.2006, 12:09
Hi Daniel,
ist das wirklich den ganzer Code??????
Da fehlt die main!! Du deklarierst zwar schön die Funktionen USART_Init, USART_Transmit und USART_Recieve aber du hast keine Main!
Du musst jetzt halt noch sowas einbinden um per USART Datenpakete zu verschicken:



int main(void)
{
//USART aktivieren mit einer Baudrate von 9600 Baud
USART_Init(9600);
//Endlosschleife
for(;;)
{
//2 über USART verschicken
USART_Transmit(2);
}
}


das nurmal als Beispiel um die Funktionen zu verwenden!
um deine Empfangsfunktion zu verwenden sowas:




unsigned char test = 0;

int main(void)
{
//USART aktivieren mit einer Baudrate von 9600 Baud
USART_Init(9600);
//Endlosschleife
for(;;)
{
//Über USART das Datenpaket empfangen und in die Variable test schreiben
test = USART_Recieve()
//den Inhalt von test per USART verschicken
USART_Transmit(test);
}
}


Gruß Michi

DanielSan
07.02.2006, 12:13
oh man ich habe noch viel zu lernen :D.

Ok damit versuch ichs mal.

würde denn meine funktion funktionieren? Also wegen den ganzen wörtern die ich senden will.

MFG

michaelb
07.02.2006, 12:24
Hi,
ok versuch's mal mit meinem!
ich weiß jetzt nicht ob deiner klappt aber ich hätte das eher so gelöst:


void send_string(unsigned char *wort)
{
while(*wort)
{
sendTxd1(wort++);
}
return 0;
}


Gruß Michi

ogni42
07.02.2006, 13:17
Das mit dem Baudrate initialisieren ist falsch. Les' bitte mal im Datenblatt des Chips nach wie der Wert berechnet wird.

@michael: Du bekommst bei Deiner Funktion mindestens ein Warning des Compilers weil Du einen int aus einer void Funktion zurück gibst.

michaelb
07.02.2006, 13:35
Hi,


@michael: Du bekommst bei Deiner Funktion mindestens ein Warning des Compilers weil Du einen int aus einer void Funktion zurück gibst.
aber spätestens dann wird man es umändern!
Stimmt mit der Baudrate hab ich gar nicht darauf geachtet!!

Des müsste dann doch so heißen oder?:


#define F_CPU 16000000
#define UART_BAUD_RATE 9600
#define UART_BAUD_SELECT (uint)(F_CPU/(UART_BAUD_RATE*16l)-1)

und


UBRRH = UART_BAUD_SELECT >> 8;
UBRRL = UART_BAUD_SELECT;


Gruß Michi

DanielSan
07.02.2006, 13:55
nein wenn ichs so mache hat er ein problem mit dem "uint"

mfg

SprinterSB
07.02.2006, 14:10
Es heisst uint16_t

SprinterSB
07.02.2006, 15:04
Schau mal ins Wiki, da hab ich was dazu geschrieben:
UART mit avr-gcc (https://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc). Kannst es gleich mal auf Herz und Nieren testen ;-)

DanielSan
07.02.2006, 16:06
Ja danke mit ui9nt16_t gehts.

@Sprintersb: Das ist aber nicht für nen mega128 d.h. dann müsste ich es wieder komplett umstricken da mache ich lieber mit meinem jetzigen weiter.
Aber trotzdem danke.

MFG

SprinterSB
07.02.2006, 16:29
Was geht denn nicht auf ATmega128?

Die Anzahl der Stopbits ist anzupassen. Und dein USBS find ich auch nirgendwo... Ansonsten sollte das für ATmega gehen.

DanielSan
07.02.2006, 16:31
So jetzt habe ich das programm mal getestet.

Eigentlich laüft es soweit. Nur irgendwie weiss ich nicht so richtig was ich da eingeben muss damit er zb. ein ganzes Wort sendet.

wenn ich die zwei sende kommt ein smiley an und wenn ich die drei sende dann kommt ein herz an.

Mfg

DanielSan
07.02.2006, 17:00
Also ich habe das jetzt so gelöst:

#include <inttypes.h>
#include <avr/io.h>
#include <avr/signal.h>
#include <string.h>


#define F_CPU 16000000
#define UART_BAUD_RATE 9600
#define UART_BAUD_SELECT (uint16_t)(F_CPU/(UART_BAUD_RATE*16l)-1)


void USART_Init (unsigned int baud)
{
/* Set baud rate */
//UBRR0H = (unsigned char)(baud>>8);
//UBRR0L = (unsigned char)baud;

UBRR0H = UART_BAUD_SELECT >> 8;
UBRR0L = UART_BAUD_SELECT;
/* Enable reciever and transmitter */
UCSR0B = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit*/
UCSR0C = (1<<USBS)|(3<<UCSZ0);
}



void USART_Transmit (unsigned char data)
{
/* Wait for empty transmit buffer */
while(!(UCSR0A & (1<<UDRE)))
;
/* Put data into buffer, sends the data */
UDR0 = data;
}

//------------------------------------------------------


void send_string(char wort[])
{
unsigned int index=0;
while(wort[index] != '\0')
{
USART_Transmit(wort[index]);
index++;
}
return;
}

//----------------------------------------------------------



unsigned char USART_Recieve(void)
{
/* Wait for data to be recieved */
while (!(UCSR0A & (1<<RXC)))
;
/* Get and return recieved data from buffer */
return UDR0;
}


long i;



int main(void)
{

DDRC = 0xff;
//USART aktivieren mit einer Baudrate von 9600 Baud
USART_Init(9600);
//Endlosschleife
for(;;)
{
PORTC=0x01;
for(i=0 ; i<160000 ; i++){}
PORTC=0x00;
for(i=0 ; i<160000 ; i++){}
//2 über USART verschicken
send_string("Hallo");
USART_Transmit(3);
}
}



Ich meinte das man zb für UBRRH -> UBRR0H schreiben muss das steht nirgendwo ausser in diesem thread ;). Ich denke das es für nen anfänger irgendwie zu schwer ist mit deiner variante wobei sie sicherlich gut ist. Sie ist nur nicht speziell genug ;) aber man kann das ja auch nicht für jeden controller schreiben.


Jetzt habe ich nur noch ein problem, ich möchte das nachjedem sende zyklus eine neue reihe begonnen wird.

mfg danielsan

SprinterSB
07.02.2006, 17:01
Du must die einzelnen Zeichen schicken. Ich habs ins Wiki dazugemacht.

ogni42
07.02.2006, 17:19
Doch, das steht im Datenblatt des jeweiligen Controllers :) Wie gesagt, die Codebeispiele sind mit Vorsicht zu genießen, zumal die meist für den IAR Compiler gemacht sind.

Ein weiteres Beispiel dafür ist, dass beim Mega128 die ISP Pins nicht auf MOSI, MISO, etc. liegen, wie das bei vielen anderen ATMegas der Fall ist. Das findet man eben auch nur im Datenblatt. In den Appnotes zum ISP von Atmel steht das auch nicht so direkt drin.

Neu Zeile:

USART_Transmit('\n');

SprinterSB
07.02.2006, 17:41
Ok, das war eher als Vorlage gedacht um mal ein Beispiel zu haben, wie es prionzipiell geht, und weniger als Fix-Fertig-Lösung zum reinkopieren ins Programm. Das wirst du eh kaum finden...

DanielSan
09.02.2006, 00:58
das mit der neuen reihe funktioniert nicht so richtig ich schreibe euch genaueres morgen wenn ich mehr zeit habe.
mfg und gute nacht!

DanielSan
10.02.2006, 00:51
Also wenn ich ne neue reihe mache,mit dem befehl USART_Transmit('\n');
dann kommt da kein zeilenumbruch. Es scheint als wird einfach eine reihe von leerzeichen eingefügt, sodass sich wenn ich beispielsweise hallo sende das so äußert:

Hallo_____________________________________________ ______________
____Hallo_________________________________________ ______________
________Hallo_______...

(ich hoffe ihr habt verstanden wie ich das meinte)

MFG Danielsan

xanadu
10.02.2006, 01:04
Dann sende mal '\r\n'.

\n ist ein LineFeed, damit wird der Ausgabecursor im Terminalprogramm eine Zeile nach unten bewegt. \r ist ein Carriage Return, damit springt der Cursor an den Anfang der Zeile.

Bei manchen Terminalprogrammen kann man auch einstelen, dass ein \n automatisch mit einem \r ergänzt werden soll.

Gruß,
Chris

DanielSan
10.02.2006, 13:04
ja auf die idee bin ich auch schon gekommen aber das ändert leider garnichts. ich versuchs einfach mal mit nem anderen terminal programm. evtl ändert das was.

DanielSan
10.02.2006, 13:27
so jetzt habe ich es mit einem anderen programm ausprobiert und es funktioniert.


http://bray.velenje.cx/avr/terminal/

man muss nur die einstellung CR=LF aktivieren und schon funktioniert alles wie es soll.

MFG Danielsan

DanielSan
10.02.2006, 13:39
jetzt habe ich doch noch ein problem.

es wird zwar jetzt im terminalprogramm folgendes ausgegeben:

Hallo!
Hallo!
Hallo!
...


Aber wenn ich sage das er die datei speichern soll dann schreibt er es doch wieder nebeneinander.

MFG Danielsan

xanadu
11.02.2006, 03:00
Das ist wieder das gleiche in grün. Für Windows muss es halt \r\n (CRLF) sein, damit eine neue Zeile mit dem ersten Zeichen beginnt. Anscheinend speichert das Terminal nur die Zeichen, die es empfängt.

Mach die Datei mal mit Wordpad auf, der müsste damit klar kommen.