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
>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.
Zeig doch mal alles. Vielleicht ist es ja auch ein simpler Tippfehler irgendwo
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 | }
|
Und wo ist die Funktion USART_Transmit? Wenn du eine Funktion verwenden willst, dann musst du sie auch implementieren!
ok danke, aber irgendwie funktioniert das itoa nicht dadurch sollten doch die ad wandlerwerte in binär angezeigt werden, was ist daran falsch?
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.
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 | }
|
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
Das programm hat eh schon mal funktioniert, nur jetzt krieg ich das mit der ausgabe in dezimal nicht hin, ich bekomm irgendwelche zeichen ausgegeben
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 }
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
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.
Ich habe den USART_Transmit geändert, jedoch bekomme ich trotzdem von termite irgendwelche zeichen (siehe anhang)
@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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.