Forum: Mikrocontroller und Digitale Elektronik [AVR] ISR in eine Klasse stecken


von Stefan K. (sk-ac)


Lesenswert?

Hallo,

ich versuche den Code aus Beitrag "PWM Signal auswerten" in 
mein C++ Projekt zu bekommen.

Irgendwie wollen die Interrupt Methoden nicht mit in die Klasse.
Ich nehme an, ISR wird über ein define überschrieben da ich so:
1
expected unqualified-id before 'extern'

bekomme.

Ohne KLASSE:: davor kann er natürlich die Attribute nicht finden. Diese 
sind ja in der Klasse.

Hat da jemand eine Lösung?

Danke,
Stefan

von Michael K. (michael007)


Lesenswert?

warum schreibt man für einen 8 bit µC ein Programm in C++...
Das versteh' ich net...

von g457 (Gast)


Lesenswert?

> Irgendwie wollen die Interrupt Methoden nicht mit in die Klasse.

In jeder Klasseninstanz eine eigene Instanz des Interrupthandlers? 
..keine gute Idee.. Wenns unbedingt C++ sein muss [1] dann lass die 
Interrupthandlder 'draussen' und mach deine Instanzen stattdessen per 
globaler Variable verfügbar, ein improvisierter 'this'-Zeiger sozusagen 
:-)

HTH

[1] C++ hat viele schöne Konzepte, aber für so einen kleinen µC ein 
bisschen Overkill..

von Stefan K. (sk-ac)


Lesenswert?

Hallo,

ich meine bei Motorola sind das "normale" Methoden, die der Compiler 
dann entsprechend umsetzt.

Dann muss ich wohl doch auf C zurück.
Ich habe auf C++ umgestellt, weil ich mit den Objekten eine bessere 
Übersicht bekommen wollte.

Danke,
Stefan

von Vlad T. (vlad_tepesch)


Lesenswert?

g457 schrieb:
> [1] C++ hat viele schöne Konzepte, aber für so einen kleinen µC ein
> bisschen Overkill..

kommt drauf an, was man alles benutzt.
virtuelle Vererbung oder collections sind definitv overkill.

Aber ein bisschen templates und Klassen machen den Code oft 
übersichtlicher.

vor allem die Möglichkeit datenstrukturen mit Funktionen versehen zu 
können vermisse ich in C.

IgnitionHandler ig;
ig.initExplosion();

ist doch viel schöner als

IgnitionHandler ig;
IgnitionHandler_initExplosion(&ig);

und das enthält überhaupt keinen Overhead.
Oder konstruktoren.
Da entfallen die ganzen init-Aufrufe.

oder Operatorüberladung für Fixpointtypen zB.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Stefan Kuhne schrieb:
> Irgendwie wollen die Interrupt Methoden nicht mit in die Klasse.
> Ich nehme an, ISR wird über ein define überschrieben da ich so:
> expected unqualified-id before 'extern'
> bekomme.
>
> Ohne KLASSE:: davor kann er natürlich die Attribute nicht finden. Diese
> sind ja in der Klasse.

Wie genau bist Du vorgegangen? Wichtig ist, daß die Interruptroutinen 
als static deklariert werden, genauso, wie es auch mit aus C-Code 
heraus aufgerufenen C++-Funktionen gemacht werden muss.

von Stefan K. (sk-ac)


Lesenswert?

Rufus t. Firefly schrieb:

Hallo,

> Wie genau bist Du vorgegangen?

Ursprung:
1
ISR(TIM1_OVF_vect) //Overflow
2
{
3
  if(!ready)
4
    overflow ++;
5
}

Überarbeitet:
1
ROTATION::ISR(TIMER1_OVF_vect)
2
//Overflow
3
{
4
  if (!ready)
5
    overflow++;
6
}

Danke,
Stefan

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> ISR(TIM1_OVF_vect) //Overflow

Sieh Dir mal den Aufbau des Macros ISR an, und berücksichtige, daß die 
Funktion als static deklariert sein muss, es also keinen this-Pointer 
innerhalb der Funktion gibt.

von Floh (Gast)


Lesenswert?

Hab ich auch schon mal versucht mit dem Ergebnis, es künftig bleiben zu 
lassen.
Du musst die ISR in der Klasse auf jeden fall static machen.
Außerdem muss dann sichergestellt sein, dass überhaupt eine Instanz 
schon vorhanden ist, sonst nützt selbst static nix.
Das ganze sollte dann über _attribute_(signal) oder so ähnlich 
funktionieren, damit erstens statt des ret ein reti am Ende der ISR 
steht und zweitens der Interruptvector beschrieben wird.
Aber das Ganze ist halt weder C noch C++-konform, da diese Sprachen per 
se keine Interrupts kennen. Daher sind diese Konstruktionen mehr oder 
minder Krücken des Compilers, die sich jederzeit ändern können 
(Interrupt -> Signal -> ISR).

von Detlev T. (detlevt)


Lesenswert?

Michael K. schrieb:
> warum schreibt man für einen 8 bit µC ein Programm in C++...
> Das versteh' ich net...
Das kann man wohl über alles sagen, was nicht Assembler ist. ;)

Ich hatte mich auch schon einmal damit beschäftigt und diese "Lösung" 
hier gefunden: 
http://waterproofman.wordpress.com/2007/02/07/avr-interrupts-in-c/

So ganz hat mich das nicht überzeugt. Es gibt IMO den grundsätzlichen 
Widerspruch, dass man von einer Klasse zwar mehrere neue Instanzen 
erzeugen kann, die damit angesteuerte Hardware aber nicht gleich mit 
erzeugt wird.

Eventuell kann man die ISR ja ganz klassisch quasi in C programmieren 
und die Objekte greifen auf dessen (globale) Daten dann zu. Wenn das nur 
ein Objekt macht, dann hat man ja in der Praxis wieder eine Art 
Kapselung.

Ich könnte mir z.B. ein UART-Objekt (UART mal als nahe liegendes 
Beispiel) vorstellen, dessen Konstruktor ein Zeiger auf die Daten der 
UART-ISR übergeben wird. Der wird in dem Objekt gespeichert (und könnte 
ggf. auch geändert werden). So "bindet" man dann Objekte an die 
Hardware. Will ich eine andere Funktion an der Schnittstelle, binde ich 
ein anderes Objekt daran. Dasselbe Objekt kann ich an unterschiedliche 
UARTs binden (natürlich nur wenn es mehrere gibt).

Ich könnte mir auch gut ein Objekt als eine Art "Torwächter" vorstellen, 
der den Zugang zur SPI oder I²C-Schnittstelle kontrolliert. Oder eine 
abstrakte ADC-Klasse, deren Nachfolger entweder interne oder externe 
ADCs ansprechen...

Ich denke, es gibt schon Gründe, C++ auf Mikrocontrollern einzusetzen. 
(ich persönliche bleibe aber bei C mit Assembler als Notnagel)

von P. S. (Gast)


Lesenswert?

Ich mache das z.B. so:
1
// Copyright 2009 Peter Stegemann
2
3
#ifndef INTERRUPT_SERVICE_H
4
#define INTERRUPT_SERVICE_H
5
6
#include "Shared/Types.h"
7
8
class INTERRUPT_Service
9
{
10
  private:
11
    volatile uint16_t timeMillis;
12
    volatile uint16_t timeSeconds;
13
14
  public:
15
    // Start processing loop.
16
    void Start( void);
17
18
    // This is for the interrupt, not for you.
19
    void Process( void);
20
};
21
22
#endif
1
// Copyright 2009 Peter Stegemann
2
3
#include "Interrupt_Service.h"
4
5
#include "Ports.h"
6
7
#include <avr/interrupt.h>
8
9
#define INTERRUPT_TICKS_PER_SECOND  1000
10
#define INTERRUPT_TICKS_PER_MS    INTERRUPT_TICKS_PER_SECOND / 1000
11
#define INTERRUPT_CLOCK_FACTOR    ( F_CPU / INTERRUPT_TICKS_PER_SECOND) / 64
12
13
static INTERRUPT_Service* INTERRUPT_Singleton;
14
15
void INTERRUPT_Service::Start( void)
16
{
17
  timeMillis = 0;
18
  timeSeconds = 0;
19
20
  INTERRUPT_Singleton = this;
21
22
  // Clear counter before use. This will also clear all other settings.
23
  TCNT0 = 0;
24
  // Wakeup often.
25
  OCR0A = INTERRUPT_CLOCK_FACTOR;
26
  // Clear timer by match and split clock for timer by 64.
27
  INPUT_TIMERA = BIT_VALUE( WGM01);
28
  INPUT_TIMERB = BIT_VALUE( CS01) | BIT_VALUE( CS00);
29
  // Switch interrupt for compare match on.
30
  TIMSK0 = BIT_VALUE( OCIE0A);
31
}
32
33
void INTERRUPT_Service::Process( void)
34
{
35
  // Time calculation is _always_ done.
36
  timeMillis++;
37
38
  // Second?
39
  if( timeMillis == 1000)
40
  {
41
    timeSeconds++;
42
    timeMillis = 0;
43
44
    // Do something every second.
45
  }
46
47
  // Do something every millisecond.
48
}
49
50
ISR( SIG_OUTPUT_COMPARE0A, ISR_NOBLOCK)
51
{
52
  INTERRUPT_Singleton->Process();
53
}

von netb (Gast)


Lesenswert?

Es gab hier einen, meiner Meinung nach, sehr sinnvollen Patchvorschlag 
von Ron Kreymborg. Der Patch hat die Nummer #6805 (Numeric interrupt 
vectors).

Eine Erklärung und ein Beispiel ist hier zu finden:
http://jennaron.com.au/avr/classinterrupts.html

Leider scheint sich dieser Patch nicht durchgesetzt zu haben, denn 
immerhin ist der Vorschlag schon etwas älter (2007). Schade eigentlich, 
aber ich hoffe immer noch, dass der Patch irgendwann umgesetzt wird.

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.