Atmel ATtiny 45 Spannung von externer Quelle messen

Gast #3880232
Lesenswert?

Hallo zusammen,
Ich habe momentan ein kleines Problem:
Ich bin vom TI Launchpad auf einen Atmel AVR ATtiny 45 umgestiegen.
Ich will mit dem ATtiny 45 die Spannung einer externen 
Spannungsversorgung auslesen. Ich habe mich im Vorferld darüber 
informiert, leider klappt es in der Praxis aber nicht.
Vom Schaltbild her ist es so, dass ich den Pin PB4 (Physical 3) vom 
ATtiny nutzen möchte. In der Theorie reicht es mir, wenn der ATtiny 
erkennt ob eine Spannung fließt oder nicht (1|0).
Ich habe bereits mehrere Codes angesehen und ausprobiert und angepasst.
Als Example:
1
void initADC()
2
{
3
  /* this function initialises the ADC 
4

5
        ADC Notes
6
  
7
  Prescaler
8
  
9
  ADC Prescaler needs to be set so that the ADC input frequency is between 50 - 200kHz.
10
  
11
  Example prescaler values for various frequencies
12
  
13
  Clock   Available prescaler values
14
   ---------------------------------------
15
   1 MHz   8 (125kHz), 16 (62.5kHz)
16
   4 MHz   32 (125kHz), 64 (62.5kHz)
17
   8 MHz   64 (125kHz), 128 (62.5kHz)
18
  16 MHz   128 (125kHz)
19

20
   below example set prescaler to 128 for mcu running at 8MHz
21

22

23
  */
24

25
  ADMUX =
26
            (1 << ADLAR) |     // left shift result
27
            (0 << REFS1) |     // Sets ref. voltage to VCC, bit 1
28
            (0 << REFS0) |     // Sets ref. voltage to VCC, bit 0
29
            (0 << MUX3)  |     // use ADC2 for input (PB4), MUX bit 3
30
            (0 << MUX2)  |     // use ADC2 for input (PB4), MUX bit 2
31
            (1 << MUX1)  |     // use ADC2 for input (PB4), MUX bit 1
32
            (0 << MUX0);       // use ADC2 for input (PB4), MUX bit 0
33

34
  ADCSRA = 
35
            (1 << ADEN)  |     // Enable ADC 
36
            (1 << ADPS2) |     // set prescaler to 64, bit 2 
37
            (1 << ADPS1) |     // set prescaler to 64, bit 1 
38
            (0 << ADPS0);      // set prescaler to 64, bit 0  
39
}
40

41

42
int main( void ) 
43
{
44
  
45
  initADC();
46

47
  while(1)
48
  {
49

50
    ADCSRA |= (1 << ADSC);         // start ADC measurement
51
    while (ADCSRA & (1 << ADSC) ); // wait till conversion complete 
52

53
    if (ADCH > 128)
54
    {
55
      // ADC input voltage is more than half of VCC
56

57
    } else {
58

59
      // ADC input voltage is less than half of VCC
60

61
    }
62

63
  }
64

65
  return 0;
66
}

Nur so nebenbei, der ATtiny läuft auch und er kann auch LEDs schalten, 
nur so als Funktionsbeweis.
Anbei befindet sich auch noch das Pinning des ATtiny.
Ich wäre sehr froh, wenn mir jemand helfen könnte.
Vielen Dank im Voraus,
MfG CortexA8
Angehängte Dateien:
Gast #3880249
Lesenswert?

Hallo spess53,
Danke für die Antwort, aber leider ja habe ich.
Ich habe die Anwendung auch bereits mit dem MSP430G2553 gemacht, dieser 
ist allerdings zu Groß und zu stromhungrig.
Hast du noch eine Idee ?
Danke schonmal
Gast #3880271
Lesenswert?

CortexA8 schrieb:
> Spannungsversorgung auslesen. Ich habe mich im Vorferld darüber
> informiert, leider klappt es in der Praxis aber nicht.

Was soll denn klappen, und woran erkennst du, daß es nicht klappt? Im 
geposteten Programm wird jedenfalls keine LED geschaltet.

> Vom Schaltbild her ist es so, dass ich den Pin PB4 (Physical 3) vom
> ATtiny nutzen möchte. In der Theorie reicht es mir, wenn der ATtiny
> erkennt ob eine Spannung fließt oder nicht (1|0).

Spannung fließt nicht. Wie sieht der Schaltplan aus?
Gast #3880351
Lesenswert?

Danke für die Anmerkung,
Ich habe den Code Modifiziert und ich schalte eine LED ein, wenn die 
Spannung kleiner gleich 128 ist.
Und ja die Spannungsquelle läuft und ich habe das ganze auch per Multi 
überprüft. Ich verwende auch eine Spannungsteiler bei 4,8 V in.
Anfürsich ist der ATtiny per 5,2 Volt versorgt und an PB4 und GND an die 
zumessende Spannungsversorgung angeschlossen.
MfG CortexA8
Gast #3880377
Lesenswert?

Hallo CortexA8,

mit Versorgungsspannung als Referenz wird das nichts. Denn mit der 
Spannung verändert sich dann auch die Referenz und dein Messwert bleibt 
gleich. In deinem Fall muß eine der internen Referenzspannungen 
eingestellt sein.

P.S. Ich habe dein Programm nicht einzeln geprüft, sondern mich am 
Kommentar "// Sets ref. voltage to VCC, bit 1" orientiert.

Gruß. Tom
Gast #3880408
Lesenswert?

Hallo CortexA8,

ich sehe eben, daß du nicht die Versorgungsspannung des Tiny45 messen 
willst, sondern irgendeine andere Versorgungsspannung. Dann ist das 
verwenden der Vcc des Tiny, als Referenz, kein Problem.

Sorry, hatte ich falsch verstanden. :(

Gruß. Tom
Gast #3880437
Lesenswert?

Besser wäre es auf jeden Fall, mit einer der internen Referenzen zu 
arbeiten. Es geht aber auch mit Vcc, wobei die Genauigkeit eben etwas 
geringer sein wird.

Das eigentliche Problem ist meiner Meinung nach aber das alleinige 
Auswerten der oberen beiden Bit des 10-Bit Messwertes "if (ADCH > 128)" 
- ADCH wird nie größer als 3 sein. Besser wäre hier den ganzen Messwert 
zu vergleichen. ADCH beinhaltet nur nur die Bit 8 und 9 von 10-Bit des 
Messwertes. Der ganze Meßwert liegt in ADCH/ADCL.

Gruß. Tom
Gast #3880457
Lesenswert?

Ist einfach nichts, wenn man sich kein gutes Bild machen kann. 
Originalprogramm (das mit dem Fehler) liegt nicht vor. Kein Schaltplan, 
Werte des Spannungsteilers unbekannt. Zu messende Spannungsquelle 
unbekannt. Wckelaufbau auf Steckbrett ohne Abblock Cs etc. Im 
geposteteten Programm erkenne ich zumindest in der Einstellung des ADC 
keinen Fehler - wenn man noch wüsste mit welchem Takt der Tiny läuft.
Gast #3880726
Lesenswert?

Hallo beisammen,
Danke für die vielen Rückmeldungen.
Der Takt des ATtiny liegt bei 16 MHz.
Ich habe leider keinen digitalen Schlatplan erstellt, dafür ist der 
Aufbau aber auch einfach (Papier).
Nochmals zum Verständnis:
Ich habe einen ATtiny 45 an einer Spannungsversorgung.
Ich will mit dem Pin PB4 die Spannung einer 2. Spannungsquelle messen.
Ich habe dafür einen Spannungsteiler mit je 10kO an R1 und R2. Zwischen 
R1 und R2 habe ich eine Verbindung zum Pin PB4 bzw. eine Leitung.
Die Masse/GND von der Spannungsversorgung 2 habe ich mit dem GND Pin vom 
ATtiny verbunden.
Meine Anforderung an das Programm wäre jetzt: Wenn eine Spannung an der 
2. Spannungsquelle anliegt soll die LED des ATtiny NICHT leuchten, 
sollte keine Spannung an der 2. Stromquelle anliegen soll die LED 
leuchten.
Der ganz oben gepostete Quellcode war nur ein Testversuch von mir, den 
ich dann auch wegen der Disfunktion verbannt habe, aber noch in meinem 
Pool von Codes liegen gelassen habe.
Ich bin auch offen für einen anderen Quellcode.
Ich hoffe ich habe alle Ungenauigkeiten beseitigt.
Vielen Dank für die zahlreichen Antworten und ich hoffe die Lösung für 
mich kommt auch ;)
MfG CortexA8
(Firma: keine) #3880736
Lesenswert?

CortexA8 schrieb:
> Der Takt des ATtiny liegt bei 16 MHz.

Und warum setzt du dann den Prescaler für 8 MHz und nicht für 16 MHz?

CortexA8 schrieb:
> Clock   Available prescaler values
>    ---------------------------------------
>    1 MHz   8 (125kHz), 16 (62.5kHz)
>    4 MHz   32 (125kHz), 64 (62.5kHz)
>    8 MHz   64 (125kHz), 128 (62.5kHz)
>   16 MHz   128 (125kHz)
> ...
> ADCSRA =
>             (1 << ADEN)  |     // Enable ADC
>             (1 << ADPS2) |     // set prescaler to 64, bit 2
>             (1 << ADPS1) |     // set prescaler to 64, bit 1
>             (0 << ADPS0);      // set prescaler to 64, bit 0
Gast #3880745
Lesenswert?

