Forum: Mikrocontroller und Digitale Elektronik Problem mit Programmunterbrechung


von Julian S. (r4id)


Lesenswert?

Hallo,

ich habe eine Platine entwickelt auf Atmega32 Basis. Diese wertet 
Sensoren aus und schaltet Aktoren.

Nun ist es so, dass eine übergeordnete Steuerung meiner Platine ein 
Go/Stop Signal übergeben kann. Ich wollte diesen PIN dann mit einem 
Interrupt abfragen, aber leider sind die externen Interruptpins alle 
belegt. Die Platine wurde professionel gefertigt und ich habe dies 
einfach nicht bedacht.

Jedenfalls kann ich dieses Go/Stop Signal immernoch an einen anderen Pin 
abfragen.

Habe das Programm schon fertig, sequentiell mit if abfragen und while 
schleifen. Also bei while auf einen Zustand warten und den Aktor 
schalten /abschalten.

Nun ist das Problem eben mit dieses Go/Stop. Das müsste ich ja in jeder 
Zeile abfragen und was passiert dann? Ich rufe eine Funktion auf es wird 
was gemacht und dann wird ja wieder in das Hauptprogramm gesprungen.

Meine Frage nun: Ist es eine bessere Lösung mit Switch case Anweisungen 
zu Arbeiten. Also in jedem case etwas mit if machen und einen Zähler 
hochsetzten der dann zur nächsten case springt. Gleichzeitig aber 
Go/Stop abfragen und wenn das zutrifft den Zähelr auf Null setzten um 
somit von vorn zu beginnen. Ist quasi das Statemachine Prinzip.

Oder gibt es noch bessere Möglichkeiten. Danke schonmal.

: Verschoben durch User
von Peter II (Gast)


Lesenswert?

Julian S. schrieb:
> Oder gibt es noch bessere Möglichkeiten. Danke schonmal.

ja, mit einer Statemachine arbeiten. Dann bist du immer in der 
Hauptschleife und kannst solche dinge sehr einfach einbauen.

Dein code ist dafür viel zu unflexibel.


http://www.mikrocontroller.net/articles/Statemachine

von Route_66 H. (route_66)


Lesenswert?

Julian S. schrieb:
> Oder gibt es noch bessere Möglichkeiten. Danke schonmal.

Hast Du einen Timer am laufen?

Falsches Forum!!!

: Bearbeitet durch User
von Julian S. (r4id)


Lesenswert?

> Hast Du einen Timer am laufen?

Ja ein Timerinterrupt ist auch vorhanden, der nach bestimmter Zeit 
auslöst wenn z.B. ein bestimmter Sensor lange nichts empfängt. Wieso die 
Frage?

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Julian S. schrieb:
>> Hast Du einen Timer am laufen?
>Wieso die Frage?

Ich vermute das dies ein Hinweis sein sollte, dass man in einem Timer 
das Signal auf dem Pin pollen könnte, und das Program darin mit einer 
While-schleife anhalten.

von Julian S. (r4id)


Lesenswert?

> Ich vermute das dies ein Hinweis sein sollte, dass man in einem Timer
> das Signal auf dem Pin pollen könnte, und das Program darin mit einer
> While-schleife anhalten.

Kannst du das kurz erklären?

von Amateur (Gast)


Lesenswert?

Hast Du es wirklich so eilig?

Kennst Du Dein eigenes Programm?

Welche maximale Zykluszeit hat Deine Hauptschleife?

Reicht daher eine einfache Abfrage pro Durchlauf nicht aus?

Selbst bei schnellen Automaten ist eine Verzögerung, von einem 
Hauptschleifendurchlauf, kein Beinbruch.

Hast Du dort aber jede Menge delay's verbraten, so hilft nur eine 
Neuprogrammierung bzw. Neustrukturierung.

von Julian S. (r4id)


Lesenswert?

>Hast Du es wirklich so eilig?
Sehr sogar.

>Kennst Du Dein eigenes Programm?
Ja.

>Welche maximale Zykluszeit hat Deine Hauptschleife?
Genau kann ich das nicht sagen. Es wird ja wie gesagt auf Zustände an 
Sensoren gewartet

>Reicht daher eine einfache Abfrage pro Durchlauf nicht aus?
>Selbst bei schnellen Automaten ist eine Verzögerung, von einem
>Hauptschleifendurchlauf, kein Beinbruch.
Nein, da in while Schleifen "gewartet" wird

>Hast Du dort aber jede Menge delay's verbraten, so hilft nur eine
>Neuprogrammierung bzw. Neustrukturierung.
Kein einziges.

von Falk B. (falk)


Lesenswert?

@ Julian S. (r4id)

>>Hast Du es wirklich so eilig?
>Sehr sogar.

Wie eilig? Siehe Netiquette!!!

>>Kennst Du Dein eigenes Programm?
>Ja.

Das sagen sie alle ;-)

>>Welche maximale Zykluszeit hat Deine Hauptschleife?
>Genau kann ich das nicht sagen. Es wird ja wie gesagt auf Zustände an
>Sensoren gewartet

Eben DAS ist dein Fehler! Siehe Multitasking!

>Nein, da in while Schleifen "gewartet" wird

FALSCH! Das macht man ANDERS! Siehe oben.

von Julian S. (r4id)


Lesenswert?

>Wie eilig? Siehe Netiquette!!!

Wäre super Nett wenn mir jemand das mit dem Pin pollen erklären 
könnte.......... Bitte! :)

von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>Wäre super Nett wenn mir jemand das mit dem Pin pollen erklären
>könnte.......... Bitte! :)

Bitte? Pollen ist neudeutsch (aka englisch) und bedeutet abfragen. Man 
fragt also den Pin ab und reagiert entsprechend. Je nach 
Programmstruktur kann die Abfrage direkt im Programmfluß stehen oder in 
einerm periodischen Timer-Interrupt.

1
if (PINC & (1<<PC4)) {
2
  // Pin ist HIGH
3
} else {
4
  // PIN ist LOW
5
}

von Julian S. (r4id)


Lesenswert?

Wie man einen Pin abfragt ist mir bewusst. Aber warum in einem Timer 
Interrupt. Interrupt Routinen sollen doch immer Kurz ohne große Abfragen 
programmiert werden.

von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>Wie man einen Pin abfragt ist mir bewusst. Aber warum in einem Timer
>Interrupt.

Weil dieser den normalen Programmablauf unterbrechen kann (Nomen est 
Omen!)

> Interrupt Routinen sollen doch immer Kurz ohne große Abfragen
> programmiert werden.

Am besten läßt man sie komplett leer, oder?

OMG!

Wie lange glaubst du, dauert so eine Pinabfrage?

von Julian S. (r4id)


Lesenswert?

Okay, ich habe falsch gedacht sorry.
Jetzt ist es mir klar.

Wenn ich nun eine Statemachine programmiere wie etwa folgendes.
1
int i=0;
2
while(1)
3
{
4
 switch(i)
5
 {
6
  case 0: if (PINC & (1<<PC4)) { PORTA |= (1<<PA0); } i++; break;
7
  case 1: if (PINC & (1<<PC3)) { PORTA &= ~(1<<PA0); } i++; break;
8
  case 2: ...; break;
9
   .
10
   .
11
   .
12
  case 20: i=0; break;
13
14
 }
15
}

Es wird in jedem case ein Timerinterrupt ausgelöst.
Bspw. in case 15 ist mein Go/Stop pin gesetzt. also der Ablauf soll 
stoppen.

Wie kann ich in der Interruptroutine den Zähler i wieder Null setzten?
Muss ich die Adresse übergeben?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>Wenn ich nun eine Statemachine programmiere wie etwa folgendes.

Sieht nicht sonderlich sinnvoll aus.

>Es wird in jedem case ein Timerinterrupt ausgelöst.

Keine Sekunde. Wie kommst du darauf?

>Bspw. in case 15 ist mein Go/Stop pin gesetzt. also der Ablauf soll
>stoppen.

Das funktioniert anders.

>Wie kann ich in der Interruptroutine den Zähler i wieder Null setzten?
>Muss ich die Adresse übergeben?

Nö, man muss sie global und volatile definieren, siehe Interrupt. 
Aber das mit der Statemachine geht doch ein wenig anders. Lies die 
Artikel und denk nach.

: Bearbeitet durch User
von Julian S. (r4id)


Lesenswert?

Okay werde ich wohl machen müssen :/

Trotzdem danke.

von Julian S. (r4id)


Lesenswert?

Ok ich habe mal eine Statemachine programmiert, dass wie folgt aussieht.

Über eine Jumperstellung wird in der main.cpp die Fkt kurve(); 
aufgerufen.
Das Problem ist aber das ich das state in der ISR nicht ändern kann.
Die ISR wird auch aufgerufen, habe ich getestet mit einem Rücksetzten 
eines Pins.

Das Problem liegt eindeutig an dem typedef enum. Hat einer eine Idee wie 
es richtig geschrieben werden muss oder wo und wie ich die Variablen 
definieren muss.

Habe schon einiges Probiert. Ich könnte diese Deklaration natürlich in 
die Funktionen.h schreiben aber das typedef enum muss in jeder Funktion 
die ich in der Switch case der main.cpp aufrufe andere Inhalte haben.

(Die States der Switch case in Funktionen.cpp haben natürlich Inhalte 
und schalten auch jeweils um, habe ich nur aus Übersichtlichkeit 
entfernt)

main.cpp
1
#define F_CPU 1000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "funktionen.h"
5
6
//Interrupt
7
ISR(TIMER0_OVF_vect)
8
{
9
  if ( (PINC & (1<<PC3)) )
10
  {
11
    state=GRUNDSTELLUNG;
12
  }
13
}
14
15
//Hauptprogramm
16
int main(void)
17
{  
18
        // Initialisierung der CPU (Timer, JTAG, usw.)
19
        init_cpu();
20
        //Initialisierung der Ports aufrufen   
21
        init_io(); 
22
  
23
        int fkt;
24
        // Jumperstellung prüfen 
25
        fkt = ~PINB & (1<<PB0 | 1<<PB1 | 1<<PB2); 
26
  
27
        //Funktion anhand von Jumperstellung laden
28
        switch(fkt)  
29
        {
30
          case 0: break;
31
          case 1: kurve();break;
32
          case 2: break;
33
          case 3: break;
34
          case 4: break;
35
          case 5: break;
36
          case 6: break;
37
          case 7: break;
38
          default:break;
39
  }
40
41
return 0;
42
}

funktionen.cpp
1
#define F_CPU 1000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "funktionen.h"
5
6
7
void init_cpu(void)
8
{
9
  // JTAG Abschalten
10
  MCUCR = (1 << JTD);
11
  MCUCR = (1 << JTD);
12
  
13
  // Interrupt einschalten
14
  sei();
15
  
16
  // Timer/Counter0 konfigurieren
17
  //- Prescaler auf 1/8
18
  TCCR0B |= (1<<CS01);
19
  //- Interrupt bei Zählerüberlauf aktivieren
20
  TIMSK0 |= (1<<TOIE0);
21
  
22
  // Timer/Counter1 konfigurieren
23
  //- Prescaler auf 1/8
24
  TCCR2B |= (1<<CS01);
25
  //- Interrupt bei Zählerüberlauf aktivieren
26
  TIMSK2 |= (1<<TOIE0);
27
  
28
}
29
30
void init_io(void)
31
{
32
  //habe ich aus Übersichtlichkeit weggelassen, hier werden aber die Ein und Ausgänge definiert
33
}
34
35
36
void kurve(void)
37
{
38
  typedef volatile enum { GRUNDSTELLUNG, FREIRAUMEN, WARTEN} state_t ; 
39
  volatile state_t state = GRUNDSTELLUNG;
40
  
41
  PORTB |= (1 << PB4); // Ausgänge anschalten
42
  
43
while(1) 
44
  {
45
46
    switch( state )  // Statemashine switch case Anweisungen
47
      {
48
        case GRUNDSTELLUNG:
49
          break;
50
          
51
        case FREIRAUMEN:
52
          break;
53
          
54
        case WARTEN:
55
          break;
56
          
57
        default:break;
58
      }
59
60
  }
61
62
}

Funktionen.h
1
#ifndef FUNKTIONEN_H_
2
#define FUNKTIONEN_H_
3
  
4
void init_cpu(void);
5
void init_io(void);
6
void kurve(void);
7
8
#endif /* FUNKTIONEN_H_ */

von Walter (Gast)


Lesenswert?

state muss natürlich global sein

und in das enum kannst du auch
fkt1_START, fkt1_ENDE, fkt2_START etc. schreiben

von Karl H. (kbuchegg)


Lesenswert?

Julian S. schrieb:

> //Interrupt
> ISR(TIMER0_OVF_vect)
> {
>   if ( (PINC & (1<<PC3)) )
>   {
>     state=GRUNDSTELLUNG;
>   }
> }

Das möchtest du in den meisten Fällen so nicht machen.

Denn: Du weisst nie im vorraus (zumindest nicht im Normalfall), wann 
genau der Interrupt zuschlägt.

Wenn der zb hier
1
....
2
3
>     switch( state )  // Statemashine switch case Anweisungen
4
>       {
5
>         case GRUNDSTELLUNG:
6
>           mach irgendwas ganz tolles
7
>           mach noch was ganz tolles
8
>
9
>           und wenn dann auch noch die Temperatur stimmt
10
>             dann 
11
>               state = FREIRAUMEN;
12
>           break;
13
>

vor der Zuweisung an state zuschlägt, dann ist dein ganzer 
Zustandeswechesel in der ISR für die Katz.


Warum nicht einfach so
1
....
2
int main()
3
{
4
  ....
5
6
  while( 1 ) {
7
8
    // hier die Statemaschine
9
    switch( state ) {
10
11
      // mit all ihren cases und sonstiger Logik, wie von einem
12
      // Zustand zum nächsten gewechselt wird
13
    }
14
15
    // und hier dann alle Aktionen, die nach der Behandlung eines
16
    // state erfolgen sollen. Wie zum Beispiel der Überprüfung von
17
    // Rücksetzbedingungen
18
19
    if( PINC & ( 1 << PANIK_TASTE ) )
20
      state = IDLE;
21
  }
22
}

Ob man den state dann auf zb IDLE setzt, oder in der Statemaschine einen 
Zustand hat, von dem ausgehend die Statemaschine sich wieder selbst in 
einen sicheren Zustand manövriert und man sie auf diesen setzt, ist eine 
andere Frage und hängt von der konkreten Statemaschine bzw. den 
Bedingungen ab. Bei einer Spritzgussmaschine wird es wahrscheinlich 
vernünftig sein, wenn sich die Maschine beim Drücken vom Notaus nicht 
einfach abschaltet, sondern die Form erst mal (langsamer als normal) 
auseinanderfährt, ehe sie dann steht.

Der springende Punkt ist aber: Da in keinem state gewartet wird, wird 
damit auch ganz automatisch immer wieder laufend geprüft, ob der Panik 
Taster gedrückt wurde und es findet dann auch zwischendrinn immer wieder 
die Prüfung statt, ob die Statemaschine in den Grundzustand 
zurückgeführt werden soll.

Eine Statemaschine zu haben, bedeutet ja nicht, dass es ausschliesslich 
und nur diese eine Statemaschine geben darf. Ein Programm kann 
beispielsweise auch 2 oder mehr Statemaschinen implementieren. Die sich 
auch gegenseitig beeinflussen können.

: Bearbeitet durch User
von Julian S. (r4id)


Lesenswert?

>Der springende Punkt ist aber: Da in keinem state gewartet wird, wird
>damit auch ganz automatisch immer wieder laufend geprüft, ob der Panik
>Taster gedrückt wurde und es findet dann auch zwischendrinn immer wieder
>die Prüfung statt, ob die Statemaschine in den Grundzustand
>zurückgeführt werden soll.

Also meinst du ich sollte ohne Timer-Interrupt arbeiten, sondern den Pin 
jedes mal am ende der Endlosschleife abfragen?

von Karl H. (kbuchegg)


Lesenswert?

Julian S. schrieb:
>>Der springende Punkt ist aber: Da in keinem state gewartet wird, wird
>>damit auch ganz automatisch immer wieder laufend geprüft, ob der Panik
>>Taster gedrückt wurde und es findet dann auch zwischendrinn immer wieder
>>die Prüfung statt, ob die Statemaschine in den Grundzustand
>>zurückgeführt werden soll.
>
> Also meinst du ich sollte ohne Timer-Interrupt arbeiten

Ich weiss nicht, was dein Timer sonst noch macht. Wenn der eine 
Systemuhr bereit stellst, die du zb für Wartesachen benutzen kannst, 
dann ist er vernünftig.

> sondern den Pin
> jedes mal am ende der Endlosschleife abfragen?

Wenn es nur um diesen Pin geht und es um die Fragestellung geht "soll 
ich den Pin in jedem einzelnen State jedesmal wieder neu abfragen" dann 
kann man sich dafür entscheiden.

Aber wie angesprochen. Welche Version man wählt, hängt auch von den 
Gegebenheiten und den persönlichen Vorlieben ab.
Gewöhn dich daran, dass es in der Programmierung kein 'One size fits 
all' gibt. Das funktioniert bei Baseballkappen, aber selten in der 
Programmierung. Deshalb ist es auch so wichtig, dass man viele Techniken 
kennt und die auch kombinieren kann. Und nicht notwendigerweise bei 
"externem Signal" gleich "Interrupt" assoziert. Ein Interrupt kann eine 
Lösung sein, muss es aber nicht.

von Julian S. (r4id)


Lesenswert?

Okay. Aber nun möchte ich doch einen Interrupt verwenden. Zwar nicht für 
den Pin, sondern soll er wenn 10s nichts passiert das state auf 
Grundstellung setzten.

Alleine das state global und volatile zu definieren reicht nicht, da 
dieses ja ein typdef enum von state_t ist, welches ja später erst in 
einer Fkt definiert wird.

von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>Über eine Jumperstellung wird in der main.cpp die Fkt kurve();
>aufgerufen.

Tu mal nicht so gescheit, das ist stinknormales C. Von C++ weit 
entfernt.

>Das Problem ist aber das ich das state in der ISR nicht ändern kann.

Wozu auch. Dort fummelt man nicht rum. Das macht man über andere 
Variablen, welche in der Statemachine abgefragt werden. Wobei dann die 
ISR aber überflüssig ist, denn die Pinabfrage kann die FSM selber 
machen.

>Das Problem liegt eindeutig an dem typedef enum.

Das Problem liegt eindeutig am schlechten Konzpt deinerseits.

>Habe schon einiges Probiert. Ich könnte diese Deklaration natürlich in
>die Funktionen.h schreiben aber das typedef enum muss in jeder Funktion
>die ich in der Switch case der main.cpp aufrufe andere Inhalte haben.

Kaum. Ein typedef ist immer wie er ist. Er wird einmal in einer .h Datei 
definiert und fertig.


>        int fkt;
>        // Jumperstellung prüfen
>        fkt = ~PINB & (1<<PB0 | 1<<PB1 | 1<<PB2);

Hier fehlt noch eine Maske. Besser so, denn die restlichen Bits sind 
sonst undefiniert!

         fkt = (~PINB & (1<<PB0 | 1<<PB1 | 1<<PB2)) & 0x07;

>void kurve(void)
>{
>  typedef volatile enum { GRUNDSTELLUNG, FREIRAUMEN, WARTEN} state_t ;
>  volatile state_t state = GRUNDSTELLUNG;

Lokale Variabeln müssen so gut wie NIE volatile sein. Bestenfalls 
GLOBALE Variablen.

von Karl H. (kbuchegg)


Lesenswert?

Julian S. schrieb:
> Okay. Aber nun möchte ich doch einen Interrupt verwenden. Zwar nicht für
> den Pin, sondern soll er wenn 10s nichts passiert das state auf
> Grundstellung setzten.
>
> Alleine das state global und volatile zu definieren reicht nicht, da
> dieses ja ein typdef enum von state_t ist, welches ja später erst in
> einer Fkt definiert wird.

Und wie schon gesagt, willst du sowieso nicht in einem Interrupt den 
State ändern. Aus genau den genannten Gründen. Du kannst im Interrupt 
ein 'Signal' setzen, dass die 10s um sind und dann darauf reagieren. Oft 
kann man das zb so machen
1
volatile uint8_t waitTime;
2
3
....
4
ISR( ... )
5
{
6
  if( waitTime )
7
    waitTime--;
8
}
9
10
11
void Motor1()
12
{
13
....
14
15
   switch( state )
16
   {
17
18
      case IDLE:
19
        if( TasterPressed ) {
20
          waitTime = 10;        // Wartezeit von 10 Sekunden
21
                                // erst danach gehts wirklich los
22
          state = WAIT_FOR_BEGIN;
23
        }
24
        break;
25
26
      case WAIT_FOR_BEGIN:
27
        if( WaitTime == 0 )
28
        {
29
          Motor1_On( FORWARD );
30
          state = WAIT_FOR_ENDPOSITION_FORWARD;
31
        }
32
        break;
33
34
      case WAIT_FOR_ENDPOSITION_FORWARD:
35
        if( Endschalter_Forward )
36
        {
37
          Motor1_Off();
38
          waitTime = 2;
39
          state = WAIT_FOR_BACKDRIVE;
40
        }
41
        break;
42
43
      case WAIT_FOR_BACKDRIVE:
44
        if( WaitTime == 0 )
45
        {
46
          Motor1_On( BACKWARD );
47
          state = WAIT_FOR ENDPOSITION_BACK;
48
        }
49
        break;
50
51
      case WAIT_FOR_ENDPOSITION_BACK:
52
        if( Endschalter_Backward )
53
        {
54
          Motor1_Off();
55
          state = IDLE;
56
        }
57
        break;
58
    }
59
}

Eine Statemaschine, die nach einem Eingangstaster 10 Sekunden wartet, 
einen Motor bis zur Endposition fährt, dort abschaltet, 2 Sekunden 
wartet und den Motor wieder in die Ausgangsposition zurückfährt. Und 
nirgends wird im Programm auf irgendwas aktiv gewartet. Die Funktion 
kann aus der Hauptschleife aus laufend aufgerufen werden und arbeitet 
sich durch ihre Aufgabe durch. Bei jedem Aufruf wird das gerade 
anstehende gemacht. Aber gewartet im Sinne eines _delay_ms, gewartet 
wird nicht.
1
int main()
2
{
3
  ....
4
5
6
  while( 1 )
7
  {
8
     mach was;
9
     mach noch was;
10
     mach ganz was anderes;
11
12
     Motor1();   // behandle den Motor 1
13
14
     ...
15
  }
16
}

Wenn die Statemaschine 'warten' soll, dann hängt sie eben in einem 
State, der prüft, ob die 'Eieruhr', die sie sich selbst gestellt hat, 
schon abgelaufen ist, oder nicht. Du stellst dir ja auch nicht den 
Küchentimer auf 45 Minuten und bleibst dann 45 Minuten ausschliesslich 
am Herd stehen.

Zum Rest: ja klar. Das ist in C so. Der Compiler liest dein Programm von 
oben nach unten. Und zwar genau 1 mal. Ehe du etwas irgendwo verwenden 
kannst, musst du es definieren. Und zwar so, dass es in diesem Scope 
auch verfügbar ist.
So wie die C Regeln eben sind.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Julian S. (r4id)

>Okay. Aber nun möchte ich doch einen Interrupt verwenden.

Bla. Diese Frage stellt sich gar nicht. SOndern WAS muss getan werden. 
DANACH kommt die Frage nach dem WIE, welche ggf. mit einem Interrupt 
beantwortet werden kann.

>den Pin, sondern soll er wenn 10s nichts passiert das state auf
>Grundstellung setzten.

Eben dafür nimmt man einen Timer. Und zwar nicht mit 10s sondern 
eher 10ms. In diesem Zeitraster wird deine FSM aufgerufen. Dort drin 
kann man dann ggf. einen Timeout über einen Zähler bis 1000 reinbauen. 
Das ist wasserdicht und lehrbuchartig. Und funktioniert.

https://www.mikrocontroller.net/articles/Multitasking#Ein_einfaches_Beispiel_f.C3.BCr_den_AVR

Bischen runterscollen, 3. Beispiel mit Timer.

>Alleine das state global und volatile zu definieren reicht nicht, da
>dieses ja ein typdef enum von state_t ist, welches ja später erst in
>einer Fkt definiert wird.

Globale Variablen und auch typedefs werden in headern (.h) deklariert 
und in einer globalen Datei (globals.-c) definiert. Damit hat jeder 
Programmteil Zugriff und Sichtbarkeit.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>oben nach unten. Und zwar genau 1 mal. Ehe du etwas irgendwo verwenden
>kannst, musst du es definieren. Und zwar so, dass es in diesem Scope
>auch verfügbar ist.
>So wie die C Regeln eben sind.

Und das ist gut so. ;-)

von Falk B. (falk)


Lesenswert?

globals.h
1
extern int var1;
2
typedef volatile enum { GRUNDSTELLUNG, FREIRAUMEN, WARTEN} state_t ;

globals.c
1
int var1;
2
volatile enum state_t state;


isr.c
1
#include "globals.h"

main.c
1
#include "globals.h"

von Karl H. (kbuchegg)


Lesenswert?

Falk Brunner schrieb:

> globals.c
>
1
> int var1;
2
> volatile enum state_t state;
3
>


Wobei ich immer noch dafür plädiere, ausser im absoluten Notfall, sich 
nicht am state einer Statemaschine ausserhalb derselben zu vergreifen. 
Hier ist die freiwillige Selbstkontrolle des Programmierers gefragt, der 
zwar akzeptiert, dass es technische Notwendigkeiten gibt, diese aber 
nicht missbrauchen wird.

Aber du hast ja auch schon in dieses Horn gestossen. Ich will das nur 
noch mal herausstreichen, weil ich das für wichtig halte.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Wobei ich immer noch dafür plädiere, ausser im absoluten Notfall, sich
>nicht am state einer Statemaschine ausserhalb derselben zu vergreifen.

Stimmt! Es ging hier nur um die globalen Variablen.

von Daniel A. (daniel-a)


Lesenswert?

Falk Brunner schrieb:
>> int fkt;
>>        // Jumperstellung prüfen        fkt = ~PINB & (1<<PB0 | 1<<PB1 |
>> 1<<PB2);
>
> Hier fehlt noch eine Maske. Besser so, denn die restlichen Bits sind
> sonst undefiniert!
>
>          fkt = (~PINB & (1<<PB0 | 1<<PB1 | 1<<PB2)) & 0x07;
>>

