Forum: Projekte & Code ADC-Pin auch als Digital-Pin benutzen


von Mehmet K. (mkmk)


Angehängte Dateien:

Lesenswert?

Servus allerseits

Jetzt, nachdem ich die Lösung gefunden habe, kann ich über mich auch nur 
den Kopf schütteln.
Aber bis es soweit war, gingen 2 Tage verloren.
Hofffe, dass ich jemandem das ersparen kann.
Anfaenglich war
R2  82k
R5  27k
R14 2,2k
Die ADC hat auch wunderbar geklappt. Bis weitere IC's eingebaut wurden, 
die ebenfalls D0 benutzten.
Solange die Spannung nur vermindert wurde, also 4,2V -> 2,7V, stimmten 
die Werte. Sobald es aber wieder nach oben ging (2,7 -> 4,2), zeigten 
die Werte ab ca. 3V den max. Wert von 0x3FF an.

Die Lösung:
1. Widerstaende verkleinern.
2. Vor der Messung D0 auf Ausgang schalten und kurz auf GND ziehen.

PS: Der Sinn der Schaltung ist es die Betriebspannung zu erfassen.
1
//============================================================================
2
// ADC_read      Achtung: Bei angeschlossener UBS funktioniert die ADC nicht,
3
//                        weil FT245 an den Data-Ausgaengen 4,7V ausgiebt
4
//----------------------------------------------------------------------------
5
// Tiefpass-Filter:
6
// adc_akt   : akt. ADC-Messwert
7
// adc_value : akt. Mittelwert
8
// adc_tmp   : Mittelwert des letzten Zyklus
9
// k         : Integer Wert mit k > 1
10
//
11
// adc_value = (k-1)/k * adc_tmp + 1/k * adc_akt
12
//============================================================================
13
void ADC_read(void)
14
{
15
  DWORD tmp;
16
  WORD adc_akt;
17
  WORD adc_tmp;
18
19
  if ( USB_IS_CONNECTED )
20
  { adc_tmp   = 0x3FF;
21
    adc_value = 0x3FF;
22
    return;
23
  }
24
    
25
  ADCSRA &= 0xF8;
26
  if (BIT_IS_CLEAR(CLKPR, CLKPS0))  // --> 16,667 MHZ
27
    ADCSRA |= (1<<ADEN) | ( 1 << ADPS2) | ( 1 << ADPS1) | ( 1 << ADPS0); // division factor 128 -> 130 kHz
28
  else
29
    ADCSRA |= (1<<ADEN) | ( 1 << ADPS2) | ( 1 << ADPS1) | ( 0 << ADPS0); // division factor  64 -> 130 kHz
30
31
  
32
  // Um die Kapazitaet der angeschlossenen IC's zu entladen:
33
  BIT_SET(  ADC_DDR,  ADC_PIN_INPUT);    // Pin PA0 wird output
34
  BIT_CLEAR(ADC_PORT, ADC_PIN_INPUT);    // Pin PA0 auf LO ziehen
35
  my_delay_us(10);                       // wichtig!!
36
  BIT_CLEAR(ADC_DDR,  ADC_PIN_INPUT);    // Pin PA0 wird wieder input
37
38
  BIT_SET(ADC_DDR, ADC_PIN_OUTPUT);     // Pin PA1 wird output
39
  BIT_SET(ADC_PORT,ADC_PIN_OUTPUT);     // Pin PA1: Vcc (damit Widerstaende Spannung erhaelt)
40
  DIDR0  |= ( 1 << ADC0D);              // disable digital input
41
     
42
  my_delay_ms(1);
43
  
44
  ADCSRA |= ( 1 << ADSC );  // enable ADC and start conversation
45
46
  // warten bis conversation beendet
47
  while(  BIT_IS_SET(ADCSRA, ADSC));
48
  adc_akt  = ADCL;
49
  adc_akt |= ADCH << 8;
50
   
51
  BIT_CLEAR (ADC_PORT,ADC_PIN_OUTPUT);  // Pin A1: LO
52
  BIT_CLEAR (ADC_DDR, ADC_PIN_OUTPUT);  // Pin A1 wird wieder input
53
  BIT_CLEAR (ADCSRA, ADEN );            // disable ADC
54
  DIDR0  &= ~( 1 << ADC0D);             // enable digital input
55
56
  if (adc_value == 0L)
57
  { adc_value = adc_akt;
58
    adc_tmp   = adc_akt;
59
  }
60
  else
61
  {
62
//    tmp =  (DWORD)adc_tmp * 75L + (DWORD)adc_akt * 25;    // k =4
63
//    adc_value = tmp / 100L;
64
    tmp =  (DWORD)adc_tmp * 875L + (DWORD)adc_akt * 125;  // k =8
65
    adc_value = tmp / 1000L;
66
    adc_tmp = adc_value;
67
  }
68
  
69
  if (adc_value <= VOLT_3p0)
70
    cam_status.low_battery = true;
71
  
72
  if (cam_status.low_battery)
73
  { if (adc_value > VOLT_3p2)
74
      cam_status.low_battery = false;
75
  }
76
}

von Karl H. (kbuchegg)


Lesenswert?

Mehmet Kendi schrieb:

> Die Lösung:
> 1. Widerstaende verkleinern.
> 2. Vor der Messung D0 auf Ausgang schalten und kurz auf GND ziehen.
>
> PS: Der Sinn der Schaltung ist es die Betriebspannung zu erfassen.

Oder die Systematik ändern, falls der AVR-µC dies unterstützt.
* Als Eingang wird die Bandgapspannung benutzt.
  Bei einem Mega16 ist dies zb die MUX Kombination 11110
* Als Referenzspannung wird die Versorgungsspannung benutzt
  Bei einem Mega16 ist dies zb REFS Kombination 01

Da die Bandgapspannung konstant bei etwa 1.22V bleibt, während die 
Referenzspannung sich verändert, ändert sich auch der Zahlenwert vom 
ADC, wenn sich die Versorgungsspannung ändert. Steigende Werte bedeuten 
eine sinkende Spannung.

Vorteil: Keinerlei Aussenbeschaltung notwendig. Der ADC-Pin kann für 
andere Aufgaben benutzt werden. Die von Atmel vorgegebene Einschränkung, 
dass keine Schaltvorgänge am Port gemacht werden sollen, solange eine 
Messung im Gange ist, sollte auch in diesem Fall eingehalten werden.

von Mehmet K. (mkmk)


Lesenswert?

Servus Karl Heinz

Ich war auswaerts taetig, weshalb ich erst jetzt dazu komme zu 
antworten.

Dein Vorschlag ist schlichtweg genial. Waerend dem Entwurf der Schaltung 
hatte ich mich wochenlang darüber geaergert, dass die Atmels keine 
interne Betriebsspannungs-Anzeige hatten.
Und waere Deine Antwort nicht so ausführlich gewesen und haettest Du nur 
gesagt "schau dir das MUX-Register an, dort gibt es eine solche Lösung" 
... also um ehrlich zu sein, ich waere nicht darauf gekommen. Einfach 
genial.

Nur einen kleinen Schönheitsfehler hat diese Art der Messung. Waerend 
ich mit meiner Lösung den Bereich zwischen 2,6V und 4,2V mit 410 
Schritten auflöse, komme ich mit Deiner Lösung nur auf 160 Schritte. 
Aber für meine Zwecke reicht das allemal.
Dafür hat aber Deine Lösung den Vorteil, dass die Werte auch ohne 
Tiefpassfilter sehr stabil daherkommen.

Nochmals vielen herzlichen Dank.

von Karl H. (kbuchegg)


Lesenswert?

Mehmet Kendi schrieb:

> Dein Vorschlag ist schlichtweg genial.

Ehre wem Ehre gebührt. Die Idee dazu kursiert seit langem hier im Forum. 
Ich glaube ich habe sie das erste mal von Hannes Lux aufgeschnappt.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

ATMEL selbst hat AppNotes veröffentlicht, wo diese Möglichkeit erklärt 
wird.

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.