Forum: Mikrocontroller und Digitale Elektronik ADC Problem und anliegen zu "FLAG"


von Christian B. (christian_buchner)


Lesenswert?

Hallo,

ich lese einen Fotowiderstand mittels ADC aus. Das klappt auch soweit. 
Den Wert speichere ich und lasse ihn mir auf einem Display ausgeben.

Allerdings "springt" der Wert während der Wandlung. Also alle 5 Sekunden 
ticken die Zahlen da ganz schnell und dann ist der Wert wieder konstant. 
Also jedesmal während der Wandlung.

Wie umgehe ich dieses Problem?

Der Wert des ADCs kann ja 0 - 1023 sein. Soweit so gut. Ich benötige 
allerdings einen Wert von 0 - 100. Die Umrechnung will irgendwie nicht 
so ganz.

Also der Fotowiderstand soll die Display Helligkeit regeln. Diese geht 
von 0 - 100. Also je Heller es ist um so Heller auch das Display.

Der ADC wird mit einem 4,7k gepullt. Der Fotowiderstand schaltet GND.

Jedoch klappt das nicht so ganz sondern genau andersrum. Wie 
"invertiere" ich den Wert nun? Also jetzt ist es so, je dunkler es ist 
um so heller das Display.

Hier mal der ADC Code
1
/* ADC initialisieren */
2
void ADC_Init(void)
3
{
4
  ADMUX = (1<<REFS0);    
5
  ADCSRA = (1<<ADPS2) |(1<<ADPS1) | (1<<ADPS0);
6
  ADCSRA |= (1<<ADEN);
7
  ADCSRA |= (1<<ADSC);
8
  while (ADCSRA & (1<<ADSC) ) {}
9
10
  (void) ADCW;
11
}
12
 
13
uint16_t ADC_Read( uint8_t channel )
14
{
15
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
16
  ADCSRA |= (1<<ADSC);
17
  while (ADCSRA & (1<<ADSC) ) {}
18
  return ADCW;
19
}
20
21
22
void read_fotowiderstand(void)
23
{  
24
  if (sekunde%10 == 0) {
25
    
26
      fotowid_temp = ADC_Read(6);
27
    
28
      if ( fotowid_temp > 1000)
29
        {
30
          bcdata[FOTOWIDERSTAND] = ((1000  / 10) - 100) + 100;
31
        }
32
        else
33
        {
34
          bcdata[FOTOWIDERSTAND] = ((fotowid_temp / 10) - 100) + 100;
35
        }
36
    }
37
}

Dann habe ich noch ein Problem mit den sogenannten "Flags".

Also ich habe folgenden Code:
1
void read_tuertaster(void)
2
{
3
  if ( !(PING & (1<<PING0)) )
4
  {
5
    bcdata[TUERLINKS_OPEN] = 1;
6
  }
7
  else
8
  {
9
    bcdata[TUERLINKS_OPEN] = 0;
10
  }
11
  
12
  if ( !(PING & (1<<PING1)) )
13
  {
14
    bcdata[TUERRECHTS_OPEN] = 1;
15
  }
16
  else
17
  {
18
    bcdata[TUERRECHTS_OPEN] = 0;
19
  }
20
}

Hier brauche ich nun eine Funktion die bei einer 1 einen PIN für 100ms 
auf HIGH schaltet. Aber nur einmal. Ob der Wert weiter 1 bleibt oder 
nicht. Und erst wenn er sich auf 0 ändern den PIN für 300ms HIGH 
schaltet. Wenn er dann wieder 1 ist für 100ms usw.

Wie macht man das mit diesen "flags"?

Ein Timer im ms Bereich ist vorhanden und funktioniert Einwand frei.

Ich danke euch schon mal.

von M. K. (sylaina)


Lesenswert?

Und mit dem Oszi hast du dir das Signal auch angeschaut? Ich meine, der 
ADC zeigt dir wirklich ein Verhalten, dass nicht da ist?

von Wolfgang (Gast)


Lesenswert?

Christian B. schrieb:
> ich lese einen Fotowiderstand mittels ADC aus.

Ein Widerstand ist keine Größe, die man mit einem ADC messen kann. Meist 
misst ein ADC Spannungen.
Was macht deine Schaltung und dein Programm WIRKLICH?

von Felix Adam (Gast)


Lesenswert?

>         {
>           bcdata[FOTOWIDERSTAND] = ((1000  / 10) - 100) + 100;
>         }
>         else
>         {
>           bcdata[FOTOWIDERSTAND] = ((fotowid_temp / 10) - 100) + 100;
>         }

Ich könnte mich ja wieder mal irren, aber warum (100-100)+100?

Das -100)+100 ergibt doch immer Null, nur dass der Wert in der Klammer 
erstmal negativ (oder groß positiv bei uint) wird.

Versuche doch diesen Pseudocode mal:

Wert=(1023-adcwert)/103

Gibt Werte bis (nahezu) 100.

Danach vielleicht eine Lookuptabelle als const in den Code schreiben.

von Bert 0. (maschinist)


Lesenswert?

Felix Adam schrieb:

> Versuche doch diesen Pseudocode mal:
>
> Wert=(1023-adcwert)/103
>
> Gibt Werte bis (nahezu) 100.


Divisionen auf dem AVR vermeide ich gerne:

Wert=((1023-adcwert)*100)>>10;

Gruß... Bert

von M. K. (sylaina)


Lesenswert?

Bert B. schrieb:
> Divisionen auf dem AVR vermeide ich gerne:
>
> Wert=((1023-adcwert)*100)>>10;
>
> Gruß... Bert

Hm
1
Wert=((1023-adcwert)*100)/103;
ist aber nicht das Selbe wie
1
Wert=((1023-adcwert)*100)>>10;
schreibst.

Und heutige Compiler sind recht klug und erkennen eine Division durch 
eine Zweierpotenz (d.h die machen Automatisch eine Shift-Operation 
daraus). Für bessere Code-Lesbarkeit würde ich da eher eine Division 
(oder auch Multiplikation) benutzen statt eine Shift-Operation.

Felix Adam schrieb:
> Wert=(1023-adcwert)/103
>
> Gibt Werte bis (nahezu) 100.

Wie das? Bei deinem Pseudo-Code kommt bestenfalls was knapp unter 10 
raus, der ADC-Wert kann ja nicht negativ werden. Oder hast du dich nur 
vertippt und wolltest 10 schreiben?

von Bert 0. (maschinist)


Lesenswert?

Michael K. schrieb:

> Hm
>
1
> Wert=((1023-adcwert)*100)/103;
2
>
> ist aber nicht das Selbe wie
>
1
> Wert=((1023-adcwert)*100)>>10;
2
>
> schreibst.

Hat ja auch niemand behauptet. Der Originalautor wollte aber den ADC auf 
Werte von 0-100 skaliert haben.

Du hast ja selbst geschrieben, daß die erste Codezeile das um den Faktor 
10 nicht erfüllt, meine aber schon.


Gruß... Bert

von Felix Adam (Gast)


Lesenswert?

Und wieder habe ich mich geirrt :-(. Asche auf mein Haupt.

von Felix Adam (Gast)


Lesenswert?

Eigentlich fehlt in meiner Rechnung das *10, bevor durch 103 geteilt 
wird. Dann hätte es gestimmt. Aber auf meinem kleinen Tablet ging mir 
das durch die Lappen...

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.