Forum: Mikrocontroller und Digitale Elektronik USART_Transmit fehler


von Thomas (Gast)


Lesenswert?

Hallo leute,

Ich habe ein Programm geschrieben jedoch bekomme ich beim ausführen eine 
fehlermelding

"undefined reference to USART_Transmit"

muss ich da eventuell irgendwelche Bibliotheken hinzufügen?

Ich habe die bibliotheken

#include <avr/io.h>
#include <inttypes.h>
#define FOSC 12000000UL  //12MHz Taktfrequenz
#define BAUD 9600UL    //9600 Baud
#define MYUBRR (FOSC/(16*BAUD))-1

bereits hinzugefügt, fehlen vielleicht welche?

Danke LG Thomas

von holger (Gast)


Lesenswert?

>Ich habe die bibliotheken
>
>....
>
>bereits hinzugefügt, fehlen vielleicht welche?

Das sind Headerfiles.

Du hast die *.c Datei wo USART_Transmit drin ist
nicht mit compiliert.

von Thomas (Gast)


Lesenswert?

was meinst du damit? was muss ich da machen?

von Karl H. (kbuchegg)


Lesenswert?

Zeig doch mal alles.

Vielleicht ist es ja auch ein simpler Tippfehler irgendwo

von Thomas (Gast)


Lesenswert?

Funktion des Programms:
Einlesen von AD Wandler Werten, danach Ausgabe an der Seriellen 
Schnittstelle in binär (deshalb das itoa)
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#define FOSC 12000000UL  //12MHz Taktfrequenz
4
#define BAUD 9600UL    //9600 Baud
5
#define MYUBRR (FOSC/(16*BAUD))-1
6
7
8
/* ADC initialisieren */
9
void ADC_Init(void) {
10
uint16_t result;
11
ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
12
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
13
ADCSRA |= (1<<ADEN); // ADC aktivieren
14
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
15
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
16
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
17
while (ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
18
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
19
Wandlung nicht übernommen. */
20
result = ADCW;
21
}
22
/* ADC Einzelmessung */
23
uint16_t ADC_Read( uint8_t channel )
24
{
25
// Kanal waehlen, ohne andere Bits zu beeinflußen
26
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
27
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
28
while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
29
;
30
return ADCW; // ADC auslesen und zurückgeben
31
}
32
33
int main (void)
34
{
35
36
 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
37
 TCCR0|=((1<<CS02)|(1<<CS00)); //Oszilatorenfrequenz durch 1024 teilen
38
39
 UBRRH=(unsigned char)(MYUBRR>>8); //4 höheren Bits des UBRR
40
 UBRRL=(unsigned char) MYUBRR; //4 niedere Bits des UBRR
41
42
 UCSRB=(1<<RXEN)|(1<<TXEN); //Empfangen und Senden ermöglichen
43
 UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //UCSRC Register wählen und via Z1 und Z0 8bit als Ergebnisslänge zum Einlesen festlegen
44
45
46
47
int ADCValue = 0;
48
ADC_Init();
49
50
char Werte[4]="";
51
52
while(1){
53
ADCValue = ADC_Read(0);
54
55
56
  int i = ADC_Read(0);
57
  itoa(i,Werte,10 );
58
  USART_Transmit(Werte[0]);
59
  USART_Transmit(Werte[1]);
60
  USART_Transmit(Werte[2]);
61
        USART_Transmit(Werte[3]);
62
63
while (!(UCSRA &(1<<UDRE))); //Überprüfen ob Senden möglich 
64
 UDR = (ADCValue); //Senden eines Returns
65
66
}
67
68
}

von Karl H. (kbuchegg)


Lesenswert?

Und wo ist die Funktion USART_Transmit?

Wenn du eine Funktion verwenden willst, dann musst du sie auch 
implementieren!

von Thomas (Gast)


Lesenswert?

ok danke,

 aber irgendwie  funktioniert das itoa nicht dadurch sollten doch die ad 
wandlerwerte in binär angezeigt werden, was ist daran falsch?

von Karl H. (kbuchegg)


Lesenswert?

Thomas schrieb:
> ok danke,
>
>  aber irgendwie  funktioniert das itoa nicht dadurch sollten doch die ad
> wandlerwerte in binär angezeigt werden,

wieso binär?
Du hast dezimale Rrepräsentierung angefordert.

char Werte[4]="";

Das ist zu knapp dimensioniert.
Du kriegst vom ADC Zahlenwerte bis 1023. Das sind alleine schon 4 
Zeichen. Dazu noch das obligatorische \0 Zeichen, das jeden C-String 
abshcliest macht 5 Zeichen.

  USART_Transmit(Werte[0]);
  USART_Transmit(Werte[1]);
  USART_Transmit(Werte[2]);
        USART_Transmit(Werte[3]);


Woher weißt du, das der String 4 Zeichen lang ist? Wenn der Messert 5 
ist, dann ist der String auch nur 1 Zeichen lang!

ALs ersts schreibst du dir jetzt erst mal eine Hilfsfunktion, die einen 
String ausgeben kann
1
void USART_Transmit_String( char* s )
2
{
3
  while( *s != '\0' ) {
4
    USART_Transmit( *s );
5
    ++s;
6
  }
7
}

dann verwendest du die Funktion, um den String auszugeben, den dir itoa 
erzeugt. Und damit du an der Ausgabe auch noch sehen kannst, wann die 
nächste Zahl anfängt, gibst du nach der 'Zahl' auch noch ein Leerzeichen 
aus. Sonst siehts du am Terminal im Zahlenwust nicht wo eine Zahl 
aufhört und wo die nächste anfängt
1
  ...
2
3
  char Werte[10];
4
5
  while(1){
6
    int i = ADC_Read(0);
7
8
    itoa( i, Werte, 10 );
9
    USART_Transmit_String( Werte );
10
    USART_Transmit( ' ' );
11
  }
12
}


und achte ein bischen besser auf eine saubere Formatierung und 
Einrückung. Deine ADC Routinen sind ein Graus und schwer lesbar, weil 
sie keine Form haben.

von Hüsameddin N. (hsameddin_n)


Lesenswert?

Hallo,
Ich habe den Programmcode jetzt umgeändert jedoch habe ich das Problem 
dass ich immer noch nicht die AD Wandler Werte abgezeigt bekomme sonder 
immer nur ein ý....

Das ist der geänderte Programmcode
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#define FOSC 12000000UL  //12MHz Taktfrequenz
4
#define BAUD 9600UL    //9600 Baud
5
#define MYUBRR (FOSC/(16*BAUD))-1
6
7
/* ADC initialisieren */
8
void ADC_Init(void) {
9
uint16_t result;
10
ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
11
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
12
ADCSRA |= (1<<ADEN); // ADC aktivieren
13
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
14
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
15
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
16
while (ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
17
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
18
Wandlung nicht übernommen. */
19
result = ADCW;
20
}
21
/* ADC Einzelmessung */
22
uint16_t ADC_Read( uint8_t channel )
23
{
24
// Kanal waehlen, ohne andere Bits zu beeinflußen
25
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
26
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
27
while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
28
;
29
return ADCW; // ADC auslesen und zurückgeben
30
}
31
32
int main (void)
33
{
34
35
 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
36
 TCCR0|=((1<<CS02)|(1<<CS00)); //Oszilatorenfrequenz durch 1024 teilen
37
38
 UBRRH=(unsigned char)(MYUBRR>>8); //4 höheren Bits des UBRR
39
 UBRRL=(unsigned char) MYUBRR; //4 niedere Bits des UBRR
40
41
 UCSRB=(1<<RXEN)|(1<<TXEN); //Empfangen und Senden ermöglichen
42
 UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //UCSRC Register wählen und via Z1 und Z0 8bit als Ergebnisslänge zum Einlesen festlegen
43
44
45
46
int ADCValue = 0;
47
ADC_Init();
48
49
50
char Werte[10];
51
52
53
while(1){
54
ADCValue = ADC_Read(0);
55
56
57
void USART_Transmit( unsigned char data )
58
{
59
while (!(UCSRA &(1<<UDRE))); //Überprüfen ob Senden möglich 
60
UDR = (ADC_Read(0)); //Senden eines Returns
61
}
62
63
void USART_Transmit_String( char* s )
64
{
65
  while( *s != '\0' ) 
66
  {
67
    USART_Transmit( *s );
68
    ++s;
69
  }
70
}
71
72
73
int i = ADC_Read(0);
74
75
    itoa( i, Werte, 10 );
76
    USART_Transmit_String( Werte );
77
    USART_Transmit( ' ' );
78
79
80
}
81
82
}

von Karl H. (kbuchegg)


Lesenswert?

Hast du denn schon mal getestet, ob die USART prinzipiell funktioniert?
(Baudrate und der ganze restliche Kram?)

Zum programm sag ich nix ausser: Kauf dir ein C-Buch

von thomad (Gast)


Lesenswert?

Das programm hat eh schon mal funktioniert, nur jetzt krieg ich das mit 
der ausgabe in dezimal nicht hin, ich bekomm irgendwelche zeichen 
ausgegeben

von Karl H. (kbuchegg)


Lesenswert?

SChau doch mal was du ausgibst

void USART_Transmit( unsigned char data )
{
while (!(UCSRA &(1<<UDRE))); //Überprüfen ob Senden möglich
UDR = (ADC_Read(0)); //Senden eines Returns
}

von Hüsameddin N. (hsameddin_n)


Lesenswert?

Der Befehl gibt ja die AD Wandlerwerte aus

UDR = (ADC_Read(0)); //Senden eines Returns

Die Überprüfung ob das senden möglich ist müsste ich eventuell 
rausnehmen, nehm ich an

von Karl H. (kbuchegg)


Lesenswert?

Hüsameddin N. schrieb:
> Der Befehl gibt ja die AD Wandlerwerte aus

Oh Mann.


NEIN!

AUfgabe der Funktion USART_Transmit ist es nicht, die 
'Wandlerergebnisse' auszugeben, sondern das Zeichen, welches die 
Funktion als Argument in Data bekommt auszugeben!

void USART_Transmit( unsigned char data )
{
  while (!(UCSRA &(1<<UDRE)))
    ;

  UDR = data;
}

das ist die Aufgabe dieser Funktion.
Der Funktion ist es nämlich schnurzpiepegal, wo das Byte herkommt, das 
es auf der USART ausgeben soll.

Im konkreten Fall kommt das Zeichen von hier

void USART_Transmit_String( char* s )
{
  while( *s != '\0' )
  {
    USART_Transmit( *s );
    ++s;
  }
}


Der String wird ausgegeben, indem Zeichen für Zeichen an die Funktion 
USART_Transmit übergeben wird, welche dann das Zeichen ausgibt.
Gibt man alle Zeichen hintereinander aus, dann hat man den kompletten 
String ausgegeben.

So

Wo kommt jetzt wieder der String her?

Der kommt von hier

   USART_Transmit_String( Werte );

Der String steht in Werte.
Wie kommt er dort rein?

  itoa( i, Werte, 10 );

der kommt dort rein, weil ihn itoa dort rein schreibt. itoa nimmt sich 
den Zahlenwert von i, erzeugt einen entsprechenden String dafür.

Wo kommt jetzt wiederrum das i her?

Von hier

int i = ADC_Read(0);

i ist also der Wert, den der ADC am Kanal 0 gelesen hat.

In Summe und in chronologischer Reihenfolge
  der ADC wird ausgelesen
  der Wert vom ADC wird in einen String gewandelt
  dieser String wird an USART_Transmit_String übergeben
  USART_Transmit_String wiederrum gibt den String Zeichen für
  Zeichen aus, indem es dazu die Funktion USART_Transmit benutzt


Und deshalb darf USART_Transmit nicht den ADC auslesen, sondern einfach 
nur seinen Job machen: Es bekommt ein Zeichen und dieses gibt es aus.

von Hüsameddin N. (hsameddin_n)


Angehängte Dateien:

Lesenswert?

Ich habe den USART_Transmit geändert, jedoch bekomme ich trotzdem von 
termite irgendwelche zeichen (siehe anhang)

von Falk B. (falk)


Lesenswert?

@Hüsameddin N. (hsameddin_n)

>Ich habe den USART_Transmit geändert, jedoch bekomme ich trotzdem von
>termite irgendwelche zeichen (siehe anhang)

Falsche Baudrate oder Taktquelle.
Alle Jahre wieder . . .

http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART

von quadrocopter (Gast)


Lesenswert?

Hallo,
Punkt 1: verwende in deinem Code in zukunft tabstopps! Das erhöht 
merklich die übersicht

Punkt 2: Schreibe Methoden nicht in dein Hauptprogramm main, sondern 
danach

Punkt 3:  um deutlich zahlen auf dem Termialprogramm ablesen zu können, 
empfehle ich die Escapesequenzen: \n -> new line, \r -> carriage return
Diese befehle der folgenden methode übergeben:
"dieser String wird an USART_Transmit_String übergeben"

Punkt 4: Schau dir noch mal genau! das AVR GCC tutorial an, dort wird 
gut erklärt, was du wie machen musst bezgl. ADC und USART (C-kenntnisse 
vorrausgesetzt)

Punkt 5: Anstatt die Baudrate zu berechnen würde ich empfehlen die im 
datenblatt vermerkten Zahlen direkt zu übergeben. Eine fehlerquelle 
weniger.

Punkt 6: Leider hast du nicht deinen versuchsaufbau beschrieben, aber 
ein weiterer fehler könnte eine fehlende GND verbindung zwischen uC und 
PC sein. Bei müssen das gleiche bezugspotenzial haben.

Punkt 7: mach die Variable werte Lokal in eine Methode (-> googlen), 
weil du damit einem Zeigerproblem aus dem Weg gehst.

Punkt 8:
1
 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
2
 TCCR0|=((1<<CS02)|(1<<CS00)); //Oszilatorenfrequenz durch 1024 teilen
Diese Zeilen sind überflüssig, da du erstens Interrupst global nicht 
aktivierst und zweitens keine ISR hast, die den interrupt 
abfängt->Streichen

Punkt 9: bei allen zuweisungen in register, fass das gesammte argument 
rechts von der Zuweisung in Klammern.

Punkt 10: Leider kenn ich deinen Chiptyp nicht, aber in AVR 
Datenblättern wird eigentlich immer angegeben (in c-code), wie du den 
internen ADC ausliest, dort mal nachschauen, ob ADCW unterstützt wird!

Punkt 11: ADCValue = ADC_Read(0); wieso? Der Wert wird nicht wieder 
verwendet, du kannst dir diese Zeile und die Definition der Variable 
sparen.

so das wars erstmal.. ich hoffe ich habe nichts doppelt erwähnt oder 
mich verlesen.

PS: lies dir mal das GCC tutorial durch, und zwar ganz! Enorm 
hilfreich..

Gruß Quadrocopter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.