Hallo,
ich hätte da mal eine Verständnisfrage:
Ich schicke über ein C# Programm 4 Bytes, verpackt in einem Array zum MC
über die Serielle Schnittstelle:
byte[] buffer0 = new byte[4];
buffer0[0] = 30;
buffer0[1] = 100;
buffer0[2] = 200;
buffer0[3] = 210;
serialPort.Write(buffer0,0,4);
Der MC empfängt diese und schreibt sie in eine Variabel, die als
volatile uint8_t s1;
s1=uart_getc();
declariert ist.
Anschließend schicke ich diese wieder zurück:
uart_putc(s1);
Das C# Programm liest dann diesen Wert in ein byte Array ein
und gibt ihn in Textfeldern aus:
byte[] inbuffer = new byte[4];
serialPort.Read(inbuffer,0,4);
label1.Text = Convert.ToString(inbuffer[0]);
label2.Text = Convert.ToString(inbuffer[1]);
label3.Text = Convert.ToString(inbuffer[2]);
label4.Text = Convert.ToString(inbuffer[3]);
Alle 4 Bytes kommen an ??
Das wundert mich, da doch der MC den UART nur in ein uint8_t s1
einliest. Nach meinem Verständnis dürfte nur das letzte Byte
zurückgeschickt werden, also buffer0[3] = 210.
Vielleicht kann mir das hier mal jemand erklären ?
Schon mal Danke für die Antworten :-)
Bitte gib das komplette µC Programm an.
Deine Beobachtung wäre erklärbar, wenn das Programm in etwa so aussieht,
d.h. das Empfangen und Senden in einer Schleife passiert.
Thomas wrote:
> C# Programm:
Das C# Programm interessiert hier nicht weiter.
Du wunderst dich doch, dass der µC 4 Byte zurückschickt
und wo er die her hat.
Also ist dann wohl auch die Programmierung des µC ineterssant.
Vielleicht noch eine kurze Erklärung:
PORTD &= ~(1<<PD6); und PORTD &= ~(1<<PD6);
sind LEDs.
Und nach der UART Library, die ich benutzt, kann ich mit
s1=uart_getc();
if (s1==0)
abfragen, ob daten gekommen sind.
Wenn das tatsächlich so gemacht wird, ist die Library nicht so toll:
Wie willst du jemals das Byte 0 übertragen, ohne es mit der
Funktionsrückgabe "Keine Daten empfangen" (uart_getc()==0)
zu verwechseln?
Mit dem neuen Code hast du die Struktur, die ich oben skizziert habe. In
einer Schleife Empfangen, was machen, dann Senden und zurück zum
Schleifenanfang und das für ewig. Passt.
Das hier wäre mal die Beschreibung für die Funktion.
Vielleicht habe ich etwas falsch verstanden:
unsigned int uart_getc ( void )
Get received byte from ringbuffer.
Returns in the lower byte the received character and in the higher byte
the last receive error. UART_NO_DATA is returned when no data is
available.
Parameters:
void
Returns:
lower byte: received byte from ringbuffer
higher byte: last receive status
0 successfully received data from UART
UART_NO_DATA
no receive data available
UART_BUFFER_OVERFLOW
Receive ringbuffer overflow. We are not reading the receive buffer fast
enough, one or more received character have been dropped
UART_OVERRUN_ERROR
Overrun condition by UART. A character already present in the UART UDR
register was not read by the interrupt handler before the next character
arrived, one or more received characters have been dropped.
UART_FRAME_ERROR
Framing Error by UART
Thomas wrote:
> Das hier wäre mal die Beschreibung für die Funktion.> Vielleicht habe ich etwas falsch verstanden:
Ja, das hast du gründlich missverstanden.
> unsigned int uart_getc ( void )
zunächst mal liefert uart_getc kein Zeichen sondern
einen Integer (also 2 Bytes) in dem sowohl das empfangene
Zeichen als auch ein möglicher Fehlerzustand kodiert
sind. Wenn du das in einem uint8_t auffängst, schmeisst du
schon mal das High Byte weg, welches die Fehlerinformation
trägt.
> Returns in the lower byte the received character and in the higher byte> the last receive error. UART_NO_DATA is returned when no data is> available.
Dann solltest du das auch so abfragen.
Aber zunächst mal den Returnwert von der Funktion korrekt
auffangen.
Die Funktion liefert einen unsigned int, also solltest du
den Wert von uart_getc auch in einem unsigned int speichern.
unsigned int s1;
.....
s1 = uart_getc();
if( s1 == UART_NO_DATA ) { // es wurde kein Zeichen empfangen
....
}
if( ( s1 & 0xFF00 ) == 0 ) { // Wenn das High Byte vom Ergebnis
// 0 ist, dann gibt es ein gültiges
// Zeichen.
...
}
Wenn ich das richtige verstehe, wurden Daten empfangen, wenn der
Rückgabewert kleiner 256 ist...
Theoretisch müsste da auch eine Warnung vom Compiler bei der Zuweisung
von uart_getc (16 bit) an s1 (8 bit) kommen. Womit auch die wertvollen
Statusinformationen hopps gehen.
Diese Timer-Geschichte ist der grösste Mist und wahrscheinlich ein
Workaround für die vernichteten Informationen.
Ich würde es mal so versuchen:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <uart.h>
#include <uart.c>
#include <util/delay.h>
#define UART_BAUD_RATE 9600
int main(void)
{
uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
sei();
while(1)
{
uint16_t s1 = uart_getc();
if (s1 < 256)
uart_putc(s1);
}
}
Also schon mal danke für die Antworten !
Aber nochmal zurück auf meine eigentliche Frage:
Wie kann es sein, dass bei der Zuweisung von 2 Bytes in ein uint8_t s
nicht eines von beiden unterschlagen wird ?
Ich werde das ganze die Tage mal Debuggen, vielleicht kann mir aber
solange jemand auf die Sprünge helfen.
Grüße
Worden da ZWEI Bytes zugewiesen?
Wenn ein Byte empfangen wurde schickst du es sofort zurück. Erst im
nächsten Durchlauf der While-Schleife wird wieder abgefragt ob ein neues
Byte da ist, das dann gleich wieder zurückgeschickt wird. Du kannst auch
1000000000 Bytes schicken und wirds genau 1000000000 Bytes
zurückbekommen. Jedes Zeichen wird immer sofort wieder zurückgeschickt.
Chris
Ich will ja letztendlich die übertagenen Bytes in mehrere Variabeln
gezielt einspeichern, um eben an die Schaltung Parameter zu übergeben,
die dort weiterverarbetet werden.
Wie könnte ich das dann realisieren ?
#define Anzahl 16
uint8_t s[Anzahl]
uint8_t z
main
{
.
.
.
z=0;
While(1);
{
.
.
.
s[z] = uart_getc();
z += 1;
.
.
.
Zugriff dann z.B. mit bla = s[4] für das 5. empfangene Zeichen (wenn du
normal zählen willst, am Anfang z=1 setzen).
Nein, das ist doch alles ganz anders: Die 4 Bytes werden ja nicht
gleichzeitig gesendet sondern nacheinander. Daher wird zunächst das
erste Byte empfangen und gleich versendet, dann das zweite usw. Deswegen
können auch viele Bytes erfolgreiche "geechot" werden. Warum der
ursprüngliche Code funktioniert, kann man vermuten: Das ursprüngliche
Programm kann alle Zeichen echon ausser 0. Wenn >kein< Zeichen empfangen
wurde, liefert uart_getc aber auch eine 0. Insofern wird von hinten
durch die Brust ins Auge doch heraus gefunden, wann ein Zeichen
empfangen wurde, aber eben nicht für 0-Bytes.