Warum ist hier etwas Undefiniert?

Beim left-shift werden doch nullen reingeschoben, wodurch 3 int werte 
mit einem gesetzten bit entstehen. Nach dem verodern sind diese bits in 
einem int wert gesetzt, der rest sind weiterhin nullen, die verundung 
dieser bitmaske mit dem int wert, der durch die Invertierung von PINB 
entstanden ist, beinhaltet auch nichts undefiniertes...

Ich sehe es einfach nicht...

Ausserdem: Woher willst du wissen, ob PB0, PB1 und PB2 keine werte > 2 
hatten? Da könnte man ja sonst gleich die Zahl hinschreiben!

von Falk B. (falk)


Lesenswert?

@ Daniel A. (daniel-a)

>>          fkt = (~PINB & (1<<PB0 | 1<<PB1 | 1<<PB2)) & 0x07;

>Warum ist hier etwas Undefiniert?

Oh, da hab ich wohl den Wald vor lauter Bäumen nicht gesehen 8-)

von Julian S. (r4id)


Lesenswert?

Erstmal danke für alle Antworten. Habe es nun hinbekommen wie ich es 
möchte. :)

@Falk Brunner

>>Über eine Jumperstellung wird in der main.cpp die Fkt kurve();
>>aufgerufen.

>Tu mal nicht so gescheit, das ist stinknormales C. Von C++ weit
>entfernt.

