Hallo zusammen, ich habe ein Problem bei einer Rechnung mit einem analogen Messwert. Folgender Hintergrund: Eingesetzt wird ein Atmega16 sowie ein IR-Sensor. Über einen analogen Eingang X1 wird der Spannungswert des IR-Sensors eingelesen. Dieser muss nun zur Weiterverarbeitung umgerechnet werden in einen entsprechenden Abstand in Metern. Die Formel dazu lautet: ((x+0.28136)/10.8429)^(-1/0.63745), wobei x den analogen Spannungswert darstellt. Hier mein Quellcode: #include <nibobee/iodefs.h> #include <nibobee/delay.h> #include <nibobee/analog.h> #include <nibobee/math.h> #include <nibobee/cdefs.h> int main() { // ***Initialisierung*** enable_interrupts(); uint16_t R; double Abstand; analog_init(); sei(); while(1==1) { R = analog_getValue(ANALOG_EXT0); // Umrechnung von [V] in [m] Abstand = 0.2 - (pow((R+0.28136)/10.8429, (-1/0.63745)))/100; } return 0; } Das Einlesen des analogen Messwertes funktioniert soweit, wenn ich allerdings versuche den Abstand zu berechnen streikt der Compiler "Build failed with 1 errors...". Eine genauere Fehlermeldung gibt es leider nicht. Ersetzt man "R = analog_getValue(ANALOG_EXT0);" durch einen beliebigen Wert z.B. "R =240;" funktioniert es. Was mache ich falsch? MfG
In dem gezeigten Quellcode ist nirgends eine Variable oder ein Makro ANALOG_EXT0 definiert. In die Includefiles kann ich nicht reinsehen. Wenn dort auch keine Definition steht, ist es klar, dass die Stelle R = analog_getValue(ANALOG_EXT0); einen Übersetzungsfehler produziert. In dem gezeigten Quellcode ist nirgends eine Funktion analog_getValue definiert. In die Includefiles und die Projekteinstellungen kann ich nicht reinsehen. Wenn dort auch keine Definition steht oder im Projekt keine Datei (C oder Library) vorhanden ist in der die Funktion analog_getValue implementiert ist, ist es klar, dass die Stelle R = analog_getValue(ANALOG_EXT0); einen Übersetzungsfehler produziert.
EagleEye schrieb: > Eine genauere Fehlermeldung gibt es leider > nicht. Was ist denn das für ein Compiler? Abgesehen davon: bist Du dir sicher, dass die Funktion analog_getValue wirklich einen Wert in Volt zurückliefert und nicht Inkremente?
EagleEye schrieb: > allerdings versuche den Abstand zu berechnen streikt der Compiler "Build > failed with 1 errors...". Eine genauere Fehlermeldung gibt es leider > nicht. Klick mal ins Ausgabefenster und scrolle nach oben. Da ist mit Sicherheit irgendwo eine Fehlermeldung.
Hallo zusammen, erstmal Danke für die schnelle Rückmeldung! @ Krapao: Die Funktion "analog_getValue(ANALOG_EXT0);" ist in den eingebundenen Dateien analog.h und cdefs.h (siehe PFDs im Anhang) definiert, sowohl die Funktion "analog_getValue()" als auch die Variable "ANALOG_EXT0". ANALOG_EXT0 ist, wenn ich das richtig verstanden habe nur ein Zeiger auf die Adresse des Portpins 1 des Ports X1. Im Datenblatt des Atmega16 auf S.216 (http://www.atmel.com/Images/doc2466.pdf) steht, dass die Ausgabe nach folgender Formel erfolgt: ADC = (Vin*1024)/Vref Das liefert mir also die Werte 0 bis 1024 (immer in Bezug auf die Versorgungsspannung Vref von ca. 5V). Das Erfassen der Analogwerte funktioniert. Ich habe probeweise einfach mal ein kleines Programm geschrieben, das mir entsprechend des Rückgabewertes R verschiedene LEDs einschaltet, also z.B. bis 2V (ADC-Wert R = 409) LED1 bis 2,1V (ACD-Wert R = 431) LED2 usw.: **************************** #include <nibobee/iodefs.h> #include <nibobee/led.h> #include <nibobee/delay.h> #include <nibobee/analog.h> #include <nibobee/math.h> #include <nibobee/cdefs.h> int main() { // ***Initialisierung*** enable_interrupts(); int16_t R; analog_init(); sei(); while(1==1) { U = 0; R = analog_getValue(ANALOG_EXT0); if(R < (409)){led_set(0,0); led_set(1,0); led_set(2,0); led_set(3,1);} if(R <(431) && R > (409)){led_set(0,0); led_set(1,0); led_set(2,1); led_set(3,0);} if(R <(460) && R > (431)){led_set(0,0); led_set(1,0); led_set(2,1); led_set(3,1);} if(R <(490) && R > (460)){led_set(0,0); led_set(1,1); led_set(2,0); led_set(3,0);} } return 0; } ***************************** Das hat auch funktioniert! Mit dem Multimeter habe ich für die tatsächliche Spannung am Port in Bezug auf Masse für einen Abstand von 10 cm 2,23V gemessen. Das wären umgerechnet nach obiger Formel R = 457 als ADC-Wert. Wenn ich den Abstand dann ein wenig variiert habe, haben die Leds entsprechend in der Reihenfolge geleuchtet. Damit war für mich klar, dass ich einen Integer-Wert zwischen 0 und 1024 in Bezug auf die Referenzspannung erhalte. In der Datei analog.h wird die Funktion "analog_getValue" folgendermaßen definiert uint16_t analog_getValue(uint8_t idx); Der Rückgabewert der Funktion sollte also ein unsigned interger sein. Jetzt zur Berechnung der Potenzfunktion pow(). Diese ist in math.h (siehe PDF im Anhang) folgendermaßen definiert: extern double pow __P((double, double)); Sie erwartet also als Eingabe zwei double Werte. Daher war mein erster Gedanke, dass es wegen der Variablen-Typen zu Problemen kommt. Testweise habe ich eine weitere Variable Q nacheinander als uint16_t, double, float definiert mit Werten belegt und an Stelle von R als ersten Parameter übergeben. Beim Compilieren gab es keine Fehler. Dann habe ich der Variable R den festen Wert 409 zugewiesen und es compiliert --> kein Fehler. Sobald ich R wieder den Rückgabewert der Funktion "analog_getValue(ANALOG_EXT0)" zugewiesen habe ist das Compilieren wieder fehlgeschlagen. Letzter Versuch: ich habe R weiterhin den Rückgabewert der Funktion zugewiesen und anschließend R über (double)R in eine double-Variable konvertiert. Auch hier tritt ein Fehler beim Compilieren auf. Warum klappt es bei allen möglichen Variationen, nur nicht mit dem Rückgabewert des AD-Wandlers??? @ Christian Gudrian: Ich verwende AVR Studio 4 in der Version 4.19 mit dem Compiler AVR GCC. Gruß Matthias
Und nochmal ich, @ Karl Heinz Buchegger: Hier die Ausgabe aus dem Ausgabefenster wenn ich das Programm erfolgreich mit fester Zuweisung R = 409 compiliere: ******************************* Build started 11.5.2012 at 14:37:20 avr-gcc -I"C:\Program Files (x86)\NIBObeeLib\include" -mmcu=atmega16 -Wall -gdwarf-2 -std=gnu99 -D_NIBOBEE_ -DF_CPU=15000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT PI_IR_Regler.o -MF dep/PI_IR_Regler.o.d -c ../PI_IR_Regler.c In file included from ../PI_IR_Regler.c:20:0: C:\Program Files (x86)\NIBObeeLib\include/nibobee/math.h:12:0: warning: ignoring #pragma ident In file included from ../PI_IR_Regler.c:21:0: C:\Program Files (x86)\NIBObeeLib\include/nibobee/cdefs.h:32:0: warning: "__P" redefined C:\Program Files (x86)\NIBObeeLib\include/nibobee/math.h:19:0: note: this is the location of the previous definition avr-gcc -mmcu=atmega16 -Wl,-Map=PI_IR_Regler.map PI_IR_Regler.o -L"C:\Program Files (x86)\NIBObeeLib\lib" -lnibobee_line -lnibobee_base -lnibobee_utils -o PI_IR_Regler.elf avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature PI_IR_Regler.elf PI_IR_Regler.hex avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex PI_IR_Regler.elf PI_IR_Regler.eep || exit 0 avr-objdump -h -S PI_IR_Regler.elf > PI_IR_Regler.lss AVR Memory Usage ---------------- Device: atmega16 Program: 1466 bytes (8.9% Full) (.text + .data + .bootloader) Data: 29 bytes (2.8% Full) (.data + .bss + .noinit) Build succeeded with 2 Warnings... *************************************** Und hier wenn ich R wieder den Rückgabewert der Funktion analog_getValue() zuordne: *************************************** Build started 11.5.2012 at 14:34:46 ../PI_IR_Regler.c In file included from ../PI_IR_Regler.c:20:0: C:\Program Files (x86)\NIBObeeLib\include/nibobee/math.h:12:0: warning: ignoring #pragma ident In file included from ../PI_IR_Regler.c:21:0: C:\Program Files (x86)\NIBObeeLib\include/nibobee/cdefs.h:32:0: warning: "__P" redefined C:\Program Files (x86)\NIBObeeLib\include/nibobee/math.h:19:0: note: this is the location of the previous definition avr-gcc -mmcu=atmega16 -Wl,-Map=PI_IR_Regler.map PI_IR_Regler.o -L"C:\Program Files (x86)\NIBObeeLib\lib" -lnibobee_line -lnibobee_base -lnibobee_utils -o PI_IR_Regler.elf collect2: ld returned 1 exit status make: *** [PI_IR_Regler.elf] Fehler 1 Build failed with 1 errors and 2 warnings... **************************************** Ich kann daraus nicht ersehen, wo genau das Problem liegt... Gruß Matthias
Puuuh, der arme Controller... Ich nehme mal an, bei dem Sensor handelt es sich um einen Sharp für 20-80cm (GP2D12 und Nachfolger). Wie um alles in der Welt kommt man auf die Idee, Exponential-Funktionen mit gebrochenem Exponenten auf einem 8-Bit Controller rechnen zu wollen. Die Umkehrfunktion für die Sensoren lässt sich mit 3-4 Geradenstücken linearisieren, die man sogar komplett ganzzahlig rechnen kann. Die Pseudo-Genauigkeit die Dir float vorgaukelt, bekommst Du doch niemals aus dem Sensor raus. Dessen Kennlinie im Datenblatt ist doch auch nur durch Geradenstücke angegeben (die Knicke erkennt man bei genauem hinsehen). Aus dem Datenblatt liest Du dir ein paar Stützstellen aus der Kennlinie heraus (oder lässt Excel die Stütztstellen im 5cm-Abstand berechnen). Mit jeweis 2 Stützstellen wird eine Geradengleichung für die Umkehrfunktion Abstand = f' (Digitalwert) erstellt. Eine Abfrage des Digitalwertes entscheidet dann, welche Geradengleichung für den Abschnitt gilt. An den Übergangsstellen ergeben beide Geraden den selben Wert, es ist also egal ob man da auf > oder >= vergleicht. Bei deinen Vergleichen im 2. Beispiel ist auch noch Optimierungspotential... Wenn der AD-Wert größer als die erste Schwelle ist, dann sind die übrigen Vergleich hinfällig. Daher nimmt man da else if: if(R > 490){led_set(0,0); blablabla...} // für alle Werte über 490 else if(R > 460){led_set(0,0); bläbläblä...} // von 461 bis 490 else if(R > 431){led_set(0,0); usw.usw.usw.} // von 432 bis 460 else // ales Werte kleiner gleich 431 { } Für die Erstellung einer Geradengleichung habe ich mal was angehängt. Der Trick mit der höheren Genauigkeit ist, dass man einfach nicht in cm sondern in mm rechnet. (sogar mit ganzzahlingen Long-Werten in µm wird das Programm noch schneller und kleiner als mit Float). tschuessle Bernhard
EagleEye schrieb: > make: *** [PI_IR_Regler.elf] Fehler 1 Steht bei dir im Makefile irgendwo ein .SILENT oder verschluckt sonst noch jemand irgendwelche Konsolen-Meldungen? Man sieht nur, dass dem Linker irgend etwas nicht gefällt. Er sagt bestimmt auch, was -- nur sieht man das nirgendwo.
Hey, @ Bernhard: Danke für die Hinweise! Bin eben was µC-Programmierung belangt ein blutiger Anfänger. Die Annäherung mit Geradenstücken wäre auch mein nächster Schritt gewesen, ich dachte nur, es ginge (für mich) einfacher durch Einprogrammieren der Umkehrfunktion des Sensors. Das das nicht die rechnerisch schnellste Lösung für den µC ist leuchtet mir ein ;). Ich werde die Alternative mit den Geraden jetzt mal versuchen umzusetzen! Prinzipiell interessiert es mich aber schon, warum das nicht funktioniert. Hier kann ich mir vllt mit der Approximation durch Geraden helfen, aber es könnte ja auch mal vorkommen, dass ich die Potenzfunktion unbedingt brauche? @ Christian Gudrian: Also ich habe die Makefile-Datei mal in den Anhang gehängt, ich finde dort aber kein .SILENT. Und sonstige Ausgaben, Hinweise, Fehlermeldungen sehe ich wie gesagt auch nicht??? Gruß Matthias
EagleEye schrieb: > Also ich habe die Makefile-Datei mal in den Anhang gehängt, ich finde > dort aber kein .SILENT. > Und sonstige Ausgaben, Hinweise, Fehlermeldungen sehe ich wie gesagt > auch nicht??? Eigenartig. Aber grundsätzlich fehlt mir da bei den Linkerlibraries ein -lm um die Math-Library einzubinden. Da du Funktionen wie pow() benutzen willst, wirst du die brauchen
1 | ... |
2 | ## Libraries |
3 | LIBS = -lnibobee_line -lnibobee_base -lnibobee_utils -lm |
EagleEye schrieb: > Hier kann ich mir vllt mit der Approximation durch Geraden > helfen, aber es könnte ja auch mal vorkommen, dass ich die > Potenzfunktion unbedingt brauche? Man kann auch mit vielen Stützstellen aus einem Array arbeiten und dann dazwischen interprolieren. Das ganze natürlich nur Ganzzahlig :-) tschuessle B.
Hallo, Danke nochmal für die flotte Hilfe, habe das ganz nun über die Linearisierung der Exponentialfunktion gelöst, funktioniert einwandfrei. Meine Frage ist damit gelöst und der Thread kann geschlossen werden. Gruß Matthias
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.