Forum: PC-Programmierung C# Serielleschnitstelle Empfang zu viele zeichen


von Tim H. (pic_fan)


Lesenswert?

Hi zusammen,

Ich bin neuling auf dem gebiet und mache es aus spaß und Hobby.
Bitte entschuldigt für mein Missverständiss in verschiedenen sachen.


ich bin grade dabei mit einem PIC 18F45k20 (PICKIT 3 Starterkit) eine 
Wetterstation zu basteln.

Mein PIC soll eine umsetzung von I2c auf seriell tun da die Sensormodule 
die ich benutze möchte I2c sind.

Zum Ablauf:

Per button soll eine anfrage an den Pic für die Module gesendetwerden 
damit ich die beötigten Daten bekomme.

Ich habe die oberfläche soweit fertig und bin an der Seriellen 
Kommunikation dran.

Über die Oberfläche sende ich als test einen Character den der Pic auch 
richtig empfängt. Den empfang gebe ich aus in dem ich Die LED´s auf dem 
Demoboard in der codierung anzeigen lasse.

Nun sendet der pic die Daten auch zurück aber nicht 1 Zeichen sondern 
mehrere.

ich möchte aber nur das eine zeichen was ich gesendet habe auch 
wiedergegben haben.

C# Programm:

 public partial class MainWindow : Window
    {
        //********************************************************************** 
**
        //================================VARIABLEN============================= 
==
        //********************************************************************** 
**
        SerialPort mySerial; //Variable von Klasser SerialPort
        Thread rxThread;

        string message; //Empfangs Message

        //********************************************************************** 
**
        //==================================MAIN================================ 
==
        //********************************************************************** 
**
        public MainWindow()
        {
            InitializeComponent();
            mySerial = new SerialPort();
        }


        //********************************************************************** 
**  //=========================SERIAL 
ONFIGURATION=========================== 
//********************************************************************** 
**
        public void serialConfig()
        {
            mySerial.PortName = "COM3";
            mySerial.BaudRate = 9600;
            mySerial.DataBits = 8;
            mySerial.StopBits = StopBits.One;
            mySerial.Parity = Parity.None;
            mySerial.ReceivedBytesThreshold = 1;
            mySerial.ReadBufferSize = 64;
            mySerial.WriteBufferSize = 64;
        }

        //********************************************************************** 
* 
//==================================BUTTONS============================= 
==
//********************************************************************** 
**
        private void btn_temp_Click(object sender, RoutedEventArgs e)
        {
            anzeigenSchliesen(); // Alte Anzeigen schliesen
            anzeige_temp.Visibility = Visibility.Visible; // Anzeige für 
temperatur Anzeigen

            serialConfig();
            mySerial.Open();
            mySerial.Write("a");
            Thread.Sleep(100); //Kein sleep = undifiniertes symbol wird 
mit gesendet
            message = Convert.ToString(mySerial.Read());

            tb_temp.Text = message; // Ausgabe der empfangenen Daten in 
der Textbox
            mySerial.Close();

            anzeige_temp.Minimum = -120; // min Wert der Temp Anzeige
            anzeige_temp.Maximum = 120; // Max Wert der Temp Anzeige
        }


PIC Programm:

/*
 * File:   RxTxMain.c
 * Author: floryd
 *
 * Created on 7. August 2014, 12:34
 */
#include <xc.h>
#include <pic18f45k20.h>
#include <stdio.h>
#include <stdlib.h>
#include "C:\Program Files 
(x86)\Microchip\xc8\v1.32\include\plib\usart.h"
#include "C:\Program Files 
(x86)\Microchip\xc8\v1.32\include\plib\delays.h"

/*=========================================================
 * PIC CONFIGURATION
 *=========================================================*/
#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF // CONFIG1H
#pragma config PWRT = ON, BOREN = SBORDIS, BORV = 30 // CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768 // CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC 
// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF // CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF // CONFIG5L
#pragma config CPB = OFF, CPD = OFF // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF // 
CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF // 
CONFIG7L
#pragma config EBTRB = OFF // CONFIG7H



void SetupClock(); // Taktfrequenz interner OSci
void BootLoad(); // Anzeige das das Programm gestartet ist. (LED einmal 
durchlaufen)

void uartOpen();// Configuration des UART Laden
/*
 *
 */


unsigned int i = 0;
unsigned int j = 0;
unsigned char empfang;

