Forum: Mikrocontroller und Digitale Elektronik Probleme mit UART @ ATMega16


von Matthias S. (bruteforce)


Lesenswert?

Hallo!
Ich baue seit einiger Zeit an einer kleinen Kiste die irgendwann mal das 
CLIP-Signal meiner Telefonanlage auswerten soll.
Ich benutze dazu einen ATMega16 mit dem CMX602B (hier im Forum gefunden 
bei suche nach "clip") und ein Dot-Matrix-Display.
Das Display läuft auch schon wunderbar. Nun stehe ich seit längerem vor 
einem Problem:
Der CMX hat ein internes 8-Bit Schieberegister. Wenn das voll ist, wird 
eine Leitung auf 0 gezogen und man kann die Bits seriell (durch Takt 
anlegen) rausbekommen. Ist ja einfach dachte ich. Als ich das 
ausprobiert habe, bekamm ich
1. viel zu wenig Zeichen (ich rechne mit ca. 50, es kamen aber nur 10 
oder so...) und
2. waren diese nicht lesbar. (Das Signal sollte mit einigen "U"s 
anfangen (10101010) und dann kommt nach ein paar steuerzeichen die 
Telefonnummer im ascii-code.)
Das habe ich dann erstmal auf fehler die ich beim programmieren gemacht 
habe geschoben. Um zu testen, ob überhaupt gescheite Daten ankommen, 
habe ich das interne register ausgeschaltet und die datenleitung (ist 
dann eine serielle 1200 baud Übertragung 1 Stoppbit, keine Parität) auf 
das UART des ATMegas gelegt. (zusätzlich noch über MAX232 auf den PC)
Auf dem PC war alles super. Ich konnte die Steuerzeichen im Hexeditor 
alle wunderbar lesen und auch die tel-nr wurde einwandfrei übertragen. 
Aber am ATMega kommt wieder nur müll an.
Ich habe mir dann ein Oszilloskop geliehen um mal das Signal anzusehen. 
Die Pegel liegen sauber bei 0/5V. Das einzige was mir aufgefallen ist, 
ist das die Bit-Zeit (kein plan ob man das so nennt :) Halt die Zeit, 
die ein Bit stabil anliegt) relativ stark schwankt (ca im Bereich 740µs 
bis 860µs, sollte eiggentlich auf 833µs sein) aber im Mittel, z.b. über 
10 Bit betrachtet nurnoch wenig Abweichung (8.32ms) vorhanden ist. Nun 
meine Frage:
Reagiert der ATMega so empfindlich auf schwankngen, oder bin ich einfach 
nur unfähig zu Programmieren? ;)

Hier der interressante Teil aus meinem Programm (enthalten, aber 
auskommentiert ist auch noch der Teil mit dem manuellen Austakten)
Timer0 macht ein bisschen PWM für die Hintergrundbeleuchtung des 
Displays (hab natürlich beim layouten verpennt die PWM-Engine des ATMega 
zu benutzen :)
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "lcd.h"
4
#include "tools.h"
5
#include "CMX_ports.h"
6
7
8
static void avr_init(void);
9
10
uint8_t duty=0x00;
11
uint8_t blup=1;  //Backlight UP (false/true)
12
13
char lcd_data[2][20] ={{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}};
14
uint8_t pointer=0;
15
16
17
ISR (TIMER0_OVF_vect)
18
{
19
   //Backlight steuerung
20
}
21
22
ISR (TIMER0_COMP_vect)
23
{
24
   // noch mehr PWM-rummel... :)
25
}
26
27
28
//wird gerufen, wenn ein Anruf erkannt wird.
29
//der CMX wird aus dem SLEEP geholt.
30
ISR (INT0_vect)  // DET
31
{
32
  while (PIND & (1 << CMX_DET));
33
  PORTD &= ~(1<<CMX_ZP);  //CMX Aufwecken
34
  PORTD |= (1<<CMX_MODE); //ZP=0, MODE=1 -> FSK-Receiver
35
  
36
  //GICR |= (1<<INT1);
37
}
38
39
/*
40
ISR (INT1_vect)  // IRQN, low, wenn 8-Bit Schieberegister volgelaufen ist
41
{
42
  uint8_t idx;
43
  uint8_t zeile, spalte;
44
  delay(10);
45
  if (pointer >= 40)
46
  {
47
    pointer = 0;
48
  }
49
  zeile=pointer / 20;
50
  spalte = pointer % 20;
51
  pointer++;
52
  lcd_data[zeile][spalte]=0;
53
  //8 Bit über RXCK austakten, RXD enthät aktuelles Bit
54
  for (idx=0; idx < 8; idx++)
55
  {
56
    if (PIND & (1 << CMX_RXD))
57
      lcd_data[zeile][spalte] |= (1 << idx);
58
    PORTD |= (1 << CMX_RXCK);
59
    delay (10);
60
    PORTD &= ~(1 << CMX_RXCK);
61
    delay (10);
62
  }
63
} */
64
65
66
ISR (USART_RXC_vect)  //USART Zeichen empfangen
67
{  
68
  uint8_t zeile, spalte;
69
70
        // Fehler anzeigen
71
  if (UCSRA & (1<<FE))
72
    lcd_data[1][19]='E';
73
  if (UCSRA & (1<<DOR))
74
    lcd_data[1][19]='D';
75
        // Daten anzeigen
76
  if (pointer >= 39)
77
  {
78
    pointer = 0;
79
  }
80
  zeile=pointer / 20;
81
  spalte = pointer % 20;
82
  pointer++;
83
  lcd_data[zeile][spalte]=UDR;
84
}
85
86
int main(void)
87
{
88
  uint8_t l,s;
89
    avr_init();
90
  backlight_on();
91
  lcd_puts("CLIPPER v0.2");
92
  for (l=0; l<150; l++)
93
    delay(10000);
94
    for(;;)
95
    {
96
    for (l=0; l<2; l++)
97
    {
98
      lcd_gotoxy(0,l);
99
      for (s=0; s<20; s++)
100
      {
101
        lcd_putc(lcd_data[l][s]);
102
      }
103
104
    }
105
    delay (10);
106
    }
107
    
108
    return(0);
109
}
110
111
112
113
static void avr_init(void)
114
{
115
    lcd_init();
116
//Ports
117
    DDRC |= 0b00010000;
118
  DDRD = 0b11010000;
119
  PORTD =0b11111111;
120
121
//Timer
122
  TCCR0 &= 0b11111000;  //Stop Timer
123
  //TCCR0 |= 0b00000100;  //Timer0 clk/256
124
125
    TIMSK |= (1<<OCIE0) | (1<<TOIE0);  // Timer 0 Output Compare Int 
126
                     // und Timer0 Overflow Int setzen
127
128
//Externe Interrupts
129
  MCUCR |= (1<<ISC00) | (1<<ISC01); // rising edge on INT0 -> interrupt
130
//  MCUCR &= ~(1<<ISC10);    // falling edge on INT1
131
//  MCUCR |= (1<<ISC11);    //    ^^
132
  
133
  GICR |= (1<<INT0);    // INT0 aktivieren
134
135
//USART
136
  UBRRH = (unsigned char)(MYUBRR >> 8);  // Baud Rate Timer Hight Byte
137
  UBRRL = (unsigned char)MYUBRR;      // Low Byte
138
139
  UCSRB |= (1<<RXCIE) | (1<<RXEN); // Receiver Interrupt und Receiver an
140
141
142
  sei();
143
    return;
144
}
Die tools.h enthält auch die Definiton der Baud-Rate:
1
#ifndef __TOOLS_H__
2
#define __TOOLS_H__
3
4
#define XTAL 12000000
5
#define delay(us)  _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 )
6
7
#define BAUD 1200
8
#define MYUBRR (XTAL/16/BAUD-1)
9
10
extern inline void _delayFourCycles(unsigned int __count);
11
12
#endif
Ich hoffe ihr könnt mir ein paar Tipps geben. :)

Danke im Voraus!
Matthias

von Matthias S. (bruteforce)


Lesenswert?

Hallo nochmal.
Mir ist noch was aufegefallen. Ich habe mein Programm so modifiziert, 
das die FrameErrors und Data OverRun Errors gezählt werden. Dabei ist 
mir aufgefallen, das es zu ein paar Data OverRun Errors kommt. Aber nur 
so 1-2 während der übertragung der Daten. Wie kann es überhaupt zu so 
einem Fehler kommen, wenn das URD direkt im Interrupt gelesen wird? So 
schnell kann doch noch kein neues Byte angekommen sein, oder?
Ich hoffe mir ist noch zu Helfen ;)

Matthias

von ich (Gast)


Lesenswert?


#define MYUBRR (XTAL/16/BAUD-1) falsch
#define MYUBRR (XTAL/16*BAUD-1) richtig

von ich (Gast)


Lesenswert?

oder
#define MYUBRR XTAL/((16*BAUD)-1)

von Matthias S. (bruteforce)


Lesenswert?

Hi!
Danke Für deine Antwort :)

Aber die Definition von MYUBBR steht doch so wie ich sie hab im 
Datenblatt (S. 151 im C-Example)
Und das stimmt auch mit der Formel UBBR=(Fosc/(16*BAUD))-1 (weiter oben 
im Datenblatt) überein, wenn mich meine Mathe-Kenntnisse jetzt nicht im 
Stich lassen. Oder habe ich da was Falsch verstanden?

Matthias

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.