Forum: Mikrocontroller und Digitale Elektronik Atmega88 reagiert nicht auf seriellen Eingang


von Micha (Gast)


Lesenswert?

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
volatile uint8_t buf[256];  // print buffer
14
volatile uint8_t ix = 0;  // index for incoming chars
15
volatile uint8_t ox = 0;  // index for outgoing chars
16
17
ISR(USART_RX_vect)  // usart receive char ISR
18
{
19
  buf[ix++] = UDR0;
20
}
21
22
int main(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
void initPorts()
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
void printChar(char c)
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
70
}
71
72
void initUSART()
73
{
74
  UCSR0C = 0b00001110;  // 8N1 format
75
  UCSR0B = 0b00011000;  // enable TX and RX
76
  UBRR0H = 0;
77
  UBRR0L = 119; // 9600 Baud for F_CPU = 18.432 MHz
78
  UCSR0A = 0b00000000;
79
  UCSR0B |= (1 << RXCIE0);  // enable interrupt for RxD
80
  sei();    // allow interrupts
81
}

von Karl H. (kbuchegg)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

>   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.

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

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?

von Micha (Gast)


Lesenswert?

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 :)

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

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.

von Micha (Gast)


Lesenswert?

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
volatile uint8_t buf[256];  // print buffer
14
volatile uint8_t ix = 0;  // index for incoming chars
15
volatile uint8_t ox = 0;  // index for outgoing chars
16
17
ISR(USART_RX_vect)  // usart receive char ISR
18
{
19
  buf[ix++] = UDR0;
20
}
21
22
int main(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
void initPorts()
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
void printChar(char c)
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
void initUSART()
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
81
  UCSR0C = (3<<UCSZ00);  // 8N1 format
82
  sei();    // allow interrupts
83
}

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

Die Anwendung dahinter nimmt Gestalt an ;)

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.