Forum: Mikrocontroller und Digitale Elektronik ATTiny 13 Soil Moisture Sensor ADC Lese Problem


von Michael D. (toxy1337)


Lesenswert?

Hallo,

ich möchte einen Soil Moisture Sensor (Sensor:YL-69, Modul YL-38) an 
meinen ATTiny13 schließen. Sensor hab ich bereits mit dem UNO getestet 
und dieser funktioniert einwandfrei. Danach hab ich den Uno als ISP 
Programmer verwendet, um Code auf den ATTiny zu spielen. Ziel ist es 
derzeit eigentlich nur den Sensor über ADC2 (=PB4) einzulesen und damit 
eine LED bei einem Treshhold an PB3 einzuschalten. Soweit so gut. Das 
Programm funktioniert mit einem Poti wie gewünscht.

Das Problem ist, egal wie ich den Wertebereich einschränke, die LED 
schaltet nie um, wenn der Sensor angesteckt ist.

Schaltung:
UNO mit ATTiny für ISP
Wassersensor: Vcc/GND/ADC2->AO
LED: PB3 -> 200Ohm -> LED -> GND


1
#define F_CPU 1200000UL // 1.2 MHz
2
#include <avr/io.h>
3
4
void adc_init()
5
{
6
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);// Prescaler 16: F_ADC = F_CPU / 16 = 9.6MHz / 128 = 75kHz
7
}
8
9
uint16_t adc_read(uint8_t channel)
10
{
11
  if(channel>3) return 0;// Catch channel numbers greater than 3, because there not more than 2 bits to choose the ADC 
12
  ADMUX |= (1<<REFS0) + channel;// select ADC channel (here: channel 3) for next conversion
13
  ADCSRA |= (1<<ADSC);// start single conversion: Start the ADC
14
  while (ADCSRA & (1<<ADSC));// wait until conversion is finished (see data sheet page 92)
15
  uint16_t result=ADCL;// store low byte of sample value in variable
16
  result+=(ADCH<<8);// add high byte of sample value
17
  return result;
18
}
19
20
int main(void){
21
  DDRB |= (1<<3);
22
  adc_init();
23
      while (1){
24
    uint16_t val=adc_read(2);
25
    if(val > 512){
26
      PORTB |= (1<<3);    //If ADC value is above 512 turn led on
27
    } else {
28
      PORTB &= ~(1<<3);
29
    }
30
    }
31
}


Des weiteren: Derzeit läuft der Controller auf den 5V vom Uno. Ist aber 
geplant ihn auf 3V Knopfzelle umzustellen. Derzeit wird ja mit ADMUX |= 
(1<<REFS0) gesagt, dass die interne 1,1V Referenspannung als Vergleich 
dient. Ich versteh zwar nicht ganz, wie er daraus dann Werte berechnet, 
aber vielleicht kann mir das ja wer erklären. Vcc=5V?!

Vielen lieben Dank im Vorhinein :)

von Bastian W. (jackfrost)


Lesenswert?

Hi,

ist die LED immer an oder aus?

Hast du die Spannung am ADC-Pin mal mit einem Multimeter gemessen ?

Bei der internen Referenzspannung von 1,1 Volt kannst du halt bis 1,1 V 
messen. Alles darüber bleibt 1023.

Gruß JackFrost

von Michael D. (toxy1337)


Lesenswert?

Hi,

Also ja, hab ich gemessen. Die LED beim Wassersensor ist immer an. Ich 
finds nur interessant, weil ja die Spannung doch auch auf knape 0V 
kommt.

Spannung ist beim Wassersensor, wie auch beim Poti zwischen 0 und 4,7V 
(bei Vcc 5v) und zwischen 0 und 2,7V (bei Vcc 3V). Eben deswegen ja 
meine Frage, wie das skaliert/gemessen wird. Interessant find ich ja 
nur, dass beim Poti eigentlich funktioniert.

Wobei: Bei einem Treshold von 500 ist die LED beim Poti bei ~0,5V 
angegangen, Bei Treshold 1000, bei ungefähr 1V... Ich seh ja den Fehler 
eh schon ungefähr. Es ist die Referenzspannung zu den internen 1,1V. Da 
dürfte der Uno wohl zu 5V referenzieren? Das Problem ist: Wenn ich ADMUX 
|=
~(1<<REFS0) schreibe, funktioniert garnichts und ich weiß nicht warum. 
Jemand eine Idee?

Grüße

von Peter II (Gast)


Lesenswert?

Michael D. schrieb:
> uint16_t result=ADCL;// store low byte of sample value in variable
>   result+=(ADCH<<8);// add high byte of sample value

warum so kompliziert?
1
return ADCW;

von Peter D. (peda)


Lesenswert?

Nur mit ner LED durchs Nadelöhr zu debuggen, ist recht mühsam.
Nimm besser ne UART und gib den ADC als Zahl (itoa) aus:
Beitrag "Re: Kleines Programm für Debug Ausgaben"

von MWS (Gast)


Lesenswert?

1
ADMUX |= (1<<REFS0) + channel;
Bevor Du die Mux-Bits veroderst, musst Du sie löschen, sonst sind 
irgendwann die verwendeten Bits = 1 und ändern sich auch nicht mehr.

von Fred R. (Firma: www.ramser-elektro.at/shop) (fred_ram)


Lesenswert?

Hier wird erklärt, warum du genau so einen Sensor NICHT verwenden 
sollst:
https://wwwvs.cs.hs-rm.de/vs-wiki/index.php/Internet_der_Dinge_WS2015/SmartPlant#Messmethode_1:_Resistiv

: Bearbeitet durch User
von Michael D. (toxy1337)


Lesenswert?

Peter D. schrieb:
> Nur mit ner LED durchs Nadelöhr zu debuggen, ist recht mühsam.
> Nimm besser ne UART und gib den ADC als Zahl (itoa) aus:
> Beitrag "Re: Kleines Programm für Debug Ausgaben"

Der ATTiny13 hat kein USART soweit ich weiß. Hab quasi das Programm auch 
mit dem UNO getestet mittels HTERM. Gibt mir sowohl für den Potti, als 
auch für den Wassersensor schöne Werte von 0 bis 1023 aus. Dürfte aber 
eben eine andere Referenzspannung sein bei ADMUX |= (1<<REFS0)

MWS schrieb:
>
1
ADMUX |= (1<<REFS0) + channel;
> Bevor Du die Mux-Bits veroderst, musst Du sie löschen, sonst sind
> irgendwann die verwendeten Bits = 1 und ändern sich auch nicht mehr.

ADMUX = 0x00;? Bin mir aber über den Nutzen dessen nicht ganz bewusst. 
Könntest du mich da nochmals aufklären? Ich will ja, dass das Register 
so aussieht: 0b01000010;

Peter II schrieb:
> Michael D. schrieb:
>> uint16_t result=ADCL;// store low byte of sample value in variable
>>   result+=(ADCH<<8);// add high byte of sample value
>
> warum so kompliziert?
>
>
1
> return ADCW;
2
>

Werd ich ausprobieren

von Michael D. (toxy1337)


Lesenswert?

Fred R. schrieb:
> Hier wird erklärt, warum du genau so einen Sensor NICHT verwenden
> sollst:
> 
https://wwwvs.cs.hs-rm.de/vs-wiki/index.php/Internet_der_Dinge_WS2015/SmartPlant#Messmethode_1:_Resistiv

Danke für den qualitativen Verweis. Ich würds jetzt aber trotzdem gerne 
mit dem Sensor machen. Das muss doch irgendwie möglich sein?

von Peter D. (peda)


Lesenswert?

Michael D. schrieb:
> Der ATTiny13 hat kein USART soweit ich weiß.

Geht auch ohne HW-UART.
Schau einfach mal den Link an.

von JoeS (Gast)


Lesenswert?

Nimm mal Vcc als Referenz, also:

ADMUX &= ~(1 << REFS0);  // clear REFS0-Bit

und dann

ADMUX |= channel;  // wenn channel <= 3

oder in einem step:

ADMUX = channel;

von JoeS (Gast)


Lesenswert?

Nachtrag:

ADMUX |= channel;

funktioniert so natürlich nur wenn MUX1:0 vorher 0 sind.

von MWS (Gast)


Lesenswert?

Michael D. schrieb:
> ADMUX = 0x00;? Bin mir aber über den Nutzen dessen nicht ganz bewusst.

Könnte man, macht man aber nicht, man löscht nur die Mux-Bits, die neu 
zu beschreiben sind und das muss auch nicht im Mux-Register selbst 
passieren.

