mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik USART_Transmit fehler


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was meinst du damit? was muss ich da machen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zeig doch mal alles.

Vielleicht ist es ja auch ein simpler Tippfehler irgendwo

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Funktion des Programms:
Einlesen von AD Wandler Werten, danach Ausgabe an der Seriellen 
Schnittstelle in binär (deshalb das itoa)

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


/* ADC initialisieren */
void ADC_Init(void) {
uint16_t result;
ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while (ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
result = ADCW;
}
/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
;
return ADCW; // ADC auslesen und zurückgeben
}

int main (void)
{

 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
 TCCR0|=((1<<CS02)|(1<<CS00)); //Oszilatorenfrequenz durch 1024 teilen

 UBRRH=(unsigned char)(MYUBRR>>8); //4 höheren Bits des UBRR
 UBRRL=(unsigned char) MYUBRR; //4 niedere Bits des UBRR

 UCSRB=(1<<RXEN)|(1<<TXEN); //Empfangen und Senden ermöglichen
 UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //UCSRC Register wählen und via Z1 und Z0 8bit als Ergebnisslänge zum Einlesen festlegen



int ADCValue = 0;
ADC_Init();

char Werte[4]="";

while(1){
ADCValue = ADC_Read(0);


  int i = ADC_Read(0);
  itoa(i,Werte,10 );
  USART_Transmit(Werte[0]);
  USART_Transmit(Werte[1]);
  USART_Transmit(Werte[2]);
        USART_Transmit(Werte[3]);

while (!(UCSRA &(1<<UDRE))); //Überprüfen ob Senden möglich 
 UDR = (ADCValue); //Senden eines Returns

}

}





Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wo ist die Funktion USART_Transmit?

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

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok danke,

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
void USART_Transmit_String( char* s )
{
  while( *s != '\0' ) {
    USART_Transmit( *s );
    ++s;
  }
}

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
  ...

  char Werte[10];

  while(1){
    int i = ADC_Read(0);

    itoa( i, Werte, 10 );
    USART_Transmit_String( Werte );
    USART_Transmit( ' ' );
  }
}


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.

Autor: Hüsameddin N. (hsameddin_n)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>
#include <inttypes.h>
#define FOSC 12000000UL  //12MHz Taktfrequenz
#define BAUD 9600UL    //9600 Baud
#define MYUBRR (FOSC/(16*BAUD))-1

/* ADC initialisieren */
void ADC_Init(void) {
uint16_t result;
ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while (ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
result = ADCW;
}
/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
;
return ADCW; // ADC auslesen und zurückgeben
}

int main (void)
{

 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
 TCCR0|=((1<<CS02)|(1<<CS00)); //Oszilatorenfrequenz durch 1024 teilen

 UBRRH=(unsigned char)(MYUBRR>>8); //4 höheren Bits des UBRR
 UBRRL=(unsigned char) MYUBRR; //4 niedere Bits des UBRR

 UCSRB=(1<<RXEN)|(1<<TXEN); //Empfangen und Senden ermöglichen
 UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //UCSRC Register wählen und via Z1 und Z0 8bit als Ergebnisslänge zum Einlesen festlegen



int ADCValue = 0;
ADC_Init();


char Werte[10];


while(1){
ADCValue = ADC_Read(0);


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

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


int i = ADC_Read(0);

    itoa( i, Werte, 10 );
    USART_Transmit_String( Werte );
    USART_Transmit( ' ' );


}

}



Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: thomad (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
}

Autor: Hüsameddin N. (hsameddin_n)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hüsameddin N. (hsameddin_n)
Datum:
Angehängte Dateien:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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_Checkl...

Autor: quadrocopter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
 TIMSK|=(1<<TOIE0); //Timer Interrupt 0 verwenden
 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.