Hi,
bin dabei mich an ADC her ran zu arbeiten. Dabei habe ich das Tutorial
genutzt, verstanden hab ich es in groben auch. Wollte es jetzt mal in
der Praxis an meinen Test-Board ausprobieren. Wenn ich an meinen Board
ein Taster drücke soll er eine Messung durchführen und dann anschließend
an geben ob die Spannung großer oder kleine als 2,5V ist. Ich habe denn
Code jetzt übernommen und auf den Teiler 128 eingestellt(da 16MHz). Groß
verändern wollte ich erst mal nix. Ich glaube ich habe etwas übersehen
oder ein Denkfehler bei der Ausführung im Hauptprogramm.
Er gibt zur Zeit an, dass die Spannung unter 2.5V ist.
Nur der Code für den ADC
1
voidADC_init(void){
2
3
4
uint16_tresult;
5
6
ADMUX=(1<<REFS0);// ACC als Referenzspannung nutzen
Jakob schrieb:> der Praxis an meinen Test-Board ausprobieren. Wenn ich an meinen Board> ein Taster drücke
Das lässt sich in deinem Code nirgends finden.
Machs doch bei deinen ersten SChritten nicht komplizierter als
notwendig. Das sind alles nur potentielle Fehlerquellen, die vom
eigentlich zu testenden Vorhaben ablenken und ihrerseits Fehler
enthalten können.
Du willst den ADC testen?
Dann tu das auch. Und zwar genau nur das.
Es spricht nichts dagegen, dass der ADC in der Hauptschleife einfach
dauernd arbeitet. Du bruachst auch nix umrechnen (weitere Fehlerquelle).
Deine 2.5V sind die Hälfte der Referenzspannung (die offenbar 5V ist).
Wenn der ADC also bei der Referenzspannung (5V) einen Wert von 1023
liefert, welchen Wert liefert er dann bei ca. 2.5V? Genau. 512. Werte
kleiner als 512 bedeuten also kleiner 2.5V. Werte größer 512 bedeuten
mehr als 2.5V. Ob das jetzt ein paar Zehntelvolt mehr oder weniger sind,
spielt erst mal keine große Rolle. Wenn du die zu messende Spannung (wie
erzeugst du die überhaupt?) von 0 bis 5V durchdrehst, dann muss die LED
in der Mitte dieses Durchdrehens ein bzw. aus gehen, je nachdem, wie du
die LED angeschlossen hast.
Das ist einfach genug, dass sich nur wenige Fehler einschleichen können,
die nichts mit dem ADC zu tun haben
1
voidADC_init(void)
2
{
3
...
4
}
5
6
7
uint16_tADC_read(uint8_tchannel)
8
{
9
...
10
}
11
12
intmain(void)
13
{
14
uint16_tadcval;
15
16
DDRB=0xff;
17
18
ADC_init();
19
20
while(1)
21
{
22
adcval=ADC_read(0);
23
24
if(adcval<512)
25
PORTB=0x0F;
26
else
27
PORTB=0x00;
28
}
29
}
Fertig. Einfach und simpel. Mit wenig Potential, dass Fehler abseits des
ADC das Programm lahmlegen könnten.
Wenn das dann wie erwartet funktioniert, dann baust du weitere Dinge
ein. Aber nicht vorher.
Gerade Neulinge neigen gerne dazu, mit einer zu komplexen
Aufgabenstellung anzufangen. Das Ergebnis ist dann oft, das nichts
funktioniert und er keine Ahnung hat, wo das Problem liegen könnte. Wenn
obiges nicht funktioniert, dann gibt es nur 2 Möglichkeiten: entweder
die LED funktionieren nicht oder im ADC ist was faul. Da nichts anderes
im Programm vorkommt, kann auch nichts anderes fehlerhaft sein.
Eine int Variable mit einem Float Wert vergleichen? Alleine dort beginnt
das Problem.
Die Zeile:
1
Messwert=5.0*ADC_read(0)/1023;
liefert kein sauberes Resultat, wenn Messwert als integer definiert ist.
Sonst ein paar Tipps:
Wenn du dein Programm ein bisschen schneller gestalten willst, lass das
Messwert rechnen komplett weg. Berechne dir lieber was für einen
Digitalisierten Wert 2,5V bei deiner Auflösung von 10 Bit hätten und
vergleich direkt diesen. Falls du 5V Referenz hast also:
1
if(ADCW<512){...
Zu deiner Funktion:
1
JakobschriebimBeitrag#3657686:
2
>returnADCW;
Diese Zeile ist unnütz. ADCW ist ein Register, welches vom Controller
vorgegeben ist und somit an jeder Stelle der Programms darauf
zugegriffen werden kann. Das ist das selbe wie du eine Globale Variable
als Return Wert zurück gibst. Ein ganz normales Return tuts da auch.
Nur gut, dass Du uns nicht mit so Kleinigkeiten wie: Woher kommt
"Auswahl" oder wie bekommst Du 2.5 in eine Ganzzahlvariable
belästigst;-)
>Groß verändern wollte ich erst mal nix.
Wo auch immer Du das abgeschrieben hast - viel scheint nicht dahinter
zustehen.
Amateur schrieb:> Woher kommt> "Auswahl"
Alleine aus dem Grund bin ich überrascht, dass der Compiler sowas
überhaupt akzeptiert. Müsste doch eine Fehlermeldung erscheinen, wenn
eine nicht definierte Variable abgefragt wird? Zumindest bei MPLAB war
das immer so.
Amateur schrieb:> 2.5 in eine Ganzzahlvariable
Kunst. Magie. Man weiss es nicht.
Genau das ist wieder einmal ein typisches Problem. Neulinge stürzen sich
auf fertige Tutorials, welche schon X-Sonderfunktionen eingebaut haben
und erhöhen sich damit die möglichen Fehlerquellen selbst.
Kann nur anraten, lieber einmal das Datenblatt zu öffnen und da selbst
etwas versuchen hinzukriegen, als ständig irgendwelche Tutorials
übernehmen und dann danach herumbasteln.
Wenn du nämlich ein Tutorial nicht richtig verstehst, also den Code
nicht richtig interpretierst, wie willst du mit diesem dann arbeiten? Du
kannst auch kein Auto fahren, wenn du nicht weisst welches Fusspedal
wofür ist.
Vielen Dank.
Ja es funktioniert.
Sie haben Recht, ich muss klein Anfangen aber man neigt gerne dazu
komplexere Code zu schreiben. Jeglich muss ich es mir angewöhnen. Der
Fehler bei mir lagt daran das ich bei der PortB ausgabe 2 mal das selbe
stehen hatte also gabs keinen Unterschied
> liefert kein sauberes Resultat, wenn Messwert als integer definiert ist.
Klar tut die das. Es ergibt nicht genau das, was Jakob sich vorstellt,
aber es gibt ein ganz sauberes Ergebnis, und das kann auch kleiner als
2.5 werden. Selbst der Vergleich zwischen float und int ist in C sauber
definiert, da passiert nichts unerwartetes.
Oliver
Oliver schrieb:> Klar tut die das. Es ergibt nicht genau das, was Jakob sich vorstellt,> aber es gibt ein ganz sauberes Ergebnis, und das kann auch kleiner als> 2.5 werden. Selbst der Vergleich zwischen float und int ist in C sauber> definiert, da passiert nichts unerwartetes.
Natürlich kann das Resdultat kleiner als 2,5 bzw in diesem Fall eher 3
werden. Ein anderes Resultat als 0, 1, 2, 3, 4 oder 5 wird er ja nie in
der Variable haben.
Es ist allerdings nicht sauber gelöst. Wenn man schon solche
Berechnungen macht, dann entweder das Resultat auch in Float lassen oder
von Anfang an eine solche Berechnung weglassen und den Vergleich einfach
mit dem Digitalisierten Wert von 2,5V also 512 bei einer Auflösung von
10-Bit vergleichen.
Ich habe nie behauptet es funktioniert so nicht. Es war lediglich ein
kleiner Tipp für die Zukunft, was er besser unterlassen sollte. Sonst
wird er einer von diesen Programmierern a la 10'000 Zeilen Programm und
alle Variablen Global definiert.
Übrigens bei Vergleichen:
Genaugenommen gibt es bei einem Vergleich 3 mögliche Resultate.
Du fragst kleiner 2.5 und größer 2.5 ab. Was soll aber mit gleich
passieren.
Aus Gründen der Übersichtlichkeit schreibt man so etwas:
XXX < 2.5
XXX > 2.5
XXX == 2.5
Dabei sollten unnötige Vergleiche durch den else-Zweig ausgeklammert
werden.
Alternativ könnte auch ein Konstrukt wie
if ( XXX <= 2.5 ) {
// kleiner oder gleich
} else {
// definitiv > 2.5 auch ohne weitere Abfrage
}
verwendet werden oder
if ( XXX < 2.5 ) {
// kleiner
} else {
if ( XXX > 2.5 ) {
// größer
} else {
// gleich bleibt über
// fehlt dieser Zweig, so ignorierst Du ==
}
}
Amateur schrieb:> Du fragst kleiner 2.5 und größer 2.5 ab. Was soll aber mit gleich> passieren.
Dieser Fall wird nie eintreffen, da sein Resultat in einer Variable vom
Typ INT gespeichert wird.
>Dieser Fall wird nie eintreffen, da sein Resultat in einer Variable vom>Typ INT gespeichert wird.
Das stimmt nur eingeschränkt!
Dein Compiler macht aus der Abfrage:
XXX < 2.5 --> XXX < 2
bzw.
2.5 < XXX --> 2 < XXX
und somit fällt zwar 2.5 nicht aber == 2 durchs Raster.
Amateur schrieb:> Dein Compiler macht aus der Abfrage:> XXX < 2.5 --> XXX < 2
Nö. Macht er nicht. Ist ein Operand eines Operators float und der andere
ein int, wird der int in ein float umgewandelt.
Oliver
Oliver schrieb:> Nö. Macht er nicht. Ist ein Operand eines Operators float und der andere> ein int, wird der int in ein float umgewandelt.
Korrekt.
Somit bliebe dann dann
XXX < 2.5 ---> XXX.0 < 2.5
Wobei XXX immer eine volle Zahl sein wird.