Globale Variable aus ISR verändern

OP (Firma: Thormann) #2733897
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.
Gast #2733914
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?
#2734000
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.
OP (Firma: Thormann) #2734009
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
}
OP (Firma: Thormann) #2734041
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
#2734082
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.
Gast #2734089
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.
Gast #2734090
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.
Gast #2734104
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
OP (Firma: Thormann) #2734858
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
#2734934
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.
#2735017
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.
#2735151
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren