Forum: Mikrocontroller und Digitale Elektronik Lichtsensor am MyAVR MK2 auslesen


von Timo B. (troxan)


Angehängte Dateien:

Lesenswert?

Guten Tag,
ich beschäftige mich seit ein paar Tagen mit Mikrocontrollern, genau 
genommen dem Atmega8A-PU (in AVR Studio muss ich immer Atmega8 angeben 
sonst funktioniert es nicht!?)

Ich habe mithilfe dieses Videos versucht den Lichtsensor auf meinem 
MyAVR-Board auszulesen.
https://www.youtube.com/watch?v=77o4I66WGHk&list=PLg8rGAQEOsuh9ZCwP6aW5ycCM5PFFqoNe&index=6
Mein Hintergedanke war das ich den Sensor am PIN C1 habe und das Signal 
über die PIN's B0-B5 über LED's ausgebe.

Ich habe versucht den Code soweit anzupassen, da im Video ein Atmega32 
verwendet wird und der Atmega8 kein ADATE (Auto-Trigger) hat.
Wenn ich das Programm aufspiele Leuchten aber durchgehen alle LED's, 
egal ob der Sensor Licht bekommt oder nicht.

Ich bin von dem kleinstem Teilungsfaktor ausgegangen,
Teilungsfaktor = 16MHz/200kHz=80 also ADPS = 111

Nochmal eine kurze Übersicht
Board: MyAVR MK2
µC: Atmega8A-PU
Belegung:
PC0(ADC0) = Sensor
PB0 - PB5 = LED's

Der Code sieht wie folgt aus:
1
#include <avr/io.h>
2
3
4
int main(void)
5
{
6
DDRB = 0b00111111; // Ausgabe des ADC-Messwertes
7
8
// ADC-Konfiguration
9
ADMUX |= (1<<ADLAR);
10
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
11
12
13
  while(1)
14
  {
15
    while(!(ADCSRA & (1<<ADIF))) {}
16
    PORTB = ADCH;
17
    ADCSRA |= (1<<ADIF);
18
  }
19
}
Ich habe die Makefile noch hochgeladen falls die irgendwie hilfreich 
sein könnte.

Ich hoffe ihr könnt mir sagen was ich falsch gemacht/verstanden habe. :)

Viele Grüße
Troxan

von Jakob (Gast)


Lesenswert?

Wenn es mehr Lichtsensoren, als DEN LICHTSENSOR geben würde,
käme hier jetzt bestimmt die DÄMLICHE Nachfrage, nach dem
Typen des Lichtsensors.

Der Zwang, irgendwelche grottigen u-tube-Videos anzuschauen,
drückt schon mächtig auf die Hilfsbereitschaft...

von Brabbel (Gast)


Lesenswert?

Ein schnöder Wald-und-Wiesen-LDR mit Vorwiderstand.

von Ralf G. (ralg)


Lesenswert?

Timo B. schrieb:
> Ich hoffe ihr könnt mir sagen was ich falsch gemacht/verstanden habe. :)

Alles ;-)

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe

von Jakob (Gast)


Lesenswert?

Ja und - kann er das mit dem LDR nicht selber rausfinden?

Wenn das Verständnis für ADC am Spannungsteiler R / LDR
schon fehlt, kann man sich den Rest auch sparen...

Leute, die was lernen wollen, hängen ein Poti an den ADC und
schauen sich die Ergebnisse an, indem sie sich z.B. die sechs
höchstwertigen Bit des ADC-Ergebnisses auf B0..5 ausgeben
lassen.

Oder probieren vorher mal, sich die Bits eines langsamen
Zählers anzeigen zu lassen...

Dann weiß man schon mal, ob es an der Ausgabe, oder am
Einstellen des ADC liegt.

EIGENTLICH steht doch alles im Datenblatt.

ANSONSTEN kommt man ohne Findigkeit auch beim nächsten
Projekt nicht viel weiter...

von Timo B. (troxan)


Lesenswert?

Ersteinmal Danke an alle,
ich habe den Plan jetzt ein wenig abgeändert, so das ich über ein Poti 
(an PC0 bzw. ADC0) die LED's ansteuern kann.
Genau genommen, soll der gemessene Wert Binär auf PB0-PB5 ausgegeben 
werden, also in binärer Zählweise 000001, 000010, 000011,... 111111 usw.
Diesmal habe ich versucht mich an dem AVR-GCC Tutorial zu orientieren.
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe

Hier mal meine Gedanken zu dem Code.

Teilungsfaktor:
Unter "Configuration Options" habe ich die Frequenz auf 8MHz gestellt 
(AVR Studio)
Also komme ich auf:
Tfmin = 8000000/200000 Hz=40
Tfmin = 8000000/50000 Hz=160
Daraus ergibt sich für ADPS = 110

ADEN: Einschalten; Ja
ADSC: Messvorgang starten; Ja
ADFR: Free Running Modus; Ja
ADIF: Interrupt; Nein
ADIE: Interrupt; Nein
ADPS2: Ja
ADPS1: Ja
ADPS0: Nein

Durch den "Free Running Modus", sollten nun also ständig Werte in das 
"ADC Data Register" geschrieben werden, wobei ADCL die ersten 8 Bit 
wieder gibt und ADCH die letzten beiden Bit wieder gibt, also 9 und 10.
Ich habe ich mir die Hilfsvariable "mess" erstellt, in die ich über den 
Bitweise verschieben Operator beide Werte hinein geschrieben habe.

Da ich nur 6 LED's angeschlossen habe, wollte ich den Wert noch auf 6 
Bit runter rechnen.
10 Bit ergeben max 1027
6 Bit ergeben max 63
1027/63 = 16,3 also teile ich "mess" durch 17.

Daraus habe ich Code erstellt:
1
#include <avr/io.h>
2
3
4
int main(void)
5
{
6
int mess; // ADC Data Register // ADCL und ADCH
7
DDRB = 0b00111111; // Ausgabe des ADC-Messwertes
8
9
// ADC-Konfiguration
10
11
/*
12
* ADEN (ADC Enable) : ADC aktivieren
13
* ADSC (ADC Start Conversion) : Messvorgang starten
14
* ADFR (ADC Free Run select) :  1 = "Free Running Modus; 0 = "Single Convention"
15
* ADIF (ADC Interrupt Flag):  Für den Interrupt Modus
16
* ADIE (ADC Interrupt Enable) : Für den Interrupt Modus
17
* ADPS2 (ADC Prescaler Select Bits): Teilungsfaktor
18
* ADPS1 (ADC Prescaler Select Bits): Teilungsfaktor
19
* ADPS0 (ADC Prescaler Select Bits): Teilungsfaktor
20
*/
21
22
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (1<<ADPS2) | (1<<ADPS1);
23
24
25
  while(1)
26
  {
27
    mess = ADCL;
28
    mess += (ADCH<<8);
29
    mess = (mess/16); // Auf 6 Bit reduzieren
30
    PORTB = mess;
31
  }
32
}

Funktionieren tut es leider immer noch nicht, aber evtl. komme ich der 
Sache ja näher.
Es leuchten immer alle LED's.

Ich gehe jetzt schlafen, evtl. fällt ausgeschlafen ja noch etwas ein.

Ich bin für jeden Hinweis dankbar. :)

Viele Grüße
Timo

: Bearbeitet durch User
von Jakob (Gast)


Lesenswert?

Schau mal nach dem ADLAR-Bit, wenn es richtig gesetzt ist,
musst du nur ADCH (obere 8 Bit) auslesen. Das Ergebnis teilst
du mit 2 x Shift-right durch 4 - und damit ist dein
6-Bit-Wert fertig.

Also:
    mess = ADCH
    mess = mess >> 2


Free Running ist für Anwendungen mit Messen und Anzeigen schon
mal Unsinn, weil niemand Messwerte, die sich mehr als 2...4 mal
in der Sekunde ändern, ablesen kann.

Wie willst du 15000 Messwerte / Sekunde ablesen?

Bei Regelschaltungen mag Free-Running erstmal besser aussehen,
dabei muss man aber die sich ergebende Auslese-Frequenz kennen,
um die ADC-Werte passend an die zeitabhängigen Auswertungs-
Gleichungen zu übergeben.

Grundsätzlich ist es besser, von einem Timer einen Interrupt
z.B. 100 mal pro Sekunde zu erzeugen. Und je nach Anzahl der
Durchläufe (40 Durchläufe = 1/5 Sekunde) das Hauptprogramm mit
einer ADC-Erfassung zu beauftragen...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Timo B. schrieb:
> 10 Bit ergeben max 1027
 10 bit ergeben immer noch max. 1023

> 6 Bit ergeben max 63
> 1027/63 = 16,3 also teile ich "mess" durch 17.
 Nein. 1024/64 = 16

 Und dein erstes Program war besser.
 Probiere das:
1
#include <avr/io.h>
2
3
int main(void)
4
{
5
DDRB = 0b00111111; // Ausgabe des ADC-Messwertes
6
7
// ADC-Konfiguration
8
ADMUX = (1<<ADLAR);
9
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
10
11
  while(1)
12
  {
13
    while(ADCSRA & (1<<ADIF)) {}
14
    PORTB = ADCH>>2;
15
  }
16
}

: Bearbeitet durch User
von Ehrenbruder69 (Gast)


Lesenswert?

Spast.

von peta (Gast)


Lesenswert?

Hallo ich verstehe hier gar nichts.

LG peta

von Verzweifelter Bruder LGS (Gast)


Lesenswert?

Hallo, wir kommen aus der Vergangenheit von Bremer. Es wird nicht gut 
enden. Rennt solange ihr noch könnt.

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.