Forum: Mikrocontroller und Digitale Elektronik Ansteueurung von 8 Heizelement durch einem Atmega8


von Patrick N. (emerand)


Angehängte Dateien:

Lesenswert?

Hallo Leute!

Ich muss im Rahmen eines Projekts 8 Heizelementen mit einem Atmega8 
ansteuern. Dabei sollen die Heizelementen
nacheinander für eine bestimmte Zeitspanne ein- und ausgeschaltet
werden. Außerdem soll ein Temperatursensor an jedem Heizelement  die
Temperatur des Heizelement erfassen. Die erfasste Daten sollen direkt an
dem AD-wandler des ATmega8 verschickt werden. Nach der Wandlung sollen 
die Werten in das EEPROM des Atmega8 gespeichert werden und später zur 
Verarbeitung über I²C (TWI) weitergeleitet werden.
Die Temperatursensoren sind dabei einfache analoge sensoren (z.b PT100)

also hier noch mal das Protokoll zusammengefasst:

Heizer1 an --> warte 200sek --> heizer1 aus --> AD wandler an wenn daten 
vorliegen --> Messdaten im EEPROM des Atmega8 speichern --> über TWI 
weiterleiten.

Heizer2 an --> warte 200sek --> heizer2 aus --> AD wandler an wenn daten 
vorliegen --> Messdaten im EEPROM speichern --> über TWI weiterleiten.

usw...
bis
Heizer8 an --> warte 200sek --> heizer8 aus --> AD wandler an wenn daten 
vorliegen  --> Messdaten im EEPROM speichern --> über TWI weiterleiten.

Und das ganze soll dann in C implementiert werden. Nur ich habe keine 
ahnung wo ich anfangen soll. Bis jetzt habe ich die verschiedene 
routinen die ich brauche (eeprom lesen/schreiben, TWI, AD-wandler ..). 
Alle aus diesem Forum (Danke schon mal dafür).

Nun ich habe keine ahnung wie mein Hauptprogramm aussehen soll. Da fehlt 
mir jegliche Ansatz. Vielleicht hat einer schon mal sowas ähnliches in C 
gemacht. Ich wäre ihn für den Code sehr dankbar. Oder ihr könnt mir 
helfen es selbst zu machen.
Danke im voraus.

von Patrick N. (emerand)


Lesenswert?

Sorry!!

Die angehängte Datei soll nicht berücksichtigt werden, denn es gehört 
nicht zu dem Beitrag.

sorry!

von Karl H. (kbuchegg)


Lesenswert?

Patrick N. schrieb:

> also hier noch mal das Protokoll zusammengefasst:
>
> Heizer1 an --> warte 200sek --> heizer1 aus --> AD wandler an wenn daten
> vorliegen --> Messdaten im EEPROM des Atmega8 speichern --> über TWI
> weiterleiten.
>
> Heizer2 an --> warte 200sek --> heizer2 aus --> AD wandler an wenn daten
> vorliegen --> Messdaten im EEPROM speichern --> über TWI weiterleiten.
>
> usw...
> bis
> Heizer8 an --> warte 200sek --> heizer8 aus --> AD wandler an wenn daten
> vorliegen  --> Messdaten im EEPROM speichern --> über TWI weiterleiten.

Bist du dir sicher, dass der Ablauf so laufen soll?
Oder soll es nicht eher so sein, dass die 8 Heizelemente voneinander 
unabhängig ihre Zeitzyklen durchlaufen sollen.

D.h. Heizelement 1 soll sein: 8 Sekunden ein, 5 Sekunden aus
Element 2 soll sein: 6 Sekunden ein, 3 Sekunden aus
Element 3 soll sein: 2 Sekunden ein, 4 Sekunden aus


in einem Zeitdiagramm soll das dann so aussehen
1
  Element  |
2
           |
3
       3   | *  *              *  *              *  *         
4
           |
5
       2   | *  *  *  *  *  *           *  *  *  *  *  *  
6
           |
7
       1   | *  *  *  *  *  *  *  *                 *  *  *  *
8
           |
9
       ----+--------------------------------------------------------> Zeit
10
             0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
11
12
( * ist ein Zeitpunkt, an dem der entsprechende Heizer ein ist)
So würde das nämlich mehr Sinn machen. Das was du beschrieben hast, 
macht nicht viel Sinn, weil die Veränderung des Zeitschemas eines 
Heizelements die Pausen aller anderen Heizelemente (und damit ihrer 
abgegebenen Durchschnittsenergie) verändert.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Siehe hier: AVR-GCC-Tutorial

von holger (Gast)


Lesenswert?

>Ich muss im Rahmen eines Projekts

Ach musst du das? Wer ist denn der Projektleiter der gerade
dich dazu ausgesucht hat? Warum hat er dich ausgesucht?

>Und das ganze soll dann in C implementiert werden. Nur ich habe keine
>ahnung wo ich anfangen soll.

Wie wäre es mit C lernen? Vergiss dein Projekt solange bis du
es geschafft hast eine LED einzuschalten.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Bist du dir sicher, dass der Ablauf so laufen soll?
> Oder soll es nicht eher so sein, dass die 8 Heizelemente voneinander
> unabhängig ihre Zeitzyklen durchlaufen sollen.


