Forum: Mikrocontroller und Digitale Elektronik AVR128DA28 Temperatursensor


von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Servus,

ich bräuchte bitte mal eure Hilfe. Bekomme den Temperatursensor nicht 
zum laufen, vielleicht fällt ja jemanden von euch etwas auf..
Die Beschaltung sieht wie folgt aus:
1
AVR läuft mit 24Mhz, keine Interrupts aktiv
2
2x 1000uF zwischen + und GND
3
AVDD(14) = 3,3V
4
GND(15) = GND
5
PORTF1 RXD -- ESP8266
6
PORTF0 TXD -- ESP8266
7
PORTA1 RXD -- PC
8
PORTA0 TXD -- PC
9
PORTD0 LED (mit Vorwiderstand)
10
PORTD1 LED (mit Vorwiderstand)

Nutze ich statt des Temperatursensors einen ADC Eingang erhalte ich 
erwartete Werte des eingangs. Der Temperatursensor hingegen gibt immer 
2047 aus.

Der Code zur Initialisierung
1
void adc_init()
2
{
3
  VREF.ADC0REF = VREF_REFSEL_2V048_gc;
4
  
5
  ADC0.CTRLC = ADC_PRESC_DIV4_gc;
6
  ADC0.CTRLA = ADC_ENABLE_bm | ADC_RESSEL_12BIT_gc | ADC_FREERUN_bm;
7
  ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc;
8
  //ADC0.MUXPOS = ADC_MUXPOS_AIN0_gc; <-Testeingang mit dem es funktionierte
9
  ADC0.COMMAND = ADC_STCONV_bm;
10
}

Auswertung,
mir geht es erstmal um den rohen ADC Wert, die Berechnung ist mir 
vorerst wurst und steht so im Datenblatt beschrieben, nehme es aber hier 
trotzdem mit zwecks der Vollständigkeit.
1
void adc_temperature(Adc *adc)
2
{
3
  if(adc->count == 0)
4
  {
5
    //ADC0.COMMAND = ADC_STCONV_bm; <- nicht benötigt da Freerun
6
    adc->count = 1;
7
  }
8
  if(adc->count == 1)
9
  {
10
    if(ADC0.INTFLAGS & ADC_RESRDY_bm)
11
    {
12
      adc->adc_raw = ADC0.RES;
13
      adc->temp = SIGROW.TEMPSENSE1 - adc->adc_raw;
14
      adc->temp *= SIGROW.TEMPSENSE0; // Result will overflow 16-bit variable
15
      adc->temp += 0x0800; // Add 4096/2 to get correct rounding on division below
16
      adc->temp >>= 12; // Round off to nearest degree in Kelvin, by dividing with 2^12 (4096)
17
      adc->result = adc->temp - 273;
18
      adc->ready = 1;
19
      adc->count = 0;
20
    }
21
  }
22
}

Aufruf im main()
1
static Adc adc = { 0 };
2
adc_init();
3
4
while(1)
5
{
6
  if(adc.ready) 
7
  { 
8
    uart_string(calca32(adc.result)); //Convertierung Int zu String, Ausgabe 2047
9
    uart_string("\r\n\r\n"); 
10
    adc.ready = 0; 
11
  }
12
  else { adc_temperature(&adc); }
13
14
}

Habe irgendwann mal im Internet gesucht und als Referenz diese Seite 
gefunden: 
https://github.com/microchip-pic-avr-examples/avr128da48-using-12-bit-adc/blob/master/avr128da48-using-12-bit-adc/ADC_Temperature_Measurement/main.c

Die machen es fast genauso aber bei mir hald ohne Funktion..
Danke euch.

BG
Stored

von Georg M. (g_m)


Lesenswert?

Stored B. schrieb:
> Der Temperatursensor hingegen gibt immer 2047 aus.

Ist das nicht in Ordnung?

von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Sind 45C umgerechnet. Indoor bei 24C kann das vielleicht schon Sinn 
machen aber Outdoor bei 0C kann ich mir das irgendwie nicht vorstellen.

