Forum: Mikrocontroller und Digitale Elektronik Problem mit ADC und ATTINY13


von Roland (Gast)


Lesenswert?

Hey Allerseits,
hat eventuell einer von euch eine Idee, warum ich immer 0 vom ADC 
zurückbekomme? (OSZI und Multimeter zeigen 0.08V direkt am pin PB4 => 
ADC-Wert sollte also 80 sein...)
1
/*
2
 * InPlugV1_ATTINY13.c
3
 *
4
 * Created: 21.10.2012 13:08:11
5
 *  Author: Roland Blank
6
 */ 
7
8
9
10
// Definitionen
11
#define F_CPU 9600000                    // Frequenze des Controllers
12
13
14
#define LWEISON PORTB |= (1<<PINB1)
15
#define LWEISOFF PORTB &= ~(1<<PINB1)
16
#define LROTON PORTB |= (1<<PINB2)
17
#define LROTOFF PORTB &= ~(1<<PINB2)
18
#define TransON PORTB |= (1<<PINB0)
19
#define TransOFF PORTB &= ~(1<<PINB0)
20
21
// Includes
22
#include <avr/io.h>
23
#include <util/delay.h>
24
#include <avr/interrupt.h>
25
#include <stdlib.h>
26
#include <stdint.h>
27
#include <avr/eeprom.h>
28
29
uint16_t readADC(uint8_t channel);
30
31
int main(void)
32
{
33
  //Init
34
  DDRB |= (1<<PINB1) | (1<<PINB2) | (1<<PINB0);      // PB0 = TransOUT, PB1 = LED-Weis, PB2 = LED-Rot
35
  DDRB &= ~(1<<PINB4);                  // PB4 als Eingang
36
  PORTB |= (1<<PINB4);
37
  //Var
38
  uint16_t t = 0;
39
  
40
  //Endlosschleife
41
  while(1)
42
    {
43
    LWEISON;
44
    TransON;
45
    _delay_ms(3);
46
    t = readADC(2);
47
    _delay_ms(1);
48
    if ((t>0))
49
    {
50
      LROTON;
51
    }else{
52
      LROTOFF;
53
    }
54
    LWEISOFF;
55
    TransOFF;
56
    _delay_ms(5);
57
    }
58
}
59
60
uint16_t readADC(uint8_t channel) {
61
  uint8_t i;
62
  uint16_t result = 0;
63
  
64
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
65
  ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
66
67
  // Kanal des Multiplexers waehlen
68
  // Interne Referenzspannung verwenden (also 2,56 V)
69
  ADMUX |= channel | (1<<REFS0);
70
  
71
  // Den ADC initialisieren und einen sog. Dummyreadout machen
72
  ADCSRA |= (1<<ADSC);
73
  while(ADCSRA & (1<<ADSC));
74
  
75
  // Jetzt 3x die analoge Spannung and Kanal channel auslesen
76
  // und dann Durchschnittswert ausrechnen.
77
  for(i=0; i<3; i++) {
78
    // Eine Wandlung
79
    ADCSRA |= (1<<ADSC);
80
    // Auf Ergebnis warten...
81
    while(ADCSRA & (1<<ADSC));
82
    
83
    result += ADCW;
84
  }
85
  
86
  // ADC wieder deaktivieren
87
  ADCSRA &= ~(1<<ADEN);
88
  
89
  result /= 3;
90
  
91
  return result;
92
}

Könnte es ein Problem sein, dass ich Debugwire aktive habe und den 
Controller mittels ICE3 + SPI/Debugwire programmiere/debugge?

Vielen Dank für eueren reichhaltigen Erfahrungsschatz :D

Gruß
Roland

von Spess53 (Gast)


Lesenswert?

Hi

Hat es einen bestimmten Grund, das du bei jedem readADC den ADC neu 
initialisierst?

MfG Spess

von Roland (Gast)


Lesenswert?

Nein eigentlich nicht... Es sollte aber auch kein Problem darstellen???

von Eumel (Gast)


Lesenswert?

Hmmm, im Datenblatt steht was von: "Das erste Resultat nach der 
Initialisierung ist Müll"
Lass es einfach, es ist unnötig ;)

von katastrophenheinz (Gast)


Lesenswert?

hi,

die interne Referenz ist 1.1V

von katastrophenheinz (Gast)


Lesenswert?

Hi,

mit

PORTB |= (1<<PINB4)

aktivierst du den internen PullUp für den Eingang.
Ich glaube

PORTB &= ~(1<<PINB4)

wäre besser

von Roland (Gast)


Lesenswert?

@Eumel: Die erste Convertierung wird jeweils nicht ausgewertet, dass 
Problem kann also nicht hier liegen...

@katastrophenheinz: Ja, die interne Referenz soll 1,1V sein...

von Roland (Gast)


Lesenswert?

Leider löst

PORTB &= ~(1<<PINB4);

das Problem auch nicht :(

von katastrophenheinz (Gast)


Lesenswert?

Hi,

Das hilft die jetzt auch nur bedingt weiter:
Bei mir läuft dein Code. Hab ich zwar nicht auf nem ATtiny ausprobiert,
sondern mit nem ATmega. Kommt genau das raus, was rauskommen soll. Der 
erste Wert weicht gering von den beiden folgenden ab, das liegt m.E. 
daran, dass die Wartezeit nach ADEN=1 zu kurz ist.

Zurück zu deinem Problem: Gibts beim ATtiny vllt. noch irgendein 
Register, mit dem man den ADC global anfeuern muss ?

von katastrophenheinz (Gast)


Lesenswert?

Hi,


ich würde nochmal folgendes ausprobieren:

1) in readADC zuerst ADMUX schreiben, dann ADCSRA ( so stehts im manual 
)

2) während der Initialisierung den digitalen Modus von PB4 komplett zu 
deaktivieren: DIDR0 = ( 1 << ADC2D )

3) Prescaler höher setzen, z.b auf Maximum.

4) nach dem Setzen von ADEN noch mal eine ms warten.

von katastrophenheinz (Gast)


Lesenswert?

Hi,

vergiss Punkt 1), Manual sagt nur, daß ADMUX nach Beginn der Wandlung 
nicht mehr geändert werden kann. Das machst du ja nicht.

von Roland (Gast)


Lesenswert?

Die Benutzung von Debugwire kann kein Problem sein?

von Katastrophenheinz (Gast)


Lesenswert?

Hi, debugwire: ich denke nicht, da nur die pins miso Mosi sck und Reset 
über den 6-poligen Stecker verbunden werden. Pb4 vom attiny13 ist keiner 
davon. Nutzt du debugwire, um durch den Code zu Steppen? Ich habe keine 
ahnung, wie sich der Adc verhält, wenn man da mit debugwire durchsteppt.
In welcher Umgebung rennt dein attiny? Irgendein protoboard? Pb4 evtl 
davon belegt?
hast du die möglichkeit, mit nem anderen atmel Controller, der einen 
Uart hat, zu testen?
Hat den Vorteil, dass man nicht nur auf blinkende LEDs starren, sondern 
auch mal Text/Werte ausgeben und interaktiv testen kann. Wenn das dann 
funzt, dann auf den attiny bringen. Das adc Zeug kann man fast ohne 
Anpassung von Typ zu Typ übertragen.

von Stone (Gast)


Lesenswert?

Einen richtigen Fehler hab ich auf die schnelle nicht gefunden, aber 
gefährliche Sachen die sich irgendwann rächen werden.
1
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
2
  ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
3
4
  // Kanal des Multiplexers waehlen
5
  // Interne Referenzspannung verwenden (also 2,56 V)
6
  ADMUX |= channel | (1<<REFS0);



Besser
1
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
2
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
3
4
  // Kanal des Multiplexers waehlen
5
  // Interne Referenzspannung verwenden (also 2,56 V)
6
  ADMUX = channel | (1<<REFS0);

Warum?
Wenn dein Programm z.B. Erst Channel 1 und dann Channel 2 auslesen soll 
ließt zu bei der zweiten Wandlung Channel 3 statt 2 aus. Du setz das 
ADMUX Register nie zurück, durch "=" statt "|=" wird das Register genau 
auf den Wert gesetzt und nicht mit einem möglicherweise falschen Inhalt 
verodert.
Positiver Effekt, durch das weggelassene verodern schneller+weniger 
Programmspeicher


1
  // Jetzt 3x die analoge Spannung and Kanal channel auslesen
2
  // und dann Durchschnittswert ausrechnen.
3
  for(i=0; i<3; i++) {
4
    // Eine Wandlung
5
    ADCSRA |= (1<<ADSC);
6
    // Auf Ergebnis warten...
7
    while(ADCSRA & (1<<ADSC));
8
    
9
    result += ADCW;
10
  }
11
  
12
  
13
  result /= 3;

Such dir lieber ne 2^n zahl aus 2,4,8,16,... Teilen im µC ist immer 
langwierig und Programmspeicher intensiv bei einer 2^n Zahl ist es eine 
einfache Shift-Operation, die geht fix und kostet kaum Speicher.


Wie sich Debugwire auf den adc auswirkt kann ich dir nicht sagen, aber 
setzt doch einfach nen Breakpoint nach der ADC-Funktion und schau dir 
das Ergebnis an dann sollte es keine Probleme geben.

Gruß Matthias

von Roland (Gast)


Lesenswert?

@Katastrophenheinz: Es ist ein selbsterstelltes Board, welches sehr 
klein ist. Mehr als ein OSZI und zwei LEDS steht mir leider nicht zur 
Verfügung.

@Matthias: Danke für die Tips, ich habe sie gleich in meinen Code 
einfließen lassen. Leider lösen sie auch nicht das Problem.

Ich werde heute mal einen anderen Attiny13A verlöten, vielleicht hat nur 
er defekt.

Kann es Schaltungstechnik noch einen Fehler geben, selbst wenn ich 
direkt an PB4 mein Signal per OSZI messen kann?

von Roland (Gast)


Lesenswert?

OK, hab das Problem gefunden. Der Controller scheint defekt zu sein. 
Nachdem ich einen Neuen eingebaut habe, hat es sofort funktioniert :D

Vielen Dank noch einmal für eure Hilfe!!!

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.