Forum: PC-Programmierung C# werte über serielle schnittstelle an Atmega8 AVR


von Tobias G. (tobe)


Lesenswert?

Hey

Für mein Technikerprojekt will ich 3 werte über die C# oberfläche an den 
Atmega8 senden und diese dort verarbeiten.
Den Atmega8 (AVR board) programmiere ich in C über das AVR studio 6.
Nach etlichen Forenbeiträgen komme ich mir irgendwie doof vor weil ichs 
nicht raffe.
Die Kommunikation c# seitig funktioniert schonmal.
Jedoch bekomme ich die Werte nicht verarbeitet bzw Variablen zugewiesen.
Hilfe wäre echt toll, denn ich verzweifel und mir rennt die zeit weg...




Danke schonmal :-P

: Verschoben durch User
von Freddi (Gast)


Lesenswert?

für eine hilfeleistung solltest du dein problem genauer beschreiben ... 
ausser das du offensichtlich im stress bist, wissen wir nicht wirklich 
viel mehr! -> sourcecode?

von Rainer U. (r-u)


Lesenswert?

Tobias Giesen schrieb:
> Die Kommunikation c# seitig funktioniert schonmal.

woran erkennst Du das?

von Tobias G. (tobe)


Angehängte Dateien:

Lesenswert?

Ich bekomme das angehängte bild ausgtegeben... nur leider empfange ich 
nicht die zeichen, die ich sende :-/


also mein Programm im uC (als Testprogramm zum senden und empfangen von 
zeichen):



/*
 * UART_CPP.cpp
 *
 * Created: 23.01.2013 09:28:50
 *  Author: K
 Terminal_MCT
 */


#include <avr/io.h>
#define F_CPU 3686400L      //Quarz = 3.6864 Mhz

void UARTInit()
{
  UBRRL=0x17;        //Baudrate 9600
  UCSRB=0x18;        //RXEN=1; TXEN=1;
  UCSRC=0x86;        //Asynchroner Modus, keine Parität, 8 Datenbits, 
1Stoppbit
}

uint8_t UARTGetChar()
{
  while(!(UCSRA&(1<<RXC)));  //warte auf Empfang
  return UDR;          //empfange Daten
}

void UARTPutChar(uint8_t val)
{
  while(!(UCSRA&(1<<UDRE)));  //warte auf freies Senderegister
  UDR=val;          //sende Daten
}

int main(void)
{
  DDRD |=(1<<PD2);
  UARTInit();
  uint8_t z;

    while(1)
    {
         z=UARTGetChar();    //warte auf empfangenes Zeichen
     UARTPutChar(z);    //sende Zeichen
     //if (z==49) PORTD|=(1<<PD2); else PORTD&=~(1<<PD2);  //zb led an


    }
  return 0;
}

von Bronco (Gast)


Lesenswert?

Bekommst Du wirklich falsche Zeichen zurück oder stellt sie Dein 
C#-Programm eventuell falsch dar?
Was passiert, wenn Du mit einem guten Terminalprogrammie wie "hterm" 
Zeichen hin- und hersendest? Funktioniert das?

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> Ich bekomme das angehängte bild ausgtegeben... nur leider empfange ich
> nicht die zeichen, die ich sende :-/

Dann nimm mal eine Fehlerquelle weg, und ersetze dein C# Programm durch 
einer Terminalprogamm am PC. Denn von dem weißt du erst mal, dass es 
korrekt funktioniet.

Weiters lässt du den AVR erst mal nur senden.

Das was der AVR sendet, muss im Terminalprogramm sauber ankommen. Erst 
dann, wenn das so ist, hast du eine gewisse Sicherheit, dass die kleinen 
Fallen wie falsche Taktfrequenz und Baudrate ausgemerzt sind und du dir 
zumindest um diese Teile keine Sorgen mehr machen brauchst.

Immer als erstes so weit es geht abspecken. Je weniger du im 
Gesamtsystem hast, was schief gehen kann - je weniger potentielle 
Fehlerquellen es gibt - desto besser. Und dann immer nur wieder ein 
neues Teil, mit einer möglichen Fehlerquelle mit dazunehmen und 
nachsehen, ob immer noch alles funktioniert.
Der Hauptfehler, den Neulinge gerne machen, besteht darin, dass sie die 
Sache unterschätzen und gleich mit zu komplexen Beispielen anfangen. Und 
dann nicht wissen, wo sie mit Fehlersuche anfangen sollen, weil der 
Fehler nicht eindeutig zuordenbar ist und im Grunde überall stecken 
kann. Da hilft nur: abspecken, abspecken, abspecken. Auf lange Sicht ist 
man schneller, wenn man mit scheinbar trivialen Setups anfängt und sich 
von dort mit vielen testbaren Zwischenstufen in Richtung endgültiges 
Ziel vorarbeitet.

von Tobias G. (tobe)


Angehängte Dateien:

Lesenswert?

bei hterm bekomm ich auch nur quatsch...

von Bronco (Gast)


Lesenswert?

Tobias Giesen schrieb:
> bei hterm bekomm ich auch nur quatsch...

Laß Dir das als HEX anzeigen, mit ASCII kommst Du bei der Fehlersuche 
nicht weit!

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> bei hterm bekomm ich auch nur quatsch...

Dann würde ich mal den Standardfehler annehmen und behaupten, dass das 
hier
1
#define F_CPU 3686400L      //Quarz = 3.6864 Mhz

nicht stimmt. Zu 98% ist es dieser Fehler.

Hast du denn schon kontrolliert, ob dein µC tatsächlich auf 3.6864Mhz 
läuft?

AVR Checkliste: UART/USART

von Bronco (Gast)


Lesenswert?

PS: Was ist mit dem Watchdog?

von Tobias G. (tobe)


Lesenswert?

hab mir das mal in HEx anzeigen lassen, mit dem ergebnis das ich egal 
was ich ein gebe immer den gleichen Wert (F8) zurück bekomme :-/
Die Taktrate ist richt... also laut beschreibung des AVR Boards...

von spess53 (Gast)


Lesenswert?

Hi

>bei hterm bekomm ich auch nur quatsch...

Die HEX-Darstellung wäre sinnvoller gewesen.

Sicher, das dein AVR wirklich mit 3.6864 Mhz lauft?

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

1
void UARTInit()
2
{
3
  UBRRL=0x17;        //Baudrate 9600
4
  UCSRB=0x18;        //RXEN=1; TXEN=1;
5
  UCSRC=0x86;        //Asynchroner Modus, keine Parität, 8 Datenbits, 
6
1Stoppbit
7
}

Bitte nicht.
Schau ins AVR-GCC-Tutorial/Der UART, wie man sowas schreiben kann, 
so dass es auch lesbar bleibt. Das hat schon seinen Grund, warum wir das 
propagieren.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:

> Die Taktrate ist richt... also laut beschreibung des AVR Boards...

Der Worte hör ich wohl, allein mir fehlt der Glaube.

Nicht 'laut Beschreibung' - kontrolliere es! Das dauert keine 5 Minuten 
und dann WEISZT du es mit Sicherheit!

Mag ja sein, dass an diesem Punkt alles korrekt ist -
Vertrauen ist gut. Kontrolle ist besser.

von Bronco (Gast)


Lesenswert?

Schick doch mal einen konstanten Wert zurück:
1
int main(void)
2
{
3
    while(1)
4
    {
5
     z=UARTGetChar();    //warte auf empfangenes Zeichen
6
     z = 'A';
7
     UARTPutChar(z);    //sende Zeichen
8
    }
9
}

von Tobias G. (tobe)


Lesenswert?

Bronco schrieb:
> Schick doch mal einen konstanten Wert zurück:
>
>
1
> int main(void)
2
> {
3
>     while(1)
4
>     {
5
>      z=UARTGetChar();    //warte auf empfangenes Zeichen
6
>      z = 'A';
7
>      UARTPutChar(z);    //sende Zeichen
8
>     }
9
> }
10
>


wenn ich z einen festen wert zuordne, bekomm ich gar nichts mehr 
zurück... so langsam nervt mich dieses Programm :D

von Max_000 (Gast)


Lesenswert?

Da gibt es ein neues µC Buch ( ISBN-10: 3645651314 ), in dem für den 
ATmega 8 die Serielle ausprogrammiert ist und auch der Sourcecode für 
ein C# Terminal angegeben ist.
Sehr innovatives Buch, schau einmal das Inhaltsverzeichnis an.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:

> wenn ich z einen festen wert zuordne, bekomm ich gar nichts mehr
> zurück...

1
int main(void)
2
{
3
  UARTInit();
4
5
  while( 1 )
6
  {
7
    UARTPutChar( 'A' );
8
    _delay_ms( 100 );
9
  }
10
}

> so langsam nervt mich dieses Programm
Aber nur weil du nicht systematisch vorgehst.
Du könntest schon längst fertig sein, wenn du nicht so stur auf deinem 
Standpunkt beharren würdest.

von Bronco (Gast)


Lesenswert?