Macht funktionell doch keinen Unterschied. Oder leidet die Performance 
beim compiliern von C++?

Mal abgesehen davon, dass ich aus juchs ein C++ Projekt erstellt habe. 
;P
Ich weiß das ich die Vorteile von C++ nicht ausnutze und wollte das 
sowieso noch in C schreiben.

von Falk B. (falk)


Lesenswert?

@ Julian S. (r4id)

>Erstmal danke für alle Antworten. Habe es nun hinbekommen wie ich es
>möchte. :)

Wie? Siehe

https://www.mikrocontroller.net/articles/Netiquette#Happy_End

>>Tu mal nicht so gescheit, das ist stinknormales C. Von C++ weit
>>entfernt.

>Macht funktionell doch keinen Unterschied. Oder leidet die Performance
>beim compiliern von C++?

Nein.

>Mal abgesehen davon, dass ich aus juchs ein C++ Projekt erstellt habe.
>;P
>Ich weiß das ich die Vorteile von C++ nicht ausnutze und wollte das
>sowieso noch in C schreiben.

Wer noch nicht mal die C und allgemeine Grundlagen solide heherrscht, 
sollte nicht von C++ rumtönen.
Oder etwas volkstümlicher formuliert

"Kein Haar am Sack aber nen Kamm in der Tasche!" ;-)