* Und schon wieder was vergessen:
Wieoft muss gemessen werden: So oft wie es nur geht ;) Ich baue das 
ganze nur als Demoapplikation auf um dann später mal eine etwas 
erweiterte Platiene zubauen.

Warum ich die interne AREF ausgeschlossen ahbe ist, laut einem 
Forumsbeitrag hat man dort das Porblem, das wenn der Wert unter 2 Volt 
sinkt, die Auswertung des ATtiny wohl verrückt spielt.
MfG CortexA8
Gast #3880749
Lesenswert?

Ich hoffe ich liege grade nicht falsch, aber diese Init geht nicht...
ADMUX =
            (1 << ADLAR) |     // left shift result
            (0 << REFS1) |     // Sets ref. voltage to VCC, bit 1
            (0 << REFS0) |     // Sets ref. voltage to VCC, bit 0
            (0 << MUX3)  |     // use ADC2 for input (PB4), MUX bit 3
            (0 << MUX2)  |     // use ADC2 for input (PB4), MUX bit 2
            (1 << MUX1)  |     // use ADC2 for input (PB4), MUX bit 1
            (0 << MUX0);       // use ADC2 for input (PB4), MUX bit 0

  ADCSRA =
            (1 << ADEN)  |     // Enable ADC
            (1 << ADPS2) |     // set prescaler to 64, bit 2
            (1 << ADPS1) |     // set prescaler to 64, bit 1
            (0 << ADPS0);      // set prescaler to 64, bit 0


Das ist doch eine logische verODERung...Richt wäre:
ADMUX =
            (1 << ADLAR) |     // left shift result
            (1 << MUX1)  |     // use ADC2 for input (PB4), MUX bit 1

  ADCSRA =
            (1 << ADEN)  |     // Enable ADC
            (1 << ADPS2) |     // set prescaler to 64, bit 2
            (1 << ADPS1) |     // set prescaler to 64, bit 1

Anmerkung: Ich bin NICHT sicher, ob es daran liegt...
Gast #3880754
Lesenswert?

Also,
Hier folgt mein modifizierter Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4

5
int     set_PORTB_bit(int position, int value);
6

7
void initADC()
8
{
9
  /* this function initialises the ADC 
10

11
        ADC Notes
12
  
13
  Prescaler
14
  
15
  ADC Prescaler needs to be set so that the ADC input frequency is between 50 - 200kHz.
16
  
17
  Example prescaler values for various frequencies
18
  
19
  Clock   Available prescaler values
20
   ---------------------------------------
21
   1 MHz   8 (125kHz), 16 (62.5kHz)
22
   4 MHz   32 (125kHz), 64 (62.5kHz)
23
   8 MHz   64 (125kHz), 128 (62.5kHz)
24
  16 MHz   128 (125kHz)
25

26
   below example set prescaler to 128 for mcu running at 8MHz
27

28

29
  */
30

31
  ADMUX =
32
            (1 << ADLAR) |     // left shift result
33
            (0 << REFS1) |     // Sets ref. voltage to VCC, bit 1
34
            (0 << REFS0) |     // Sets ref. voltage to VCC, bit 0
35
            (0 << MUX3)  |     // use ADC2 for input (PB4), MUX bit 3
36
            (0 << MUX2)  |     // use ADC2 for input (PB4), MUX bit 2
37
            (1 << MUX1)  |     // use ADC2 for input (PB4), MUX bit 1
38
            (0 << MUX0);       // use ADC2 for input (PB4), MUX bit 0
39

40
  ADCSRA = 
41
            (1 << ADEN)  |     // Enable ADC 
42
            (1 << ADPS2) |     // set prescaler to 64, bit 2 
43
            (1 << ADPS1) |     // set prescaler to 64, bit 1 
44
            (1 << ADPS0);      // set prescaler to 64, bit 0  
45
}
46

47

48
int main( void ) 
49
{
50
  DDRB = PB3;
51
  initADC();
52
  
53
  while(1)
54
  {
55

56
    ADCSRA |= (1 << ADSC);         // start ADC measurement
57
    while (ADCSRA & (1 << ADSC) ); // wait till conversion complete 
58

59
    if (ADCH > 128)
60
    {
61
      // ADC input voltage is more than half of VCC
62
    set_PORTB_bit(3,1);
63

64
    } else {
65

66
      // ADC input voltage is less than half of VCC
67
    set_PORTB_bit(3,0);
68
    }
69

70
  }
71

72
  return 0;
73
}
74

