Hallo! Bin ganz neu im Forum, und hoffe es kann mir jemand bei meinem Problem weiterhelfen. Ich versuche eine globale variabel in einer ISR zu setzen um sie dann in meiner main() weiter zu verwenden. Leider bleibt sie immer 0, wenn ich sie testhalber in der ISR deklariere funzt die zuweisung, jedoch logischerweise nur bis zum ende der ISR. THX in vorraus! CODE: //---------------------------------------------------------------------- #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards #include <avr/io.h> // AVR Register und Konstantendefinitionen #include <inttypes.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdint.h> volatile int8_t globvar1; ISR(TIM1_COMPB_vect) { globvar1 = 55; } main () // Hauptprogramm, startet bei Power ON und Reset { DDRA=0b11111000; DDRB=0b00000000; DDRC &= ~ ((1<<PC0) | (1<<PC1) | (1<<PC2)); PCMSK1 |= ((1<<PCINT8)|(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11)); //Pins B0-B3 für Pin change interrupt in Maske 1 setzen GIMSK |= (1<<PCIE1); //****************TIMER*************** // Timer 0 konfigurieren TCCR1A = 0b00001011; //TCCR0B = 0b00000011; TIMSK = 0b00010000; //OCIE0A = 1 => Timer output compare A enable OCR1A = 0b00001010; // auf 10 laden sei(); while (1) { globvar1++; } } PS: Dass das Programm ziemlich sinnfrei ist weiß ich selber, ist ja nur zum üben.
1 | ISR(TIM1_COMPB_vect) |
2 | ^ |
3 | TIMSK = 0b00010000; //OCIE0A = 1 => Timer output compare A enable |
4 | ^ |
Des weiteren:
> GIMSK |= (1<<PCIE1);
Wo ist die ISR dafür?
noch vergessen: Ich empfehle dir die bits in den Konfigurationsregistern per Schiebeoperation und Namensersetzung zu setzen. Das ist viel übersichtlicher. Also z.B. statt TCCR1A = 0b00001011; TCCR1A = (1<<COM1B0)|(1<<WGM11)|(1<<WGM10); Willst du COM1B0 setzen?
THX für die schnellen Antworten Das ist nicht der ganze code da der andere teil ja funzt (die PCINT ISR's), .. und ja der Timer läuft und im suimulator sehe ich auch das er in die ISR springt. Testen tu ich das ganze mit dem AVR simulator.
Robert Thormann schrieb: > THX für die schnellen Antworten > > > Das ist nicht der ganze code da der andere teil ja funzt (die PCINT > ISR's), .. und ja der Timer läuft und im suimulator sehe ich auch das er > in die ISR springt. Aber nicht mit dem von dir geposteten Programm. Tip: Es ist immer gut, wenn man ein Programm abspeckt, das man es vor dem posten mal testet, ob sich das Problem dort überhaupt zeigt, bzw. ob man nicht beim Abspecken selber einen Fehler gemacht hat.
OKY, dann der ganze code mit allem Mist den ich sonst ncoh so ausprobiert hab ;)
1 | /*
|
2 | * UwTasterbox_2.c
|
3 | *
|
4 | * Created: 26.06.2012 11:33:17
|
5 | * Author: robert.thormann
|
6 | */
|
7 | |
8 | /*
|
9 | * AVRGCC8.c
|
10 | *
|
11 | * Created: 26.06.2012 09:29:00
|
12 | * Author: robert.thormann
|
13 | */
|
14 | |
15 | //----------------------------------------------------------------------
|
16 | #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards
|
17 | #include <avr/io.h> // AVR Register und Konstantendefinitionen |
18 | #include <inttypes.h> |
19 | #include <util/delay.h> |
20 | #include <avr/interrupt.h> |
21 | #include <stdint.h> |
22 | |
23 | |
24 | static volatile int8_t globvar1; |
25 | |
26 | /*
|
27 | volatile int8_t Merker1;
|
28 | volatile int8_t Merker2;
|
29 | volatile unsigned int i=0;
|
30 | volatile unsigned int j=0;
|
31 | //Variablen für die Zeit
|
32 | volatile int millisekunden;
|
33 | int sekunde;
|
34 | int minute;
|
35 | int stunde;
|
36 | */
|
37 | //----------------------------------------------------------------------
|
38 | //**********************************************Delay CODE*********************************************************************************************
|
39 | |
40 | void warte_ms(unsigned int wartezeit) |
41 | {
|
42 | volatile unsigned int i; // Schlaufenzähler für Millisekunden-Loop |
43 | while(wartezeit != 0) // Schlaufe für jede Millisekunde |
44 | {
|
45 | i = F_CPU/17000; // Berechne Startwert für Millisekunden-Loop |
46 | |
47 | while(i != 0) // Schlaufe, solange i nicht gleich null ist |
48 | |
49 | {
|
50 | i = i-1; // i minus eins |
51 | } // Schlaufen-Ende wenn i gleich null ist |
52 | wartezeit = wartezeit-1; // minus eine Millisekunde |
53 | } // Schlaufen-Ende wenn wartezeit gleich 0 ist |
54 | |
55 | } // Funktionsende => return |
56 | |
57 | |
58 | //************************************************ADC BEHANDLUNG********************************************************************************
|
59 | uint16_t readADC(uint8_t channel) |
60 | {
|
61 | // Funktion 1 zum Auslesen der Spannung
|
62 | |
63 | uint8_t i; // Variablen definieren (Zählervariable i + Resultat) |
64 | uint16_t result = 0; |
65 | |
66 | ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1); //ADEN = ADC Enable |
67 | // wenn adps1+2 on sind und adps0 off, dann ist der Teilungsfaktor 64 (Tabelle Datasheet)
|
68 | |
69 | ADMUX = channel; //Kanal wählen; REFs0+1 -> interne Referenz 2,56V verwenden, REFS1 gibt es bei Attiny13 nicht |
70 | //externen Kondensator mit 100nF (Aufdruck 104) an AREF auf Masse
|
71 | |
72 | //Dummy-Readout (unten), misst 1* Ergebnis, wird nicht gespeichert
|
73 | ADCSRA = ADCSRA | (1<<ADSC); // Schaltet bei ADCSRA das ADSC-Bit ein, d.h. Messung starten |
74 | while(ADCSRA & (1<<ADSC)); //Warte bis Messvorgang vorbei ist |
75 | |
76 | // Nun 3* Spannung auslesen, Durchschnittswert ausrechnen
|
77 | for (i=0; i<3; i++) |
78 | {
|
79 | // Schleife, startet 3*
|
80 | ADCSRA = ADCSRA |(1<<ADSC); // Einmal messen |
81 | while(ADCSRA & (1<<ADSC)); //Warte bis Messung vorbei |
82 | |
83 | result = result + ADCW; // Resultate zusammenzählen (R1+R2+R3) -> später alles /3 |
84 | }
|
85 | |
86 | ADCSRA = ADCSRA & (~(1<<ADEN)); //ADC wieder deaktivieren |
87 | |
88 | result=result/3; // Durchschnittswert |
89 | |
90 | return result; |
91 | }
|
92 | |
93 | |
94 | |
95 | //************************************Taster abfragen*************************************************************************************************
|
96 | |
97 | |
98 | void Taster(void) |
99 | {
|
100 | uint8_t tmp_sreg; // temporaerer Speicher fuer das Statusregister |
101 | |
102 | tmp_sreg = SREG; // Statusregister (also auch das I-Flag darin) sichern |
103 | cli(); // Interrupts global deaktivieren |
104 | |
105 | /* hier "unterbrechnungsfreier" Code */
|
106 | |
107 | |
108 | |
109 | SREG = tmp_sreg; // Status-Register wieder herstellen |
110 | // somit auch das I-Flag auf gesicherten Zustand setzen
|
111 | }
|
112 | |
113 | ISR(PCINT1_vect) //ISR Kommt wenn irgendein Taster gedrückt ist |
114 | |
115 | {
|
116 | cli(); |
117 | if (!(PINB & (1<<PINB0))) //wegen ACTIVE LO von Eingang ==> Taste 1 gedrückt |
118 | {
|
119 | blink(1); |
120 | OUT1(); |
121 | }
|
122 | |
123 | |
124 | if (!(PINB & (1<<PINB1))) //wegen ACTIVE LO von Eingang ==> Taste 2 gedrückt |
125 | {
|
126 | blink(2); |
127 | OUT2(); |
128 | }
|
129 | |
130 | sei(); |
131 | }
|
132 | |
133 | |
134 | |
135 | void OUT1(void) |
136 | {
|
137 | uint16_t result1 = readADC(0); // ruft die ADC Funktion auf an Pin0 =ADC0 |
138 | PORTA |= (1<<PA4); //1 ein |
139 | warte_ms(result1); |
140 | PORTA &= ~(1<<PA4); //1 ein |
141 | |
142 | }
|
143 | void OUT2(void) |
144 | {
|
145 | uint16_t result2 = readADC(1); // ruft die ADC Funktion auf an Pin0 =ADC0 |
146 | PORTA |= (1<<PA3); //1 ein |
147 | warte_ms(result2); |
148 | PORTA &= ~(1<<PA3); //1 ein |
149 | |
150 | |
151 | }
|
152 | |
153 | void blink(uint8_t channel) |
154 | {
|
155 | if (channel == 1) |
156 | {
|
157 | PORTA |= (1<<PA6); //Taster LED Bedienen |
158 | warte_ms(50); |
159 | PORTA &= ~(1<<PA6); |
160 | warte_ms(50); |
161 | PORTA |= (1<<PA6); //Taster LED Bedienen |
162 | warte_ms(50); |
163 | PORTA &= ~(1<<PA6); |
164 | }
|
165 | |
166 | else if (channel == 2) |
167 | {
|
168 | PORTA |= (1<<PA7); //Taster LED Bedienen |
169 | warte_ms(50); |
170 | PORTA &= ~(1<<PA7); |
171 | warte_ms(50); |
172 | PORTA |= (1<<PA7); //Taster LED Bedienen |
173 | warte_ms(50); |
174 | PORTA &= ~(1<<PA7); |
175 | }
|
176 | |
177 | else
|
178 | {
|
179 | return; |
180 | }
|
181 | }
|
182 | |
183 | |
184 | ISR(TIM1_COMPB_vect) |
185 | {
|
186 | |
187 | globvar1 = 55; |
188 | |
189 | /*if(millisekunden == 1000)
|
190 | {
|
191 | sekunde = sekunde + 1;
|
192 | millisekunden = 0;
|
193 | if(sekunde == 60)
|
194 | {
|
195 | minute++;
|
196 | sekunde = 0;
|
197 | }
|
198 | if(minute == 60)
|
199 | {
|
200 | stunde++;
|
201 | minute = 0;
|
202 | }
|
203 | if(stunde == 24)
|
204 | {
|
205 | stunde = 0;
|
206 | }
|
207 | }*/
|
208 | |
209 | }
|
210 | |
211 | |
212 | |
213 | main () // Hauptprogramm, startet bei Power ON und Reset |
214 | {
|
215 | |
216 | |
217 | DDRA=0b11111000; |
218 | DDRB=0b00000000; |
219 | DDRC &= ~ ((1<<PC0) | (1<<PC1) | (1<<PC2)); |
220 | PCMSK1 |= ((1<<PCINT8)|(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11)); //Pins B0-B3 für Pin change interrupt in Maske 1 setzen |
221 | GIMSK |= (1<<PCIE1); |
222 | //****************TIMER***************
|
223 | // Timer 0 konfigurieren
|
224 | TCCR1A = 0b00001011; |
225 | //TCCR0B = 0b00000011;
|
226 | TIMSK = 0b00010000; //OCIE0A = 1 => Timer output compare A enable |
227 | OCR1A = 0b00001010; // auf 10 laden |
228 | sei(); |
229 | |
230 | while (1) |
231 | {
|
232 | |
233 | globvar1 ++; |
234 | }
|
235 | }
|
Robert Thormann schrieb: > OKY, dann der ganze code mit allem Mist den ich sonst ncoh so > ausprobiert hab ;) Auch hier ist der erste Teil meines obigen Posts gültig. Die ISR wird also nie ausgeführt. Wenn du im Simulator was anderes siehst, dann ist der irgendwie durcheinander gekommen (oder im Simulator ist der falsche Controller ausgewählt).
Hmm versteh ich nicht. die IST ISR(TIM1_COMPB_vect) { globvar1 = 55; /*if(millisekunden == 1000) { sekunde = sekunde + 1; millisekunden = 0; if(sekunde == 60) { minute++; sekunde = 0; } if(minute == 60) { stunde++; minute = 0; } if(stunde == 24) { stunde = 0; } }*/ } wird ausgeführt sobald mein timer 1 den wert 0A erreicht OCR1A = 0b00001010; // auf 10 laden
Robert Thormann schrieb: > wird ausgeführt sobald mein timer 1 den wert 0A erreicht Aber nicht bei dem gezeigten Code, weil dort der passende Interrupt gar nicht enabled wird (sondern ein ganz anderer). PS: Zur Sicherheit solltest du aber vielleicht mal sagen, welchen Controller du überhaupt benutzt (kann aber eigentlich nur ATtiny25/45/85 sein).
ist ein TINY40 TIMSK = 0b00010000; und ich denke das hier der interrupt aktiviert wird,
BZW. wenn ich das ganze in meine Hardware lade und einen Ausgang in der ISR setze und in der while(1) lösche flunkert der in der eingestellten Zeit (nur mit oszi zu sehen gg)
Robert Thormann schrieb: > ist ein TINY40 > > TIMSK = 0b00010000; > > und ich denke das hier der interrupt aktiviert wird, Bei einem Tiny40 tatsächlich. Dann stimmt aber der Kommentar dahinter nicht. Gutes Beispiel, warum man den Controller immer gleich von Anfang an mit nennen sollte. Denn so war ich auf Raten angewiesen und habe auf Tiny25/45/85 getippt, denn nur dort passt der Name der ISR (TIM1_COMPB_vect), des Registers (TIMSK) und der Kommentar in der Zeile zusammen.
.. und abgesehen von den ganzen vermeindlichen ISR Problemen funzt ja der teil while (1) { globvar1++; } schon garnicht weil globvar1 steht immer auf 0 und lässt sich nicht hochzählen. lg Robert
SRY ic hhab vergessen das am anfang zu erwähnen dass es ein tiny40 ist, wie gesagt bin neu in diesem Forum :)
TCCR0B auskommentiert, sollte aber dafür sorgen, daß der Timer nicht läuft. Ich kenne das Datenblatt des benutzten Prozessors zwar nicht, aber falls das einigermaßen symmetrisch läuft, muss der Timer auch gestartet werden. Das meinte ich mit meiner Suggestivfrage und ich glaub Herr Buchegger ebenfalls.
Zum debuggen: Mach doch mal ein neues Projekt und initialisier nur den ocr des Timers und lass in der isr eine Led Blinken. Das muss ohne irgendwelchen Ballast ja erst mal sicher klappen - und das ist am einfachsten ja in der Insellösung, da suchen alle auch leichter nach dem Problem wenn der Code klein ist.
unregistered schrieb: > TCCR0B auskommentiert, sollte aber dafür sorgen, daß der Timer nicht > läuft. Bei einem Tiny40 passt das schon, da gibt es gar kein TCCR0B (und die CS-Bits sind in TCCR0A).
Ok kann man nicht von a auf b schließen. Vielleicht doch besser informieren ,-) Den Timer samt isr ans laufen zu bringen, d.h. ein ganz eigenes Projekt nur damit, würde ich umso mehr als notwendiges Ziel sehen
Ähm, ein TCCR0B gibt es doch. Aber es ging ja auch eigentlich um Timer 1, und ein TCCR1B gibt es nicht. ;-)
Ähm while (1) { globvar1++; } schon mal was von atomaren Zugriff gehört? while (1) { cli(); globvar1++; sei(); } Und aus den ISR nimmst du die sei() und cli() alle raus. Die will ich nicht gesehen haben.
Guten Morgen! Das mit dem atomaren zugriff stimmt schon, jedoch ändert das nichts an meinem Problem! es ligt ja eigentlcih nicht an der ISR wie ich herausgefunden habe, ich kann eine "global" definierte Variabel nicht beschreiben, ev. mache ich was bei der Deklaration falsch? #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards #include <avr/io.h> // AVR Register und Konstantendefinitionen #include <inttypes.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdint.h> volatile int8_t globvar1; LG Robert
Es gibt doch auch zumindest die Möglichkeit, daß der Simulator da einen Bug hat? Haste schon mal ein entkerntes Programm versucht?
Robert Thormann schrieb: > Guten Morgen! > > Das mit dem atomaren zugriff stimmt schon, jedoch ändert das nichts an > meinem Problem! Doch tut es. Denn der µC kann globavr1++ nicht in EINEM Schritt ausführen. Was muss er machen globvar lesen globvar um 1 erhöhen globvar zurückschreiben JEDER Interrupt, der irgendwo dazwischen ausgeführt wird, beschreibt zwar deine Variable, aber: in der Hauptschleife wird der Effekt sofort wieder zunichte gemacht, da in der Hauptschleife der Wert zurückgeschrieben wird, der vorher gelesen wurde (und um 1 erhöht). Und da in deiner Hauptschleife sonst nichts weiter passiert, ist die Wahrscheinlichkeit sehr gross, dass dein Interrupt genau immer wieder dann erfolgt wenn die Hauptschleife die globvar schon ausgelesen hat.
Ich habe um zu beweisen das es nicht am atomaren zugriff liegt das I flag abgeschalter und in der main nur die Variable auf einen wert gesetzt! ist aba noch immer 0
Jetzt muss ich auch nachfragen. Wie testest du? Simulator? reale Hardware? Was zählt ist immer nur die reale Hardware. Und wenn es da ein Problem mit globalen Variablen gäbe, dann hätten ca. 130 tausend 5 hundert 8 und 9 zig Programmierer, die deinen Compiler benutzen, bereits laut aufgeheult.
Karl Heinz Buchegger schrieb: > Was zählt ist immer nur die reale Hardware. > Und wenn es da ein Problem mit globalen Variablen gäbe, dann hätten ca. > 130 tausend 5 hundert 8 und 9 zig Programmierer, die deinen Compiler > benutzen, bereits laut aufgeheult. Nun ja, der Tiny40 ist einer der Brain-Dead-Tiny, da sind solche grundlegenden Probleme nicht ganz so unwahrscheinlich. Wenn ich den Code z.B. dem Studio5.0 zum Fraß vorwerfe, dann entsteht folgendes für das Inkrementieren von globavr1:
1 | 1d6: 80 91 40 00 lds r24, 0x0040 |
2 | 1da: 8f 5f subi r24, 0xFF ; 255 |
3 | 1dc: 80 93 40 00 sts 0x0040, r24 |
Und das ist definitiv falsch, denn bei den Brain-Dead sind lds und sts nur ein Word groß. Keine Ahnung wie es bei 5.1 oder 6.0 aussieht.
Hier sollte die Ursache des problems und eine möglich Lösung stehen : http://www.wutj.info/attiny10-binutils-patch Danke an Sternst für den Tipp! @ Buchegger! Das Aufheulen der 130598 Programmierer war warscheinlich. icht laut genug! Aber ab jetzt sind es ja 130599 ;) Ich werde den lösungsvorschlag testen und das Ergebnis natürlich posten. lg
Robert Thormann schrieb: > @ Buchegger! Das Aufheulen der 130598 Programmierer war warscheinlich. > icht laut genug! Aber ab jetzt sind es ja 130599 ;) Tatsächlich. Hätt ich nicht gedacht. (und ich hab mich schon gefragt, was wohl mit "brain dead" gemeint sein könnte)
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.