Problem mit ADC & Tipps zum Code?

Gast #2888780
Lesenswert?

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
Angehängte Dateien:
Gast #2888812
Lesenswert?

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.
Gast #2888815
Lesenswert?

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?
Gast #2888831
Lesenswert?

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?"
Gast #2888835
Lesenswert?

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.
Gast #2888844
Lesenswert?

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.
Gast #2888857
Lesenswert?

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
Gast #2888865
Lesenswert?

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) {
Gast #2888902
Lesenswert?

Problem gefunden -.-
1
if(!(PINC & (1 << T_STOP)) || (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?
Gast #2888903
Lesenswert?

gehts denn jetzt?
Grundsätzlich zu deinem Code:
Konstanten mit #define, also
1
#define ADC_MIN  200  // ADC 10-Bit (0 - 1024) 5V/1024 = 4,88mV/Einheit
2
#define ADC_MAX  600
spart ram und macht effizienteren code

statt
1
PORTD &= ~(1 << MOTOR);
besser
1
#define MOTOR_PIN 4                           // PD4
2
#define MOTOR_AUS (PORTD &= ~(1 << MOTOR_PIN)) 
3
#define MOTOR_EIN (PORTD |= (1 << MOTOR_PIN ))
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
Gast #2888912
Lesenswert?

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.
Gast #2888955
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren