Forum: Mikrocontroller und Digitale Elektronik Korrektes auslesen des USARTs


von Pat K. (c63)


Lesenswert?

Hallo zusammen,

habe ein Problem mit folgendem Quellcode:
1
#ifndef _UART_H_
2
#define _UART_H_
3
4
#include <avr/io.h>
5
6
extern void uart_init(void);
7
8
9
10
static inline int
11
uart_putc (const uint8_t c)
12
{
13
  // Warten, bis UDR bereit ist für einen neuen Wert
14
  while (!(UCSRA & (1 << UDRE)))
15
  ;
16
17
  // UDR Schreiben startet die Übertragung
18
  UDR = c;
19
20
  return 1;
21
}
22
23
static inline uint8_t
24
uart_getc_wait(void)
25
{
26
  // Warten, bis etwas empfangen wird
27
  while (!(UCSRA & (1 << RXC)))
28
  ;
29
30
  // Das empfangene Zeichen zurückliefern
31
  return UDR;
32
}
33
34
static inline int
35
uart_getc_nowait(void)
36
{
37
  // Liefer das empfangene Zeichen, falls etwas empfangen wurde; -1 sonst
38
  return (UCSRA & (1 << RXC)) ? (int) UDR : -1;
39
}
40
41
#endif /* _UART_H_  */
42
43
#include <avr/io.h>
44
#include <avr/interrupt.h>
45
#include <util/delay.h>
46
47
48
49
#define BAUDRATE 38400UL 
50
51
//int a;
52
volatile unsigned char a = 0x00;
53
54
void uart_init()
55
{
56
  uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BAUDRATE) - 1);
57
  
58
  UBRRH = (uint8_t) (ubrr>>8);
59
  UBRRL = (uint8_t) (ubrr);
60
  
61
  // UART Receiver und Transmitter anschalten
62
  // Data mode 8N1, asynchron
63
  UCSRA = (1 << RXC);
64
  UCSRB = (1 << RXEN) | (1<<RXCIE);
65
  UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
66
67
  // Receive-Buffer leeren 
68
  do
69
  {
70
    UDR;
71
  }
72
  while (UCSRA & (1 << RXC));
73
74
  DDRD |= (1<<PD6);    // PortD als Ausgang deklarieren
75
  //PORTD = 0x00;   // Ports auf LOW schalten
76
77
}
78
79
80
// Einen 0-terminierten String übertragen.
81
82
void uart_puts (const char *s)
83
{
84
  do
85
  {
86
    uart_putc (*s);
87
  }
88
  while (*s++);
89
}
90
91
92
93
// Interupt wartet, bis Empfangsbit gesetzt wird und führt dann Routine aus
94
95
ISR(USART_RXC_vect) 
96
{
97
  a = UDR;
98
  //PORTD ^=(1<<PD6);
99
  if (a == 1) 
100
  {
101
    PORTD |= (1<<PD6);
102
  }
103
  else
104
  {
105
    PORTD &=~(1<<PD6);
106
  }
107
108
}
109
110
111
112
113
114
int main(void)
115
{
116
  
117
  uart_init();
118
  sei();
119
  
120
  
121
122
123
  while (1) {
124
    
125
    while (!(UCSRA & (1 << RXC)));
126
127
  }
128
129
130
131
  return 0;
132
}

Und zwar sende ich Zeichen mittels VB über die serielle Schnittstelle an 
meinen ATmega8.
In VB befinden sich zwei Buttons, der eine Sendet "1", der andere "0" 
(SerialPort1.Write ("1" & vbCr).
Leider bekomme ich es nicht auf die Reihen, dass PD6 auf High schaltet, 
wenn ich "1" sende und auf Low bei der "0".
Togglen des PD6 funktioniert, sprich die Interrupt Routine wird auch 
ausgeführt.
Mit BASIC läuft es ohne Probleme, nur mit C bekomm ich es einfach nicht 
auf die Reihe.

Für eure Hilfe bedanke ich mich schon mal im Voraus.
mfg
c63

von Roland .. (rowland)


Lesenswert?

1 != "1", vermutlich kodiert der Befehl "SerialPort1.Write ("1" & vbCr)" 
die Eins in ASCII.

Versuch im µC Code mal die Abfrage auf

if (a == '1')

zu ändern.

von Pat K. (c63)


Lesenswert?

Hi Roland,

danke für die schnelle Antwort.
Leider kein Erfolg.
Hätte auch schon versucht die 1 in Binärschreibweise zu übermitteln, 
leider ohne Resultat :-(

von Roland .. (rowland)


Lesenswert?

Hm, und die eingestellte Datenrate ist sicher sowohl beim VB-Programm 
als auch beim µC ident?

von Pat K. (c63)


Lesenswert?

Baudrate ist identisch

von Karl H. (kbuchegg)


Lesenswert?

Problem Ungelöst schrieb:
> Baudrate ist identisch

Das heißt noch lange nicht, dass die Übertragungsrate korrekt ist. Denn 
die hängt auch von der Taktrate des AVR ab.

Daher wird auch generell gerne der Tipp gegeben.
Bevor du dich an die Übertragung vom PC zum AVR machst, mach erst mal 
die Gegenrichtung: vom AVR zum PC, wobei auf dem PC ein Terminalprogramm 
läuft.
Denn das hat den Vorteil, dass du im Terminalprogramm siehst, was 
eigentlich ankommt, wenn der AVR zb eine ASCII-1 wegschickt. Und das ist 
wiederrum besser, als die umgekehrte Richtung, in der du nur indirekt 
erschliessen kannst, was am AVR ankommt wenn der PC was wegschickt.

Dein erstes Testprogramm sollte also zb lauten ...
1
int main(void)
2
{
3
  uart_init();
4
5
  while (1) {
6
    uart_putc( 'x' );
7
  }
8
  return 0;
9
}
... und solange in deinem Terminalprogramm da nicht lauter 'x' 
auftauchen, brauchst du die Gegenrichtung erst gar nicht versuchen.

Erst dann, wenn das klappt, kannst du soweit sicher sein, dass zumindest 
die technische Komponente der UART Übertragung korrekt abläuft.
Wenn das dann klappt, dann ist dein nächster Milestone, dass du im AVR 
dir einen Empfangscode machst, und dem händisch vom Terminal aus 
"ansteuerst". Wenn dieses dann klappt, dann machst du das ganze von VB 
aus.

Grundprinzip ist es immer: habe so wenig unbekannte Teilsysteme im 
System wie möglich.
Du stehst im Moment mit einem VB Programm da, von dem du nicht weißt ob 
es korrekt ist; mit einem AVR Programm da, von dem du nicht weißt ob es 
korrekt ist; mit einer UART Übertragung, von der du nicht weißt ob sie 
korrekt ist.
Das sind zu viele 'ich weiß nicht, ob das korrekt ist'. Also heißt es 
Teilsysteme eliminieren und erst mal durch 'Von dem und dem Teilsystem 
weiß ich mit Sicherheit dass es korrekt ist' ersetzen.

: Bearbeitet durch User
von Pat K. (c63)


Lesenswert?

Thx @ Roland und Karl Heinz für die tolle Unterstützung (y)
Fehler lag in der falschen Baudrate.
Jetzt funktioniert es wie gewünscht.

mfg
c63

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.