Oder noch simpler:
1
#include <avr/io.h>
2
#define F_CPU 3686400L      //Quarz = 3.6864 Mhz
3
int main(void)
4
{
5
    DDRD |=(1<<PD2);
6
    while(1)
7
    {
8
      _delay_ms( 250 );
9
      PORTD |=  (1<<PD2);
10
      _delay_ms( 250 );
11
      PORTD &= ~(1<<PD2); 
12
    }
13
}

Blinkt die LED mit 2Hz?
Nein:
-> falsche Taktfrequenz
-> Watchdog
-> WTF?

Prüfe die Fuses!
Prüfe den Watchdog!

von Tobias G. (tobe)


Lesenswert?

sooo hab jetzt mal nen festen wert ausgeben lassen...

stelle ich im c programm den festwert 5 ein, bekomme ich bei der 
kommunikation eine 8 ausgegeben :-/

von Bronco (Gast)


Lesenswert?

Tobias Giesen schrieb:
> wenn ich z einen festen wert zuordne, bekomm ich gar nichts mehr
> zurück...

Tobias Giesen schrieb:
> stelle ich im c programm den festwert 5 ein, bekomme ich bei der
> kommunikation eine 8 ausgegeben :-/

???

von Karl H. (kbuchegg)


Lesenswert?

hast du jetzt endlich mal den Frequnzcheck gemacht?

Aus dem Checklisten Link
1
// Testprogramm für CPU Takt
2
// Hier die vermeintliche Taktrate des µC eintragen
3
 
4
#define F_CPU 3686400UL
5
 
6
#include <avr/io.h>
7
#include <util/delay.h>
8
 
9
// Hier die tatsächlich verwendeten Parameter angeben
10
 
11
#define LED_PORT    PORTB
12
#define LED_DDR     DDRB
13
#define LED_PIN     PB0
14
 
15
int main()
16
{
17
   LED_DDR |= 1 << LED_PIN;
18
 
19
   while (1)
20
   {
21
      LED_PORT ^= 1 << LED_PIN;
22
      _delay_ms(1000);
23
   }
24
 
25
   return 0;
26
}


Für den Port musst du noch was einstellen, wo im Idealfall sowieso schon 
eine LED drann hängt, bzw. wo du einfach mal eine kurzfristig anklemmen 
kannst.

Wie oft blinkt die LED in 10 Sekunden? Armbanduhr-Genauigkeit genügt.

Das ist doch nicht so schwer. Und wenn diese Frage beantwortet ist, dann 
wissen wir, ob die 3.6864 Mhz stimmen, oder ob das noch die Default 1Mhz 
ab Werk sind, die da arbeiten. Und ohne das dieses ein für allemal 100% 
sicher abgeklärt ist, brauchen wir da gar nicht weiter machen. Diesen 
Test MUSS dein µC bestehen!

von Tobias G. (tobe)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Tobias Giesen schrieb:
>
>> wenn ich z einen festen wert zuordne, bekomm ich gar nichts mehr
>> zurück...
>
>
>
1
> int main(void)
2
> {
3
>   UARTInit();
4
> 
5
>   while( 1 )
6
>   {
7
>     UARTPutChar( 'A' );
8
>     _delay_ms( 100 );
9
>   }
10
> }
11
>


hier bekomme ich lediglich ne 8 raus!

von Tobias G. (tobe)


Lesenswert?

so... LED Blinkt in 10sek 2 mal!

sry wenns manchmal was länger dauert...

von spess53 (Gast)


Lesenswert?

Hi

>hier bekomme ich lediglich ne 8 raus!

Ich könnte wetten, dein ATMega läuft mit 1MHz.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> so... LED Blinkt in 10sek 2 mal!

Womit der Beweis erbracht ist.

Dein µC läuft auf 1Mhz und nicht auf 3.6864Mhz.
Soviel zum Thema: "eigentlich laut Beschreibung".


Wenn du die Fuses dann auf Quarzverwendung (du hast doch einen Quarz 
drann, oder nicht?) umgefused hat, dann muss dein µC in 10 Sekunden 
genau 10 Blinker machen. Nur dann stimmt die F_CPU angabe mit der 
Realität überein.

Soweit waren wir vor anderthalb Stunden schon mal. Hättest du den Test 
gemacht, dann hättest du dir anderthalb Stunden 'nerven' gespart.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Wenn du die Fuses dann auf Quarzverwendung (du hast doch einen Quarz
> drann, oder nicht?) umgefused hat, dann muss dein µC in 10 Sekunden
> genau 10 Blinker machen.

Natürlich 5 komplette Blinker.
jeweils 1 Sekunde an, 1 Sekunde aus. In 10 Sekunden geht das 
logischerweise nur 5 mal.

von Bronco (Gast)


Lesenswert?

Tobias Giesen schrieb:
> Jedoch bekomme ich die Werte nicht verarbeitet bzw Variablen zugewiesen.