Vergiss diese Nachfrage.

Nachdem ich dich zb hier
Beitrag "3 led mit atmega8"
wiedergefunden habe, glaub ich dir deine beschriebene Aufgabenstellung 
(auch wenn sie nach wie vor, sagen wir mal, "suboptimal" ist)


Woran scheitert es denn?

(Die Sache mit dem ADC, dem EEPROM und TWI stellst du jetzt erst mal 
zurück. Es ist sinnlos, wenn du im Moment daran einen Gedanken 
verschwendest. Du hast noch ganz andere Probleme. Viel grundlegendere.)

> Ich wäre ihn für den Code sehr dankbar. Oder ihr könnt mir
> helfen es selbst zu machen.

Du machst und wenn du konkrete Fragen hast, dann helfen wir. Aber 
irgendwie werde ich das Gefühl nicht los, dass das eigentlich eine 
Schulaufgabe ist und du mächtig hinterher hinkst.

von Patrick N. (emerand)


Lesenswert?

Erstmal danke für die schnelle antwort!

>Bist du dir sicher, dass der Ablauf so laufen soll?

Ja genauso soll es laufen erstmal laufen!

von Tom (Gast)


Lesenswert?

Patrick N. schrieb:
> Nun ich habe keine ahnung wie mein Hauptprogramm aussehen soll.

Dein Hauptprogramm könnte aus einer Initialisierung und einem kleinen 
Taskmanager bestehen, der die erforderlichen Tasks anstößt. Dazu wäre 
vielleicht eine Uhr ganz praktisch, die einen Sekundentakt als Basis für 
die Zeitabläufe bereitstellt.

von Patrick N. (emerand)


Lesenswert?

Hallo Leute! ich habe mir eure Ratschläge zu Herzen genommen und konnte 
nach sehr viel Anlaufe diesen ersten Code zusammen basteln.
Da ich es hardwaremäßig nicht testen kann brauche eure Hilfe.
Und zwar meint ihr das es das tut was ich oben beschrieben habe?
wie kann ich hier mein Interrupt(der timer1_ovf der eigentlich jede 
Sekunde die Daten konvertieren soll) auslösen?
Danke im voraus

Hier ist der code
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include <stdint.h>
5
#include <Stdio.h>
6
#include <avr/eeprom.h>
7
#include <util/delay.h>
8
9
10
#define F_CPU  1000000UL                 // Interner Takt 1MHz
11
12
#define PRESCALER 1024;                  // Timer 1 Vorteiler
13
#define STARTWERT 65537-F_CPU/PRESCALER; //Zähler Startwert, überlauf bei 65536
14
#define HEIZDAUER 10
15
#define SENSOR_NR 8
16
#define DELAY 1
17
18
/* Variablen */  
19
unsigned int adWert;                         // AD-Wert 
20
unsigned int eeFooWord EEMEM = 280;          // EEprom Speicher
21
22
/** Unterprogramme */
23
24
//warte 1sek
25
void warten_1sek() 
26
{
27
  unsigned long n;
28
  for(n=0; n<50; n++)
29
    _delay_ms(20);   // 50*(20/1) ms = 1Sekunde bei 1MHz
30
}
31
32
//warte n sek
33
void warten_Nsek (unsigned long n) 
34
{
35
    unsigned long k;
36
    for (k=0; k<n; k++)
37
      warten_1sek();
38
}
39
40
41
/* Initialisierung des Mikrocontroller */
42
void port_init(void)                 // initialisiert die ports
43
{                                     
44
  DDRB = 0b00000000;                // PORT B2, B3, B5 als Ausgang (SPI modul für 74hc595)
45
  DDRC = 0b00110000;           // PORT C4 und C5 als Ausgang (TWI/ I2C modul), PORT C0 als Eingang der analogen Werten
46
}
47
48
void ad_init(void)                  // initialisiert der  a/d-wandler 
49
{
50
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung 2,5V nutzen (siehe dantenblatt)
51
  ADCSRA = 0b11000111;                  // enable ADC
52
}
53
54
55
void timer_init(void)              // timer 1 und 2 overflow 
56
{
57
  TCCR1B = 0b00000101;               // Vorteiler (Prescaler) auf 1024 stellen
58
  TIMSK |= (1 << TOIE1);            // Timer 1 Overflow Interrupt enable
59
  TCNT1  = STARTWERT;               // vorbesetzen (zählt bis 65535) 
60
}
61
 