Ich schreibe auch keine Abhandlungen über Quantenmechanik, nur weil ich 
nen Laserpointer besitze.

von Julian S. (r4id)


Lesenswert?

>Wie?

Indem ich bei jeden Durchlauf der FSM am anfang den Pin Prüfe.
So wie Karl Heinz das beschrieben hat. Nach dem Schema...
1
....
2
int main()
3
{
4
  ....
5
6
  while( 1 ) {
7
8
    // hier die Statemaschine
9
    switch( state ) {
10
11
      // mit all ihren cases und sonstiger Logik, wie von einem
12
      // Zustand zum nächsten gewechselt wird
13
    }
14
15
    // und hier dann alle Aktionen, die nach der Behandlung eines
16
    // state erfolgen sollen. Wie zum Beispiel der Überprüfung von
17
    // Rücksetzbedingungen
18
19
    if( PINC & ( 1 << PANIK_TASTE ) )
20
      state = IDLE;
21
  }
22
}


>Wer noch nicht mal die C und allgemeine Grundlagen solide heherrscht,
>sollte nicht von C++ rumtönen.
>Oder etwas volkstümlicher formuliert

Ich denke das ich C und auch C++ ganz gut beherrsche, nur ist es schon 
ein Unterschied wenn man von reinen theoretischen C-Code der nur im 
Command Menu lustig vor sich hinfrimelt hin zu Mikrocontrollern geht.
Zum Beispiel habe ich gelernt niemals globale Variablen anzulegen, 
sondern über Adressen und Zeigern auf Adressen usw. zu gehen. Mal 
abgesehen von den Endlosschleifen ;).

