Forum: Mikrocontroller und Digitale Elektronik Globale Variable ist irgendwie nicht global?!


von Sefco (Gast)


Lesenswert?

Hallo!

Thema: RC-Auto
Folgendes soll mein Programm machen:
Ich möchte den Hebel meiner Fernsteuerung komplett auslenken und damit 
eine LED anschalten. Dann möchte ich die LED wieder ausschalten können, 
indem ich den Hebel zurück in Mittelstellung bringe und anschließend 
wieder auslenke.

Einfach erklärt:
start:
Hebel MITTE
Hebel HOCH: LED an
Hebel MITTE
Hebel HOCH: LED aus
goto start;


Es geht hierbei ja darum, mit einem Interrupt die steigende Flanke des 
Empfängers zu detektieren und dann durch Warten (max. 2 us) und erneutes 
abfragen des PINs, festzustellen, wie der Hebel ausgelenkt ist.

Das ganze klappt wunderbar, solange ist meine LED im Interrupt Vektor 
schalte. Nutze ich allerdings eine globale Variable, um den 
Schaltvorgang in die main-Funktion zu bringen, klappt das nicht. Die 
Variable on1 die global definiert ist wird irgendwie nicht verändert, 
oder bzw. wird verändert, aber die main Funktion scheint das nicht zu 
sehen. Weiß jemand warum?
1
#include <avr/io.h>          
2
#include "util/delay.h"
3
#include <avr/interrupt.h>
4
5
uint8_t reset = 0;
6
uint8_t on1 = 0;
7
8
int main()
9
{
10
11
  DDRB = 0b11111111; //PORTB auf Ausgang schalten; LED angeschlossen
12
  PORTB = 0b11111111;
13
  DDRD = 0b00000000; //PORTD auf Eingang schalten
14
  
15
  GICR = (1 << INT1); //INT0-Interrupt aktivieren
16
17
  MCUCR = (1 << ISC11)|(1 << ISC10); //Aktiviere Sensitivität auf steigende Flanke
18
19
  sei(); //Generell Interrupts aktivieren
20
21
22
  while (1) //Hauptschleife
23
  {
24
    if(on1==1)
25
    {  
26
      PORTB =~ PORTB;
27
    }
28
  }
29
30
  return 0;
31
32
}
33
34
35
ISR(INT1_vect) //Interruptfunktion: Hier wird hingesprungen, wenn ein Interrupt ausgelöst werden soll.
36
{
37
38
  if(reset==0) //Muss Hebel in Mitte? reset=0 NEIN ; reset=1 JA
39
  {
40
    //Wird Fernsteuerungshebel ausgelenkt? --> Impulsbreite beträgt mind. 1,8us
41
    _delay_us(1800);  
42
    if(PIND & (1 << PD3)) //Ist der Pin nach 1,8us noch High?
43
    {
44
      on1=1;  //Ja ist er: Hebel ist fast ganz ausgelenkt --> LED einschalten
45
      reset = 1; //Hebel muss in Mitte!
46
47
    }
48
  }
49
50
  else //Hebel muss gesenkt werden, damit er durch erneutes Auslenken die LED wieder ausschalten kann
51
  {
52
    _delay_us(1600);  
53
    if( !(PIND & (1 << PD3)) ) //Wenn nach 1,6us kein High mehr an Pin anliegt --> Hebel ist in Mittelstellung
54
    {
55
      reset = 0; 
56
    }
57
  }
58
59
60
}

von Hugo (Gast)


Lesenswert?

probier mal

volatile uint8_t on1 = 0;

von Simon G. (grosi)


Lesenswert?

Hallo,
versuch es einmal mit volatile uint8_t on1 = 0.
Mfg

von Sefco (Gast)


Lesenswert?

Das klappt schon viel besser! Kann mir einer erklären was das genau 
bedeutet? Ich hab das nicht verstanden was genau da passiert wenn ich 
das weglasse...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Sefco schrieb:
> Ich hab das nicht verstanden was genau da passiert wenn ich
> das weglasse...

Ganz einfach: Ich setze eine globale Variable auf 2.
Preisfrage: Welchen Wert hat die Variable?

von Sefco (Gast)


Lesenswert?

>Ganz einfach: Ich setze eine globale Variable auf 2.
>Preisfrage: Welchen Wert hat die Variable?

Den Wert 2. Wieso muss ich dann volatiel davor packen?

von Lukas K. (carrotindustries)


Lesenswert?

Sefco schrieb:
> Das klappt schon viel besser! Kann mir einer erklären was das genau
> bedeutet? Ich hab das nicht verstanden was genau da passiert wenn ich
> das weglasse...

Ist in AVR-GCC-Tutorial: Datenaustausch mit Interrupt-Routinen 
erschöpfend ausgeführt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Sefco schrieb:
>>Ganz einfach: Ich setze eine globale Variable auf 2.
>>Preisfrage: Welchen Wert hat die Variable?
>
> Den Wert 2.

Nö, inzwischen hat sie den Wert 3, weil eine ISR den Wert verändert hat.

C-Funktionen bestehen aus Anweisungen, die sequentiell ausgeführt 
werden. Wenn nun eine ISR (oder die Hardware) einen Wert unter der Hand 
ändert, muss man das dem Compiler mittelen. Und das macht man mit 
volatile.

von Christopher G. (cbg)


Lesenswert?

Das fehlende volatile wurde ja schon erwähnt und ebenfalls erklärt. Ich 
geh mal davon aus, dass du noch nicht soviel Erfahrung mit 
µC-Programmierung hast. Ich geb dir gleich mal einen Tipp, wie du dein 
Programm besser und vielseitiger gestalten kannst.

Das Busywaiting in der ISR solltest du dir schnell abegwöhnen. Das 
funktionniert zwar, ist aber wenn mal drüber nachdenkst einfach Pfui. 
Bei deinem Problem kannst du sehr schön die Nützlichkeit eines Timers 
erlernen. Ich geh mal davon aus, du hast in deinem AVR einen 16 Bit 
Timer mit Input Capture Funktion. Mit dem Input Capture Modus kannst du 
die Länge des Impulses sehr genau messen (genauer wirds mit einem AVR 
nicht) und dann abhängig von der Länge des Impulses darauf reagieren. 
Falls das Ding Batteriebetrieben werden soll (bzw auch wenn nicht, 
Stromsparen sollte man wo immer möglich) solltest du dir auch die Sleep 
Modes anschauen und den µC schlafen lassen, wenn er nichts zu tun hat.

Ist ein ganz gutes Anfängerprojekt um sich mit Timern zu beschäftigen.

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.