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.
Sorry!! Die angehängte Datei soll nicht berücksichtigt werden, denn es gehört nicht zu dem Beitrag. sorry!
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.
>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.
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.
Erstmal danke für die schnelle antwort!
>Bist du dir sicher, dass der Ablauf so laufen soll?
Ja genauso soll es laufen erstmal laufen!
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.
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 | }
|
@ 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
Ich freue mich natürlich auf jede verbesserung! Welche hättest du denn Falk? danke für die schnelle antwort Mfg
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.