Ob dann diese Behauptung noch zu halten ist?

von Kaj (Gast)


Lesenswert?

Probier doch mal als erstes das USART_Init Beispiel aus dem Datenblatt. 
Probiers einfach, wenns dann nicht geht kann man weiter suchen...
1
voidUSART_Init( unsigned intbaud )
2
{
3
/* Set baud rate*/
4
UBRRH = (unsigned char)(baud>>8);
5
UBRRL = (unsigned char)baud;
6
/* Enable Receiver and Transmitter*/
7
UCSRB = (1<<RXEN)|(1<<TXEN);
8
/* Set frame format: 8data, 2stop bit*/
9
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
10
}

kann es sein das du den falschen Pin als ausgang setzt?
Du setzt PD2... TxD ist aber PD1 / RxD ist PD0
Oder ist PD2 für was anderes gut?

Das würde (vielleicht?!) erklären weshalb du immer den gleichen wert 
bekommst...

Grüße

von spess53 (Gast)


Lesenswert?

Hi

>kann es sein das du den falschen Pin als ausgang setzt?
>Du setzt PD2... TxD ist aber PD1 / RxD ist PD0
>Oder ist PD2 für was anderes gut?

Mit

'UCSRB = (1<<RXEN)|(1<<TXEN);'

übernimmt die UART die Kontrolle über das TXD- und das RXD-Pin. Die 
Einstellung im DDR-Register spielt keine Rolle mehr.

MfG Spess

von Tobias G. (tobe)


Lesenswert?

sooo... jetzt bin ich fast schon glücklich :D

ich bekomm jetzt auch in meinem eigenen c# programm das gleiche raus was 
ich eingebe...
next problem... mit
 z=UARTGetChar();
weise ich doch den in c# eingegebene wert der variablen z zu oder!?
wenn ich nun allerdings nicht ein sondern 3 textfelder in c# habe und 
dort variablem übergeben will, wie sieht das dann aus?