int main(int argc, char** argv) {

    SetupClock();
    TRISD = 0x00; // LEDs OUTPUT
    BootLoad();


RXLOOP:
    uartOpen();

    while(!DataRdyUSART()){
      Delay10KTCYx(2);
      empfang = ReadUSART();

        Delay10KTCYx(2);
        LATD = empfang; // empfangene Datei ausgeben mit leuchtend er 
LED

        Delay10KTCYx(3);
        WriteUSART(empfang); // zurück senden der empfangenen Datein
    }
    CloseUSART();

   goto RXLOOP;
   return (EXIT_SUCCESS);
}
//Clock Speed
void SetupClock(){
    asm("BANKSEL OSCCON");
    asm("MOVLW 0x60");
    asm("MOVWF OSCCON");
}
// The PIC is Starting
void BootLoad(){
    for(i;i<=255;i++){
        Delay10TCYx(200);
        LATD = i;
    }
    //LED Blinken lassen wenn test durchlauf Finished
    if(LATD == 0xFF){
        for(i=0;i<5;i++){
            LATD = 0xFF;
            Delay10KTCYx(50); // 0,25s (250ms)
            LATD = 0x00;
            Delay10KTCYx(50);
        }
    }
}
// UART Confuguration
void uartOpen(){
    OpenUSART(USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_TX_INT_OFF & 
USART_RX_INT_OFF & USART_BRGH_HIGH,51);
}

Danke Im Vorraus

Mit freundlchen Grüßen
-Tim-

von bluppdidupp (Gast)


Lesenswert?

1
message = Convert.ToString(mySerial.Read());
Wie schaffst du das denn? Die SerialPort-Klasse aus dem .NET-Framework 
hat gar kein parameterloses .Read()?

Ich würde noch den Zeichensatz setzen (via mySerial.Encoding)

von Peter II (Gast)


Lesenswert?

Tim Halbach schrieb:
> mySerial.Write("a");
>             Thread.Sleep(100); //Kein sleep = undifiniertes symbol wird
> mit gesendet

warum sollte ohne Sleep etwas undefiniertes gesendet werden. Eventuell 
hast du ja noch irgendwelche Hardware Probleme. .Net sendet zumindest 
nur das was man senden will.

von Tim H. (pic_fan)


Lesenswert?

hi danke für dei schnellen antworten,

ja das mit dem Read habe ich mich vertan habe ReadLine() reingeschreiben
mit dem entcoding werd ich mal Probieren.

Undifiniertes Senden:

Ich sehe das noch andere sachen gesendet werden da die LED´s wie 
verrückt blinken. sobald ich das slepp einfüge funktioniert es ohne 
probleme.

habe gelesen das bei einem string ein line feed oder carriage return 
(\n,\r) gesendet wird. leider kann ich das nicht kontrollieren ob das 
der fall ist.

das andere ist ich weis nicht wie man in c (beim Pic) einen carragie 
return rausfiltert.

villt liegt es auch daran das der buffer überläuft da gesendete daten 
noch nciht ganz raus sind.

habe auch mit .DiscardOutBuffer versucht es zu beheben. irgendwie sendet 
er aber dann trozdem ncoh blödsin mit.

von bluppdidupp (Gast)


Lesenswert?

SerialPort.Write("xyz") sendet nur "xyz" ohne CR/LF.
SerialPort.WriteLine("xyz") würde (auf Windows-Maschinen) "xyz\r\n" 
senden.

D.h. wenn du aktuell vom PC aus nur "a" sendest und der PIC alles was 
reinkommt 1:1 zurückschickt, müsste deine Anwendung bei .ReadLine() 
eigentlich blockieren, da es unendlich lange auf ein "\r\n" wartet (da 
kein Timeout gesetzt wurde)

