Forum: Mikrocontroller und Digitale Elektronik Interruptroutine atmega C++


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Frank (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich möchte einen Timerinterrupt für meinen AVR in C++ erstellen.
Habe mir 
https://www.mikrocontroller.net/articles/AVR_Interrupt_Routinen_mit_C%2B%2B 
durchgelesen und es versucht umzusetzen.
Allerdings bekomme ich beim Kompilieren einen Error
undefined reference to `timer::timerInterrupt::timerInterrupt(int, 
timer*)'
Das heisst ja, dass der kompiler das nicht finden kann, das ist aber in 
timer.h vorhanden.

Was habe ich bei meiner Umsetzung falsch gemacht?

Frank

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Da fehlt die Implementierung der Elementfunktion (en).

Ausserdem ist Dein Beispiel nicht vollständig.

von Ausführlichprogrammierer (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
1
uint32_t damitichdiesevariableauchversteheheisstsiecounter32 = 0;

von Matthias T. (mati123)


Bewertung
0 lesenswert
nicht lesenswert
Hier meine Lösung für ATtiny 2313:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/atomic.h>
5
6
volatile uint32_t epoch=0; // globaler Zeitstempel in 1/10 sec. nach Start
7
8
void timer_init(void)
9
{
10
  // Timer 0 konfigurieren
11
  TCCR0A = (1<<WGM01); // CTC Modus
12
  TCCR0B |= (1<<CS00) | (1<<CS01)  ; // Prescaler 64, d.h bei jedem 64en Takt wird hochgezählt.
13
  /* Ich will alle 1/100 sec  einen Timerüberlauf
14
  F_CPU / 64 * 0,01 = 156,2 */
15
  OCR0A = 155;
16
17
  // Compare Interrupt erlauben
18
  TIMSK |= (1<<OCIE0A);
19
20
  // Global Interrupts aktivieren
21
  sei();
22
23
}
24
25
int main(void)
26
{
27
  timer_init();
28
        while (1) {
29
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
30
        sek_aktuell=epoch / 10;
31
// auf epoch nur vor Interrupts geschützt zugreifen
32
                 }
33
// mache irgendetwas mit den sekunden
34
  }
35
}
36
37
/*
38
Der Compare Interrupt Handler
39
wird aufgerufen, wenn
40
TCNT0 = OCR0A = 156-1
41
ist (156 Schritte), d.h. genau alle 10 ms
42
*/
43
ISR (TIMER0_COMPA_vect)
44
{
45
  static uint8_t dezisekunden;
46
  dezisekunden++;
47
  if(dezisekunden > 9) {
48
    // alle 10 dezisec, d.h. alle 100 ms zählt epoch hoch.
49
    epoch++;
50
    dezisekunden = 0;
51
  }
52
}

von Ausführlichprogrammierer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Matthias T. schrieb:
> Hier meine Lösung für ATtiny 2313:

Und was hat das mit Klassen-Programmierung und C++ zu tun?

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Ausführlichprogrammierer schrieb:
> Matthias T. schrieb:
>> Hier meine Lösung für ATtiny 2313:
>
> Und was hat das mit Klassen-Programmierung und C++ zu tun?

Ich kenne ja ne Menge von Programmierparadigmen, (s.a.

https://de.wikipedia.org/wiki/Programmierparadigma

), aber was ist "Klassenprogrammierung"?

Du meintest wohl OOP, wobei man in C++ ja nicht OOP machen muss(!).

von Matthias T. (mati123)


Bewertung
0 lesenswert
nicht lesenswert
Ausführlichprogrammierer schrieb:

> Und was hat das mit Klassen-Programmierung und C++ zu tun?
Nichts. Ein funktionierendes C-Beispiel sollte aber auch für C++ helfen 
...

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Matthias T. schrieb:
> Ausführlichprogrammierer schrieb:
>
>> Und was hat das mit Klassen-Programmierung und C++ zu tun?
> Nichts. Ein funktionierendes C-Beispiel sollte aber auch für C++ helfen
> ...

Das löst aber nicht sein Problem, dass er die ODR verletzt hat!

von Ausführlichprogrammierer (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> aber was ist "Klassenprogrammierung"?

Korinthenkacker scheinen es nicht zu verstehen, andere schon.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Ausführlichprogrammierer schrieb:
> Wilhelm M. schrieb:
>> aber was ist "Klassenprogrammierung"?
>
> Korinthenkacker scheinen es nicht zu verstehen, andere schon.

Es geht hier nicht um Erbsenzählerei, sondern darum, dass man sich in 
einer (technischen) Disziplin am prägnantesten mit den richtigen Termini 
unterhält. Das ist hier bei der Programmierung so, oder in der 
E-Technik, oder ...

Dieses Forum soll doch Hilfe zur Selbsthilfe geben! Deswegen sollte der 
TO auch die richtigen Bergriffe verwenden. Sonst wird er beim googlen ja 
auch nichts finden. Er sollte sich also mal auf den Weg machen und nun 
auch ODR nachschlagen.

von Ausführlichprogrammierer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> dass er die ODR verletzt hat!

https://de.wikipedia.org/wiki/ODR

Ich als Korinthenkacker ... also ich nehm mal <Octal Data Rate>.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Ausführlichprogrammierer schrieb:
> Wilhelm M. schrieb:
>> dass er die ODR verletzt hat!
>
> https://de.wikipedia.org/wiki/ODR
>
> Ich als Korinthenkacker ... also ich nehm mal <Octal Data Rate>.

Ging es nicht um C++?

von Frank (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ausführlichprogrammierer schrieb:
> Matthias T. schrieb:
>> Hier meine Lösung für ATtiny 2313:
>
> Und was hat das mit Klassen-Programmierung und C++ zu tun?

In C bekomme ich die Timer auch zum laufen. Allerdings wollte ich das 
ganze anders machen um mein C++ zu verbessern.

Wilhelm M. schrieb:
> Ausserdem ist Dein Beispiel nicht vollständig.

Was fehlt denn noch? Die main.cpp sieht noch ziemlich kahl aus. diese 
ist noch leer
1
#include "system.h" // hier ist nur define F_CPU
2
#include <util/delay.h>
3
#include <avr/io.h>
4
#include "Timer/timer.h"
5
#include "Interrupt/interrupt.h"
6
7
int main(void)
8
{
9
  while(1){
10
11
  }
12
  
13
}

interrupt.cpp
1
#include "interrupt.h"
2
#include "../Timer/timer.h"
3
4
void interrupt::handler1() {
5
  if(owner[0])
6
  owner[0]->serviceRoutine();
7
}
8
9
void interrupt::record(int interruptNumber, interrupt *i) {
10
  owner[interruptNumber - 1] = i;
11
}

int timer.cpp habe ich nocht
1
void timer::timerInterrupt::serviceRoutine() {
2
  if(ownerTimer != 0)
3
  ++ownerTimer->i;
4
}
 hinzugefügt.

timer.h hat noch bekommen
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
#include <stdint.h>

Jetzt bekomme ich für timer.h den Error
expected class-name before '{' token
-> class timerInterrupt : public interrupt {

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Frank schrieb:

> Jetzt bekomme ich für timer.h den Error
> expected class-name before '{' token
> -> class timerInterrupt : public interrupt {


Kann es sein, dass Du die Header-datei mit "interrupt" nicht includiert 
hast?

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Frank schrieb:
>
>> Jetzt bekomme ich für timer.h den Error
>> expected class-name before '{' token
>> -> class timerInterrupt : public interrupt {
>
>
> Kann es sein, dass Du die Header-datei mit "interrupt" nicht includiert
> hast?

 ... und am besten ein Minimalbeispiel (in einer Datei) und vollständige 
Fehlermeldungen. Dann ist es mit weniger Aufwand nachzuvollziehen ...

von Ausführlichprogrammierer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> ... und am besten ein Minimalbeispiel (in einer Datei) und vollständige
> Fehlermeldungen.

Volle Zustimmung. Kann man alles zur Überprüfung der Funktionsfähigkeit
in eine einzige Datei packen.

UndmitkurzenprägnantenIdentifiernlässtessichnochvielleichterverstehen.

von Ausführlichprogrammierer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Frank schrieb:
> int timer.cpp habe ich nocht
> void timer::timerInterrupt::serviceRoutine()
> {
>   if(ownerTimer != 0)
>   ++ownerTimer->i;
> }
>  hinzugefügt.

Du meinst also dieses Chaos inklusive Salamitaktik soll man
vernünftig nachvollziehen können?

Du machst es dir leicht, aber nicht denen die dir vielleicht
helfen wollen.

von gelegenheitsprogrammierer (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
1
#ifndef TIMER_H_
2
#define TIMER_H_
3
4
#include "../Interrupt/interrupt.h"
5
6
class timer {
7
  
8
  public:
9
  timer(volatile uint8_t &timerCounterControlRegister, uint8_t tccrNewState, volatile uint8_t &timerInterruptMaskRegister, uint8_t timskNewState, int interruptNumber);
10
  ~timer();
11
  
12
  volatile uint32_t i;
13
14
  class timerInterrupt : public interrupt {
15
    timer *ownerTimer;
16
    void serviceRoutine();
17
    
18
    public:
19
    timerInterrupt(int interruptNumber, timer *ownerTimer);
20
  } nestedTimerInterrupt;
21
    
22
  friend timerInterrupt;
23
  
24
};
25
26
27
28
#endif

Hier wird die Klasse timerInterrupt innerhalb von der Klassendeklaration 
timer deklariert. Das alleine sieht schon komisch aus. Dazu wird in 
timerInterrupt noch ein Pointer auf ein Objekt vom Typ timer deklariert. 
Deswegen meckert dein Kompiler.

Die Deklaration von timerInterrupt gehört hier nicht hin.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
gelegenheitsprogrammierer schrieb:

>
> Die Deklaration von timerInterrupt gehört hier nicht hin.

Nested classes kann man schon machen.

Ich warte erst mal auf das Minimalbeispiel, denn gegenüber der ersten 
Version am Anfang hat der TO ja auch noch was geändert ...

von Frank (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe jetzt mal beide (timer und interrupt)in eine datei gemacht.
leider bekomme ich immer noch den Fehler
expected class-name before '{' token

Line 13
-> class timerInterrupt : public interrupt {

von Frank (Gast)


Bewertung
0 lesenswert
nicht lesenswert
gelegenheitsprogrammierer schrieb:
> Hier wird die Klasse timerInterrupt innerhalb von der Klassendeklaration
> timer deklariert. Das alleine sieht schon komisch aus. Dazu wird in
> timerInterrupt noch ein Pointer auf ein Objekt vom Typ timer deklariert.
> Deswegen meckert dein Kompiler.
>
> Die Deklaration von timerInterrupt gehört hier nicht hin.

Das ist doof, da ich mir diese Seite als Vorlage genommen habe
https://www.mikrocontroller.net/articles/AVR_Interrupt_Routinen_mit_C%2B%2B#Interrupt_Routine_in_einer_geschachtelten_Klasse
und es hier genauso gemacht worden ist

von Wilhelm M. (wimalopaan)


Bewertung
1 lesenswert
nicht lesenswert
Der C++ Compiler ist im wesentlichen ein one-pass Compiler, d.h. er geht 
von oben nach unten vor.  An der Stelle, wo der Typ interrupt gebraucht 
wird, ist er noch gar nicht deklariert. Er kennt also den Typ nicht.

Deswegen muss die Deklaration der BasisKlasse vor der abgeleiteten 
Klasse stehen (oder inkludiert werden).

von Sheeva P. (sheevaplug)


Bewertung
0 lesenswert
nicht lesenswert
Frank schrieb:
> Habe jetzt mal beide (timer und interrupt)in eine datei gemacht.
> leider bekomme ich immer noch den Fehler
> expected class-name before '{' token
>
> Line 13
> -> class timerInterrupt : public interrupt {

In Deiner Datei timerinterrupt.h deklarierst Du zunächst die Klasse 
"timer" und danach die Klasse "interrupt". In der Definition der Klasse 
"timer" willst Du aber eine nested class "timerInterrupt" definieren, 
die von der an dieser Stelle noch unbekannten Klasse "timer" erbt.

Verschieb' die Deklaration von "interrupt" einfach mal nach oben vor die 
Deklaration von "timer", dann sollte es klappen -- vorausgesetzt, Du 
hast keine weiteren Fehler eingebaut.

von Kai (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Deswegen muss die Deklaration der BasisKlasse vor der abgeleiteten
> Klasse stehen (oder inkludiert werden).

Das stimmt. Das hätte mir eigentlich auch auffallen müssen.
Habe ich auch geändert, jedeoch kommt dann der nächste Fehler:

undefinied reference to 'interrupt::owner'
1
void interrupt::handler1() {
2
    if(owner[0])
3
    owner[0]->serviceRoutine();
4
}
5
[code]
6
7
das kommt daher, dass dieser noch niergends initialisiert ist.
8
Auf der Seite steht:
9
Das owner-Array wird - auch hier der Vollständigkeit des Codes halber - auf Null initialisiert.
10
interrupt *interrupt::owner[] = {0};
11
12
aber wo mache ich das genau?
13
in der main-funktion?
14
15
[code]
16
#include "TimerInterrupt/timerinterrupt.h"
17
18
int main(void)
19
{
20
  
21
  timer timer0(TCCR0B,
22
  TCCR0B | (1 << CS00) & ~(1 << CS01) | (1 << CS02),
23
  TIMSK0,
24
  TIMSK0 | (1 << TOIE0),
25
  TIMER0_OVF_vect_num);
26
27
  interrupt *interrupt::owner[] = {0};
28
29
  while(1)
30
  {
31
  }
32
}

bekomme so aber die Fehler:
-suggest parantheses around arithmetic in operand of '|'[-Wparentheses]
-qualified-id in declaration before '[' token
-expected initializer before '[' token

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Kai schrieb:
> Wilhelm M. schrieb:
>> Deswegen muss die Deklaration der BasisKlasse vor der abgeleiteten
>> Klasse stehen (oder inkludiert werden).
>
> Das stimmt. Das hätte mir eigentlich auch auffallen müssen.
> Habe ich auch geändert, jedeoch kommt dann der nächste Fehler:
>
> undefinied reference to 'interrupt::owner'
>
> [code]
> void interrupt::handler1() {
>     if(owner[0])
>     owner[0]->serviceRoutine();
> }
> [code]
>
> das kommt daher, dass dieser noch niergends initialisiert ist.

Es scheint mit, dass Deine C++-Kenntnisse nur rudimentär sind ...

owner ist ein static-member der Klasse. Das ist dann nur eine 
Deklaration - die Definition muss in einer Implementierungsdatei 
erfolgen -> ODR-Rule!

Wenn Dir die Grundlagen nicht klar sind, so tust Du Dir mit C++ auf dem 
uC keinen Gefallen. Lerne C++ auf dem PC, und dann kannst Du umsteigen 
damit auf den uC. Man programmiert auf dem uC in C++ zusätzlich auch 
noch sehr viel anders als mit C++ auf dem PC ...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.