von Georg M. (g_m)


Lesenswert?

Ich bekomme 2071 als ADC0.RES.

((3347 - 2071)*943 + 4096/2) / 4096 = 294 K = 21°C



Stored B. schrieb:
> AVR läuft mit 24Mhz
> ADC0.CTRLC = ADC_PRESC_DIV4_gc;

Vielleicht etwas zu schnell?

von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Georg M. schrieb:
> Vielleicht etwas zu schnell?

Habe mal den Teiler 256 eingestellt, seitdem bekomme ich wechselnde 
Werte zwischen 2130-2150, vielleicht war wirklich dass das Problem.

Wüsste aber nicht das im Datenblatt gesehen zu haben das 6Mhz zu schnell 
für den ADC ist. Muss ich mal genauer nachsehen.

Danke dir auf jeden Fall für den Tipp. Ich denke das sollte dass Problem 
gelöst haben. Welchen Vorteiler nutzt du?

von Georg M. (g_m)


Lesenswert?

Stored B. schrieb:
> Wüsste aber nicht das im Datenblatt gesehen zu haben das 6Mhz zu schnell
> für den ADC ist.

Tatsächlich. Im Datenblatt steht nur:
"The minimum ADC_CLK frequency is 150 kHz."

Das wusste ich nicht. Bei den früheren AVR gab es auch die obere Grenze.
Deswegen stelle ich immer noch die ADC-Frequenz im Bereich 250-750kHz 
ein.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

solcher zerstückelter Code ist immer Mist. Man sollte immer kompletten 
reduzierten Testcode zeigen der das Problem noch beinhaltet. Wenn ich 
das jedoch richtig sehe fehlt, bei dir das Löschen des ADC0 Interrupt 
Flags.

Hier mein Programm, ist für Arduino zeigt aber die für dich relevanten 
Sachen mit direkter Programmierung. Ist im Grunde nichts weiter wie die 
App Notes zusammengefügt.
1
/*
2
    AVR128DB64 
3
    'onChip ADC temperatur measuring with 32kHz onchip RTC Event Trigger"
4
*/
5
6
Stream &cout {Serial2};
7
8
void setup()
9
{
10
  Serial2.swap(1);        // PF4 TXD2 / PF5 RXD2
11
  Serial2.begin(250000);
12
  initRTC();
13
  initADC0();
14
  initEventSystem();
15
  cout.println(F("\nuC Reset ###"));
16
}
17
18
void loop (void)
19
{ 
20
  readingADC0(cout);
21
}
22
23
void readingADC0 (Stream &cout)
24
{  
25
  if (ADC0.INTFLAGS & ADC_RESRDY_bm)
26
  {
27
    const uint32_t reading {ADC0.RES};
28
    cout.print("ADC0: "); cout.print(reading); cout.print(" Digits");
29
    ADC0.INTFLAGS = ADC_RESRDY_bm;          // clear result ready interrupt flag
30
31
    uint16_t sigrow_slope  {SIGROW.TEMPSENSE0};
32
    uint16_t sigrow_offset {SIGROW.TEMPSENSE1};
33
    
34
    int32_t temp {0};
35
    temp = sigrow_offset - reading; 
36
    temp *= sigrow_slope;   // Result will overflow 16-bit variable 
37
    temp += 0x0800;         // Add 4096/2 to get correct rounding on division below 
38
    temp >>= 12;            // Round off to nearest degree in Kelvin, by dividing with 2^12 (4096)
39
    const int16_t result = temp - 273;    // Convert from Kelvin to Celsius (0 Kelvin - 273.15 = -273.1°C)
40
    cout.print(" = "); cout.print(result); cout.println("°C");
41
  }
42
}
43
44
void initADC0()
45
{
46
  ADC0.CTRLA = 0;
47
  
48
  cout.println(ADC0.CTRLA, BIN);
49
  VREF.ADC0REF = VREF_REFSEL_2V048_gc;      // Internal 2.048V reference 
50
  ADC0.CTRLC = ADC_PRESC_DIV64_gc;          // 16MHz / 64 = 250kHz
51
  ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc;    // select internal temp sensor
52
  ADC0.EVCTRL = ADC_STARTEI_bm;             // enable event triggered conversion
53
  ADC0.CTRLA = ADC_ENABLE_bm | ADC_RESSEL_12BIT_gc;
54
  
55
  // erste Messung verwerfen  
56
  ADC0.COMMAND = ADC_STCONV_bm;             // start conversion
57
  while (!(ADC0.INTFLAGS & ADC_RESRDY_bm))
58
  { ; } 
59
  ADC0.INTFLAGS = ADC_RESRDY_bm;            // clear result ready interrupt flag 
60
  cout.println(ADC0.CTRLA, BIN);
61
}
62
63
void initRTC (void)
64
{
65
  RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;    // period duration 30,518µs
66
  RTC.PER = 64;                         // 64 set period = 1000ms / 15,625ms
67
  RTC.CTRLA = RTC_PRESCALER_DIV512_gc;  // prescaler 512 -->> 30,518µs * 512 = 15,625ms
68
  while (RTC.STATUS > 0) { ; }          // wait for all register to be synchronized
69
  RTC.CTRLA |= RTC_RTCEN_bm;            // RTC enable  
70
}
71
72
void initEventSystem(void)
73
{
74
  EVSYS.CHANNEL7 = EVSYS_CHANNEL7_RTC_OVF_gc;     // connect 'RTC OVF' to channel 7
75
  EVSYS.USERADC0START = EVSYS_USER_CHANNEL7_gc;   // connect generator 'RTC OVF' with user 'ADC0' via channel 7
76
}

: Bearbeitet durch User
von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Uiuiui, bitte nochmal im Datenblatt genauer nachlesen!

Danke dennoch für deinen Code. Denke aber dass das Problem der Vorteiler 
war. Seit der Umstellung erhalte ich meiner Meinung nach richtige Werte

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich habe das nochmal mit Prescaler 2 probiert und erhalte damit 40°C 
statt 24°C. Der Controller wird aktuell mit 20MHz getaktet. Warum es 
keine ADC Taktobergrenze im Manual gibt weiß ich nicht. Man sollte einen 
ADC aber nur so schnell takten wie nötig, also "etwas" über Minimum 
125kHz. Wird hier ja auch wieder deutlich.
Wegen dem Flag löschen. Habe nachgelesen. :-) Das wird auch automatisch 
gelöscht nachdem ADCn.RES gelesen wurde. Also das passt bei dir so.
Die ADC Werte sind bei mir übrigens sehr stabil zwischen 2116 ... 2118. 
Falls deine Werte stärker schwanken kannst du den eingebauten 
Akkumulator verwenden. Oder es ist noch irgendwas anderes faul.
> AVR läuft mit 24Mhz, keine Interrupts aktiv
> 2x 1000uF zwischen + und GND
> AVDD(14) = 3,3V
> GND(15) = GND
1000µF klingen zwar gut, aber der Controller benötigt auch die typischen 
100nF an den Vcc Pin. Elkos alleine sind zu träge. Könnte auch für die 
schwankenden Werte verantwortlich sein.

: Bearbeitet durch User
von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Veit D. schrieb:
> ich habe das nochmal mit Prescaler 2 probiert und erhalte damit 40°C
> statt 24°C.

Danke dir fürs Testen! Dann lag es ja wenigstens nur Teilweise an mir :) 
Höchstens in der Errata steht noch was..

Veit D. schrieb:
> Die ADC Werte sind bei mir übrigens sehr stabil zwischen 2116 ... 2118.
> Falls deine Werte stärker schwanken kannst du den eingebauten
> Akkumulator verwenden. Oder es ist noch irgendwas anderes faul.

Werde wahrscheinlich beides Testen, Akkumulator und kleinere 
Kondensatoren. Danke dir!

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.