Ich würde zunächst mal prüfen, was denn tatsächlich rausgesandt wird und 
den PIC erstmal außen vor lassen.
z.B. COM3 mit anderem freien COM-Port passend verbinden und mit putty 
o.ä. schauen was tatsächlich aus COM3 raus kommt.
Oder z.B. via com0com virtuelle COM-Ports passend verbinden (signierter 
Treiber ist hier zu finden: 
https://code.google.com/p/powersdr-iq/downloads/list)

von Tim H. (pic_fan)


Lesenswert?

danke das mit dem Readline() wusste ich nicht das es auf ein CR und LF 
wartet.

Getestet habe ich schon wie folgt:

FTDI Kablel RX mit einer Büroklammer an TX angeschlossen, dann Putty 
geöffnet.

Es Funktioniert und kommt auch richtig an.

von Peter II (Gast)


Lesenswert?

Tim Halbach schrieb:
> danke das mit dem Readline() wusste ich nicht das es auf ein CR und LF
> wartet.

was soll denn sonst bei ReadLine passieren? woher soll er wissen das die 
Line zu ende ist?

von Tim H. (pic_fan)


Lesenswert?

als du es sagtest war es mir klar. Weil bei Console.WriteLine(); macht 
er auch eine neue zeile.

die übertragung stimmt jetzt ich bekomme das zeichen was ich haben 
wollte allerdings immer noch so 8 mal.

kann das villt daran liegen das beim PIC erstabgeschickt wird wenn der 
buffer gefüllt ist?

müsste das mit einem timer gelöst werden? Wenn ja. wie berechne ich die 
Zeit das der pic es genau zum richtigen zeitpunkt verschickt.

von Tim H. (pic_fan)


Angehängte Dateien:

Lesenswert?

Ich habe euch mal einen screenshot gemacht wie es aussieht und wie die 
rückgabe aussieht.

Wie man auf dem bild erkennt bekomme ich den wert a richtig 
zurückgegeben allerdings 3 mal anstatt nur einmal wie ich ihn gesendet 
habe.

und da komme ich nciht weiter DIe kommunikation funktioniert. kann 
senden und auch empfangen allerdings bekomme ich nciht die richtige 
anzahl wieder.


danke im voraus

von Holger L. (max5v)


Lesenswert?

Bin kein Pic'ler aber das sieht mir ein wenig seltsam aus.

Sicher das diese Zeile ( in rxloop ) so richtig ist ?
while(!DataRdyUSART())

(MPLAB® C18 C Compiler Libraries)
DataRdyUSART
Return Value:
1 if data is available
0 if data is not available

Wenn ich das Übersetze würde doch
"wenn NICHT DataRdyUSART() == 1 "
herauskommen ?
Hoffe das ich gerade keinen Knoten im Kopf habe.

von Peter II (Gast)


Lesenswert?

das ständige öffnen und schließen vom com-port in C# ist Unsinn. Das 
macht man einfach nicht.

Auch wartest du nicht bis alle Daten empfangen wurden, du liest einfach 
alles was das ist (ReadExisting) und hoffst das alles das ist. Das 
garantiert dir aber niemand.

von Tim (Gast)


Lesenswert?

Wie Kontrolier ich das den? es sollte doch alles da sein ich brauche zum 
senden von einem byte 104µs ink startund stop bit (1s /9600baudrate * 
10bit 1 startbit 1 stopbit 8 datenbits).  wenn der Buffer mit 64 
definiert ist habe ich 104µs * 64 = 6656 µs also 6,6ms. selbst wen der 
pic dann ncoh mal 1 ms pro byte schieben ins TXREG brauch sind es 70,6 
ms ich habe bei mir eine thread sleep von 100ms bis er den empfang 
abfragen sollte.

Da gehe ich mal aus das alles da sein sollte.
Aber wie mache ich den dann eine abfrage ob alle daten empfangen sind? 
Beim Pic frage cih das einfach mit dem Flag bit ab TXIF nur bei C# keine 
ahnung.

Das ander ist das von dem 64 Buffersize ja nur das 1byte gefüllt sein 
dürfte, da dies das zeichen ist was ich zurücksende und die anderen 
sollten 0 sein und nicht auch a.

von bluppdidupp (Gast)


Lesenswert?

Tim schrieb:
> Beim Pic frage cih das einfach mit dem Flag bit ab TXIF nur bei C# keine
> ahnung.

TXIF=1 sagt doch nur, dass der Transmit-Buffer leer ist und das nächste 
Byte zum Versand in den Buffer geschrieben werden kann? Dass das Byte 
auch von der Gegenstelle empfangen wurde kann man daraus nicht direkt 
schließen.

In C# ist TXIF nicht nötig. Das System wird alle Bytes raussenden oder 
bei .Write* eine Exception werfen.


>Getestet habe ich schon wie folgt:
>FTDI Kablel RX mit einer Büroklammer an TX angeschlossen, dann Putty
>geöffnet.
Damit die C#-Anwendung getestet oder die Kommunikation mit dem PIC?

von Peter II (Gast)


Lesenswert?

Tim schrieb:
> Wie Kontrolier ich das den?

in dem du eine Endezeichen festlegst. Und die Liest so lange bis das 
ende erreicht ist. Für ASCII Übertragung bietet sich ein \r[\n] an, dann 
kannst du auch wieder ReadLine verwenden. Du kannst auch ein \0 als ende 
Festlegen und dann liest du einfach ein einer schleife bis eine \0 
kommt. Dann muss man auch nicht irgendwie mit Sleep arbeiten, was früher 
oder später schief geht.

RS232 kann selber nie ein ende feststellen.

von bluppdidupp (Gast)


Lesenswert?

Tim schrieb:
> Wie Kontrolier ich das den?

In dem man ein bestimmtes Protokoll definiert, das beide Gegenstellen 
nutzen.
Im einfachsten Fall kann z.B. ein '\n'-Zeichen bedeuten, dass ein 
Befehl/Paket abgeschlossen ist.
Die Buffersize von 64 sagt nur, dass die SerialPort-Klasse nur 64 Bytes 
zum Puffern nutzen soll. Der Treiber selbst kann aber auch noch Puffer 
besitzen. Und das ein "Paket" 64 Bytes groß ist sagt man damit auch 
nicht. D.h. ein .ReadExisting() liest keine 64 Bytes ein, sondern das 
was gerade schon im Empfangspuffer angekommen ist.

Wenn der µC z.B. "HALLO\r\n" sendet und auf PC-Seite .ReadLine() 
aufgerufen wird, wartet .ReadLine() solange bis "\r\n" angekommen ist 
und liefert dann "HALLO" zurück.

Man könnte z.B. damit anfangen auf dem µC in Schleife "HALLO\r\n" zu 
senden und dann z.B. via putty zu schauen, ob im Terminal lauter "HALLO" 
untereinander erscheinen.
Anschließend kann man schauen, dass auch die C#-Anwendung lauter HALLO's 
empfängt.

von Tim H. (pic_fan)


Lesenswert?

bluppdidupp schrieb:
> Damit die C#-Anwendung getestet oder die Kommunikation mit dem PIC?

Die Kommunikation von der c# Anwendung.

bluppdidupp schrieb:
> TXIF=1 sagt doch nur, dass der Transmit-Buffer leer ist und das nächste
> Byte zum Versand in den Buffer geschrieben werden kann?

Damit hast du recht ich mache mir da einen Counter der zählt wie oft das 
TXIF bit gesetzt wurde.

z.B. definier ich mir immer ein char da es genau 1 byte oder ein char 
ARRAY
mit fest definierter index größe (char Zeichen[5]) und sage ihm wenn das 
TXIF bit gesetzt wurde der counter +1 wird und wenn er 5 erreicht hat 
soll er nicht mehr senden und nichts mehr in den TXREG schieben.

Peter II schrieb:
> Für ASCII Übertragung bietet sich ein \r[\n] an, dann
> kannst du auch wieder ReadLine verwenden. Du kannst auch ein \0 als ende
> Festlegen und dann liest du einfach ein einer schleife bis eine \0
> kommt.

Vielen Danke Peter an sowas habe ich garnicht gedacht. Programmier noch 
nicht so lange aber es macht mir einen heiden spaß zu lernen und das 
verständinis dafür zu entwickeln.

bluppdidupp schrieb:
> Man könnte z.B. damit anfangen auf dem µC in Schleife "HALLO\r\n"

z.B. so?

int i= 0;
char tx_Hallo[7] = {'H','a','l','l','o','\r','\n'};

for(i;i<=7;i++){
   WriteUSART(Hallo[i]);
   Delay_ms(1);
}

bluppdidupp schrieb:
> In dem man ein bestimmtes Protokoll definiert

So ein Protokoll?! schreib ich das in eine separate Funktion?
Könntest du mir villt. erklären wie man sowas aufbaut und worauf man 
achten muss. BITTE aber keinen fertigen code maximal Pseudocode.

Danke allen für ihre gedult

von bluppdidupp (Gast)


Lesenswert?

Tim Halbach schrieb:
> z.B. so?

Jo das sieht doch gut aus, noch ein while(true) drum herum und dann mal 
schauen, was am PC (z.B. in putty o.ä.) ankommt. Wenn da HALLO nicht 
ordentlich ankommt, stimmt vermutlich was mit dem PIC-Code nicht und das 
"µC & Elektronik"-Forum wäre dafür wohl dann doch geeigneter als 
"PC-Programmierung". Wenn das HALLO sauber ankommt, könnte man dann mal 
schauen dass die C#-Anwendung das ebenfalls sauber einliest.
Quasi eins nach dem andern ;D

Wie das Protokoll konkret aussehen könnte, wird man vermutlich von der 
Anwendung abhängig machen. In deinem Fall, würde ich auf dem µC wohl 
sowas basteln:
1
while(true)
2
{
3
   cmd=readLineFromUART();
4
   if (cmd=="TEMPERATURE")
5
   {
6
      temperature_value=readTemperatureFromSensor();
7
      sendToUART("TEMPERATURE: "+temperature_value+"\r\n");
8
   }
9
   else if (cmd=="HUMIDITY")
10
   {
11
      humidity_value=readHumidityFromSensor();
12
      sendToUART("HUMIDITY: "+humidity_value+"\r\n"); 
13
   }
14
   else
15
   {
16
      // Unknown command
17
   }
18
}
(...oder evtl. auch gar nicht auf Befehle vom PC warten und die 
Sensorwerte einfach ununterbrochen nacheinander raussenden ;D)

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.