Forum: Mikrocontroller und Digitale Elektronik Laminator Regelung AVR fehlfunktion


von Fritz B. (kleinfritzchen)


Angehängte Dateien:

Lesenswert?

Hallo,
bei der Regelung soll die Temperatur auf der einen Seite über ein Poti 
(durch versuch ermittelter Wert) eingestellt werden und auf der anderen 
Seite soll ein Relais die Heizung schalten.
Ich bin noch in der Versuchsphase und habe ein kleines Programm das 
momentan nur eine mit verschiedenen Frequenzen blinkende Diode hat 
geschrieben.
Es hat sich rausgestellt das der Attiny 13 anscheinend bei einem Regeln 
auf +5V sich "aufhängt" und erst nach einem Neustart wieder sauber 
funktoniert.
Meine Frage ist jetzt: Muss ich an der Sftware was ändern (evtl. 
Watchdog) oder liegt es an der Hardweare?
Der schaltplan spiegelt gerade den augenblicklichen Zustand auf dem 
Versuchs-Board wieder! Ist also noch nicht vollständig. Geplant ist als 
Sensor eine Diode zu verwenden deren Spannungsabfall mit dem Poti 
verglichen wird und dementsprechend das Relai geschaltet wird.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
//#define F_CPU = 1200000UL
4
uint8_t leseKanal(uint8_t mux);
5
uint8_t verz=0, i;
6
int main (void){
7
  DDRB=0x03;
8
  
9
  
10
  while (1){
11
    PORTB ^= 0x01;
12
    verz =  leseKanal(0x23);
13
    for ( i=0;i<=verz;i++){
14
      _delay_ms(3);
15
    }
16
  } return 0;
17
  
18
}
19
20
//Routine zum einlesen eines Kanales
21
uint8_t leseKanal(uint8_t mux)
22
{
23
  uint8_t i;
24
  uint8_t ergebniss;
25
  uint8_t foo;
26
  ADCSRA |= (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1);
27
    //ADC einschalten, Teiler auf 8
28
  ADMUX =mux;
29
  //lerlauf zum syncronisoeren
30
  ADCSRA |= (1<<ADSC);
31
  while (ADCSRA & (1<<ADSC)){
32
    ;
33
  }
34
  foo = ADCL;
35
  foo = ADCH;
36
    
37
  foo = 0;
38
  //eigentlicher Abfragezyklus
39
  for(i=0;i<1;i++){
40
    
41
    ADCSRA |= (1<<ADSC);
42
    while (ADCSRA & (1<<ADSC)){
43
      ;
44
    }
45
    ergebniss = ADCL;
46
    ergebniss = ADCH;
47
  }
48
  //ergebniss = foo;
49
  //ergebniss = (ergebniss>>2);
50
  return ergebniss;
51
  
52
}

von Mike (Gast)


Lesenswert?

Fritz Bie schrieb:
> Meine Frage ist jetzt: Muss ich an der Sftware was ändern (evtl.
> Watchdog) oder liegt es an der Hardweare?

Der Watchdog hilft nur, wenn das Kind schon in den Brunnen gefallen ist.

Im Schaltplan ist ein grundlegender Fehler: Es fehlt ein 
Abblockkondensator am Prozessor. Und das Poti hat sicher auch einen 
bestimmten Wert?

von visitor (Gast)


Lesenswert?

Hängt er sich tatsächlich auf, oder läuft dein Regler in die Sättigung 
und kommt von dort nicht mehr heraus um herunter zu regeln. Dies 
solltest du mal prüfen.

von Hubert G. (hubertg)


Lesenswert?

ergebniss = ADCL;
ergebniss = ADCH;

Was wird in ergebniss stehen?
Der Wert von ADCL oder von ADCH ?

von Fritz B. (kleinfritzchen)


Lesenswert?

