Daten vom PC über RS232 zum MC schicken

Gast #733163
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 :-)
Persönliche Seite #733174
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
}
Gast #733178
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);
        }


    }
}
Gast #733181
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;
  }


}}
Gast #733183
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.
Gast #733184
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;
  }


}}
Gast #733194
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
#733203
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.
        ...
     }
Gast #733213
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);
  }
}
Gast #734171
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
Gast #734184
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
Gast #734192
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 ?
Gast #734196
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).
Gast #734446
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren