Forum: Mikrocontroller und Digitale Elektronik Spannungskomperator mit ADC


von Jens K. (mister232)


Lesenswert?

Guten Abend!

Ich habe folgendes Programm welches nicht so läuft wie ich es mir 
wünsche:
Ein ATtiny45 soll über einen seiner ADC-Kanäle eine Spannung einlesen 
(Sensorspannung). Anschließend wird der Kanal umgeschaltet und es wird 
eine weitere Spannung eingelesen (Referenzspannung). Nur soll verglichen 
werden, ob die eingelesene Referenzspannung größer ist, als die 
eingelesene Sensorspannung. Trifft das zu, so sollen zwei LEDs 
eingeschaltet werden, sonst aus.
Leider bleiben die LEDs dunkel und ein Test mit einer Debug-LED hat 
ergeben, dass er immer in den zweig springt "Referenzspannung kleiner 
als Sensorspannung".
Hier das Programm:
Die Main:
1
/*
2
 * Tank_Heater.c
3
 *
4
 * Created: 06.01.2015 19:52:30
5
 *  Author: *****
6
 */ 
7
8
#define F_CPU 800000UL
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/delay.h>
13
#include "ADC.h"
14
15
#define HEATER PB1
16
#define LED PB3
17
#define DEBUG_LED PB0
18
19
void init_ports(void);
20
void checkTemperature(void);
21
void debug(void);
22
23
int main(void)
24
{
25
  uint8_t i; 
26
  
27
  init_ADC();
28
  init_ports();
29
  
30
  // Toggle LED again, to show -> initialisation done
31
  for(i = 0; i < 2; i++ )
32
  {
33
    PORTB = (1<<LED);
34
    _delay_ms(1000);
35
    PORTB &= ~(1<<LED);
36
    _delay_ms(1000);
37
  }
38
  
39
  // Toggle heater, so the user can see if it is all right
40
  PORTB = (1<<HEATER);
41
  _delay_ms(2000);
42
  PORTB &= ~(1<<HEATER);
43
  
44
    while(1)
45
    {
46
    checkTemperature();
47
    
48
    _delay_ms(500);
49
    }
50
  
51
  return 0;
52
}
53
54
// Initialize the port-pins
55
void init_ports(void)
56
{
57
  // LED-Port (output), Relay-Port (for heater) (output)
58
  DDRB |= (1<<LED) | (1<<HEATER) | (1<<DEBUG_LED);
59
  
60
  PORTB &= ~(1<<LED);
61
  PORTB &= ~(1<<HEATER);
62
  PORTB &= ~(1<<DEBUG_LED);
63
}
64
65
// Function which compares the actual temperature value with the user-set value. Depending on the result, the heater is controlled
66
void checkTemperature(void)
67
{
68
  uint16_t tempValue, refTemp;
69
  
70
  // Get the actual temperature value from sensor
71
  tempValue = getNewSensorValue();
72
  
73
  // Get the actual reference temperature
74
  refTemp = setNewTempValue();
75
  
76
  // Control the heater depending on the measure
77
  if(tempValue < refTemp)
78
  {
79
    // Heater on
80
    PORTB |= (1<<HEATER);
81
    PORTB |= (1<<LED);
82
  }
83
  else
84
  {
85
    // Heater off
86
    PORTB &= ~(1<<HEATER);
87
    PORTB &= ~(1<<LED);
88
  }
89
}
90
91
void debug(void)
92
{  
93
  PORTB = (1<<DEBUG_LED);
94
  _delay_ms(500);
95
  PORTB &= ~(1<<DEBUG_LED);
96
  _delay_ms(500);
97
}

Der Header:
1
/*
2
 * ADC.h
3
 *
4
 * Created: 26.08.2014 13:44:10
5
 *  Author: ******
6
 */ 
7
8
9
#ifndef ADC_H_
10
#define ADC_H_
11
12
#include <avr/io.h>
13
14
extern void init_ADC(void);
15
extern uint16_t setNewTempValue(void);
16
extern uint16_t getNewSensorValue(void);
17
extern void debug(void);
18
19
#endif /* ADC_H_ */

Und die ADC-Datei:
1
/*
2
 * ADC.c
3
 *
4
 * Created: 26.08.2014 13:44:00
5
 *  Author: ******
6
 *
7
 * This file includes initialization and access function for the use of the build in ADC of an ATtiny45
8
 */ 
9
10
#include <avr/io.h>
11
#include "ADC.h"
12
13
// Function to initialize the ADC
14
void init_ADC(void)
15
{
16
  // Select the reference voltage source (VCC)
17
  ADMUX &= ~(1<<REFS0) | ~(1<<REFS1);
18
  
19
  // Select prescaler to clk/32
20
  ADCSRA |= (1<<ADPS2) | (1<<ADPS0);
21
  ADCSRA &= ~(1<<ADPS1);
22
  
23
  // Enable the ADC
24
  ADCSRA = (1<<ADEN);
25
  
26
  // Do one conversion, for start-up of the ADC
27
  ADCSRA |= (1<<ADSC);
28
  // Wait for conversion complete
29
  while(ADCSRA & (1<<ADSC)){}
30
  
31
  // The value has to be read, because otherwise it could cause a false value next time converting
32
  (void) ADCW;
33
}
34
35
// Function to get a new set-temperature
36
uint16_t setNewTempValue(void)
37
{
38
  // Select temperature-set-channel
39
  ADMUX &= ~(1<<MUX1);
40
  ADMUX = (1<<MUX2);
41
  
42
  // Get a new value
43
  ADCSRA |= (1<<ADSC);
44
  // Wait for conversion complete
45
  while(ADCSRA & (1<<ADSC)){}
46
  
47
  // Return new value
48
  return ADCW;
49
}
50
51
// Function to read the actual temperature from sensor
52
uint16_t getNewSensorValue(void)
53
{
54
  // Select sensor-measuring-channel
55
  ADMUX &= ~(1<<MUX2);
56
  ADMUX = (1<<MUX1);
57
  
58
  // Get a new value
59
  ADCSRA |= (1<<ADSC);
60
  // Wait for conversion complete
61
  while(ADCSRA & (1<<ADSC)){}
62
  
63
  // Return value
64
  return ADCW;
65
}
Achja, hardwaremäßig sieht das ganze so aus, da ich am 
Referenzspannungseingang fest 2,5V habe und am Sensorspannungseingang 
ein Poti mit dem ich zwischen 1V und 5V regeln kann. Die Spannungen an 
den Eingängen habe ich gemessen, dass passt soweit.

Ich hoffe ihr habt ein paar Ideen ;-)

von isidor (Gast)


Lesenswert?

Jens K. schrieb:
> #define F_CPU 800000UL

CPU Frequenz 800 KHz?

Dann laufen deine _delay_ms eventuell 10 mal so lang
wie vielleicht mit 8 Mhz erwartet.

von Jens K. (mister232)


Lesenswert?

Das ist ein weiteres Problem, hatte ich vergessen zu erwähnen, sorry:

Normalerweise setze ich F_CPU auf 8000000UL bei einem 8MHz Quarz und 
alles läuft wie es soll. Nun habe ich den interen Oszillator mit 8 MHz 
(laut AVR Studio) eingeschaltet und wie gewohnt 8000000UL definiert. 
Dann dauert ein _delay_ms(1000) allerdings auf einmal 10 Sekunden? bei 
800000UL läuft alles perfekt?!

: Bearbeitet durch User
von isidor (Gast)


Lesenswert?

Ich kenne deinen Tiny nicht, aber ich denke du musst die Fuses
auf dem Controller bezüglich der Taktfrequenz mit einem Programmer
korrekt setzen bevor er so tut wie du willst.

von Kalli (Gast)


Lesenswert?

Sieht nach CKDIV8 Fuse aus? Dann läuft der Tine nur mit 1MHz und der ADC 
viel zu langsam?

von isidor (Gast)


Lesenswert?

10-fach und 8-fach sollte man schon unterscheiden können.

von Jens K. (mister232)


Lesenswert?

Ja, jetzt funktioniert das mit dem Takt. Stimmt, hatte ich ganz 
vergessen, aber klar das er dann so langsam ist :-)

Das hilft mir aber leider mit dem ADC Problem nicht weiter :-(

von isidor (Gast)


Lesenswert?

Ich vermute den Fehler in den Zeilen
1
ADMUX = (1<<MUX2);

Damit überschreibst du alle Bits des Registers mit 0,
bis auf das MUX2 Bit. Und damit geht die Einstellung des
Wandlers verloren.

Vermutlich muss es einfach lauten
1
ADMUX |= (1<<MUX2);

von Jens K. (mister232)


Lesenswert?

Das habe ich bereits ausprobiert, funktioniert aber leider nicht.

von Jens K. (mister232)


Lesenswert?

Ich bin das Problem nun umgangen, indem ich den internen analog 
Komparator des Tinys nutze. Ich würde aber trotzdem gerne wissen warum 
das Andere nicht funktioniert.

von isidor (Gast)


Lesenswert?

1
 
2
 // Enable the ADC
3
  ADCSRA = (1<<ADEN);

In dieser Initialsierung ist auch noch ein Konfigurations-Zerstörer

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.