In Deinem Fall, da Du nur einen Kanal ansprichst, ändert das nichts, ist 
also nicht der Fehler, wird aber zum Fehler, wenn die Funktion adc_read 
mit mehr als einem Kanal aufgerufen wird.

In Deinem Fall hätte ein:
1
ADMUX = (1<<REFS0) + channel;
ausgereicht, um das zu korrigieren.
Aber auch das macht man üblicherweise nicht so, sondern man setzt die 
Referenz einmal in einer Initialisierung und lässt die dann in Ruhe. 
Verändert werden nur die Mux-Bits, die den Kanal bezeichnen, alle 
anderen Bits lässt man in Ruhe.
1
ADMUX = (ADMUX & ~((1 << MUX1) | (1 << MUX0))) | channel;

von MWS (Gast)


Lesenswert?

JoeS schrieb:
> oder in einem step:
>
> ADMUX = channel;

Sicher nicht, da werden alle anderen Bits, REFS0 oder ADLAR gelöscht.

von JoeS (Gast)


Lesenswert?

MWS schrieb:
> JoeS schrieb:
>> oder in einem step:
>>
>> ADMUX = channel;
>
> Sicher nicht, da werden alle anderen Bits, REFS0 oder ADLAR gelöscht.

Ich meine das im Bezug auf die Initialisierung aus der ursprünglichen 
Routine. Ist mir auch klar, daß man damit alle anderen Bits löscht,
aber so war es ja oben auch vorgesehen.

von MWS (Gast)


Lesenswert?

JoeS schrieb:
> Ich meine das im Bezug auf die Initialisierung aus der ursprünglichen
> Routine.

Egal wo Du's meinst, ist's falsch.

> ADMUX &= ~(1 << REFS0);  // clear REFS0-Bit
> und dann
> ADMUX |= channel;  // wenn channel <= 3
> oder in einem step:
> ADMUX = channel;

Denn in "in einem step" würde damit REFS0 gelöscht. Nur wenn man ADMUX = 
channel ganz zu Anfang stellt und alle nachfolgenden Registerbits 
verodert, würde das klappen, das wär' aber eine ungewöhnliche 
Vorgehensweise.

von JoeS (Gast)


Lesenswert?

MWS schrieb:
> JoeS schrieb:
>> Ich meine das im Bezug auf die Initialisierung aus der ursprünglichen
>> Routine.
>
> Egal wo Du's meinst, ist's falsch.
>
>> ADMUX &= ~(1 << REFS0);  // clear REFS0-Bit
>> und dann
>> ADMUX |= channel;  // wenn channel <= 3
>> oder in einem step:
>> ADMUX = channel;
>
> Denn in "in einem step" würde damit REFS0 gelöscht. Nur wenn man ADMUX =
> channel ganz zu Anfang stellt und alle nachfolgenden Registerbits
> verodert, würde das klappen, das wär' aber eine ungewöhnliche
> Vorgehensweise.

Einzelne Anweisungen aus dem Kontext gerissen machen nie viel Sinn.
Deshalb nochmal im Ganzen:

Der TO wählte beim T13 die interne Referenz, hatte beim Arduino aber
Vcc als Referenz, wo es dann wohl funktionierte. Deshalb war mein
Vorschlag die Refernz beim T13 auch auf Vcc zu setzen: clear REFS0 bit

Um in der Routine nun den richtigen channel zu setzen müssen
die MUX0:1 0 sein um den Wert channel richtig zu odern.
Und wenn man nur die beiden MUX-Bits setzen will, dann geht
ADMUX = channel; sehr wohl in diesem Zusammenhang.

von Michael D. (toxy1337)


Lesenswert?

Peter D. schrieb:
> Michael D. schrieb:
>> Der ATTiny13 hat kein USART soweit ich weiß.
>
> Geht auch ohne HW-UART.
> Schau einfach mal den Link an.

Ganz geschafft hab ichs nicht. Was genau muss an der Schaltung dafür 
ändern?

Grüße

von Michael D. (toxy1337)


Lesenswert?

