mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR ADC auswerten klappt nicht


Autor: Loginus (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

um das Ätzmittel in meiner Keramikschale auf richtiger Temperatur zu 
halten, habe ich die angehängte Schaltung geplant und geätzt sowie mit 
Codevision die Programme für die beiden Mikrocontroller in C 
geschrieben.

Ich möchte mit dem LM335 (Beinchen sind in Schrumpfschlauch eingepackt 
und verklebt) die Temperatur der Ätzflüssigkeit messen und bei Erreichen 
einer bestimmten Temperatur die Lastwiderstände auf der Unterseite der 
Keramikschale ein- bzw. ausschalten. Später sollen die Heizwiderstände 
statt nur ein- und ausgeschaltet zu werden mit PWM mit niedriger 
Frequenz angesteuert werden.

Mein Problem ist nun, dass mir die 7-Segment-Anzeigen immer den Wert 29 
ausgeben, unabhängig davon, ob der LM335 erwärmt oder gekühlt wird. Die 
Übertragung zwischen den Mikrocontrollern selbst funktioniert. Wenn ich 
die Temperatureinlesung auskommentiere und die Bits direkt festlege, 
werden diese auch angezeigt.

Könnt Ihr mir sagen, wo mein Fehler liegt?

Vielen Dank im Voraus für Eure Zeit.


Hier der Code von dem Attiny25:
 
/*******************************************************
Projekt:        Aetzwanne

Version :        ATTiny25 - 1
Erstellt:        20.09.2016
Letze Aenderung: 25.09.2016

Chip: Attiny25 mit internen 8.0 MHz
*******************************************************/

/// Header-Dateien///
#include <io.h>
#include <delay.h>

/// Definierungen ///
#define Lastwiderstaende    PORTB.0
#define DataOut             PORTB.1
#define InterruptOut        PORTB.2   
#define Target_low          40          //Minimale Temperatur
#define Target_high         45          //Maximale Temperatur

// Bandgap Voltage Reference: Off
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR))

//// Prototypen ////
int read_adc ();

/// Globale Variablen ///
char temp = 0;
char temp_part = 0;

char temp_einer_bit0 = 1;
char temp_einer_bit1 = 0;
char temp_einer_bit2 = 0;
char temp_einer_bit3 = 0;

char temp_zehner_bit0 = 0;
char temp_zehner_bit1 = 1;
char temp_zehner_bit2 = 0;
char temp_zehner_bit3 = 0;

