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.
1 | #include <avr/io.h> |
2 | #include <inttypes.h> |
3 | |
4 | volatile uint8_t s1; |
5 | |
6 | // Funktionsdefinition von uart_getc()
|
7 | // ...
|
8 | |
9 | // Funktionsdefinition von uart_putc()
|
10 | // ...
|
11 | |
12 | int main(void) |
13 | {
|
14 | // UART initialisieren
|
15 | // ...
|
16 | |
17 | while(1) |
18 | {
|
19 | s1 = uart_getc(); // Empfangen |
20 | uart_putc(s1); // Senden |
21 | }
|
22 | }
|
C# Programm: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO.Ports; namespace rs232 { public partial class Form1 : Form { public Form1() { InitializeComponent(); serialPort.Open(); } private void button2_Click(object sender, EventArgs e) { byte[] buffer0 = new byte[4]; buffer0[0] = 30; buffer0[1] = 100; buffer0[2] = 200; buffer0[3] = 210; serialPort.Write(buffer0,0,4); } private void button1_Click(object sender, EventArgs e) { 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]); inbuffer[0] = 0; inbuffer[1] = 0; inbuffer[2] = 0; inbuffer[3] = 0; } private void button3_Click(object sender, EventArgs e) { label1.Text = Convert.ToString(0); label2.Text = Convert.ToString(0); label3.Text = Convert.ToString(0); label4.Text = Convert.ToString(0); } } }
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.
C Programm auf ATMega8 #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 volatile uint8_t s1; volatile uint8_t update=0; ISR (TIMER1_COMPA_vect) { TCNT1=0; update++; } int main(void) { DDRD=0xff; //PORTD=0b01100000; TCCR0|=(1<<CS00)|(1<<CS02); // Timer 0 Initialisierung TIMSK|=(1<<TOIE0); TCCR1B|=(1<<CS12);TIMSK|=(1<<OCIE1A); //Timer1 OCR1A=15000; uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU)); sei(); while(1) { if (update==1) { s1=uart_getc(); if (s1==0) PORTD &= ~(1<<PD6); if (s1>0) { PORTD |= (1<<PD6); s1++; s3++; uart_putc(s1); uart_putc(s2); uart_putc(s3); uart_putc(s4); } update=0; } }}
s1=uart_getc(); ... uart_putc(s1); uart_putc(s2); uart_putc(s3); uart_putc(s4); Sind für mich vier Bytes die gesendet werden ;-)
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.
Oh...sorry, ich habe mittlerweile weiter rumexperimentiert: Das hier war der Originalcode: #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 volatile uint8_t s1; volatile uint8_t update=0; ISR (TIMER1_COMPA_vect) { TCNT1=0; update++; } int main(void) { DDRD=0xff; //PORTD=0b01100000; TCCR0|=(1<<CS00)|(1<<CS02); // Timer 0 Initialisierung TIMSK|=(1<<TOIE0); TCCR1B|=(1<<CS12);TIMSK|=(1<<OCIE1A); //Timer1 OCR1A=15000; uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU)); sei(); while(1) { if (update==1) { s1=uart_getc(); if (s1==0) PORTD &= ~(1<<PD6); if (s1>0) { PORTD |= (1<<PD6); uart_putc(s1); } update=0; } }}
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
Ich habe jetzt auch mal 20 Bytes in die 8Bit Variabel s geschickt und die gibt diese auch ohne Verlust zurück ???
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.