Forum: Mikrocontroller und Digitale Elektronik Problem mit ADC & Tipps zum Code?


von Marcel (Gast)


Angehängte Dateien:

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

von katastrophenheinz (Gast)


Lesenswert?

Hi,

wieso hast du den hier auskommentiert
1
 // interne Referenzspannung als Refernz für den ADC wählen:
2
  //ADMUX = (1<<REFS0);

von Marcel (Gast)


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.

von katastrophenheinz (Gast)


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?

von katastrophenheinz (Gast)


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

von Marcel (Gast)


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.

von Marcel (Gast)


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.

von katastrophenheinz (Gast)


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

von Marcel (Gast)


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

von Marcel (Gast)


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?

von katastrophenheinz (Gast)


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

von Marcel (Gast)


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.

von katastrophenheinz (Gast)


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.

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
Noch kein Account? Hier anmelden.