Forum: Mikrocontroller und Digitale Elektronik Daten vom PC über RS232 zum MC schicken


von Thomas (Gast)


Lesenswert?

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 :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
}

von Thomas (Gast)


Lesenswert?

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);
        }


    }
}

von Karl H. (kbuchegg)


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

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;
  }


}}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

s1=uart_getc();
    ...
    uart_putc(s1);
    uart_putc(s2);
    uart_putc(s3);
    uart_putc(s4);

Sind für mich vier Bytes die gesendet werden ;-)

von Thomas (Gast)


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

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;
  }


}}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.
        ...
     }

von Thomas (Gast)


Lesenswert?

Ok,

vielen Dank soweit für deine Hilfe.

von Verwirrter (Gast)


Lesenswert?

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);
  }
}

von Verwirrter (Gast)


Lesenswert?

Hm. Zu langsam. Müsst Ihr nicht in Bett :-)

von Thomas (Gast)


Lesenswert?

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

von Thomas (Gast)


Lesenswert?

Ich habe jetzt auch mal 20 Bytes in die 8Bit Variabel s geschickt und 
die gibt diese auch ohne Verlust zurück ???

von Chris (Gast)


Lesenswert?

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

von Thomas (Gast)


Lesenswert?

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 ?

von Chris (Gast)


Lesenswert?

#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).

von Verwirrter (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.