Hallo,
erst mal zum Ergebniss. Das ergebniss ist ADCH weil man beim auslesen 
erst das Low und dann das High Byte. Die Reihenfolge ist laut Datenblatt 
vorgeschrieben. Ich habe  Das Bit 6 im ADMUX Register gesetzt was 
bedeutet das das Ergebniss linksbündig ausgegeben wird. Dies hat zur 
Folge das die unteren beiden Bit abgeschnitten werden wenn ich nur ADCH 
verwende.
Das mache ich aus dem Grund weil ich so die Störfaktoren ein wenig 
eingrenzen kann um ein klares Ergebniss zu haben.
Nun zu den C zwischen Masse und Vcc: hat nichts gebracht.
Das Poti hat 10k als Wert.
Ich bin am Überlegen ob ich den ADC auf 1V Referenz umschalte um eine 
besser ausnutzung des Messbereichs zu  bekommen. Die Diode die ich als 
Sensor  verwende verursacht einen Spannungsabfall von 20 °C = 0,534V zu 
250°C = 0,231V.
Dann könnte ich für das Poti 2k und 8k in reihe verwenden.
Die Diode müsste ich dann auch über einen Spannungsteiler versorgen.

Bezüglich der Sättigung weis ich leider nicht was das bedeutet (noch zu 
wenig Ahnung von der Materie). Der Regler (7805) liefert jedenfalls in 
jedem Fall die erforderliche Spannung.

von spess53 (Gast)


Lesenswert?

Hi

>Das ergebniss ist ADCH weil man beim auslesen
>erst das Low und dann das High Byte. Die Reihenfolge ist laut Datenblatt
>vorgeschrieben.

Nicht ganz richtig. Entweder erst Low- dann Highbyte oder nur Highbyte. 
In deinem Fall ist das Lesen des Lowbytes also unnötig.

MfG Spess

von Felix P. (fixxl)


Lesenswert?

Wo im Schaltplan ist der Spannungsregler mit seiner Beschaltung zu 
sehen? Grundsätzlich ist ein Abblockkondensator von 100nF an VCC 
jedenfalls nie verkehrt.

In der ADC-Auslese-Funktion würde ich es mir ersparen, immer eine neue 
Initialisierung zu starten. Eine Initialisierung vor der Endlosschleife 
wäre meines Erachtens die bessere Lösung.

von Fritz B. (kleinfritzchen)


Angehängte Dateien:

Lesenswert?

Das mit dem nur auslesen des ADCH hab ich zwar so nicht verstanden aber 
mein Englisch ist ...5  also nicht sonderlich. Ich hab jetzt einen 610 
Ohm Wiederstand in Reihe zum Poti geschaltet so das also die Max. 
Spannung nicht ganz Vcc wird.
Auf dem Bild ist meine Spannungsversorgung, gespeist wird sie von einem 
9V Block.

von Fritz B. (kleinfritzchen)


Lesenswert?

Ich wusste gar ncht das eine Initialisierung reicht. Schließlich schalte 
ich den ADC immer wieder aus weil ich ja nur einen Zyklus durchlaufen 
lasse. Außerdem will ich mit der Funktion ja auch die Spannung an der 
Diode auslesen und in der Hauptschleife vergleichen um das Relais ein 
oder aus zu schalten.
Reicht es da aus wenn die Initialisierung nur einmal aufgerufen wird?

Ich hab grad mal im Datenblatt nachgeschaut und dort nichts wegen der 
Auslesereihenfolge gefunden. Im AVR Turorial sthet zwar was anderes aber 
ich probier es mal aus nur ADCH auszulesen.

von Peter D. (peda)


Lesenswert?

Fritz Bie schrieb:
> for ( i=0;i<=verz;i++){

Bei verz = 255 -> endlos

von spess53 (Gast)


Lesenswert?

Hi

>Ich wusste gar ncht das eine Initialisierung reicht. Schließlich schalte
>ich den ADC immer wieder aus weil ich ja nur einen Zyklus durchlaufen
>lasse.

An welcher Stelle schaltest du ihn aus?

>Ich hab grad mal im Datenblatt nachgeschaut und dort nichts wegen der
Auslesereihenfolge gefunden. Im AVR Turorial sthet zwar was anderes aber
ich probier es mal aus nur ADCH auszulesen.

Was hältst du davon (Datenblatt):

Consequently, if
the result is left adjusted and no more than 8-bit precision is 
required, it is sufficient to read ADCH.

MfG Spess

von qwertzuiopü+ (Gast)


Lesenswert?

Auch wenn Peter Dannegger das Problem schon gefunden hat, was soll diese 
Zeile?

Fritz Bie schrieb:
> for(i=0;i<1;i++){

Is doch Schwachsinn eine for-Schleife für einen Durchlauf zu 
programmieren.

von Fritz B. (kleinfritzchen)


Lesenswert?

Die Zeile stammt noch aus der ersten Version die mit Word Werten lief.
Ist jetzt so nicht nötig weil ich nicht wie forher den Durchschnitt aus 
4 durchläufen ziehen kann.
Ich versuche grad mir einen Spannungsteiler aus ein paar Wiederständen 
zu basteln. Mit welchem Strom sollte man da arbeiten. Bei dem reinen 10k 
Poti sind es ja 0.0005A. Ich nehme an man sollte nicht wesentlich 
niedriger gehen. Das Problem ist das ich nur 1k,10k,und 25k Potis hab. 
Ich muss erst mal sehen was ich noch so alles an Wiederständen finde.
Ach ja, wenn ich nur einen Abfragezyklus hab bleibt dann die 
Initialisierung erhalten ohne das ich beim neuen abfragen noch mal 
Initialisieren muss?

von Felix P. (fixxl)


Lesenswert?

Hier als Beispiel mal ADC-Funktionen, wie sie aussehen könnten.

Diese Funktion initialisiert den ADC vor der Hauptschleife:
1
void adc_init(void) {
2
  uint8_t __attribute__ ((unused)) result;
3
4
  ACSR |= 1 << ACD;                         // Komparator abschalten
5
        ADMUX |= 1<<ADLAR;                        // Resultat linksbündig
6
7
  ADCSRA |= ((1 << ADPS1) | (1 << ADPS0));  // Frequenzvorteiler 8
8
  ADCSRA |= (1 << ADEN);                    // ADC aktivieren
9
10
  ADCSRA |= (1 << ADSC);                    // eine ADC-Wandlung
11
  while (ADCSRA & (1 <<ADSC));              // auf Abschluss der Konvertierung warten
12
13
  result = ADCH;
14
}

Und diese Funktion wird dann immer zum Auslesen aufgerufen:
1
uint8_t adc_read(uint8_t channel) {
2
  uint8_t adcwert;
3
  channel &= 0x0F;               // Sicherstellen, dass Kanal im erlaubten Bereich liegt
4
  ADMUX &= 0xF0;                 // Kanalbits 0 setzen
5
  ADMUX |= channel;              // Kanal einstellen
6
  ADCSRA |= (1 << ADSC);         // eine Wandlung "single conversion"
7
  while (ADCSRA & (1 << ADSC));  // auf Abschluss der Konvertierung warten
8
  adcwert = ADCH;
9
10
  return adcwert;
11
}

Das gibt keine Probleme, solange du die ADC-Register nicht zwischendurch 
anderweitig überschreibst.

von Fritz B. (kleinfritzchen)


Lesenswert?

danke
ich werd das mal nachher umschreiben. Ich bin jetzt auf die Idee 
gekommen nur die Abfrage des Poti's mit Vcc zu machen und die Abfrage 
der Diode mit der internen Referenz von 1V. Auf diese Weise hoffe ich 
das es funktioniert.
Ich wüsste jetzt nicht wie man die ADC Register anderweitig 
überschreiben könnte. Ich war immer der Meinung das diese Register bei 
interner Verwendung vom Controler automatisch auf dem Stack gesichert 
und wiederhergestellt werden.
Als Ziel ist ja nur ein Vergleich der beiden Abfragen von Poti und Diode 
und daraus resultierend ein Schalten eines Relais für die Heizung. Ich 
denke das man da nicht alzuviel verkehrt machen kann.

von spess53 (Gast)


Lesenswert?

Hi

>ich werd das mal nachher umschreiben. Ich bin jetzt auf die Idee
>gekommen nur die Abfrage des Poti's mit Vcc zu machen und die Abfrage
>der Diode mit der internen Referenz von 1V. Auf diese Weise hoffe ich
>das es funktioniert.

Warum verstärkst du das Diodensignal nicht einfach auf eine vernünftige 
Größe?

MfG Spess

von Cyblord -. (cyblord)


Lesenswert?

Wenn man eben davon absehen würde, heute noch den altbackenen Tiny13 zu 
nehmen, dann könnte man einen Tiny85 nehmen, der bereits eine 
zuschaltbare 20x Verstärkung für die ADCs eingebaut hat.

Und sogar diff. ADCs besitzt. Kann man immer brauchen.

von Fritz B. (kleinfritzchen)


Lesenswert?

Hier mal das fertige Programm (erster Versuch)
1
#include <avr/io.h>
2
#include <util/delay.h>
3
//#define F_CPU 1200000UL
4
#define led  1
5
#define relais  2
6
7
void adc_init(void);
8
uint8_t leseKanal(uint8_t mux);
9
uint8_t poti=0, dioden_wert;
10
int main (void){
11
  DDRB=0x03;
12
  adc_init();
13
  
14
  while (1){
15
    
16
    poti =  leseKanal(0b00100011); //ADLAR Linksbuendig,
17
                    //ADC3 (Pin 2)
18
    dioden_wert = leseKanal(0b0110001); //Interne Referenzspannung,
19
                      //ADLAR Linksbuendig,
20
                      //ADC1 (Pin 7)
21
    if (poti>dioden_wert){
22
      PORTB |= (1<<relais); //Heizung einschalten
23
      PORTB |= (1<<led);  //Betriebsanzeige einschalten 
24
    }else{
25
      PORTB &= ~(1<<relais);  //Heizung ausschalten
26
      PORTB &= ~(1<<led);    //Betriebsanzeige ausschalten
27
    }
28
    _delay_ms(1000);
29
    
30
  } return 0;
31
  
32
}
33
34
//ADC Initialisieren
35
void adc_init(void) {
36
  uint8_t __attribute__ ((unused)) result;
37
38
  ACSR |= 1 << ACD;                         // Komparator abschalten
39
        ADMUX |= 1<<ADLAR;                        // Resultat linksbündig
40
41
  ADCSRA |= ((1 << ADPS1) | (1 << ADPS0));  // Frequenzvorteiler 8
42
  ADCSRA |= (1 << ADEN);                    // ADC aktivieren
43
44
  ADCSRA |= (1 << ADSC);                    // eine ADC-Wandlung
45
  while (ADCSRA & (1 <<ADSC));              // auf Abschluss der Konvertierung warten
46
47
  result = ADCH;
48
}
49
50
//Routine zum einlesen eines Kanales
51
uint8_t leseKanal(uint8_t mux)
52
{
53
  
54
  uint8_t ergebniss;
55
  
56
  
57
  //eigentlicher Abfragezyklus
58
  
59
    
60
    ADCSRA |= (1<<ADSC);
61
    while (ADCSRA & (1<<ADSC)){
62
      ;
63
    }
64
    //ergebniss = ADCL;
65
    ergebniss = ADCH;
66
  
67
  //ergebniss = foo;
68
  //ergebniss = (ergebniss>>2);
69
  return ergebniss;
70
  
71
}

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.