Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller USART Zeichenkette


von Lars Lesslauer (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen, habe folgendes Problem und zwar soll mein Programm 
sobald ich die Backspace taste betätige ein zeichen zurück gehen und bei 
10 zeichen die zeichenkette ausgeben. Jedoch geht er nicht in die If 
Bedingung hinein nun meine Frage Wieso?. Wenn ich in die If bedingung 
ein 'a' oder so reinmache dann funktioniert es aber sobald ich in die If 
bedingung Backspace reinmache geht es nicht mehr.

Ich hoffe ihr könnt mir helfen.
Als Anhang lade ich euch mal mein Programm hoch

Mit freundlichen Grüßen

Lars

von Stefan F. (Gast)


Lesenswert?

Das angehängte rar File ist defekt. Mache das bitte ohne Packprogramm.

Und beschrieeb dein problem präziser:

> Jedoch geht er nicht in die If Bedingung hinein

welche?

> Wenn ich in die If bedingung ein 'a' oder so reinmache

Ich mache in die Kloschüssel rein. Was meinst du damit?

von Stefan F. (Gast)


Lesenswert?

Ich konnte das rar File mit einem anderen Programm öffnen. Der 
eigentliche Quelltext ist:
1
#include <avr/io.h>            // Headerdatei einbinden zur Registerdefinition
2
#include <avr/interrupt.h>
3
#include <string.h>
4
5
#define CHAR_CR (char)0x0D    // Zeichen f. Carriage Return
6
#define CHAR_LF (char)0x0A    // Zeichen f. Line Feed
7
#define CHAR_BEEP (char)0x07  // Zeichen f. Beep
8
#define CHAR_BSP (char)0x08    // Zeichen f. Backspace
9
#define CHARBUF_SIZ    50    // Standard-Puffergröße
10
11
#define ERR_NO_ERR    0
12
#define ERR_BUF_OVFL  -1
13
#define ERR_TX_OVRRUN  -2
14
15
16
ISR(USART0_TX_vect);
17
ISR(USART0_RX_vect);
18
19
#define EOL_STR_LEN    3    // Länge des EOL-Strings
20
// (inklusive terminierender Null)
21
char EOL_Str[EOL_STR_LEN] = {CHAR_CR, CHAR_LF, '\0'};
22
23
struct CharBuffer
24
{
25
    char Buffer[CHARBUF_SIZ];
26
    unsigned short BufPtr=0;
27
};
28
//
29
// Puffer für empfangene Zeichen
30
//
31
CharBuffer RXData;
32
33
//
34
// Puffer für zu sendende Zeichen
35
//
36
CharBuffer TXData;
37
38
39
int main(void)
40
{
41
    
42
    UCSR0B = (1 << RXEN0) | (1 << RXCIE0) | (1<<TXEN0);   // USART0 Receiver&Transmitter und RX Interput einschalten
43
    
44
    
45
    UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
46
    
47
    UBRR0H = 0;              // Einstellen der Baudrate
48
    UBRR0L = 51;            // Werte aus der Tabelle im Datenblatt
49
    
50
    sei();
51
    
52
    // Hauptprogramm (Endlosschleife)
53
    
54
    while(1)
55
    {    
56
        
57
        
58
        
59
    }
60
    
61
    return 0;    
62
}
63
64
ISR(USART0_TX_vect)
65
{
66
    extern CharBuffer 
67
            TXData;  
68
    if (RXData.Buffer[RXData.BufPtr]&&(RXData.BufPtr == 0))
69
    {
70
        while (!(UCSR0A & (1 << UDRE0)))
71
        {}
72
        UDR0 = CHAR_LF;
73
    }
74
    if (RXData.Buffer[RXData.BufPtr])
75
    {
76
        
77
        while (!(UCSR0A & (1 << UDRE0)))
78
        {}
79
        UDR0 = RXData.Buffer[RXData.BufPtr];
80
        RXData.BufPtr++;
81
    }
82
    else
83
    {
84
        while (!(UCSR0A & (1 << UDRE0)))
85
        {}
86
        UDR0 = CHAR_CR;
87
        while (!(UCSR0A & (1 << UDRE0)))
88
        {}
89
        UDR0 = CHAR_LF;
90
        UCSR0B = (1 << RXEN0) | (1 << RXCIE0) | (1<<TXEN0);
91
        RXData.BufPtr = 0;
92
    }
93
    
94
    
95
}
96
97
ISR(USART0_RX_vect)
98
{
99
    extern CharBuffer RXData;
100
    unsigned char RXChar;  
101
    RXChar = UDR0;
102
    if(RXChar ==('b'))
103
    {
104
        while (!(UCSR0A & (1 << UDRE0)))
105
        {}
106
        UDR0 = CHAR_BSP;
107
        if (RXData.BufPtr>0)
108
        {
109
            RXData.BufPtr=RXData.BufPtr-1;
110
            RXData.Buffer[RXData.BufPtr] = '\0';
111
        }
112
    }
113
    else 
114
    {
115
        RXData.Buffer[RXData.BufPtr] = RXChar;
116
        while (!(UCSR0A & (1 << UDRE0)))
117
        {}
118
        UDR0 = RXChar;
119
        RXData.BufPtr++;
120
        
121
        if(RXData.BufPtr==10)
122
        {
123
            UCSR0B = (1<<TXCIE0) | (1<<TXEN0);
124
            RXData.BufPtr = 0;
125
            while (!(UCSR0A & (1 << UDRE0)))
126
            {}
127
            UDR0 = CHAR_CR;
128
        }
129
    }
130
    
131
}

Beitrag #5603206 wurde vom Autor gelöscht.
von Stefan F. (Gast)


Lesenswert?

Warum sendest du in der receive ISR Daten obwohl du auch eine ISR für 
das Senden hast?

> UDR0 = CHAR_BSP;
> UDR0 = CHAR_CR;
> UDR0 = RXChar;

Warum hast du das geschrieben?
> if(RXChar ==('b'))

Wo hast du nun das 'a' hingemacht?

von Lars L. (lars_l577)


Angehängte Dateien:

Lesenswert?

So jetzt mal Präziser erklärt: Mein Programm macht folgendes sobald ich
ein Buchstabe in das Terminalprogramm (benutze PuttY) eingebe, tut das
Programm automatisch nach 10 zeichen die Zeichenkette unterbrechen und
abschicken. Nun soll man aber mit der Backspace taste ein zeichen zurück
gehen können und damit dan das Zeichen ändern kann. Jedoch geht er nie
in diese Bedingung rein. Wenn ich nun die Bedingung änder auf eine
andere Taste zum zurückgehen von Zeichen funktioniert es einwandfrei.
Nun war meine Frage wie ich das hinbekomm das es mit der Backspace taste
auch funktioniert.

Hab dazu mal ein Bild hochgeladen, da man hier nicht ein ganzen Ordner
hochladen kann.

von Lars L. (lars_l577)


Lesenswert?

@Stefanus F.  das 'b' hab ich geschrieben um zu testen ob das 
Rückwärtsgehen überhaupt funktioniert. Ändere das 'b' mal auf '\b' und 
dan wirst du sehen das die Bedingung nie wahr wird. Die Frage ist 
wieso??

von Stefan F. (Gast)


Lesenswert?

Ich denke, es ist eine ganz schlechte Idee, in der Receive ISR darauf zu 
warten, dass du etwas senden darfst. Während dessen verpasst du andere 
empfangene Zeichen.

In deinem Quelltext steht:
> if(RXChar ==('b'))

In deinem Screenshot steht:
> if(RXChar ==('/b'))

Ein backspace schreibt man aber so: '\b'

Schalte mal alle Compiler Warnungen an, denn '/b' hätte er midnestens 
laut anmeckern müssen. Ein char kann nämlich nicht aus zwei bytes 
bestehen.

Warum benutzt du nicht CHAR_BSP?

von Lars L. (lars_l577)


Lesenswert?

@Stefanus F hast Recht habe das Falsch gemacht aber dennoch funktioniert 
es nicht hab auch schon Probiert mit 0x08 Funktioniert aber auch nicht. 
Die frage bleibt immer noch warum. Es müsste eigentlich funktionieren da 
es mit den anderen Ascii zeichen auch funktioniert

von Lars L. (lars_l577)


Lesenswert?

@Stefanus CHAR_BSP hatte ich als erstes stehen hat aber auch nicht 
funktioniert. Deshalb habe ich alternativen Probiert, aber alles ohne 
Erfolg er geht einfach nicht mit Backspace in die Bedingung rein

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Eventuell sendet dein Terminalprogramm das Zeichen gar nicht.

Viele Terminalprogramme werten die Eingabe Zeilenweise aus und senden 
sie erst, wenn du Enter drückst oder auf einen Send Button klickst.

Mit Hammer Terminal kannst du auf jeden Fall alle Steuerzeichen senden. 
Hier ist eine Version für Java 8 und 9 (vielleicht auch neuere): 
http://stefanfrings.de/avr_tools/hterm.tar.gz, die originale geht nur 
bis Java 8.

von Lars L. (lars_l577)


Lesenswert?

Ok hat geholfen vielen Dank :)

