Forum: Mikrocontroller und Digitale Elektronik Atmega16 ADC. Wo ist der Fehler?


von Robert P. (robert-p)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe eine Schaltung mit einem Mega16 und KTY81-110 aufgebaut. 
Schaltplan im Anhang.

Derzeit gebe ich die ADC-Werte und die berechnete Temperatur auf einem 
Display aus und die Werte stimmen nicht mit den erwarteten überein.

Bei ca 22°C Raumtemperatur sollte der ADC einen Wert von 276 liefern, 
jetzt komme ich aber nur auf 9°C und einen Wert von 255. Die 255 macht 
mich schon stutzig, wenn ich aber den Sensor abziehe, steigt der 
ADC-Wert wie erwartet auf 1023 an. Stecke ich einen Jumper statt des KTY 
auf, kommt wie erwartet eine 0.

Ein paar relevante Routinen:
1
/***********************************************************************************************/
2
int16_t calculate_temperature(uint16_t adc){
3
  //t=0,64593625*adc-155,4
4
  //#warning "TODO: update equation" done ;)
5
  int32_t adc_temp = 13229 * (uint32_t) adc;
6
  adc_temp = adc_temp / 2048;
7
  adc_temp = adc_temp - 1554;
8
  adc_temp = adc_temp / 10;
9
  return (int16_t) adc_temp;
10
}
11
/***********************************************************************************************/
12
void sprint_temperature(char* str,int16_t temperature){
13
  uint8_t one = 0, ten = 0, houndred = 0;
14
  bool _signed = false;
15
  if(temperature < 0){
16
    temperature *= -1;
17
    str[0] = '-';
18
    _signed = true;
19
    if(temperature > 99) temperature = 99;
20
  }
21
  one = temperature % 10;
22
  ten = (temperature % 100) / 10;
23
  houndred = (temperature % 1000) / 100;
24
  if(houndred == 0){
25
    if(ten == 0){
26
      if(_signed){
27
        str[1] = str[0];
28
      }else{
29
        str[1] = ' ';
30
      }
31
      str[0] = ' ';
32
    }else{
33
      if(_signed){
34
        str[0] = str[0];
35
      }else{
36
        str[0] = ' ';
37
      }
38
      str[1] = ten + '0';
39
    }
40
  }else{
41
    str[0] = houndred + '0';
42
    str[1] = ten + '0';
43
  }    
44
  str[2] = one + '0';
45
}
46
/***********************************************************************************************/
47
void adc_init(void){
48
  uint16_t result;
49
  ADMUX |= (1<<REFS0);                    // VCC with external capacitor at AREF
50
  ADCSRA |= (1<<ADEN) |/* (1<<ADPS2) | (1<<ADPS1) | */(1<<ADPS0); // ADC enabled, prescaler: 1
51
  ADCSRA |= (1<<ADSC);
52
  while(ADCSRA & (1<<ADSC)){;}
53
  result = ADCW; //dummy readout
54
  //ADCSRB = 0x00;
55
}
56
/***********************************************************************************************/
57
uint16_t read_adc(uint8_t portbit){
58
  /*uint16_t result;*/
59
  //ADMUX |= portbit;
60
  //uint16_to_string(str5,ADMUX);
61
  ADCSRA |= (1<<ADSC);
62
  while(ADCSRA & (1<<ADSC)){;}
63
  /*result = ADCW; //dummy readout
64
  result = 0;
65
  for(i=0;i<4;i++){
66
    while(ADCSRA & (1<<ADSC)){;}
67
    result += ADCW;
68
  }
69
  //ADMUX &= ~portbit;*/
70
  return ADCW;
71
}
72
static void avr_init(void)
73
{
74
  
75
  //Enable SPI
76
  spi_init();
77
  adc_init();
78
  
79
  //init communication
80
  //*
81
  USART_Init(0);
82
  
83
  
84
  RELAY_DDR |= (1<<RELAY_DISPLAY) | (1<<RELAY_CAM);
85
86
  DDRC |= (1<<PORTC5);
87
88
  CTRL_DDR |= (1<<REQUEST) | (1<<DISPLAY_READY);
89
  CTRL_PORT |= (1<<REQUEST) | (1<<DISPLAY_READY);
90
  //*/
91
  //Set power mode
92
  set_sleep_mode(SLEEP_MODE_IDLE);   
93
  
94
  //init PAL SYNC port
95
  set_bit(DDRC,7);
96
  //B.4 is sync:1000 ohm + diode to 75 ohm resistor
97
  //MOSI is video:330 ohm + diode to 75 ohm resistor
98
    
99
  // Initialize Sync for PAL
100
  OCR1A = 1024;        //One PAL line 64us
101
  TCCR1B = (1<<WGM12)|(1<<CS10);//full speed; clear-on-match
102
  TCCR1A = 0x00;      //turn off pwm and oc lines
103
  TIMSK = 1<<OCIE1A;    //enable interrupt from Timer1 CompareA
104
  return;
105
}
Im Hauptprogramm werden nur diese Routinen aufgerufen, der Sensor hängt 
am PA0.

Ich habe auch einen zweiten Mega16 probiert, da ist das gleiche Bild. 
Hängt man ein Poti statt des Sensors dran, springt der ADC-Wert von 316 
auf 255 und dann auf 0.

Der Widerstand des 2k7 Pullup stimmt nach Multimetermessung auch und 
kalte Lötstellen konnte ich nicht entdecken.

Ich danke euch für eure Hilfe.

von Sven (Gast)


Lesenswert?

was ist "houndred" ;-)

ohne groß in dein Programm geschaut zu haben:
versuch Mal den Orginal-ADC Wert auszugeben

beim Debuggen immer alles in Einzelschritten testen

von holger (Gast)


Lesenswert?

>  ADCSRA |= (1<<ADEN) |/* (1<<ADPS2) | (1<<ADPS1) | */(1<<ADPS0); // ADC 
>enabled, prescaler: 1

Mal den Dreck wegräumen

  ADCSRA |= (1<<ADEN) | (1<<ADPS0); // ADC enabled, prescaler: 1

Läuft deine CPU mit 200kHz?
Ich würde den Prescaler mal höher machen.

von Robert P. (robert-p)


Lesenswert?

> Läuft deine CPU mit 200kHz?
> Ich würde den Prescaler mal höher machen.
Danke! Das hat geholfen. Ich habe die ADC-Routinen zum Teil aus anderen 
Programmen kopiert. deshalb habe ich ja gefragt.

Danke, danke, danke!

von Bronco (Gast)


Lesenswert?

Der ADC braucht eine gewisse Zeit für Sample und Hold.
Ich weiß es beim AVR nicht auswendig, aber bei anderen µCs kann man 
diese Zeiten einstellen, und zwar in ADC-Clock-Takten.
Wenn die Zeiten zu Kurz sind (weil Dein ADC-Takt zu hoch), kann der ADC 
nicht genau arbeiten.

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.