Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt Fehler __vector_16


von Tekki-Amateur (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte mit Hilfe eines ATMEGA328P eine Frequenzmessung machen, und 
das gemessene auf vier BCD-Anzeigen ausgeben. Das ist allerdings bei 
meinem Problem relativ unwichtig.

Da für mich das Thema Interrupts relativ neu ist, und ich es mir selber 
beibringe, gehe ich gerade bei der Programmentwicklung Schritt für 
Schritt vor. Noch arbeite ich auf einem ARDUINO UNO, weshalb ich zum 
Programmieren die Arduino IDE verwende. Trotzdem wird der Code in 
normalem C verfasst.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
int zaehler;
5
6
void setup() {
7
8
  DDRD |= (1 << PD5);   //Ausgang für A Eingang
9
  DDRD |= (1 << PD0);   //Ausgang für B Eingang
10
  DDRD |= (1 << PD1);   //Ausgang für C Eingang
11
  DDRD |= (1 << PD4);   //Ausgang für D Eingang
12
  DDRD &= ~(1 << PD2);    //Eingang für Interrupt INT0
13
14
  DDRB |= (1 << PB5);   //Ausgang für LED an Pin 13
15
16
  PORTD &= ~(1 << PD2);   //Pull-Up abschalten
17
18
  //8 Bit Timer auf 2,5 ms mit Prescale von 256
19
  TCCR0A = 0;
20
  TCCR0B = 0;
21
  TCNT0 = 100;
22
  TCCR0B |= (1 << CS02);
23
  TIMSK0 |= (1 << TOIE0);
24
25
  //16 Bit Timer auf 1 s mit Prescale von 256
26
  TCCR1A = 0;
27
  TCCR1B = 0;
28
  TCNT1 = 3036;
29
  TCCR1B |= (1 << CS12);
30
  TIMSK1 |= (1 << TOIE1);
31
32
  //Ext. Interrupt (INTO) aktiviern und auf steigende Flanke triggern
33
  EICRA |= (1 << ISC01) | (1 << ISC00); //Trigger INT0 nach steigender Flanke
34
  EIMSK |= (1 << INT0);       //INT0 aktivieren
35
}
36
37
void loop() {
38
39
}
40
41
ISR(TIMER1_OVF_vect) {
42
  TCNT1 = 3036;
43
  BiZahl();
44
}
45
46
ISR(TIMER0_OVF_vect) {
47
  TCNT0 = 100;
48
  EIMSK |= (1 << INT0);       //INT0 aktivieren
49
}
50
51
ISR(INT0_vect) {
52
  if (zaehler < 9) {
53
    zaehler ++;
54
  } else {
55
    zaehler = 0;
56
  }
57
58
  EIMSK &= ~(1 << INT0);       //INT0 deaktivieren
59
}
60
61
void BiZahl() {
62
  switch (zaehler) {
63
    case 0:
64
      PORTD &= ~(1 << PD5);
65
      PORTD &= ~(1 << PD0);
66
      PORTD &= ~(1 << PD1);
67
      PORTD &= ~(1 << PD4);
68
69
      break;
70
    case 1:
71
      PORTD |= (1 << PD5);
72
      PORTD &= ~(1 << PD0);
73
      PORTD &= ~(1 << PD1);
74
      PORTD &= ~(1 << PD4);
75
76
      break;
77
    case 2:
78
      PORTD &= ~(1 << PD5);
79
      PORTD |= (1 << PD0);
80
      PORTD &= ~(1 << PD1);
81
      PORTD &= ~(1 << PD4);
82
83
      break;
84
    case 3:
85
      PORTD |= (1 << PD5);
86
      PORTD |= (1 << PD0);
87
      PORTD &= ~(1 << PD1);
88
      PORTD &= ~(1 << PD4);
89
90
      break;
91
    case 4:
92
      PORTD &= ~(1 << PD5);
93
      PORTD &= ~(1 << PD0);
94
      PORTD |= (1 << PD1);
95
      PORTD &= ~(1 << PD4);
96
97
      break;
98
    case 5:
99
      PORTD |= (1 << PD5);
100
      PORTD &= ~(1 << PD0);
101
      PORTD |= (1 << PD1);
102
      PORTD &= ~(1 << PD4);
103
104
      break;
105
    case 6:
106
      PORTD &= ~(1 << PD5);
107
      PORTD |= (1 << PD0);
108
      PORTD |= (1 << PD1);
109
      PORTD &= ~(1 << PD4);
110
111
      break;
112
    case 7:
113
      PORTD |= (1 << PD5);
114
      PORTD |= (1 << PD0);
115
      PORTD |= (1 << PD1);
116
      PORTD &= ~(1 << PD4);
117
118
      break;
119
    case 8:
120
      PORTD &= ~(1 << PD5);
121
      PORTD &= ~(1 << PD0);
122
      PORTD &= ~(1 << PD1);
123
      PORTD |= (1 << PD4);
124
125
      break;
126
    case 9:
127
      PORTD |= (1 << PD5);
128
      PORTD &= ~(1 << PD0);
129
      PORTD &= ~(1 << PD1);
130
      PORTD |= (1 << PD4);
131
132
      break;
133
  }
134
}

Der 16Bit Timer läuft einwandfrei (habe ich zuvor mit einem Zähler 
ausprobiert). Dieser soll wenn das Programm fertig ist bestimmen, wann 
die Daten auf den Anzeigen aktualisiert werden.

Im aktuellen Programm (siehe oben) verwende ich den externen Interrupt, 
um mit Hilfe eines Tasters eine der Anzeigen hochzuzählen. Das klappt 
soweit, allerdings ohne Entprellung

Daraufhin wurde der 8Bit Timer erstellt, welcher am Ende für das 
Multiplexing der Anzeigen benutzt werden, nun allerdings erstmal als 
Entprellung dienen soll.

Wenn ich mein Programm Kompilieren will kommt folgende Fehlermeldung
1
Arduino: 1.6.8 (Windows 7), Board: "Arduino/Genuino Uno"
2
3
wiring.c.o (symbol from plugin): In function `__vector_16':
4
5
(.text+0x0): multiple definition of `__vector_16'
6
7
C:\Users\plauer\AppData\Local\Temp\buildaa90d1ab3a570bf160fd05c3c4d65e96.tmp\sketch\_7_SEG_INTERRUPT.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
8
9
collect2.exe: error: ld returned 1 exit status
10
11
exit status 1
12
Fehler beim Kompilieren für das Board Arduino/Genuino Uno.

Bei der Fehlersuche, bin ich wie folgt Vorgegangen:
  -Überprüfen der Programm-Syntax
  -Überprüfen der Registerzuweisungen
  -Überprüfen der Zahlenbereiche
  -Nochmaliges Überprüfen der Registerzuweisungen

von Peter II (Gast)


Lesenswert?

Tekki-Amateur schrieb:
> C:\Users\plauer\AppData\Local\Temp\buildaa90d1ab3a570bf160fd05c3c4d65e96 
.tmp\sketch\_7_SEG_INTERRUPT.ino.cpp.o
> (symbol from plugin):(.text+0x0): first defined here

steht doch alles da. Die ISR (__vector_16) wird doppelt definiert.

wiring.c.o
_7_SEG_INTERRUPT.ino.cpp.o


schein wohl etwas internes vom Arduino zu sein.

von THOR (Gast)


Lesenswert?

Peter II schrieb:
> schein wohl etwas internes vom Arduino zu sein.

Das Arduino Framework benutzt einen der Timer intern, ja. Allerdings ist 
arduino.h ja oben gar nicht eingebunden.

Mal in den Projektsettings nachgucken ob da gegen irgendne Arduino Lib 
gelinkt wird.

Oder auf Geany + avrdude umsteigen :P

von Peter II (Gast)


Lesenswert?

THOR schrieb:
> Das Arduino Framework benutzt einen der Timer intern, ja. Allerdings ist
> arduino.h ja oben gar nicht eingebunden.

eine Headerdatei kann auch dafür nicht verantwortlich sein. Im Projekt 
wird noch eine CPP dabei kompiliert und eingebunden.

von Arno (Gast)


Lesenswert?

Dann lies dir die Fehlermeldung nochmal genau durch... übersetzt steht 
da:

> wiring.c.o (symbol from plugin): In function `__vector_16':

In der Datei wiring.c.o in der Funktion __vector_16:

> (.text+0x0): multiple definition of `__vector_16'

__vector_16 ist mehrfach definiert

> C:\Users\plauer\AppData\Local\Temp\buildaa90d1ab3a570bf160fd05c3c4d65e96 
.tmp\sketch\_7_SEG_INTERRUPT.ino.cpp.o  (symbol from plugin):(.text+0x0): first 
defined here

Die erste Definition findet sich in dieser (seltsamen) Datei.

Ich vermute daher, dass du noch eine andere Datei mit kompilierst und 
linkst, die einen in deiner oben gezeigten Datei verwendeten ISR 
ebenfalls benutzt. Vielleicht ungewollt (nutzt dir Arduino-Umgebung den 
Timer 0 auch? Ist ja wohl aufgetreten, als du den Timer0-ISR hinzugefügt 
hast?)

Du kannst auch nochmal in die iom328p.h schauen (die von io.h 
eingebunden wird) ob TIMER0_OVF_vect wirklich Interrupt-Vektor Nummer 16 
ist.

MfG, Arno

von Mitlesa (Gast)


Lesenswert?

Tekki-Amateur schrieb:
> Daraufhin wurde der 8Bit Timer erstellt,

Wie soll das gehen? Du kannst keiner Timer erstellen, der
ist in deinem Arduino schon drin.

Timer0 wird vomArduino Framework bereits verwendet und
steht für weitere Anwendung nur beschränkt zur Verfügung.
Daher kannst du die ISR nicht deklarieren.

Aber du kannst dich vom Framework lösen indem du selbst ein
1
int main (void)
2
{
3
}

schreibst und darin dein setup() aufrufst und die Loop implementierst.

von Tekki-Amateur (Gast)


Lesenswert?

Ändert man
1
void setup(){
2
  ...
3
}
4
5
void loop(){
6
  ...
7
}

in
1
int main(){
2
  ...
3
4
  while(1){
5
    ...
6
  }
7
8
  return 0;
9
}

funktioniert erst einmal gar kein Interrupt mehr!

mit dem Befehl
1
sei();
 (globale Interrupts freischalten) löst sich das Problem.

Kurz gesagt: Das 'Global Interrupt Enable'-Bit muss gesetzt werden.

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.