von AVR (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich denke, es ist eine ganz schlechte Idee, in der Receive ISR darauf zu
> warten, dass du etwas senden darfst. Während dessen verpasst du andere
> empfangene Zeichen.

Hallo,
wie würde es denn sauber gelöst aussehen?
Kann man da den UDRE-Interput verwenden, um nicht versehentlich bereits 
ein Zeichen zu senden, obwohl man noch nicht "darf".

MfG

von M. K. (sylaina)


Lesenswert?

AVR schrieb im Beitrag #5603251:
> Kann man da den UDRE-Interput verwenden, um nicht versehentlich bereits
> ein Zeichen zu senden, obwohl man noch nicht "darf".

Dein Gegenüber sollte dir eigentlich sagen, wenn er bereit ist. 
(Stichwort RTR/CTS)

von Stefan F. (Gast)


Lesenswert?

tefanus F. schrieb:
>> Ich denke, es ist eine ganz schlechte Idee, in der Receive ISR
>> darauf zu warten, dass du etwas senden darfst. Während dessen
>> verpasst du andere empfangene Zeichen.

AVR schrieb im Beitrag #5603251:
> wie würde es denn sauber gelöst aussehen?

Zunächst mal kann man ausnutzen, dass der UART genau so schnell sendet, 
wie er empfängt. Wenn es Dir lediglich darum geht, ein Echo zurück zu 
schicken, mach das ruhig so.

Du sendest aber mehrere Zeichen, spätestens ab dem 2. musst du warten, 
dass der Sendepuffer frei wird. Das ist der Moment, wo du andere 
Empfangdaten verpasst.

Richtig löst man das zum Beispiel mit Puffern. Alle empfangenen Daten 
werden (wie gehabt) von der Receive-ISR in den Puffer gelegt. Die 
Verabeitung der empfangenen Daten findet aber in der Haputschleife 
statt, nicht in der ISR.

Für das Senden hast du einen zweiten Puffer. Alle zu sendenden Zeichen 
legst du in diesen Puffer ab, mit Ausnahme des ersten Zeichens, das 
legst du direkt in das UDR Register, damit der Sender aktiv wird.

Also musst du beim Senden für jedes einzelne Zeichen unterscheiden:
a) Ist der Puffer leer, dann UDR=c, sonst
b) c in den Puffer legen.

Die ISR für UDRE wird nach dem Senden jedes Zeichens aufgerufen. Nun ist 
es Aufgabe der entprechenden ISR, das nächste Zeichen aus dem 
Sende-Puffer in das UDR Register zu schreiben. Wenn es nichts mehr zu 
senden gibt, dann endet die ISR einfach, der Tx Sender wird dadurch 
inaktiv.

Dafür gibt es sicher einige Tutorials, die es vorführen.

Ich verzichte in meinem Programmen meistens auf diese Komplexität. Ich 
empfange mit ISR und Puffer, aber sende immer direkt (ohne Puffer). Der 
Nachteil dieser Vorgehensweise ist, dass mein Programm während des 
Senden in Warteschleifen hängt und nichts anderes tun kann.

Auf jeden Fall soll man in der Receive ISR entweder gar nichts senden 
oder maximal ein Zeichen. Sonst musst du nämlich wie oben Warteschleifen 
in die ISR einbauen und damit stellt man sich selbst ein Bein. 
Warteschleifen und delays in ISR sind sehr häufig der Anfang von neuen 
Problemen.

Ein häufiger Fall ist, Kommandos zeilenweise zu empfangen. Man will bis 
zum Zeilenumbruch empfangen und danach diese eine Zeile verarbeiten. 
Dazu kannst du in der Receive-ISR prüfen, ob der Zeilenumbruch erreicht 
wurde. Wenn ja, setzt du ein globales Flag auf 1. Das Hauptprogramm 
beschäftigt sich derweil mit anderen Aufgaben oder wartet einfach nur, 
bis dieses Flag auf 1 geht. Verarbeitete es die empfangene Zeile und 
setzt das Flag wieder auf 0, um für die nächste Zeile bereit zu sein.

Vergiss nicht, die Variable für das Flag als volatile zu deklarieren und 
dass sie 8bit klein sein muss.

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.