Forum: PC-Programmierung C# Serial Port funktioniert nicht richtig


von Dominic A. (neo123)


Lesenswert?

Hallo zusammen,

Ich habe mir eine Schaltung zur Steuerung von RGB-Leds entwickelt. Diese 
funktioniert auch so wie sie sollte. Auf der Schaltung befindet sich ein 
PIC16F1509 mit einem MAX232 zur Komunikation mit einem Computer. Diese 
Komunikation funktioniert auch ohne Probleme über Putty oder anderen 
Terminal- Programmen mit 250k Baud.
Nun zum Problem: Ich habe in C# ein kleines Programm geschrieben das die 
eingestellten Farbwerte über einen COM Port an den Mikrocontroller 
sendet. Dies funktioniert jedoch nicht richtig. Als erstes übergebe ich 
ein Zeichen welches definiert welche Farbe gesetzt werden muss. 
Anschliessend die Helligkeit dieser Farbe.
Der Code sieht so aus:

serialPort.Write("g");  //Farbe Grün
serialPort.Write("63"); // Helligkeitsstufe 63

Jedoch funktioniert dieser Code so nicht.

Wenn ich es jedoch so mache:

serialPort.Write("g"); //Farbe Grün
serialPort.Write("6"); // Helligkeitsstufe 63
serialPort.Write("3");

Funktioniert es.
Auch wenn ich in Putty g63 tippe funktioniert es.

Ausgewertet werden die Empfangenen Zeichen mit folgendem Programm auf 
dem Mikrocontroller:
1
unsigned int rot = 0, grun = 0, blau = 0;
2
void main(void)
3
{
4
    init();
5
    initPWM();
6
    rs232_init();
7
    PEIE = 1; //Peripherie-Interrupts akivieren
8
    GIE = 1; //Globale Interrupts akiviere
9
    RCIE = 1; //Receive Interru
10
    while (1)
11
    {
12
        PWMsetlin(rot, grun, blau);
13
        delay_ms(1);
14
    }
15
}
16
void interrupt isr_rs232(void)
17
{
18
    if (RCIE && RCIF)
19
    {
20
        RCIE = 0;
21
        char c;
22
        c = rs232_getc();
23
        if (c == 'r')
24
        {
25
            rot = rs232_getint();
26
        }
27
        else if (c == 'g')
28
        {
29
            grun = rs232_getint();
30
        }
31
        else if (c == 'b')
32
        {
33
            blau = rs232_getint();
34
        }
35
        RCIE = 1;
36
    }
37
}
Weiss jemand aus welchem Grund es nicht richtig funktioniert?

Grüsse

von Frank M. (aktenasche)


Lesenswert?

ich vermute einfach mal, dass du diese funktion verwendest:
1
uint16_t RS232_getint(void)
2
{
3
    uint8_t high;
4
    uint8_t low;
5
   
6
    low = RS232_getc();
7
    high = RS232_getc();
8
   
9
    return (high<<8) + low;
10
}

die streng genommen nicht funktionieren dürfte, da der char "6" und der 
int "6" nicht die gleichen werte in der asciitabelle haben.

1. alle relevanten funktionen posten.
2. "funktioniert so nicht" ist als fehlerbeschreibung nicht ausreichend
3. kopple das Tx signal des rechners zurück in den Rx port und schau dir 
an was du wirklich rausschickst.
4. stell die baudrate runter, es kann sein dass die zweite zahl (in dem 
fall 3) ankommt während RCIE=0 ist.

von Peter II (Gast)


Lesenswert?

welche codierung hast du auf dem com port eingestellt? C# Verwendet 
standardmäßig Unicode zum senden von Strings.

Senden lieber bytes, dann ist sicher was raus geht.

http://msdn.microsoft.com/de-de/library/vstudio/ms143551.aspx

von Dominic A. (neo123)


Lesenswert?

Frank Meier schrieb:
> ich vermute einfach mal, dass du diese funktion verwendest:
Nein, ich verwende eine andere. Eigentlich ist der Name rs232_getint 
falsch:

1
signed int rs232_getint(void)
2
{
3
    char string[2];
4
    char c;
5
    unsigned int laenge = 0, i = 0, a = 0;
6
    do
7
    {
8
        a++;
9
        c = rs232_getc(); //Einzelnes Zeichen empfangen
10
        string[laenge] = c; //Empfangenes Zeichen in String ablegen
11
        laenge++;
12
    }
13
    while (a < 2); //Bis 2 Zeichen empfangen wurden
14
15
    i = atoi(string);
16
    return i;
17
}

> 2. "funktioniert so nicht" ist als fehlerbeschreibung nicht ausreichend
Es passiert schlicht gar nichts.

> 3. kopple das Tx signal des rechners zurück in den Rx port und schau dir
> an was du wirklich rausschickst.
Ich habe den Logic Analyzer angeschlossen. Es kommen genau diese 3 
Zeichen/Zahlen.