von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>Indem ich bei jeden Durchlauf der FSM am anfang den Pin Prüfe.
>So wie Karl Heinz das beschrieben hat. Nach dem Schema...

Kann man so machen, ist solide.

>Ich denke das ich C und auch C++ ganz gut beherrsche,

;-)
Der Herr belieben zu scherzen?
Wer nicht mal elementare Regeln zur Deklaration von Variablen und der 
Sichtbarkeit kennt, "beherrscht" rein gar nichts. Schon gar nicht C++.

Beitrag "Re: Problem mit Programmunterbrechung"

Der ganze Thread erweckt nicht ein einziges Mal die Vermutung, dass hier 
jemand mit soliden Kenntnissen unterwegs ist.

von Julian S. (r4id)


Lesenswert?

>;-)
>Der Herr belieben zu scherzen?
>Wer nicht mal elementare Regeln zur Deklaration von Variablen und der
>Sichtbarkeit kennt, "beherrscht" rein gar nichts. Schon gar nicht C++.

Die Diskussion ist jetzt eh Quatsch. ;)
Aber:
Variablendeklaration und deren Geltungsbereich sind mir sehr bewusst, 
nur meinte ich eben die Tatsache das es üblich ist im µC Bereich mit 
globalen Variablen zu arbeiten, was wieder zu "Spagetti-Code" führt und 
weg von objektorientierter Programmierung ist.

von Falk B. (falk)


Lesenswert?

@Julian S. (r4id)

>nur meinte ich eben die Tatsache das es üblich ist im µC Bereich mit
>globalen Variablen zu arbeiten, was wieder zu "Spagetti-Code" führt und
>weg von objektorientierter Programmierung ist.

Es ist die pragmatische Version von Sempaphoren etc. Wenn man es 
diszipliniert macht, ist das kein "Spagetti-Code". Schließlich sind alle 
IO Register auch global.

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.