uint8_t z, t, x;

    while(1)
    {
         z=UARTGetChar();
         t=UARTGetChar();
         x=UARTGetChar();

!? oder ist das quatsch?

von Karl H. (kbuchegg)


Lesenswert?

Lasst ihn doch erst mal seinen Quarz aktivieren.

Danach wird die Init mal vernünftig unter Verwendung der F_CPU und der 
zu erzielenden Baudrate geschrieben (obwohl die bisher verwendete 
Konstante gestimmt hätte). Und dann ... wird er sehen, dass seine UART 
plötzlich 'magisch' funktioniert.
Wenn das Senden klappt, dann wird auch das Empfangen bzw. Zurücksenden 
mehr oder weniger auf Anhieb klappen (sein Kabel bzw. der MAX232 dürfte 
ja in Ordnung sein), und dann wird auch sein C# Programm höchst 
wahrscheinlich funktionieren.

Und die Rate der Nicht-funktionierenden UARTS aufgrund falscher 
µC-Taktrate hebt sich von 99.950005% auf 99.950006%.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> sooo... jetzt bin ich fast schon glücklich :D
>
> ich bekomm jetzt auch in meinem eigenen c# programm das gleiche raus was
> ich eingebe...
> next problem... mit
>  z=UARTGetChar();
> weise ich doch den in c# eingegebene wert der variablen z zu oder!?

Nö.

Dein C# schickt ein Zeichen über die Schnittstelle.
WO auch immer dieses Zeichen herkommt, was es auch immer mit diesem 
Zeichen für eine Bewandtniss hat. Der AVR kann das nicht wissen. Für 
ihnen sind das einfach nur Bytes, die aus der UART herauspurzeln. Von C# 
oder gar Variablen oder gar Textfeldern weiß der nichts.

> wenn ich nun allerdings nicht ein sondern 3 textfelder in c# habe und
> dort variablem übergeben will, wie sieht das dann aus?

Dann musst du eben irgendetwas auf der Seriellen Schnittstelle 
mitsenden, anhand dessen der AVR unterscheiden kann, welcher WErt was 
darstellen soll.

WEnn du zb aus ASCII übertragung setzt, dann bietet es sich zb an, in 
den Text gewisse 'Hinweise' einzubauen.

Zb
H=12;
und das steht beispielsweise für "Set Hour to 12 o'clock", also die 
Aufforderung die AVR interne Uhr in den Stunden auf 12 zu setzen.

>     while(1)
>     {
>          z=UARTGetChar();
>          t=UARTGetChar();
>          x=UARTGetChar();
>
> !? oder ist das quatsch?

sobald aus irgendeinem Grund 1 Zeichen verloren geht, kommt alles 
durcheinander.
Und: bist du sicher, dass dir 8 Bit reichen werden, um deine Zahlen 
auszudrücken?

Binär zu übertragen ist schön und vor allen Dingen schnell. Aber wenn 
man keine Bytewerte hat, die man zur Synchronisierung benutzen kann, 
dann wirds schnell mit dem Protokoll aufwendig.
Übertragung per Text hat zwar den Vorteil, dass die Protokolle einfach 
zu implementieren sind (denn für Steuerungszwecke hat man genügend 
Bytewerte frei), dafür ist die Auswertung etwas aufwändiger. Aber so 
wild auch wieder nicht. Und man hat den Vorteil: Das PC-Frontend muss 
nicht fertig sein. Denn ob ein Benutzer am Terminal H=12 (gefolgt von 
Return) eingibt, oder ab ein Programm einen derartigen String schickt: 
dem AVR ist das ja egal. Der sieht ja nicht, wer da am anderen Ende mit 
dem Spannungspegel wackelt.

von Bronco (Gast)


Lesenswert?

Tobias Giesen schrieb:
> wenn ich nun allerdings nicht ein sondern 3 textfelder in c# habe und
> dort variablem übergeben will, wie sieht das dann aus?

Nur so am Rande:
Ist Dir klar, was für Datentypen deine "Textfelder" haben bzw. an den µC 
schicken?
Ist Dir klar, daß es Datentypen gibt, die größer als 1 Byte sind?
Ist Dir klar, daß die Zahl "124532552545" (aus Deinem Bild oben) in 
ASCII 12 Bytes enthält?
Ist Dir klar, ob Du nicht vielleicht Strings übertragen willst?

von Tobias G. (tobe)


Lesenswert?

ok... nach viel bahnhof in meinem kopf werde ich mal was konkreter :D

ich muss drei wunschfülllstände von Flüssigkeiten übertragen... also 3 
Werte die wohl alle 2 bis maximal 3 Stellig sind... leider habe ich null 
plan von der übertragung (wie ihr vll schon gemerkt habt) bzw obs vll 
sinnvoller ist strings zu verwenden... so langsam habe ich auch das 
gefühl das mein betreuungslehrer es lustig fand als er sagte es wäre 
ganz einfach mit dem C' Programm veriablem im uC zu verändern^^

also schließe ich aus dem letzten beitrag das es vll sinnvoller ist das 
ganze in sogenannten "Strings" zu übergeben?!

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:

> also schließe ich aus dem letzten beitrag das es vll sinnvoller ist das
> ganze in sogenannten "Strings" zu übergeben?!

Für einen Anfänger hätte ich gesagt: Ja.

Das lässt sich PC-seitig leicht generieren, AVR seitig leicht empfangen 
und wenn man seine String-Funktionen kennt, lässt es sich auch 
AVR-seitig leicht wieder zerlegen und in Zahlen verwandeln.

Du musst das ja nicht so aufwendig machen.
Definiere einfach:
Jede 'Anweisung' an den AVR ist eine Zeile. Also eine Abfolge von 
Charactern, die mit einem Carriage Return (du kannst auch jedes andere 
Zeichen wählen, ';' ist zb sehr beliebt) endet.
Jede Anweisung beginnt immer mit einem Buchstaben, wobei der Buchstabe 
('A' bis 'Z', nur Grossbuchstaben erlaubt) eine Aussage darüber macht, 
welcher Füllstand zu ändern ist. Die restlichen Character bis zum 
Zeilende sind dann Ziffern, die zusammengenommen die einzustellende Zahl 
ergeben.

zb (ich verwende ';' als Ende-Zeichen)
A649;
bedeutet: setze Füllstand 1 auf den Wert 649
B98;
bedeutet: setze Füllstand 2 auf den Wert 98
C?;
bedeutet: gib mir den Wert für Füllstand 3

Das kannst du zb leicht mit dem hTerm erst mal ohne PC-Programm testen, 
einfach indem du die Texte eintippst. Und Programmmässig sind solche 
Dinge auch leicht zu erzeugen.

Auf dem AVR läuft einfach eine Routine, die Zeichen die reinkommen an 
einen String anhängt, solange bis es den ';' erkennt. Ist der erkannt, 
dann hat es einen kompletten String und macht sich daran, diesen zu 
zerlegen. Das ist aber einfach, denn das erste Zeichen im String sagt 
dir, mit welchem Füllstand du es zu tun hast, die weiteren Zeichen, was 
damit zu tun ist.

Also: frisch ans Werk und für den AVR mal eine Funktion geschrieben, die 
solange Zeichen in einem char-Array sammelt, bis ein ';' daher kommt und 
wenn das der Fall ist, einen C-String draus macht und einfach mal den 
String zurückschickt. (Du merkst schon: dein C# Programm kannst du erst 
mal zur Seite legen. Das machst du alles PC-seitig erst mal mit dem 
Terminal-Programm. Getreu dem Motto: kein 2-Fronten-Krieg. Immer nur 1 
Baustelle)

von Bronco (Gast)


Lesenswert?

Was Du brauchst, nennt sich "Protokoll".
Ein Protokoll (in diesem Zusammenhang) definiert, in welcher Form 
Informationen kommuniziert werden.
D.h. Du mußt Dir ein Protokoll ausdenken, was Deinen Ansprüchen genügt 
und dann dieses gleichermaßen in Deinem C#-Programm als auch im µC 
umsetzen.

Beispiel:
Dein Telefon klingelt und der Anrufer sagt "10" und legt auf.
Was bedeutet das jetzt? 10 Käsekuchen? Treffen um 10:00? Daß er Dir 10 
Euro geben will oder daß Du ihm 10 Euro geben sollst?
Du siehst, Daten sind nichts wert, wenn nicht klar ist, was sie 
bedeuten.

von Tobias G. (tobe)


Lesenswert?

10 bedeutet immer das ich 10€ bekomme :D

ok...vielen vielen dank schonmal für die hilfe! allein wäre ich jetzt 
immernoch bei 1Mhz und würde denken ich sage dem uC das z=400 ist^^... 
ich werde mich heute und morgen mal an den code setzen und versuchen das 
hier kommunizierte zu verarbeiten^^
mittwoch melde ich mich hier garantiert nochmal zu wort^^ entweder mit 
positiven oder negativen neuigkeiten^^

euch schonmal einen schönen abend!

von Bronco (Gast)


Lesenswert?

Dann freue ich mich schon auf die nächste Fehlermeldung:
"Ich habe in C# die Variable 400 programmiert und bekomme dieses 
Textfeld  nicht im µC verarbeitet."
|^)

von Karl H. (kbuchegg)


Lesenswert?

Bronco schrieb:

> "Ich habe in C# die Variable 400 programmiert und bekomme dieses
> Textfeld  nicht im µC verarbeitet."
> |^)