> 4. stell die baudrate runter, es kann sein dass die zweite zahl (in dem
> fall 3) ankommt während RCIE=0 ist.

Genau das war das Problem. Ich habe die Baudrate nun auf 2400 gestellt 
und nun funktioniert es. AUf welche Art würde es dann mit einer höheren 
Baudrate funktionieren?

von Frank M. (aktenasche)


Lesenswert?

ah ok na die funktion macht schon mehr sinn. die frage ist, wieso mehr 
baudrate ;)

ehrlichgesagt hab ich nach kurzem blick ins datenblatt ein paar fälle im 
kopf durchgespielt woran es liegen könnte. mir ist nix eingefallen, du 
könntest aber mal OERR in RCSTA checken (siehe 22.1.2.5)

ich persönlich hab immer versucht, die isrs schlank zu halten. für 
diesen fall könnte man einen puffer verwenden, in den die empfangenen 
bytes abgespeichert werden. hierzu wird in der isr nur das zeichen im 
puffer gespeichert. das stellt sicher, dass auch wirklich alle zeichen 
verfügbar sind, wenn die umwandlung erfolgt (die uU lange dauern kann, 
kenne die performance von pics nicht)

in etwa so:
1
char _buffer[3];
2
INT8U _currentPosition;
3
4
void main()
5
{
6
...
7
  _currentPosition = 0;
8
9
  while(1)
10
  {
11
    if(_currentPosition > 2)
12
    {
13
      _currentPosition = 0;
14
      SetNewPWMValue();
15
    }    
16
  }
17
}
18
19
void interrupt isr_rs232(void)
20
{
21
  GIE = 0; //global interrupt disable
22
  if(RCIF) 
23
  {
24
    buffer[_currentPosition] = RCREG;
25
    _currentPosition++;
26
  }
27
  GIE = 1;
28
}
29
30
void SetNewPWMValue()
31
{
32
  //lets hope there will be no interrupt here. set GIE=0 if shit happens
33
  INT8U newVal;
34
  //no fast way to work with atoi here. code performance shoudl be comparable
35
  newVal = (_buffer[1] - '0')*10 + (_buffer[2] - '0');  
36
  switch(_buffer[0])
37
  {
38
    case 'r': rot = newVal; break;
39
    case 'g': gruen = newVal; break;
40
    case 'b': blau = newVal; break;
41
    default : rot = 0xFF; gruen = 0; blau = 0; break;//error indicator
42
  }
43
  PWMsetlin(rot, grun, blau);
44
}

der puffer ließe sich beliebig erweitern, d.h. du könntest auch mehr 
befehle als nur diesen senden. ein passendes kommando zum setzen der PWM 
wäre zB PWMg63. wenn du nun PWM in deinem puffer erkennst, weisst du die 
nächsten 3 zeichen sind dafür da, die farbe neu zu setzen.

ich weiss es ist unschön den fehler im eigenen code nicht zu finden, 
aber manchmal muss man einfach redesignen ;)

von Dominic A. (neo123)


Lesenswert?

Frank Meier schrieb:

> du könntest aber mal OERR in RCSTA checken (siehe 22.1.2.5)

Vielen Dank für den Tipp. In der Funktion zum Empfangen eines Zeichen 
lösche ich das Errorbit CREN jedes mal.
1
unsigned char rs232_getc(void)
2
{
3
    CREN = 0;
4
    CREN = 1; //clear OERR-Overflow-Error-Bit
5
    while (!RCIF); //Warten auf Empfangs-Interrupt-Flag
6
    return RCREG; //Empfangens Byte zurückgeben
7
}

> in etwa so:
>
> der puffer ließe sich beliebig erweitern, d.h. du könntest auch mehr
> befehle als nur diesen senden. ein passendes kommando zum setzen der PWM
> wäre zB PWMg63. wenn du nun PWM in deinem puffer erkennst, weisst du die
> nächsten 3 zeichen sind dafür da, die farbe neu zu setzen.

Das ist genial. Funktioniert wunderbar. Auch das mit den weiteren 
Befehlen kommt mir sehr entgegen da ich noch verschiedene Übergänge usw. 
geplant habe.

Nun läuft alles mit 19.2k Baud.
Vielen Dank für deine Unterstützung

von Juergen R. (stumpjumper)


Lesenswert?

Hallo Dominic,
ich würde die Zeichenkette string 3 Zeichen lang machen und mit Nullen 
vorinitialisieren. Normalerweise wird ein Ende der Zeichenkette durch 
ein Nullbyte erkannt, wenn die Kette aber nur 2 Zeichen hat ist es 
meiner Ansicht nach nur Zufall dass es funktioniert weil der Speicher 
hinter der Zeichenkette zufällig auf null steht.

>char string[2];

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.