PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verarbeitung von RS232 Input



cbg
08.07.2008, 17:31
Hallo!
Ich hab ein kleines Problem bei der Realisierung von meiner Steuerung.
Ich möchte vom PC / Laptop / irgendwas aus sagen wir mal 5 Bytes an den Bot schicken, wobei das erste Byte ein Escapezeichen ist und die folgenden 4 Datenbytes die Benötigten Informationen enthalten.
Ich sende vom PC aus diese 5 Bytes wann immer sie benötigt werden, sprich wenn ich was gedrückt habe.
Wie soll ich das jetzt am Bot (Atmega32) verarbeiten?
Wenn ich in die ISR vom UART Rx komme, dann heisst das ja, dass ein Byte angekommen ist. Soll ich dort nun prüfen, ob es das Escapebyte ist und die darauf folgenden 4 in einer globalen Variable speichern? In der main() würde ich dann in der Hauptschleife immer diese Variable prüfen und je nachdem was drinsteht etwas ausführen oder eben nicht.
Ist dies so sinnvoll?
Wie würdet ihr das regeln?

Danke!

cbg
09.07.2008, 00:24
O.K. das mit dem direkt in der ISR verarbeiten hat irgendwie nicht funktionniert.
Ich hab nun den UART so wie im C Tutorial (mit Interrupts).
Im der main() hab ich dann folgendes...

...
int a, b, c, d;
while(1) {
if(uart_getc_nowait() == '$') { // $ ist hier mein Escape-Zeichen
waitms(5);
a = uart_getc_nowait();
b = uart_getc_nowait();
c = uart_getc_nowait();
d = uart_getc_nowait();
}
...
}
...
Was mich jetzt daran stört, ist dass ich nach der Escapezeichenüberprüfung das waitms(5); brauche. Ohne geht es nicht.
Komisch finde ich, dass ich es nicht zwischen den einzelnen Zuweisungen brauche.

gummi_ente
09.07.2008, 01:13
Hi,

wieso brauchst Du das Delay?

Wie sieht die Routine uart_getc_nowait aus.
Wenn dies die ISR ist, so hast Du was falsch verstanden.

Die ISR empfängt die Zeichen und schreibt diese in einen Puffer, sie kann Dir dann auch ein Flag setzen, welches du im HP abprüfst.

Die ISR rufst nicht Du im HP aus, sondern diese wird automatisch gestartet wenn ein Zeichen eintrifft. Dies ist ja der Sinn, das man sich da nicht drum kümmern muß.

Grüße

cbg
09.07.2008, 02:42
Das uart_getc_nowait() ist nicht die ISR. Ich habs so wie im C Tutorial aus dem RN Artikelbereich, siehe hier (https://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc#Variante_2:_Mit_Interrupts).
Das Delay brauch ich, da ich sonst denselben Rückgabewert bekomme, wie wenn kein Zeichen geschickt wurde (-1). Komischerweise brauch ichs aber nur direkt nach der IF-Bedingung.
Ich möchte nicht wirklich die uart_getc_wait() Methode verwenden, ka wieso.

Ich schicke vom PC aus immer 5 Bytes, also z.B. $1234 (als String gesehen), keine Ahnung, warum ich das Delay brauche und vor allem nur dort.

Pierce466
09.07.2008, 19:52
Hallo,
also ich arbeite in Zusammenhang mit RS232 immer mit dieser Routine



#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer[rx_wr_index]=data;
if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
if (++rx_counter == RX_BUFFER_SIZE)
{
rx_counter=0;
rx_buffer_overflow=1;
};
};
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif

// USART Transmitter buffer
#define TX_BUFFER_SIZE 8
char tx_buffer[TX_BUFFER_SIZE];

#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif

// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter)
{
--tx_counter;
UDR=tx_buffer[tx_rd_index];
if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
};
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index]=c;
if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
++tx_counter;
}
else
UDR=c;
#asm("sei")
}
#pragma used-
#endif


ich frage den Puffer direkt über die Variable rx_counter ab



if(rx_counter>0) //rx_counter ist immer dann größer 0 wenn Zeichen im Puffer vorhanden sind
{
myVariable=getchar();//wenn Zeichen über RS232 empfangen wird Zeichen in cZeichenEmpfangen gespeichert
switch (myVariable) //je nachdem welches Zeichen empfangen wird, führe Anweisung aus
{
case 'A': ...

break;

case 'B':
break;

default;
}


das ist der Quellcode der automatisch erzeugt wird wenn man bei CodevisionAVR mit dem CVodeVizzard arbeitet und man die Einstelungen für die Schnittstelle macht (funktioniert nur mit der Vollversion, haben in der Schule damit gearbeitet)...

vielleicht hilft dir das ja...

Gruß Pierce