:-)

> > also schließe ich aus dem letzten beitrag das es vll sinnvoller ist das
> ganze in sogenannten "Strings" zu übergeben?!

Vor allen Dingen das 'sogenannte' macht mir jetzt schon Kummer. Das 
verspricht wieder mal für die Zukunft die Aufforderung "Kauf dir ein 
C-Buch" einsetzen zu müssen.

von Sascha (Gast)


Lesenswert?

Du kannst es dir sogar noch ein wenig einfacher machen in dem du 
definierst, dass alle Anweisungen eine feste Länge haben. Um bei dem 
Beispiel von  Karl Heinz Buchegger zu bleiben:
Jeder Code hat 4 Zeichen gefollgt von einem Terminator (;)
dann wären das z.B.:
A649;  (Füllstand 1 = 649)
B098;  (Füllstand 2 =  98)
C???;  (Abfrage Füllstand 3) (Antwort könnte dann z.B. F193; sein)
Auf diese weise kannst du dann auch rellativ einfach ungültige Codes 
erkennen und verwerfen.

von Karl H. (kbuchegg)


Lesenswert?

Sascha schrieb:
> Du kannst es dir sogar noch ein wenig einfacher machen in dem du
> definierst, dass alle Anweisungen eine feste Länge haben.

Kann man machen, ist aber nicht so schlimm. atoi ist da sehr brauchbar 
einzusetzen (wenn man Übertragungsfehler erst mal ignorieren kann)

  if( isalpha( Input[0] ) )

    // Abfrage eines Wertes
    if( Input[1] == '?' ) {
      char Answer[10];
      switch( Input[0] )
      {
        case 'A':
          sprintf( Answer, "A%d;", (int)Fuellstand1 );
          break;

        case 'B':
          ....
      }
    }

    // Neu setzen eines Wertes
    else {
      int Wert = atoi( &Input[1] );
      switch( Input[0] )
      {
        case 'A':
          Fuellstand1 = Wert;
          break;

        case 'B':
          .....
      }
    }
  }

Wenn er erst mal den String sauber hat, ist die Auswertung bei nur 3 
möglichen Werten nicht mehr so wild und sollte ihn eigentlich vor keine 
großen Probleme stellen. Aber erst mal muss er den String sauber haben 
:-)

von Tobias G. (tobe)


Angehängte Dateien:

Lesenswert?

Sooooo liebe leute...

Pünktlich zur nächsten Fehlermeldung meldet sich der junior wieder...