75

76
// Function code
77
int set_PORTB_bit(int position, int value)
78
{
79
  // Position = PINB
80
  // Value HiGH OR LOW bzw. 1 or 0
81
  
82
  
83
  if (value == 0)
84
  {
85
    PORTB &= ~(1 << position);      // Set bit position low
86
  }
87
  else
88
  {
89
    PORTB |= (1 << position);       // Set high, leave others alone
90
  }
91

92
  return 1;
93
}
#3880757
Lesenswert?

CortexA8 schrieb:
> Warum ich die interne AREF ausgeschlossen ahbe ist, laut einem
> Forumsbeitrag hat man dort das Porblem, das wenn der Wert unter 2 Volt
> sinkt, die Auswertung des ATtiny wohl verrückt spielt.

ich fürchte du verwechselst einiges

wenn der Wert unter 2 Volt.....

ist was völlig anders als

wenn die AVCC / VCC unter 2 Volt......

da der Tiny bis 1,8V arbeiten kann

aber ob der Tiny an einer Batterie hängt hast du ja immer noch 
verschwiegen


manno so macht das keinen Spass, mach dir mal eine Checkliste....
Gast #3880789
Lesenswert?

EDIT !!!!
Es läuft !! Danke für die Kommentare, schlussendlich hat das 
Auskommentieren der Werte von ADMUX geholfen, dann musste ich noch den 
Schwellenwert ADCH nach unten absenken. Unten steht der funktionierende 
Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4

5
int     set_PORTB_bit(int position, int value);
6

7
void initADC()
8
{
9
  /* this function initialises the ADC 
10

11
        ADC Notes
12
  
13
  Prescaler
14
  
15
  ADC Prescaler needs to be set so that the ADC input frequency is between 50 - 200kHz.
16
  
17
  Example prescaler values for various frequencies
18
  
19
  Clock   Available prescaler values
20
   ---------------------------------------
21
   1 MHz   8 (125kHz), 16 (62.5kHz)
22
   4 MHz   32 (125kHz), 64 (62.5kHz)
23
   8 MHz   64 (125kHz), 128 (62.5kHz)
24
  16 MHz   128 (125kHz)
25

26
   below example set prescaler to 128 for mcu running at 16MHz
27

28

29
  */
30

31
  ADMUX =
32
            (1 << ADLAR) |     // left shift result
33
            //(0 << REFS1) |     // Sets ref. voltage to VCC, bit 1
34
            //(0 << REFS0) |     // Sets ref. voltage to VCC, bit 0
35
            //(0 << MUX3)  |     // use ADC2 for input (PB4), MUX bit 3
36
            //(0 << MUX2)  |     // use ADC2 for input (PB4), MUX bit 2
37
            (1 << MUX1);       // use ADC2 for input (PB4), MUX bit 1
38
            //(0 << MUX0);       // use ADC2 for input (PB4), MUX bit 0
39

40
  ADCSRA = 
41
            (1 << ADEN)  |     // Enable ADC 
42
            (1 << ADPS2) |     // set prescaler to 64, bit 2 
43
            (1 << ADPS1) |     // set prescaler to 64, bit 1 
44
            (1 << ADPS0);      // set prescaler to 64, bit 0  
45
}
46

47

48
int main( void ) 
49
{
50
  DDRB = PB3;
51
  initADC();
52
  
53
  while(1)
54
  {
55

56
    ADCSRA |= (1 << ADSC);         // start ADC measurement
57
    while (ADCSRA & (1 << ADSC) ); // wait till conversion complete 
58

59
    if (ADCH > 50)
60
    {
61
      // ADC input voltage is more than half of VCC
62
    set_PORTB_bit(3,0);
63

64
    } else {
65

66
      // ADC input voltage is less than half of VCC
67
    set_PORTB_bit(3,1);
68
    }
69

70
  }
71

72
  return 0;
73
}
74

75

76
// Function code
77
int set_PORTB_bit(int position, int value)
78
{
79
  // Position = PINB
80
  // Value HiGH OR LOW bzw. 1 or 0
81
  
82
  
83
  if (value == 0)
84
  {
85
    PORTB &= ~(1 << position);      // Set bit position low
86
  }
87
  else
88
  {
89
    PORTB |= (1 << position);       // Set high, leave others alone
90
  }
91

92
  return 1;
93
}
Ich füge noch demnächst das digitale Schaltbild an, damit man das ganze 
auch noch später anchvollziehen kann.
Vielen, vielen Dank
MfG CortexA8

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