62
63
//schreibe den Temperatur ins EEPROM
64
void Schreibe_temp(unsigned int wert)
65
{
66
   eeprom_write_word(&eeFooWord, wert); // schreibe in EEPROM
67
}
68
69
70
//lese PORTC0 (ADC0)
71
int leseAD(void)
72
{
73
  uint16_t wert;                    // Hilfsvariable
74
  uint8_t  highwert;                // Hilfsvariable
75
  ADCSR |= (1<<ADSC);               // eine Wandlung starten
76
  //while ( ADCSR & (1<<ADSC) ) {;}   // auf Abschluss der Konvertierung warten
77
  wert     = ADCL;                  // Low  auslesen  
78
  highwert = ADCH;                  // High auslesen
79
  wert = wert + highwert*256;       // 10bit Wert berechnen
80
  return wert;
81
}
82
83
//Timer Interrupt - kommt genau jede Sekunde
84
SIGNAL (TIMER1_OVF_vect){           // Timer1 overflow 
85
  cli();                            // Alle Int. sperren solange in INT-Routine
86
  TCNT1 = STARTWERT;                // Vorbesetzen (1s)
87
  adWert=leseAD();                  // lese Spannungswert 
88
  sei();                            // enable interrupts
89
}
90
91
92
93
94
95
int main ()
96
{
97
  unsigned long n;
98
  port_init();
99
  ad_init();
100
  timer_init();
101
  sei();        
102
  while(1)
103
  {
104
     
105
    for (n=0; n< SENSOR_NR; n++)
106
    {
107
      PORTB |=(1<<n);         // sensor an
108
      adWert = leseAD();
109
      warten_Nsek(HEIZDAUER);
110
      PORTB &=~(1<<n);          // sensor aus
111
      Schreibe_temp(adWert);
112
    }     
113
  }       
114
}

von Falk B. (falk)


Lesenswert?

@  Patrick N. (emerand)

>Und zwar meint ihr das es das tut was ich oben beschrieben habe?

Als Ansatz OK, wenn gleich natürlich mit Raum für Verbesserungen.

>wie kann ich hier mein Interrupt(der timer1_ovf der eigentlich jede
>Sekunde die Daten konvertieren soll) auslösen?

Lies mal was über Timer und Interrupt.

MfG
Falk

von Patrick N. (emerand)


Lesenswert?

Ich freue mich natürlich auf jede verbesserung!
Welche hättest du denn Falk?
danke für die schnelle antwort
Mfg

von Falk B. (falk)


Lesenswert?

Lies mein Posting und die Links darin.

von Karl H. (kbuchegg)


Lesenswert?

Patrick N. schrieb:
> Ich freue mich natürlich auf jede verbesserung!

Da gibts schon noch einiges essentielles
1
//Timer Interrupt - kommt genau jede Sekunde
2
SIGNAL (TIMER1_OVF_vect){           // Timer1 overflow 
3
  cli();                            // Alle Int. sperren solange in INT-Routine
4
  TCNT1 = STARTWERT;                // Vorbesetzen (1s)
5
  adWert=leseAD();                  // lese Spannungswert 
6
  sei();                            // enable interrupts
7
}

In einer ISR kümmerst du dich NICHT um cli() und sei(). Das passiert von 
alleine. Und ganz im Gegenteil, mit einem sei() kannst du dich in 
Teufels Küche bringen.

Weiter:
SIGNAL ist veraltet. Benutze den ISR Mechanismus, wie er seit vielen 
Jahren Standard und auch dokumentiert ist.

Weiters:
Entweder du liest den ADC in dieser ISR aus (nicht empfehlenswert) oder 
du machst das in der Hauptschleife. Aber nicht an beiden Stellen! Die 
ISR 'benachrichtigt' die Hauptschleife, dass es wieder an der Zeit ist 
eine Messung vorzunehmen:
1
...
2
volatile uint8_t performMeasure;
3
4
ISR( .... )
5
{
6
  performMeasure = 1;
7
}
8
9
10
int main()
11
{
12
  ....
13
14
  while( 1 ) {
15
16
    if( performMeasure ) {
17
      performMeasure = 0;
18
      adWert=leseAD();
19
      Schreibe_temp(adWert);
20
    }
21
22
  }
23
}

> wie kann ich hier mein Interrupt(der timer1_ovf der eigentlich
> jede Sekunde die Daten konvertieren soll) auslösen?

Den brauchst du nicht auslösen. Wenn der Timer seinen Maximalwert 
erreicht hat, dann löst ER den Interrupt aus. Das passiert also ganz von 
alleine. Das ist ja (mehr oder weniger) der Sinn von Timern, dass sie 
Dinge ganz von alleine auslösen können.

> Da ich es hardwaremäßig nicht testen kann brauche eure Hilfe.
Das musst du abstellen!
Testen ist essentiell wichtig bei der Softwareentwicklung. Dein Code ist 
umfangmässig an der Kippe, an der man zumindest als Neuling schon längst 
hätte mit Testen anfangen müssen.

von Karl H. (kbuchegg)


Lesenswert?

Und die beiden Funktionen
1
//warte 1sek
2
void warten_1sek() 
3
{
4
  unsigned long n;
5
  for(n=0; n<50; n++)
6
    _delay_ms(20);   // 50*(20/1) ms = 1Sekunde bei 1MHz
7
}
8
9
//warte n sek
10
void warten_Nsek (unsigned long n) 
11
{
12
    unsigned long k;
13
    for (k=0; k<n; k++)
14
      warten_1sek();
15
}

die löscht du gleich mal mitsamt ihrer Verwendung aus deinem Code raus. 
Die willst du nicht haben. Du hast Timer und mit denen wird gearbeitet.

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.