USART_Transmit fehler

Gast #2013941
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
Gast #2014032
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
}
#2014069
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.
#2016926
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
}
#2017701
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.
Gast #2018263
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren