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