JoeS schrieb:
> Der TO wählte beim T13 die interne Referenz, hatte beim Arduino aber
> Vcc als Referenz, wo es dann wohl funktionierte. Deshalb war mein
> Vorschlag die Refernz beim T13 auch auf Vcc zu setzen: clear REFS0 bit
>
> Um in der Routine nun den richtigen channel zu setzen müssen
> die MUX0:1 0 sein um den Wert channel richtig zu odern.
> Und wenn man nur die beiden MUX-Bits setzen will, dann geht
> ADMUX = channel; sehr wohl in diesem Zusammenhang.

Hab ich schon versucht, leider tut sich dann garnichtsmehr. Als Referenz 
Vcc wäre auch schon mein Plan gewesen, aber ohne Debugging/UART ist es 
einfach so schwer was aus den dingern rauszubekommen. )=

von JoeS (Gast)


Lesenswert?

Wieviel mV hast Du denn am Sensor?
Mal bitte mit dem Multimeter messen.

von Michael D. (toxy1337)


Lesenswert?

JoeS schrieb:
> Wieviel mV hast Du denn am Sensor?
> Mal bitte mit dem Multimeter messen.

Bei Vcc=5V:
Trocken 3,2V
Nass 1,6V...

Es bahnt sich hier das Problem an... wie könnte ich das lösen? Er 
vergleicht doch jetzt 5V zu 1,1V intern. oder wenn ich ADMUX = 
~(1<<REFS0) setze 5V mit 5V, bekomm aber dafür mit poti und Sensor 
nichts vernünftiges raus.

von JoeS (Gast)


Lesenswert?

Da liegst Du aber deutlich über 1.1V.
Also Versuchs mal mit Vcc als Referenz.

1
#define F_CPU 1200000UL // 1.2 MHz
2
#include <avr/io.h>
3
4
void adc_init()
5
{
6
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
7
  // Prescaler 16: F_ADC = F_CPU / 16 = 9.6MHz / 128 = 75kHz
8
}
9
10
uint16_t adc_read(uint8_t channel)
11
{
12
  uint16_t result;
13
  if(channel > 3) 
14
    return 0;
15
16
  ADMUX = channel; // no ADLAR, use Vcc as Referenz, set MUX1:0
17
  ADCSRA |= (1<<ADSC);// start single conversion
18
  while (ADCSRA & (1<<ADSC))
19
   ;
20
  result = ADC; // oder ADCW schau noch mal im Datenblatt nach
21
22
  return result;
23
}
24
25
int main(void){
26
  DDRB |= (1 << PB3);
27
  adc_init();
28
  while (1){
29
    uint16_t val = adc_read(2);
30
    if(val > 512){
31
      PORTB |= (1 << PB3);    //If ADC value is above 512 turn led on
32
    } else {
33
      PORTB &= ~(1 << PB3);
34
    }
35
  }
36
}

von JoeS (Gast)


Lesenswert?

Michael D. schrieb:
> Es bahnt sich hier das Problem an... wie könnte ich das lösen? Er
> vergleicht doch jetzt 5V zu 1,1V intern. oder wenn ich ADMUX =
> ~(1<<REFS0) setze 5V mit 5V, bekomm aber dafür mit poti und Sensor
> nichts vernünftiges raus.

ADMUX = ~(1 << REFS0);

ist falsch. Da setzt Du alle Bits auf 1 bis auf das REFS0 Bit.

von MWS (Gast)


Lesenswert?

JoeS schrieb:
> dann geht
> ADMUX = channel; sehr wohl in diesem Zusammenhang.

Yep, das geht ist aber dennoch unsinnig.

von Michael D. (toxy1337)


Lesenswert?

JoeS schrieb:
> Michael D. schrieb:
>> Es bahnt sich hier das Problem an... wie könnte ich das lösen? Er
>> vergleicht doch jetzt 5V zu 1,1V intern. oder wenn ich ADMUX =
>> ~(1<<REFS0) setze 5V mit 5V, bekomm aber dafür mit poti und Sensor
>> nichts vernünftiges raus.
>
> ADMUX = ~(1 << REFS0);
>
> ist falsch. Da setzt Du alle Bits auf 1 bis auf das REFS0 Bit.

Wahnsinn, bin ich ein Depp ._.
Hatte mir ja fast gedacht, dass es sowas ist, deswegen bin ich das 
Programm eh mehrmals step-by-step durchgegangen, aber da wär ich noch 
Wochen gesessen. Funkt einwandfrei jetzt. Großes Dankeschön :)

von JoeS (Gast)


Lesenswert?

