AVR128DA28 Temperatursensor

OP (Firma: drx) #7362200
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

OP (Firma: drx) #7362463
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?

#7362557
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
}
#7362599
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.

OP (Firma: drx) #7362609
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!

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