Bin grade am verzweifeln - eine Schaltung mit einem Atmega 88 der aus
einem seriellen Input einen Output zum parallelen Drucker machen soll.
Letzteres hab ich bereits ausgiebig getestet, das funktioniert.
Heute hab ich den seriellen Input drangebastelt, aber der Atmega
reagiert nicht auf Input. Sieht eventuell jemand einen offensichtlichen
Fehler in dem folgenden Code? Vielen Dank schon mal.
1
/*
2
* DruckerSteuerung.c
3
*
4
* Created: 14.10.2012 10:42:54
5
* Author: Michael Berger
6
*/
7
8
#include"main.h"
9
#include<util/delay.h>
10
#include<avr/io.h>
11
#include<avr/interrupt.h>
12
13
volatileuint8_tbuf[256];// print buffer
14
volatileuint8_tix=0;// index for incoming chars
15
volatileuint8_tox=0;// index for outgoing chars
16
17
ISR(USART_RX_vect)// usart receive char ISR
18
{
19
buf[ix++]=UDR0;
20
}
21
22
intmain(void)
23
{
24
initPorts();
25
initUSART();
26
while(1)
27
{
28
if(ix!=ox){
29
printChar(buf[ox++]);
30
if(((ix-ox)%256)>100){// modulo operator to determine abs. difference
31
// send XOFF
32
while(ox!=ix)printChar(buf[ox++]);
33
// send XON
34
}
35
}
36
}
37
}
38
39
voidinitPorts()
40
{
41
DDRB=0b11111111;// PB0 is Strobe, PB1 is Init
42
DDRC=0b11111111;// PC0..PC5 is D0..D5
43
DDRD=0b11000011;// Port D pins used as follows:
44
/*
45
PD7,PD6 is D7,D6
46
PD5 Ack
47
PD4 Busy
48
PD3 Paper Out
49
PD2 Sel
50
*/
51
PORTC=CR;// sometimes this gets printed after a reset...
52
PORTD&=0b00111111;// 2 high bits of CR, both 0
53
54
PORTB&=~(1<<INIT_PIN);// init printer
55
_delay_ms(10);
56
PORTB|=1<<INIT_PIN;
57
_delay_ms(100);// give the printer some time to settle
58
}
59
60
voidprintChar(charc)
61
{
62
while(PIND&1<<BUSY_PIN){}// wait for Busy signal
63
PORTC=c&0b00111111;// data bits 0..5
64
PORTD&=0b00111111;// delete pins 6,7
65
PORTD|=c;// set pins 6,7 to char pattern
66
PORTB&=~(1<<STROBE_PIN);
67
_delay_ms(5);
68
PORTB|=(1<<STROBE_PIN);
69
while(!(PIND&1<<ACK_PIN)){}// wait for /Ack signal
Das erste, was du bei einer seriellen Schnittstelle IMMER machen
solltest, ist die Richtung umzudrehen.
Anstatt den µC empfangen zu lassen, lässt du ihn erst mal senden!
Einfach zb in einer Endlosschleife ein 'X' senden lassen. Ev. mit einer
kleinen Pause zwischen den Zeichen.
Am anderen Ende des Kabels sitzt dann ein PC mit einem Terminalprogramm,
welches dir anzeigt was es vom µC erhalten hat, was immer das auch ist.
Warum ist das das erste?
Weil du am µC normalerweise keine vernünftige Anzeigemöglichkeit hast,
an der du verfolgen kannst, ob überhaupt etwas ankommt, bzw. wenn etwas
ankommt, ob das das richtige ist. So gesehen ist die Serielle
Schnittstelle im PC sowie das Terminalprogramm und dessen Anzeige für
dich eine 'getestete Komponente', von der erst mal angenommen werden
kann, dass sie funktioniert. Wenn daher die Übertragung nicht
funktioniert, dann muss das Problem entweder zb am Kabel oder im µC
liegen.
Beim Kabel gibt es die Möglichkeit, das es falsch gekreuzt ist. Wenn gar
nichts auf dem PC rauskommt, dann ist das eine nicht unwahrscheinliche
Möglichkeit.
Wenn was rauskommt, allerdings die Zeichen falsch sind, dann stimmt die
Baudrate im µC nicht. Etwas, das wiederrum in mehr als 98% der Fälle auf
eine fehlerhafte Taktrate im µC zurückzuführen ist. Allerdings ist
damit nachgewiesen, das das Kabel schon mal richtig rum gekreuzt ist
Klappt dann die Übertragung µC -> PC, dann klappt auch die Übertragung
PC -> µC (die sich leider in den meisten Fällen nicht so einfach
debuggen lässt) auf Anhieb. Wenn dann immer noch Probleme im µC sind,
dann liegen die im Programm, welches die eingetrudelten Zeichen
weiterverarbeiten bzw. weiterverteilen. Daher ist es wichtig, dass du
erst mal feststellst, ob die USART grundsätzlich funktioniert. Und das
geht am einfachsten, wenn der µC sendet und der PC empfängt. Immer so
wenig Unbekannte wie möglich und ungetestete Systeme die Fehler
enthalten können im System haben!
> UCSR0C = 0b00001110; // 8N1 format> UCSR0B = 0b00011000; // enable TX and RX
Sorry. Aber das tu ich mir nicht an, da die Einzelbits
auseinanderzudröseln.
Benutze die Bitnamen. Da bleiben dann noch genug andere Stolpersteine
übrig - man muss sich nicht mutwillig Prügel zwischen die Beine werfen.
An welchem Pin fütterst du den Mega88 denn mit den seriellen Daten? (ich
will jetzt kein "RXD" hören!)
Was sitzt alles zwischen dem Controller und dem COM-Port des PCs?
Was hast du bisher unternommen um sicherzustellen dass die seriellen
Daten auch am Controller ankommen?
ich hab inzwischen mal nach einem brauchbaren Muster für eine USART_init
spezifisch für den Atmega88 gesucht und bin hier fündig geworden:
Beitrag "Atmega88 USART"
Danach funktioniert jetzt erst mal was, d.h. der Drucker druckt, bis er
sich verstolpert, was aber normal ist da ich das XOFF/XON Protokoll
bisher weder auf Sender- noch auf Empfängerseite implementiert habe.
Daher erst mal vielen Dank für die Antworten! Problem gelöst :)
Micha schrieb:> ich hab inzwischen mal nach einem brauchbaren Muster für eine USART_init> spezifisch für den Atmega88 gesucht und bin hier fündig geworden:> Beitrag "Atmega88 USART"
Dann zeig doch mal bitte, wie du diese Initialisierung übernommen hast.
Hallo Magnus,
hier ist der mittlerweile für den Atmega88, mit 18,432MHz getaktet,
funktionierende Code, bzw. der interessante Teil davon in der initUSART
Funktion. Ursprünglich hatte ich in das UCSR0A Register 0 geschrieben,
damit ging es nicht. In dieser Version wird das UCSR0A Register in Ruhe
gelassen so wie es ist, damit geht es. Muss wohl mal genauer nachlesen.
Das Datenblatt das ich mir von Reichelt geladen hatte geht nur bis Seite
35, muss wohl mal ein komplettes Datenblatt suchen...
1
/*
2
* DruckerSteuerung.c
3
*
4
* Created: 14.10.2012 10:42:54
5
* Author: Michael Berger
6
*/
7
8
#include"main.h"
9
#include<util/delay.h>
10
#include<avr/io.h>
11
#include<avr/interrupt.h>
12
13
volatileuint8_tbuf[256];// print buffer
14
volatileuint8_tix=0;// index for incoming chars
15
volatileuint8_tox=0;// index for outgoing chars
16
17
ISR(USART_RX_vect)// usart receive char ISR
18
{
19
buf[ix++]=UDR0;
20
}
21
22
intmain(void)
23
{
24
initPorts();
25
initUSART();
26
while(1)
27
{
28
if(ix!=ox){
29
if(buf[ox]>10)printChar(buf[ox]);// supress LF because printer misinterprets it
30
ox++;
31
if(((ix-ox)%256)>100){// modulo operator to determine abs. difference
32
// implement XOFF here
33
while(ox!=ix){
34
if(buf[ox]>10)printChar(buf[ox]);
35
ox++;
36
}
37
// implement XON here
38
}
39
}
40
}
41
}
42
43
voidinitPorts()
44
{
45
DDRB=0b11111111;// PB0 is Strobe, PB1 is Init
46
DDRC=0b11111111;// PC0..PC5 is D0..D5
47
DDRD=0b11000011;// Port D pins used as follows:
48
/*
49
PD7,PD6 is D7,D6
50
PD5 Ack
51
PD4 Busy
52
PD3 Paper Out
53
PD2 Sel
54
*/
55
PORTC=CR;// sometimes this gets printed after a reset...
56
PORTD&=0b00111111;// 2 high bits of CR, both 0
57
58
PORTB&=~(1<<INIT_PIN);// init printer
59
_delay_ms(10);
60
PORTB|=1<<INIT_PIN;
61
_delay_ms(100);// give the printer some time to settle
62
}
63
64
voidprintChar(charc)
65
{
66
while(PIND&1<<BUSY_PIN){}// wait for Busy signal
67
PORTC=c&0b00111111;// data bits 0..5
68
PORTD&=0b00111111;// delete pins 6,7
69
PORTD|=c;// set pins 6,7 to char pattern
70
PORTB&=~(1<<STROBE_PIN);
71
_delay_ms(5);
72
PORTB|=(1<<STROBE_PIN);
73
while(!(PIND&1<<ACK_PIN)){}// wait for /Ack signal
74
}
75
76
voidinitUSART()
77
{
78
UBRR0H=0;
79
UBRR0L=119;// 9600 Baud for F_CPU = 18.432 MHz
80
UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);// enable interrupt for RxD
Eine eigene Frage?
Dieser Thread ist über 13 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.