mit meinem C-Programm im Controller bin ich eigendlich ganz zufrieden. 
(Die ansteuerung der LED´s ist lediglich zum Test, hat also nicht viel 
sinn!)

Mein Problem liegt nun in dem Part :

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            char[] wert = new Char[3];
            wert[0] = Convert.ToChar(numericUpDown1.Value/4);
            wert[1] = Convert.ToChar(numericUpDown2.Value/4);
            wert[2] = Convert.ToChar(numericUpDown3.Value/4);
            serialPort1.Write(wert, 0, 3);
        }

auf drängen meines Betreuungslehrers habe ich das ganze einfach versucht 
in arrays zu packen und dann zu übertragen, statt wie von euch 
vorgeschlagen Strings zu nutzen... nun zeigt mir mein Visual Studio aber 
die Convertierung der "NumericUpDown" Schaltfläsche als fehlerhaft an... 
habe ich da irgendwo nen dicken Bock drin!?

von Arc N. (arc)


Lesenswert?

NumericUpDown.Value ist vom Typ decimal
Convert.ToChar gibt es zwar in einer passenden Variante, die aber nur 
InvalidCastException auslöst (ebenso wie ein cast von decimal nach 
char).
D.h. vorher in was passendes umwandeln oder casten.

Weiteres mögliches "Problem": Char ist 16-Bit Unicode, die Methoden der 
SerialPort-Klasse konvertieren beim Senden/Empfangen zwar, aber 
voreingestellt nach/von ASCII d.h. alles >127 kommt nicht richtig an.
Da müsste dann u.U. einmal nach dem Erzeugen mit
serialPort.Encoding = System.Text.Encoding.GetEncoding(1252);
(Windows Codepage 1252)
oder
serialPort.Encoding = System.Text.Encoding.GetEncoding(28591);
(ISO 8859-1)
die Voreinstellung geändert werden, damit das nicht passiert.

p.s. da ist noch ein Problem die "4" ist ein int, die decimal-Konstante 
hat noch ein "m" am Ende -> "4m" oder "4.0m"

von Tobias G. (tobe)


Lesenswert?

das /4 soll den eingegebenen Wert von ml in Bits umwandeln, da ich laut 
Auflösung 4ml jeh Bit genauigkeit habe... soll also nicht übertragen 
werden

von Arc N. (arc)


Lesenswert?

Tobias Giesen schrieb:
> das /4 soll den eingegebenen Wert von ml in Bits umwandeln, da ich laut
> Auflösung 4ml jeh Bit genauigkeit habe... soll also nicht übertragen
> werden

Ja, hatte mich da auch vertan integer werden automatisch in decimal 
umgewandelt.
Das Problem mit Convert.ToChar besteht aber weiterhin.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> das /4 soll den eingegebenen Wert von ml in Bits umwandeln, da ich laut
> Auflösung 4ml jeh Bit genauigkeit habe... soll also nicht übertragen
> werden


Das ist erst mal ziemlich egal.
Denn die Convert.ToChar Methode macht das Problem und nicht worauf du es 
anwendest.

Den Datentyp Char musst du auf dem PC vermeiden. Das ist nicht derselbe 
'Character', den du vom AVR kennst. Auf dem PC sind die Dinge ein wenig 
komplizierter, weil deine Programme auch auf Einzelcharacter-Ebene auch 
mit chinesischen Schriftzeichen klar kommen müssen - sprich: da ist 
Unicode ein Thema, welches du auf einem AVR nicht hast.

Auf dem PC wird wohl eher der Datentyp byte angebracht sein. Der 
entspricht noch am ehesten dem, was du auf dem AVR als char kennst.


> auf drängen meines Betreuungslehrers habe ich das ganze einfach
> versucht in arrays zu packen und dann zu übertragen, statt wie
> von euch vorgeschlagen Strings zu nutzen...

Einen schönen Gruß von uns.
Gleich danach stellst du dein PC-Programm auf Dauersenden mit 
wechselnden Werten um, ziehst das USART-Kabel ab, steckst es wieder ein 
und erfreust dich daran, dass dein AVR unsinnige Kommandos ausführt. Und 
dann fragst du ihn mal scheinheilig, ob ein Protokoll vielleicht doch 
keine so schlechte Idee gewesen wäre.

von Tobias G. (tobe)


Lesenswert?

jep... und da hab ich erlich gesagt null ahnung... ok also ich kann den 
decimal nicht direkt in char umwandeln...
wie und in was wandel ich das ganze denn am besten?!