MWS schrieb:
> JoeS schrieb:
>> dann geht
>> ADMUX = channel; sehr wohl in diesem Zusammenhang.
>
> Yep, das geht ist aber dennoch unsinnig.

Ist es nicht, unter Berücksichtigung des impliziten
Wunsches Adlar und REFS0 auf 0 zu setzen und die MUX-Bits
entsprechend auf 00 01 10 oder 11 zu setzen.

Vermutlich bestehst Du darauf es so zu formulieren, daß
wirklich nur die gewünschten MUXe gesetzt werden, was ja in einem
anderen Kontext auch Sinn macht, aber hier geht es, wie Du ja selber 
sagst,
auch so.

von MWS (Gast)


Lesenswert?

JoeS schrieb:
> MWS schrieb:
>> Yep, das geht ist aber dennoch unsinnig.
>
> Ist es nicht, unter Berücksichtigung des impliziten

Wenn man die Schwierigkeiten des TE bei der Codeerstellung sieht, dann 
ist so eine "Abkürzung" definitiv unsinnig.

von Joe S. (joesch)


Lesenswert?

Wikipedia:
Unsinn, auch Widersinn, ist ein von Sinn und Logik gelöster oder grob 
falscher Sachverhalt – bisweilen (absichtlich) scherzhaft. Die 
Eigenschaft eines solchen wird als Unsinnigkeit bezeichnet. Unsinnig 
kann auch bedeuten: ohne erkennbaren Sinn.

MWS schrieb:
> Wenn man die Schwierigkeiten des TE bei der Codeerstellung sieht, dann
> ist so eine "Abkürzung" definitiv unsinnig.

Allerhöchstens undurchsichtig.

von MWS (Gast)


Lesenswert?

Joe S. schrieb:
> Wikipedia:
> Unsinn, auch Widersinn, ist ein von Sinn und Logik gelöster oder grob

Versuch' mal Brain V1.0 anstatt Wiki zu zitieren.

> Allerhöchstens undurchsichtig.

Unsinnig in Bezug auf den Nutzen für den TO, wobei "Unsinn" doch 
freundlich ausgedrückt war. In Anbetracht seines auch für Dich 
erkennbaren Kenntnisstandes wäre "böswillig" auch etwas, das mir da 
einfällt. Nachher lernt der noch so 'nen Schmarrn.

von Joe S. (joesch)


Lesenswert?

MWS schrieb:
> Unsinnig in Bezug auf den Nutzen für den TO, wobei "Unsinn" doch
> freundlich ausgedrückt war. In Anbetracht seines auch für Dich
> erkennbaren Kenntnisstandes wäre "böswillig" auch etwas, das mir da
> einfällt. Nachher lernt der noch so 'nen Schmarrn.

Also,
n bischen mal selber nachvollziehen kann man vom TO schon erwarten.
Schlußendlich hat er es ja dann auch gemerkt.

von Michael D. (toxy1337)


Lesenswert?

MWS schrieb:
> Unsinnig in Bezug auf den Nutzen für den TO, wobei "Unsinn" doch
> freundlich ausgedrückt war. In Anbetracht seines auch für Dich
> erkennbaren Kenntnisstandes wäre "böswillig" auch etwas, das mir da
> einfällt. Nachher lernt der noch so 'nen Schmarrn.

Ah, darauf hab ich ja fast gewartet.
So als abschließendes Statement hätte ich noch gern eine perfekte 
Schreibweise von MWS um das ganze Thema abschließen zu können und noch 
was zu lernen:

von Joe S. (joesch)


Lesenswert?

Michael D. schrieb:
> MWS schrieb:
>> Unsinnig in Bezug auf den Nutzen für den TO, wobei "Unsinn" doch
>> freundlich ausgedrückt war. In Anbetracht seines auch für Dich
>> erkennbaren Kenntnisstandes wäre "böswillig" auch etwas, das mir da
>> einfällt. Nachher lernt der noch so 'nen Schmarrn.
>
> Ah, darauf hab ich ja fast gewartet.
> So als abschließendes Statement hätte ich noch gern eine perfekte
> Schreibweise von MWS um das ganze Thema abschließen zu können und noch
> was zu lernen:

Mach Dir nichts draus, manche Leute können einfach nicht anders.
Ich finde es gut, daß Du Dein Problem in den Griff gekriegt hast.

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.