Hallo,
habe ein Problem bei einer AD-Wandlung und hoffe, dass ihr mit helfen
könnt.
Und ob ihr mir gleich mal ein paar Tipps zum Code geben könnt.
Also es geht um ein Schulprojekt. Wir haben ein Modell einer
Abfüllanlage (Förderband das LKWs befüllt).
Hardware:
ATMega8, int. 4 MHz
1 Motor f. Förderband
2 Ampeln (Vor und nach dem Befüllplatz)
1 Orange Blitzleuchte
1 Duo-StatusLED Rot/Grün
1 Piezo als Sirene
3 Taster (Start, Stop, Not-Aus)
1 Waage mit 4 DMS verstärkt auf 0V-5V
Ich habe 2 AD-Wandlungen.
Die 1. checkt, ob auf der Waage das min.gewicht des LKWs erreicht ist
und wenn das nicht der Fall ist den Fehler auslöst. Das funktioniert.
Die 2. checkt, ob der LKW voll ist und sollte bei überschreiten den
Befüllvorgang stoppen. Das geht nicht.
ARef ist an Vcc (5V).
Am AD-Wandler hängen zurzeit noch 2 Spannungsteiler (offen 5V (voll),
2,5V (leer aber LKW ist da) oder 0V (LKW nicht da)).
Den Code hab ich mal angehägt, weil n bisschen lang.
lg Marcel
katastrophenheinz schrieb:> Hi,>> wieso hast du den hier auskommentiert // interne Referenzspannung als Refernz
für den ADC wählen:
> //ADMUX = (1<<REFS0);
Weil ich REFS0 und REFS1 testweise auf 0, 0 haben wollte (ext.
Referenz).
Habs grad nochmal wieder reingenommen, geht trotzdem nicht.
Hab vergessen zu erwähnen, dass ich mit Proteus simuliere, da die
Hardware noch nicht ganz steht, weiß nicht ob das wichtig ist.
ich kenne Proteus nicht.
Wie kann Proteus denn überhaupt einen ADC simulieren?
Kannst du dem sagen, welchen Wert er in ADCW zurückgeben soll?
Oder ist das ein echter Emulator, der den ADC korrekt nachbildet?
der adc-code sieht korrekt aus bis auf eine kleinigkeit, die ist aber
nicht fehlerverursachend. atmega8 hat nur 4 MUX-Bits, dementsprechend
solltest du auch nur mit 0x0f ver-unden.
Was genau geht denn nicht? Liefert der ADC falsche Werte ? Was genan
meinst du mit "geht nicht?"
katastrophenheinz schrieb:> ich kenne Proteus nicht.> Wie kann Proteus denn überhaupt einen ADC simulieren?> Kannst du dem sagen, welchen Wert er in ADCW zurückgeben soll?> Oder ist das ein echter Emulator, der den ADC korrekt nachbildet?
Habs seit heute morgen aufm Rechner und muss mich noch einarbeiten. Habe
gerade beim Google überfliegen ein paar PICs gesehen, die den ADC
benutzt haben. Bei den Sampels ist leider nichts dabei.
Habe gerade die Funktion entdeckt, dass ich in die Register des ATMega8
gucken kann, muss mich nur zurechtfinden, was davon mein PC0 ist.
katastrophenheinz schrieb:> der adc-code sieht korrekt aus bis auf eine kleinigkeit, die ist aber> nicht fehlerverursachend. atmega8 hat nur 4 MUX-Bits, dementsprechend> solltest du auch nur mit 0x0f ver-unden.>> Was genau geht denn nicht? Liefert der ADC falsche Werte ? Was genan> meinst du mit "geht nicht?"
Die MUX-Bits korrigiere ich gleich, danke.
Geht nicht heißt, dass
1
2
if(ADC_Read(0) > ADC_MAX) { ..
3
// ADC_MAX überschritte (LKW ist voll)
niemals Wahr ist.
ADC_MAX ist auf 600 (600 * 4,88mV/Einheit = ~3V) gesetzt, selbst wenn
ich PC0 auf 5V lege, ist die Abfrage nicht erfüllt.
Marcel schrieb:> Geht nicht heißt, dass>if(ADC_Read(0) > ADC_MAX) { ..> // ADC_MAX überschritte (LKW ist voll)> niemals Wahr ist.>> ADC_MAX ist auf 600 (600 * 4,88mV/Einheit = ~3V) gesetzt, selbst wenn> ich PC0 auf 5V lege, ist die Abfrage nicht erfüllt.>
... was zurückführt auf die ursprüngliche Frage: Kann der Simulator
wirklich AD-Wandlungen simulieren oder ist der so doof, daß der immer
nur 0 in ADCW zurückliefert? Das würde das von dir beobachtete Verhalten
erklären
Habe grad die Register zum ADC gefunden.
Der AD-Wandler wandelt und speichert die richtigen Werte in den
Registern.
0,xxV - 0x000B
2,6xV = 0x0218
4,9xV = 0x03FE = Dez. 1022
1022 > 600,
if(ADC_Read(0) > ADC_MAX) {
Nu gehts :)
Er kam ja nur zur AD-Wandlung, wenn Stop gedrückt worden wäre.
Das die richtigen Spg-Werte in den Register lagen, lag an der
Fehlerüberprüfung.
Naja, hab heute viel über die Funktionsweise des ADC gelernt.
Habt ihr noch anmerkungen zum Code an sich?
ist viel einfacher lesbar. die anderen Dinge (Ample, Ventil, ... )
entsprechend
in main fehlen noch kommentare, was du mit Timer0 eigenlich machst
und die timer0-ovf-routine würd ich anders bauen, aber fürs Verständnis
und für diesen Anwendungfall voll ok.
Die Variablennamen sind tw. etwas spartanisch da würde ein sprechender
name oder zumindest ein kommentar hinder der deklaration helfen
katastrophenheinz schrieb:> gehts denn jetzt?
jap, manchmal ist einfach die Zeile darüber Schuld :D
> Grundsätzlich zu deinem Code:> Konstanten mit #define, also#define ADC_MIN 200 // ADC 10-Bit (0 - 1024)
5V/1024 = 4,88mV/Einheit
> #define ADC_MAX 600> spart ram und macht effizienteren code>> stattPORTD &= ~(1 << MOTOR);> besser#define MOTOR_PIN 4 // PD4> #define MOTOR_AUS (PORTD &= ~(1 << MOTOR_PIN))> #define MOTOR_EIN (PORTD |= (1 << MOTOR_PIN ))> ist viel einfacher lesbar. die anderen Dinge (Ample, Ventil, ... )> entsprechend
Das seh ich zum ersten Mal, muss ich mal ausprobieren.
> in main fehlen noch kommentare, was du mit Timer0 eigenlich machst> und die timer0-ovf-routine würd ich anders bauen, aber fürs Verständnis> und für diesen Anwendungfall voll ok.
Magst du kurz anreißen, was du meinst? Werde ganz bestimmt noch öfter
Timer brauchen.
> Die Variablennamen sind tw. etwas spartanisch da würde ein sprechender> name oder zumindest ein kommentar hinder der deklaration helfen
Stimmt, bin beim Schreiben oft zu faul, nach dem Motto "Ich weiß ja noch
wofür das war"
Dankeschön.
Hi, das von mir angedachte timer0-ovf routinen design
lässt sich in deinem code nicht umsetzen, weil du aktiv auf irgendwelche
änderungen wartest.
Das design beruht darauf, daß der prozessor nur dann was tun muss, wenn
sich was ändert und den rest derzeit schläft er einfach. Das ist für
Anwendungen,die mit Batterien rennen, elementar, weil Ruhestrom ca 100 x
geringer.
d.h. alles was passiert zunächst in ISR-Routinen abgehandelt, nicht nur
wie bei dir die Zeitbasis, sondern auch Änderungen an Input-Pins,
Empfang von Zeichen via Uart, usw. Die Schnittstelle zw. ISR und
eigentlichem Programm sind dann nur irgendwelche Statusbits, die main
periodisch abfragt, drauf reagiert und wenn nichts zu tun ist,
weiterschläft.
Für einfache Programme ist das Overkill, für komplexe fast schon ein
must.
Die mir bekannte beste Umsetzung dieses Konzeptes ist das
OpenHR20-Projekt, falls es dich interessiert, Sourcecode ist öffentlich.
In deinem Code würde ich in der Interrupt-Routine nur noch mal durch
Kommentar hervorheben, daß der obere Teil alle 0.5s und der untere Teil
jede s durch ausgeführt wird und damit finde ich dann deine Umsetztung
voll ok für ein Schulprojekt.