und der Punkt mit der übertragung >127...
muss ich dann einfach

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            char[] wert = new Char[3];
            wert[0] = Convert.ToChar(numericUpDown1.Value/4);
            wert[1] = Convert.ToChar(numericUpDown2.Value/4);
            wert[2] = Convert.ToChar(numericUpDown3.Value/4);
            serialPort1.Write(wert, 0, 3);
            serialPort.Encoding = 
System.Text.Encoding.GetEncoding(28591);
        }


schreiben!?

von Tobias G. (tobe)


Lesenswert?

>
> Einen schönen Gruß von uns.
> Gleich danach stellst du dein PC-Programm auf Dauersenden mit
> wechselnden Werten um, ziehst das USART-Kabel ab, steckst es wieder ein
> und erfreust dich daran, dass dein AVR unsinnige Kommandos ausführt. Und
> dann fragst du ihn mal scheinheilig, ob ein Protokoll vielleicht doch
> keine so schlechte Idee gewesen wäre.

da wird er sich freuen :D

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:

>
> da wird er sich freuen :D

Das liegt in der Natur der Sache. :-)

Im Ernst.
Wenn man nur 1 Messwert hat (also bei dir nur 1 Füllstand), bestehend 
aus 1 Byte, dann kann man das so machen, dass man ohne Protokoll fährt. 
Aber für alles andere ist ein Protokoll eine zwingende Voraussetzung. 
Alles andere ist einfach nur amateuerhafter Murks.
Daran ändert auch nichts, dass er es dir jetzt erst mal so einfach wie 
möglich machen will. Da soll er dir lieber beibringen, wie man in C mit 
Strings hantiert. Da haben alle mehr davon und so schwer ist das dann 
auch wieder nicht.

von Arc N. (arc)


Lesenswert?

Tobias Giesen schrieb:
>         private void button1_Click(object sender, EventArgs e)
>         {
>             ...
>             serialPort1.Write(wert, 0, 3);
>             serialPort.Encoding =
> System.Text.Encoding.GetEncoding(28591);
>         }
>
>
> schreiben!?

An der Stelle ist es für das erste Senden zu spät, am einfachsten ist es 
das bspw. im Konstruktor der Form zu machen.
1
public Form1() {
2
    InitializeComponent();
3
    serialPort1.Encoding = ...
4
}

von Tobias G. (tobe)


Lesenswert?

ok... ich merk schon ihr seid echte fans meines Lehrers :D
leider werde ichs wohl (ob nun gut oder schlecht) so machen müssen wie 
er es vorgibt :(
ok... also sollte ich die sache vll in Byte schreiben!?

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            Byte[] wert = new Byte[3];
            wert[0] = Convert.ToByte(numericUpDown1.Value/4);
            wert[1] = Convert.ToByte(numericUpDown2.Value/4);
            wert[2] = Convert.ToByte(numericUpDown3.Value/4);
            serialPort1.Write(wert, 0, 3);
        }

?!

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:

> ok... also sollte ich die sache vll in Byte schreiben!?

Ich würde sagen: Ja.
Denn letzten Endes sind es ja eigentlich auch nur Bytes ohne spezielle 
Bedeutung (im Gegensatz zu Strings), die da über die Serielle rauschen.

von Tobias G. (tobe)


Lesenswert?

Soo.. Im grundsatz funktioniert alles^^
Jedoch muss ich beim senden über c# immer mehrmals auf den "mischen" 
button zum senden klicken, damitich werte im controller empfange... 
Jemand ne idee!?

von Karl H. (kbuchegg)


Lesenswert?

Tobias Giesen schrieb:
> Soo.. Im grundsatz funktioniert alles^^
> Jedoch muss ich beim senden über c# immer mehrmals auf den "mischen"
> button zum senden klicken, damitich werte im controller empfange...
> Jemand ne idee!?

Wie immer:
Als erstes mal feststellen auf welcher Seite das 'Problem' liegt.
Sender oder Empfänger

Ein einfacher Weg ist zb die INstallation eines Port Sniffers auf dem 
PC. Damit siehst du alle Bytes, so wie sie über die Serielle gehen.
Wenn bei Klicken auf einen Button dort auch was auftaucht, dann wird 
wohl der Empfänger die Bytes verschludern. Wenn nicht ....

Danach weiß man schon mal, worauf man sich konzentrieren muss.

Der erste Schritt im Bugfixing ist IMMER die Einkreisung des Problems 
auf den relevanten Teil. In deinem Fall ist das erst mal die Frage: 
Sender oder Empfänger?

von Tobias G. (tobe)


Lesenswert?

Haste nen tipp für einen solchen sniffer?!

von Karl H. (kbuchegg)


Lesenswert?

http://www.serialmon.com/

google
"pc serial port sniffer"

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.