void main(void)
{
    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) |   
    (0<<CLKPS0);
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    // Port Initialisierung
    // Port B -  Bit5 = Out, Bit4 = Out, Bit3 = Out, Bit2 = Out, Bit1 = Out, Bit0 = In   
    DDRB=(1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (0<<DDB0);
    PORTB=(0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); 
    
    //ADC Initialisierung
    ADMUX |= (1 << MUX0);  //ADC3 (PB3), Output vom LM335
    ADMUX |= (1 << MUX1); 
    ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);    //Frequenz: 62.5 kHz  
                   
    delay_ms(100);   //Sicherstellen, dass Attiny2313 empfangsbereit ist
    
    while (1)
    {      
        /// Temperatur einlesen ///
      //Temperatur in Celsius errechnen (10mV/K)
        temp = read_adc() * 0.00488759 * 100 - 273.15; 
        
        /// Temperatur auswerten ///
  //Temperatur zu niedrig? Lastwiderstaende ein
        if (temp < Target_low)                             
            Lastwiderstaende = 1;
                              
  //Temperatur zu hoch? Lastwiderstaende aus
        else if (temp > Target_high)                    
            Lastwiderstaende = 0; 
                         
        /// Temperatur zerlegen ///
        //Einerstelle in BCD zerlegen 
        temp_part = temp % 10;                        
        
        switch (temp_part)
        {     
            case 0:
                temp_einer_bit0 = 0;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 0;
                break; 
                    
            case 1:
                temp_einer_bit0 = 1;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 0;
                break;
                    
            case 2:
                temp_einer_bit0 = 0;
                temp_einer_bit1 = 1;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 0;
                break;   
                    
            case 3:
                temp_einer_bit0 = 1;
                temp_einer_bit1 = 1;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 0;
                break;
                    
            case 4:
                temp_einer_bit0 = 0;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 1;
                temp_einer_bit3 = 0;
                break;
                    
            case 5:
                temp_einer_bit0 = 1;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 1;
                temp_einer_bit3 = 0;
                break;
                    
            case 6:
                temp_einer_bit0 = 0;
                temp_einer_bit1 = 1;
                temp_einer_bit2 = 1;
                temp_einer_bit3 = 0;
                break;
                    
            case 7:
                temp_einer_bit0 = 1;
                temp_einer_bit1 = 1;
                temp_einer_bit2 = 1;
                temp_einer_bit3 = 0;
                break;
                    
            case 8:
                temp_einer_bit0 = 0;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 1;
                break;
                    
            case 9:
                temp_einer_bit0 = 1;
                temp_einer_bit1 = 0;
                temp_einer_bit2 = 0;
                temp_einer_bit3 = 1;
                break;
        }         
        
        //Zehnerstelle in BCD zerlegen 
        temp_part = (temp - temp_part) / 10;
        
        switch (temp_part)
        {     
            case 0:
                temp_zehner_bit0 = 0;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 0;
                break; 
                    
            case 1:
                temp_zehner_bit0 = 1;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 0;
                break;
                    
            case 2:
                temp_zehner_bit0 = 0;
                temp_zehner_bit1 = 1;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 0;
                break;   
                    
            case 3:
                temp_zehner_bit0 = 1;
                temp_zehner_bit1 = 1;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 0;
                break;
                    
            case 4:
                temp_zehner_bit0 = 0;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 1;
                temp_zehner_bit3 = 0;
                break;
                    
            case 5:
                temp_zehner_bit0 = 1;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 1;
                temp_zehner_bit3 = 0;
                break;
                    
            case 6:
                temp_zehner_bit0 = 0;
                temp_zehner_bit1 = 1;
                temp_zehner_bit2 = 1;
                temp_zehner_bit3 = 0;
                break;
                    
            case 7:
                temp_zehner_bit0 = 1;
                temp_zehner_bit1 = 1;
                temp_zehner_bit2 = 1;
                temp_zehner_bit3 = 0;
                break;
                    
            case 8:
                temp_zehner_bit0 = 0;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 1;
                break;
                    
            case 9:
                temp_zehner_bit0 = 1;
                temp_zehner_bit1 = 0;
                temp_zehner_bit2 = 0;
                temp_zehner_bit3 = 1;
                break;
        }   
        
        /// Temperaturwert uebertragen ///
        //Einerstelle uebertragen
        DataOut = temp_einer_bit0;   //Zu uebertragendes Bit anlegen
        InterruptOut = 1;            //Signalisieren, dass Bit angelegt ist
        delay_ms(1);                 //Warten, bis Bit uebernommen ist
        InterruptOut = 0;
        delay_ms(1);       
        
        DataOut = temp_einer_bit1;  
        InterruptOut = 1;            
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);
        
        DataOut = temp_einer_bit2;   
        InterruptOut = 1;            
        delay_ms(1);                
        InterruptOut = 0;
        delay_ms(1);
        
        DataOut = temp_einer_bit3;   
        InterruptOut = 1;            
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);
                
        //Zehnerstelle
        DataOut = temp_zehner_bit0;   
        InterruptOut = 1;            
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);
        
        DataOut = temp_zehner_bit1;   
        InterruptOut = 1;            
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);
        
        DataOut = temp_zehner_bit2;   
        InterruptOut = 1;            
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);
        
        DataOut = temp_zehner_bit3;   
        InterruptOut = 1;           
        delay_ms(1);                 
        InterruptOut = 0;
        delay_ms(1);    
        
        //Warten bis zur naechten Messung
        delay_ms(1000);     
     }  
}

/// Funktionen ///
int read_adc ()
{    
    // ADC starten
    ADCSRA |= (1 << ADSC);

    // Auf Ende des Messvorgangs warten
    while (ADCSRA & (1 << ADSC));
          
    // 10-Bit-Ergebnis zurueckgeben
    return (ADCH<<8 | ADCL);
}

Hier der Code von dem Attiny2313A:
/*******************************************************
Projekt:        Aetzwanne

Version :        ATTiny2313A - 1
Erstellt:        22.09.2016
Letze Aenderung: 25.09.2016

Chip: Attiny2313A mit internen 8.0 MHz
*******************************************************/

/// Header-Dateien ///
#include <io.h>
#include <delay.h>

/// Definierungen ///
#define InterruptIn PIND.2
#define DataIn      PIND.3

#define SegmentA    PORTB.7
#define SegmentB    PORTB.6
#define SegmentC    PORTB.5
#define SegmentD    PORTB.4
#define SegmentE    PORTB.3
#define SegmentF    PORTB.2
#define SegmentG    PORTB.1

#define Digit1      PORTB.0
#define Digit2      PORTD.6

/// Prototypen ///
void write_bitmuster (char temp_part);
 
/// Globale Variablen ///
char interruptzaehler = 0;

char temp_einer_bit0;
char temp_einer_bit1;
char temp_einer_bit2;
char temp_einer_bit3;

char temp_zehner_bit0;
char temp_zehner_bit1;
char temp_zehner_bit2;
char temp_zehner_bit3;

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
    switch (interruptzaehler)
    {
        case 0: 
            temp_einer_bit0 = DataIn;
            break;
        
        case 1: 
            temp_einer_bit1 = DataIn;
            break;
            
        case 2: 
            temp_einer_bit2 = DataIn;
            break;
        
        case 3: 
            temp_einer_bit3 = DataIn;
            break; 
            
        case 4: 
            temp_zehner_bit0 = DataIn;
            break; 
            
        case 5: 
            temp_zehner_bit1 = DataIn;
            break; 
            
        case 6: 
            temp_zehner_bit2 = DataIn;
            break; 
        
        case 7: 
            temp_zehner_bit3 = DataIn;
            break;   
    }
            
    interruptzaehler++;
        
    if (interruptzaehler == 8)
        interruptzaehler = 0;  
}

void main(void)
{
    //Lokale Varibalen
    char temp_part = 0;  
    
    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    /// Port Initialisierung ///
    // Port A: Bit2=Out Bit1=Out Bit0=Out 
    DDRA=(1<<DDA2) | (1<<DDA1) | (1<<DDA0);
    PORTA=(0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

    // Port B: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out 
    DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
    PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

    // Port D: Bit6=Out Bit5=Out Bit4=Out Bit3=In Bit2=In Bit1=Out Bit0=Out 
    DDRD=(1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (0<<DDD3) | (0<<DDD2) | (1<<DDD1) | (1<<DDD0);
    PORTD=(0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0); 
    
    // Externe Interrupts Initialisierung: INT0: ein
    MCUCR=(0<<ISC11) | (0<<ISC10) | (1<<ISC01) | (1<<ISC00);
    GIMSK=(0<<INT1) | (1<<INT0) | (0<<PCIE0) | (0<<PCIE2) | (0<<PCIE1);
    GIFR=(0<<INTF1) | (1<<INTF0) | (0<<PCIF0) | (0<<PCIF2) | (0<<PCIF1);

    #asm("sei")
    
    while (1)
    {            
        //Einerstelle ausrechnen und Multiplexen 
        temp_part = temp_einer_bit0 + temp_einer_bit1 * 2 + temp_einer_bit2 * 4 + temp_einer_bit3 * 8;
        write_bitmuster (temp_part); 
        Digit2 = 1;
        delay_ms (1); 
        Digit2 = 0;
        
        temp_part = temp_zehner_bit0 + temp_zehner_bit1 * 2 + temp_zehner_bit2 * 4 + temp_zehner_bit3 * 8;
        write_bitmuster (temp_part);  
        Digit1 = 1;
        delay_ms (1); 
        Digit1 = 0;
    }
}

void write_bitmuster (char temp_part)
{
    switch (temp_part)
    { 
        case 0:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 1;
            SegmentF = 1;
            SegmentG = 0;   
            break;   
                
        case 1:     
            SegmentA = 0;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 0;
            SegmentE = 0;
            SegmentF = 0;
            SegmentG = 0; 
            break;
                
        case 2:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 0;
            SegmentD = 1;
            SegmentE = 1;
            SegmentF = 0;
            SegmentG = 1; 
            break;
                
        case 3:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 0;
            SegmentF = 0;
            SegmentG = 1;
            break;
                
        case 4:     
            SegmentA = 0;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 0;
            SegmentE = 0;
            SegmentF = 1;
            SegmentG = 1;
            break;
                
        case 5:     
            SegmentA = 1;
            SegmentB = 0;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 0;
            SegmentF = 1;
            SegmentG = 1;
            break;
                
        case 6:     
            SegmentA = 1;
            SegmentB = 0;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 1;
            SegmentF = 1;
            SegmentG = 1;
            break;
                
        case 7:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 0;
            SegmentE = 0;
            SegmentF = 0;
            SegmentG = 0; 
            break;
                
        case 8:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 1;
            SegmentF = 1;
            SegmentG = 1;   
            break;
                
        case 9:     
            SegmentA = 1;
            SegmentB = 1;
            SegmentC = 1;
            SegmentD = 1;
            SegmentE = 0;
            SegmentF = 1;
            SegmentG = 1;   
            break;
    }
}

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
>>Wichtige Regeln - erst lesen, dann posten!
>>
>>    Groß- und Kleinschreibung verwenden
>>    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

-------------------------^^^^^^^^^^^^^^^^^^^^^^^^

Autor: Karl M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

zur Schönheit, das Ergebnis ohne Vorzeichen ist:

uint16_t read_adc(void);

Dann schaue dir bitte im Datenblatt die Auflistung unter:
17.13.2 ADCSRA – ADC Control and Status Register A
an.

Speziell:
Bits 2:0 – ADPS[2:0]: ADC Prescaler Select Bits
Table 17-5. ADC Prescaler Selections

Bei 8MHz würde ich einen 1/64 ADC-Vorteiler wählen und bei der Messung 
immer auch eine Mittelwertbildung in betracht ziehen.

Z.B. über 4 Messwerte.

Dann gibt es noch das schöne Register:
DIDR0 – Digital Input Disable Register 0

Dies verwende ich bei Nutzung des ADC immer.

Dann setze ich noch im:
ACSR – Analog Comparator Control and Status Register
ACSR.ACD = 1;

Autor: Loginus (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Wäre sinnvoll gewesen :/ Hier der Code als Textdatei. Vielleicht kann 
ein netter Mod ja den Code im ersten Post löschen.

Autor: Arduinoquäler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Loginus schrieb:
> Hier der Code als Textdatei.

Ja aber der Automatismus zum korrekten Anzeigen von Dateien
möchte gerne  *.c haben.

Autor: Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Loginus schrieb:
> return (ADCH<<8 | ADCL);

ADCL muß vor ADCH ausgelesen werden. Kannst du das hier gewährleisten?

Also überlasse es dem Compiler, dafür zu sorgen, daß es richtig gemacht 
wird.
return ADC;

: Bearbeitet durch User
Autor: Loginus (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke für Eure Antworten. Der neue Code ist angehängt.

Wenn ich mit einem Netzteil Spannung an X6 anlege, zeigt die 
7-Segment-Anzeige etwa 10 Grad weniger an, als ich erwarte. Lege ich 
beispielsweise 3,5V an, erwarte ich 86 Grad, angezeigt werden aber 76 
Grad. Da die Differenz aber immer gleich bleibt, kann ich das durch die 
Software ausgleichen.

Nun aber zum Problem: Wenn ich den LM335 anschließe (X5 und X6 
verbinden, Plus an X6, Masse an X7, ADJ-Pin bleibt frei), messe ich über 
dem Widerstand R2 5V und habe dann logischerweise 0V am ADC Pin 
anliegen.

Ich habe dann erneut das Netzteil angeschlossen und die Stromaufnahme 
gemessen: 80mA fließen, wenn ich das Netzteil an X6 und X7 anschließen.
Nur warum?

Autor: Jakob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn 80 mA von (+) in einen Port-Pin fließen, ist er wohl als
Ausgang (Low) geschaltet.

Dafür sind die DDR-Bits zuständig, falls der Port-Pin nicht schon
durch vorherige missglückte Versuche einen Schluss nach Masse hat...

Der ADC misst dann den Spannungsabfall am Low-Side-Transistor.

Autor: Loginus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jap, das war es. Nun läuft alles. Hatte beim Schaltplan den Portpin 
geändert und es auch in den Definierungen geändert aber die Änderung bei 
der Port Initialisierung vergessen. Mein armer Attiny. Nochmals danke an 
alle!

Autor: Duden (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Loginus schrieb:
> Definierungen

herrlich ...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.