Forum: Mikrocontroller und Digitale Elektronik Probleme mit der Datenausgabe per UART durch Interrupts AtMega168


von Christoph B. (christophbu)


Lesenswert?

Hallo,

nachdem mir die Suchfunktion nicht mehr weiterhelfen kann und auch meine 
Bekannten mir nicht mehr helfen konnten wende ich mich mit meinem 
Problem ans Forum.

Ich habe die Aufgabe 2 4-schrittige Quadraturencoder auszulesen und 
diese Daten an den Rechner zu schicken, damit eine Weiterverarbeitung in 
Labview folgen kann. Das Programm zum Auslesen basiert auf dem 
Beispielcode von Peter Dannegger. Zur Kommunikation mittels Uart 
verwende ich fertige Dateien und Initialisierungsbefehle von Peter 
Fleury.
Ich verwende einen ATMega 168 Crumb Modul. Dieses Modul trägt den 
ATMega168 einen UART zu USB Wandler und ein Quarz das, auf 20 MHz 
taktet.
Die Versuche Strings per UART in der Mainmethode zu senden waren 
erfolgreich und konnten mit Putty angezeigt werden.

Es sollte ein Programm folgen, dass über Interrupts die Encoder 
ausliest, und die Werte sendet.
Ich möchte Timer 0 verwenden um die Encoder auszulesen und Timer 2 um 
die akkumulierten Werte auszugeben.
Um eine Beschädigung der Encoder vollständig auszuschließen. Wird das 
Programm getestet, ohne dass sie angeschlossen sind. Es müsste die 
durchgehende Ausgabe des Wertes 0 für jeden Encoder folgen.
Leider funktioniert nichts. Putty detektiert keine Datenausgabe des 
Mikrocontrollers. Die Kompilierung des C-Programms erzeugt 0 Warnungen.
Wo liegt der logische Fehler in diesem Programm?

gruß Christoph
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include "uart.h"
5
6
7
#ifndef F_CPU
8
9
#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 20000000"
10
#define F_CPU 20000000UL  // Systemtakt in Hz - Definition als unsigned long beachten 
11
                         // Ohne ergeben sich unten Fehler in der Berechnung
12
#endif
13
 
14
#define UART_BAUD_RATE      9600
15
//Target Atmega 168
16
17
18
19
#define PHASE_A1 (PINC & 1<<PINC0)
20
#define PHASE_B1 (PINC & 1<<PINC1)
21
#define PHASE_A2 (PINC & 1<<PINC2)
22
#define PHASE_B2 (PINC & 1<<PINC3)
23
24
25
26
int8_t enc_delta1; //-128 ... 127
27
int8_t enc_delta2;
28
int8_t Wert1 = 0;
29
int8_t Wert2 = 0;
30
char out1[4]  ;
31
char out2[4]  ;
32
33
void encode_init(void)
34
{
35
TCCR2B = (1<<WGM22) | (1<<CS22) | (1<<CS21) | (1<<CS20);
36
OCR2B = 10;
37
TCCR0B = (1<<WGM01) | (1<<CS02) | (1<<CS00);
38
OCR0B = 1;
39
TIMSK2 = 1<<OCIE2B;
40
TIMSK0 = 1<<OCIE0B; 
41
//beide Zähler initialisieren
42
}
43
44
45
ISR (TIMER2_COMPB_vect) //Abtastzeit
46
{
47
static int8_t last1;
48
static int8_t last2;
49
int8_t new1,diff1;
50
int8_t new2,diff2;
51
new1 = 0;
52
if(PHASE_A1)
53
  new1 = 3;
54
if(PHASE_B1)
55
  new1 ^=1; //convert grey to binary
56
diff1 = last1 -new1; //difference last - new
57
if (diff1 & 1){ //bit 0 = value (1)
58
  last1 = new1; //store new as next last
59
  enc_delta1 += (diff1 & 2) -1; //bit 1 = direction(+/-)
60
  }
61
62
new2 = 0;
63
if(PHASE_A2)
64
  new2 = 3;
65
if(PHASE_B2)
66
  new2 ^=1; //convert grey to binary
67
diff2 = last2 -new2; //difference last - new
68
if (diff2 & 1){ //bit 0 = value (1)
69
  last2 = new2; //store new as next last
70
  enc_delta2 += (diff2 & 2) -1; //bit 1 = direction(+/-)
71
  }
72
73
}
74
75
ISR (TIMER0_COMPB_vect){ //Interrupt, der per UART daten an den PC sendet
76
cli();
77
itoa(Wert1,out1,10);
78
itoa(Wert2,out2,10);
79
uart_puts(out1);
80
uart_puts("\r\n");
81
uart_puts(out2);
82
uart_puts("\r\n");
83
Wert1 = 0;
84
Wert2 = 0;
85
sei();
86
}
87
88
89
90
int8_t encode_read1(void) //read four step encoders
91
{
92
int8_t val1;
93
cli();
94
val1 = enc_delta1;
95
enc_delta1 &= 3;
96
sei();
97
return val1 >> 2;
98
}
99
100
int8_t encode_read2(void) //read four step encoders
101
{
102
int8_t val2;
103
cli();
104
val2 = enc_delta2;
105
enc_delta2 &= 3;
106
sei();
107
return val2 >> 2;
108
}
109
110
int main(void)
111
{
112
  
113
  encode_init();
114
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   
115
116
  sei();
117
  
118
  while(42){
119
  
120
  Wert1 =Wert1 + encode_read1();
121
  Wert2 =Wert2 + encode_read2();
122
  }
123
124
return 0;
125
}

von Grrrr (Gast)


Lesenswert?

1
ISR (TIMER0_COMPB_vect){ //Interrupt, der per UART daten an den PC sendet
2
cli();
3
itoa(Wert1,out1,10);
4
itoa(Wert2,out2,10);
5
uart_puts(out1);
6
uart_puts("\r\n");
7
uart_puts(out2);
8
uart_puts("\r\n");
9
Wert1 = 0;
10
Wert2 = 0;
11
sei();
12
}
Grusel.

Raus mit dem ganzen Zeug aus dem Interrupts. Dann klappts auch mit dem 
Encoder. Merke: In Interrupts kommt nur das allernotwendigste. 
Verarbeitung in main.

>Interrupt, der per UART daten an den PC sendet

Spätestens, wenn ich das 'U' in dem Kommentar tippen würde, würde ich 
wahrscheinlich so ein unkontrollierbares Zittern kriegen.

von Tom M. (Gast)


Lesenswert?

Schliesse mich meinem Vorredner an bezüglich UART...

Lass die sei() cli() Orgie in den ISR weg. cli macht ohnehin keinen Sinn 
in der ISR, da beim IRQ das I-Flag ohnehin gelöscht ist (keine "nested 
interrupts" per Default).

Bist sicher, dass uart_* bei gesperrten Interrupts funktioniert?

von spess53 (Gast)


Lesenswert?

Hi

Wenn ich mich nicht verrechnet habe, schlägt dein Timerinterrupt 
(TIMER0_COMPB_vect) alle 102,4 µs zu. Die Übertragung eines Zeichens bei 
9600 Baud dauert 1,04mS. Das sollte dir zu denken geben. Ansonsten 
schließe ich mich  Grrrr an.

MfG Spess

von Grrrr (Gast)


Lesenswert?

spess53 schrieb:
> schlägt dein Timerinterrupt
> (TIMER0_COMPB_vect) alle 102,4 µs

Na dann sollte Christoph mal seine Strategie neu überdenken. Alle 102,4 
µs was tun, was mindestens 1,04ms dauert? Da hilft auch auslagern in 
main nichts. Ist aber auf jeden Fall der bessere Weg.

von Christoph B. (christophbu)


Lesenswert?

Danke erst mal für die Antworten. Ich werde es ohne Interrupts 
versuchen.

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.