Forum: Compiler & IDEs Globale Variable aus ISR verändern


von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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.

von unregistered (Gast)


Lesenswert?

Läuft dein Timer überhaupt? Wie testest du das Programm?

von Stefan E. (sternst)


Lesenswert?

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?

von unregistered (Gast)


Lesenswert?

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?

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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
}

von Stefan E. (sternst)


Lesenswert?

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).

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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).

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

ist ein TINY40

TIMSK =  0b00010000;

und ich denke das hier der interrupt aktiviert wird,

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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)

von Stefan E. (sternst)


Lesenswert?

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.

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

.. 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

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

SRY ic hhab vergessen das am anfang zu erwähnen dass es ein tiny40 ist, 
wie gesagt bin neu in diesem Forum :)

von unregistered (Gast)


Lesenswert?

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.

von unregistered (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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).

von unregistered (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

Ähm, ein TCCR0B gibt es doch.
Aber es ging ja auch eigentlich um Timer 1, und ein TCCR1B gibt es 
nicht. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Ä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.

von Robert T. (Firma: Thormann) (robertthormann)


Lesenswert?

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

von unregistered (Gast)


Lesenswert?

Es gibt doch auch zumindest die Möglichkeit, daß der Simulator da einen 
Bug hat?
Haste schon mal ein entkerntes Programm versucht?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Robert Thormann (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Robert Thormann (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.