ATtiny85 ADC mit interne REV

#7205320
Lesenswert?

Hallöchen,

auf der Seite: https://elektro.turanis.de/html/prj306/index.html
ist ganz gut beschrieben wie man eine Spannung direkt am Eingang eines 
ATtinys mit Hilfe der internen Referenzspannung misst.

Meine Frage ist nun, wie muss ich die Funktion umschreiben, damit man 
eine Spannung mit der Internen Referenzspannung an einem anderen Pin zb. 
PIN2 messen kann?
1
void setup()
2
{
3
    Serial.begin(9600);
4
}
5

6
void loop()
7
{
8
    Serial.println(String(getVcc()/1000.0) + "V");
9
    delay(1000);
10
}
11

12
int getVcc()
13
{
14
    // reads internal 1V1 reference against VCC
15
    #if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny44__)
16
        // for ATtiny84
17
        ADMUX = _BV(MUX5) | _BV(MUX0);
18
    #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
19
        // for ATtiny85/45
20
        ADMUX = _BV(MUX3) | _BV(MUX2);
21
    #elif defined(__AVR_ATmega1284P__)
22
        // for ATmega1284
23
        ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
24
    #else
25
        // for ATmega328
26
        ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
27
    #endif
28

29
    delay(5); // wait for Vref to settle
30

31
    ADCSRA |= _BV(ADSC); // reading ADC
32
    while (bit_is_set(ADCSRA, ADSC));
33

34
    uint8_t low = ADCL;
35
    unsigned int adcVal = (ADCH << 8) | low;
36

37
    // discard previous result
38
    ADCSRA |= _BV(ADSC); // Convert
39
    while (bit_is_set(ADCSRA, ADSC));
40
    low = ADCL;
41
    adcVal = (ADCH << 8) | low;
42

43
    return ((long)1024 * 1100) / adcVal;
44
}


mit freundlichen Grüßen
Dustin
#7205341
Lesenswert?

Hallo,

Ich habe mal die relevanten Stellen aus dem Datenlatt heraus kopiert, da 
ich sie sowieso lesen mußte. Im Link wird ja gar nicht erklärt, welcher 
Eingang warum und wie genutzt wird. Eine sensationell erschöpfend 
ausführliche  Anleitung.

https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf

"The analog input channel and differential gain are selected by writing 
to the MUX[3:0] bits in ADMUX. Any of the
four ADC input pins ADC[3:0] can be selected as single ended inputs to 
the ADC.

17.13.1 ADMUX – ADC Multiplexer Selection Register

• Bits 3:0 – MUX[3:0]: Analog Channel and Gain Selection Bits
The value of these bits selects which combination of analog inputs are 
connected to the ADC. In case of differential
input (ADC0 - ADC1 or ADC2 - ADC3), gain selection is also made with th 
ese bits. Selecting ADC2 or ADC0 as
both inputs to the differential gain stage enables offset measurements. 
Selecting the single-ended channel ADC4 enables the temperature sensor. 
Refer to Table 17-4 for details. If these bits are changed during a 
conversion, the change will not go into effect until this conversion is 
complete (ADIF in ADCSRA is set)."

Um auf Deinen PIN2 = PB3 zu schalten, gilt:
MUX[3:0]   0011 ADC3 (PB3), also MuUX1=1 und MUX0 = 0.


Deshalb hier:
    #elif defined(_AVR_ATtiny85_) || defined(_AVR_ATtiny45_)

        // for ATtiny85/45

        ADMUX = _BV(MUX3) | _BV(MUX2);
ändern zu:

    #elif defined(_AVR_ATtiny85_) || defined(_AVR_ATtiny45_)

        // for ATtiny85/45

        ADMUX = _BV(MUX1) | _BV(MUX0);

In ADMUX sollen die beiden untersten Bits gesetzt sein. Bit 2 = 0 und 
Bit 3 = 0. Korrektur erwünscht, falls ich mich da vertan haben sollte.

mfg
#7206012
Lesenswert?

Vielen Dank für die Antwort.

zum probieren habe ich das so geändert:
1
#include "SoftwareSerial.h"
2

3
#define Rx  1 //
4
#define Tx  2 //
5

6
SoftwareSerial mySerial(Rx, Tx);
7

8
void setup() {
9
  pinMode(Rx, INPUT);
10
  pinMode(Tx, OUTPUT);
11
  mySerial.begin(9600);
12

13
}
14

15
void loop() {
16
  int vcc = readVccPIN() ;
17
  mySerial.println (vcc);
18
  delay(1000);
19

20
}
21

22
int readVccPIN()
23
{
24

25
     ADMUX = _BV(MUX1) | _BV(MUX0); // Auslesen an PIN2    
26
 
27
    delay(5); // wait for Vref to settle
28
    ADCSRA |= _BV(ADSC); // reading ADC
29
    while (bit_is_set(ADCSRA, ADSC));
30
    uint8_t low = ADCL;
31
    unsigned int adcVal = (ADCH << 8) | low;
32
    // discard previous result
33
    ADCSRA |= _BV(ADSC); // Convert
34
    while (bit_is_set(ADCSRA, ADSC));
35
    low = ADCL;
36
    adcVal = (ADCH << 8) | low;
37
    return ((long)1024 * 1100) / adcVal;
38
}

Also der PIN2 reagiert schon mal aber
wenn ich nun an PIN2 eine Spannung anlege dann kommen da nur komische 
Werte raus.
PIN2 gegen GND = -1
PIN2 gegen 0,95V = 5313

Die zu messende Spannung war immer unter 1,1V
Der Tiny85 wird mit 5V versorgt

gibt es noch eine andere Lösung oder habe ich etwas falsch gemacht ?

mfg
Gast #7206055
Lesenswert?

> Was bedeutet ...

Das frage ich mich auch - hängt wohl mit dem merkwürdigen Bruch nach 
return zusammen: je größer der ADC-Wert, umso kleiner der Return-Wert.

Wo wird der ADC eigentlich eingeschaltet, ich sehe kein ADEN?
Und 'interne REF'? Wird in ADMUX nicht explizit gesetzt, folglich gilt 
'VCC used as Voltage Reference, disconnected from PB0 (AREF)'.
Gast #7206111
Lesenswert?

Ein Versuch:
1. Die Zeile 'ADMUX =...' ergänzen um '| _BV(REFS1)'
2. Unmittelbar danach den ADC einschalten mit 'ADCSRA = _BV(ADEN)'
3. return: Im Datenblatt nachlesen (empfiehlt sich allgemein) unter 'ADC 
Conversion Result', Unterpunkt 'Single Ended Conversion', dort steht die 
benötigte Gleichung, muss nur noch umgestellt werden.
4. nicht zu optimistisch sein (wieder laut Datenblatt): 'Internal 
Voltage Reference 1.0 .. 1.1 .. 1.2 V'.
#7206214
Lesenswert?

habe den Tipp von S. Landolt probiert. Leider ohne Erfolg. Trotzdem 
Danke!

Allgemein möchte ich Eine Spannung messen, die unabhängig von der 
Versorgungsspannung ist.

analogRead() funktioniert leider nicht da sich der Wert verfälscht wenn 
die Versorgungspannung schwankt. Deshalb dachte ich man kann mit der 
Internen Referenzspannung arbeiten z.b. 1,1V dann könnte ich halt 
Spannungen bis 1,1V an einem Pin messen, wenn das irgendwie 
funktioniert..

Sorry bin gerade erst mit dem Programmieren angefangen.
Beitrag #7206238 wurde von einem Moderator gelöscht.
#7206296
Lesenswert?

EAF schrieb:
> Ähmm...
> Denn schließlich gibt es ja auch noch: analogReference()
>  analogReference(INTERNAL1V1);

das funktioniert soweit ganz gut! Dankeschön :)

habe davor mit dem damellis/attiny statt TinyCore gearbeitet, da 
funktioniert analogReference() nicht.


Nur habe ich jetzt das Problem wenn ich TinyCore verwende funktioniert 
die Radiohead Libary nicht mehr aber gut dann ist das halt so .. falls 
noch jemand eine komplette Funktion mit Bits setzen, in der Arduino IDE 
und mit  damellis/attiny hat wäre das ein Traum :)
Gast #7206567
Lesenswert?

> bin gerade erst mit dem Programmieren angefangen

Dann als allgemeiner Ratschlag: mit der Rückmeldung
> ... probiert. Leider ohne Erfolg ...
alleine ist keine Zusammenarbeit möglich. Es muss zumindest gezeigt 
werden, was genau gemacht wurde, in diesem Fall das aktuelle Programm 
vorstellen, und worin der 'Misserfolg' besteht, d.h. welche (falschen) 
Werte nun erscheinen.
Gast #7206608
Lesenswert?

Dustin S. schrieb:
> funktioniert
> die Radiohead Libary nicht mehr
1. Von Radiohead war nie die Rede!
2. "funktioniert nicht" ist eine unzureichende Problem Beschreibung


Hier mal ein ADC Beispiel, welches mit dem Tiny85 funktionieren sollte.
Ungetestet.
1
#include <CombieAdc.h>
2
using Combie::Adc;
3

4
Adc adc;
5

6

7
#include "SoftwareSerial.h"
8
#define Rx  1 //
9
#define Tx  2 //
10
SoftwareSerial mySerial(Rx, Tx);
11

12
void setup() 
13
{
14
  pinMode(Rx, INPUT);
15
  pinMode(Tx, OUTPUT);
16

17
   mySerial.begin(9600);
18

19
   adc  .enable()
20
        .setClockDivisor() // automatisch
21
        .setReference(Adc::REF_11)
22
        .setSource(Adc::MUX_ADC0); 
23
}
24

25
void loop() 
26
{
27
  mySerial.println(adc);
28
  delay(1000);
29
}
Angehängte Dateien:

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