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