Forum: Mikrocontroller und Digitale Elektronik Frage zu RS232 Verbindung


von Christian (Gast)


Lesenswert?

Hallo zusammen,

zur Zeit versuche ich eine RS232 Verbindung zwischen einem 
PIC-µConrtroller (PIC18F450) und einem PC (WinXP) aufzubauen.

Es ist mir gelungen, den µController mit dem PC zu verbinden und ein 
µController-Programm zum Senden und Empfangen von Daten zu schreiben. 
Verbunden mit dem WinXP Hyperterminal funktioniert sowohl senden, als 
auch empfangen wunderbar.

Letztlich soll der µController jedoch mit einem C++ Programm 
kommunizieren. Dieses C++ Programm habe ich auf Basis von Anton Zechners 
"ComTools" aufgebaut und die Kommunikation mit einem anderen PC (wieder 
zum Hyperterminal) getestet. Auch hier funktioniert das Senden und 
Empfangen zwischen C++ Programm und Hyperterminal einwandfrei.

Jetzt meine Frage: Verbinde ich nun C++ Programm und µController, so 
scheint irgendetwas schief zu gehen. Jedenfalls kommt keine 
ordnungsgemäß laufende Verbindung zu Stande.

Zu Testzwecken sendet das C++ Programm in einer Endlosschleife einen 
String und der µController soll nach erfolgreichem Empfang seinerseits 
ebenfalls einen definierten String zurücksenden. - Wie gesagt, mit dem 
Hyperterminal als Gegenstück funktionieren beide Programme genauso, wie 
sie es sollen....

Für die Kommunikation habe ich folgende Parameter ausgewählt:
- Bautrate 19200
- kein Paritätsbit
- 1 Stoppbit
- keine Flusssteuerung


Hat vielleicht jemand eine kluge Idee, woran es liegen könnte, dass 
µController und C++ Programm nicht miteinander kommunizieren möchten?

Dank euch!
Christian

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Möglicherweise "überfährst" Du Deinen µC, d.h. Du sendest ihm Daten 
schneller, als er sie verarbeiten kann. Damit meine ich nicht die 
Baudrate, sondern die (fehlende) Zeit zwischen einzelnen Zeichen bzw. 
zwischen den einzelnen übertragenen Strings.

von Krapao (Gast)


Lesenswert?

Möglicherweise zickt dein C++ Programm bzw. die C++-Library am 
andersartigen Zeilenende rum auf das dein µC-Programm anders 
Hyperterminal sendet. Würde man den Sourcecode sehen, bräuchte man nicht 
raten...

von cskulkw (Gast)


Lesenswert?

Christian schrieb:
> Letztlich soll der µController jedoch mit einem C++ Programm
>
> kommunizieren. Dieses C++ Programm habe ich auf Basis von Anton Zechners
>
> "ComTools" aufgebaut und die Kommunikation mit einem anderen PC (wieder
>
> zum Hyperterminal) getestet.

Aus diesem Satz schließe ich, dass die ComTools auf dem µC keinen 
Programmcode erzeugen, der in der Lage ist, Zeichenketten zu erkennen 
und bei Übereinstimmung, eine vorher festgelegte Aktions zu starten. Das 
könnte das das Senden eines Antwortstrings sein.

Sehe ich das richtig?

von Christian (Gast)


Lesenswert?

hier ist der Sourcecode:

C++ ::
1
//*****************************************************************************
2
//*
3
//*
4
//*    ComDemo.cpp
5
//*
6
//*
7
//*****************************************************************************
8
9
#include <conio.h>
10
#include <stdio.h>
11
#include <windows.h>
12
#include "ComTools.h"
13
#include <iostream>
14
using namespace std;
15
16
17
#define   COM1    0
18
#define   COM2    1
19
#define   COM3    2
20
#define   COM4    3
21
22
#define   ESC      27
23
24
25
//*****************************************************************************
26
//*
27
//*    main
28
//*
29
//*****************************************************************************
30
int main(int argc, char* argv[])
31
{
32
int    iLen;
33
char  iKey[4];
34
char  cBuffer[65];
35
36
  ComInit();
37
38
  if(!ComOpen(COM1, 19200,P_NONE,S_1BIT,D_8BIT))
39
    {
40
    cout << "Kann die Schnittstelle nich oeffnen !" << endl << endl;
41
    return -1;
42
    }  
43
44
  while(true) {
45
46
  iKey[0] = 't'; iKey[1] = 't'; iKey[2] = 't'; iKey[3] = 't';
47
  ComWrite(COM1, iKey, 4);
48
  cout << "GetComWriteCount:" << ComGetWriteCount(COM1) << endl;        
49
  cout << "GetComReadCount:" << ComGetReadCount(COM1) << endl << endl;  
50
  iLen=ComRead(COM1,cBuffer,64);
51
  if(iLen>0){      
52
    cBuffer[iLen]=0;
53
    cout << "Emfpangen: "<< cBuffer << endl << endl;
54
  }
55
  Sleep(1000);
56
57
}    
58
  
59
  ComClose(COM1);
60
  ComExit();
61
62
return 0;
63
}



µController ::
1
#include <18F4550.h>
2
#include <stdio.h>
3
#include <string.h>
4
5
#fuses HS, NOWDT, NOBROWNOUT, NOPROTECT, NOLVP, NOVREGEN, CCP2B3, PUT
6
7
#use delay (clock=20000000)
8
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
9
10
11
void Init_Ports(void)
12
{
13
14
   /* OUTPUT = 0; INPUT = 1; 0x0F => Pin 7..4=output, Pin 3..0=input*/
15
16
   /************** ANALOG PORT A DEFINITIONS
17
   *  A7   A6   A5   A4   A3   A2   A1   A0
18
   *
19
   *  nc   nc   nc   nc   nc   nc   nc TACHO
20
   *
21
   ****************************************/
22
   SETUP_ADC_PORTS(AN0);
23
   SETUP_ADC(ADC_CLOCK_INTERNAL);
24
   SET_ADC_CHANNEL(0);
25
26
   /********************* PORT B DEFINITIONS
27
   *  B7   B6   B5   B4   B3   B2   B1   B0
28
   *
29
   *  nc   nc   IN1  IN2  PWM  nc   nc   nc
30
   *
31
   *  PGD  PGC            CCP2
32
   *
33
   ****************************************/
34
   SET_TRIS_B(0x00);
35
36
   /********************* PORT C DEFINITIONS
37
   *  C7   C6   C5   C4   C3   C2   C1   C0
38
   *
39
   * AUX7 AUX6 AUX5 AUX4 n.a. AUX2 AUX1 AUX0
40
   *
41
   *                               CCP1
42
   *
43
   ****************************************/
44
   //SET_TRIS_C(0b00010000);
45
46
   /********************* PORT D DEFINITIONS
47
   *  D7   D6   D5   D4   D3   D2   D1   D0
48
   *
49
   * UA-0 UA-1 UA-2 UA-S  nc   nc   nc   nc
50
   *
51
   ****************************************/
52
   SET_TRIS_D(0xF0);
53
54
   OUTPUT_LOW(PIN_B5);
55
   OUTPUT_LOW(PIN_B4);
56
57
   SETUP_CCP2(CCP_PWM);
58
   SETUP_TIMER_2(T2_DIV_BY_1, 255, 1); // 19.53125kHz PWM -> Period: 51.2us
59
60
   SET_PWM2_DUTY(0);
61
62
   SETUP_TIMER_0(RTCC_INTERNAL);
63
}
64
65
66
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
67
//  Main Program
68
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
69
void main()
70
{
71
   char _4recive[8];
72
   int _MODE = 0, _dRE = 0, _dAB = 0;
73
74
75
   delay_ms( 500 );
76
  Init_Ports();
77
   delay_ms( 500 );
78
   puts("HALLO WELT");
79
   delay_ms( 500 );
80
81
   while(1)
82
   {
83
84
      switch(_MODE){
85
86
      case 0:
87
       if (kbhit()) {
88
         gets(_4recive);
89
         if(_4recive[0] == 't' && _4recive[1] == 'r' && _4recive[2] == 's' && _4recive[3] == '2' && _4recive[4] == '3' && _4recive[5] == '2' && _4recive[6] == '0' && _4recive[7] == '0'){
90
            puts("RECIVED1");
91
         }
92
         else {
93
         puts("no match");
94
         }
95
       }
96
       break;
97
98
      }
99
100
      switch(_dRE){
101
102
      case 0:
103
         break;
104
105
      case 1:
106
         puts("RELATIVE");
107
         break;
108
109
      }
110
111
      switch(_dAB){
112
113
      case 0:
114
         break;
115
116
      case 1:
117
         puts("ABSOLUTE");
118
         break;
119
120
      }
121
122
123
   }
124
}

von Krapao (Gast)


Lesenswert?

Sendet dein puts ein Zeilenende mit?

Hast du eine 3-Draht-Verbindung oder eine Verbindung mit zusätzlicher 
DTR/RTS Beschlaltung. Ich habe ComTools im Netz gefunden, die ein 
CreateFile machen mit:
1
  sDcb.fDtrControl  = DTR_CONTROL_ENABLE;
2
  sDcb.fRtsControl  = RTS_CONTROL_ENABLE;

von Karl H. (kbuchegg)


Lesenswert?

Wenn das gets hier
   gets(_4recive);
auch nur ansatzweise wie ein normales gets funktioniert, dann wartet es 
auf ein Carriage Return von der Gegenstelle, welches aber
  iKey[0] = 't'; iKey[1] = 't'; iKey[2] = 't'; iKey[3] = 't';
  ComWrite(COM1, iKey, 4);
niemals gesendet wird.


Und PS: du solltest dir in deinem C-Buch das Kapitel über Strings 
nochmal durchlesen. Man kann, man muss aber nicht bei Strings ständig 
auf Einzelzeichenebene rumkriechen.

Und noch ein 2.tes PS:
gets ist eine extrem gefährliche Funktion, deren Verwendung bei 
Prügelstrafe verboten werden sollte.

von Christian (Gast)


Lesenswert?

Danke für eure Denkansätze! Ich habe das Problem nochmal ein wenig 
untersucht und es scheint tatsächlich am carriage return zu liegen.

Ich habe nun in meinem C++ Programm die "Sendezeile" überarbeitet:
ComWrite(COM2, "test\r\n\0", 7);

Lasse ich nun zwei Instanzen von diesem Programm auf zwei Rechnern 
miteinander kommunizieren, dann funktioniert das einwandfrei. Auch ein 
carriage return scheint nun richtig implementiert zu sein.

Die Kommunikation mit dem µController funktioniert allerdings weiterhin 
nicht!! :(


Grüß euch,
Christian


PS: Es mag durchaus sein, dass puts() keine gute Wahl ist. Ich bin kein 
Informatiker und habe im Grunde genommen auch keine richtige Ahnung... 
Was wäre denn eine bessere Wahl anstatt Puts() und Gets()????

von Uwe (Gast)


Lesenswert?

Dein µC wartet aber auf den String "trs23200"  und senden tust du 
"tttt". Jetzt die Frage was soll da passieren ?

von Karl H. (kbuchegg)


Lesenswert?

> ComWrite(COM2, "test\r\n\0", 7);

Wozu das \0 Byte?
Ein direkt angegebener String ist sowieso immer automatisch mit einem \0 
Byte abgeschlossen. Das macht der Compiler. Und das \0 Byte brauchst du 
auch nicht zu übertragen.

Hast du auf dem µC neben der UART noch eine andere Möglichkeit um dir 
irgendetwas ausgeben zu lassen? Zb ein LCD?

Wenn ja, dann vereinfache mal dein Empfängerprogramm. Schmeiss alles 
raus, was du nicht brauchst und was das Programm nur in die Länge zieht. 
Empfange eine Zeile und gibt sie am LCD aus. Die Devise heißt: Möglichst 
wenig, was schief gehen kann. Bei dir können momentan 2 Dinge schief 
gehen:
a) die Übertragung einer Text-Zeile vom PC zum µC
b) die Übertragung einer Text-Zeile vom µC zum PC

in einem von beiden steckt ein Problem und du weißt nicht in welchem. 
Also musst du einen der beiden Problemkreise loswerden, damit ein 
möglicher Fehlerfall wegfällt

(PS:

Woher weiß eigentlich das PC-Programm hier

  cout << "GetComReadCount:" << ComGetReadCount(COM1) << endl << endl;
  iLen=ComRead(COM1,cBuffer,64);

wann es eine Zeile empfangen hat?
Das wird so nicht funktionieren.

Wenn du zeilenweise überträgst, was ich dir sehr ans Herz legen würde, 
dann musst du vom µC auch eine Zeile wegschicken.
  puts("RECIVED1\n");

Jetzt ist es eine Zeile und du kannst am PC anhand des \n feststellen, 
dass du eine Zeile bekommen hast.


> Es mag durchaus sein, dass puts() keine gute Wahl ist.

puts() ist nicht das Problem. gets() ist das Problem!
Beantworte doch einfach mal die Frage, wie dich gets() davor schützen 
soll, dass die Gegenstelle mittels eines langen Strings deinen 
char-Buffer überläuft? Dazu müsste gets() wissen, wie gross der Buffer 
ist. Das geht aber mit der Schnittstelle nicht, gets hat keine Chance 
das rauszufinden. Daher ist gets() eine 'Funktiona non grata'. fgets ist 
besser.

Aber lass das erst mal. Deine Problem liegen noch viel einfacher. Erst 
mal sieh zu, dass du die Kommunkation generell hinkriegst.

Wenn du kein LCD oder sowas hast, dann mach dein erstes Testprogramm so 
einfach wie möglich. zb so
1
int main()
2
{
3
   char received[80];
4
5
....
6
7
   while(1)
8
   {
9
     gets( received );
10
     // ideal wäre es hier, wenn du eine LED toggeln könntest oder
11
     // irgendwas anderes machen könntest, was dir zweifelsfrei mitteilt:
12
     // gets hat eine Zeile geliefert
13
     puts( "*" );
14
     puts( received );
15
     puts( "*\n" );
16
   }
17
}

Also einfach nur zurückschicken.
Das testest du erst mal mit Hyperterminal und dann mit deinem 
PC-Programm.
Wenns nicht funktioniert, dann konzentrierst du dich erst mal nur auf 
dein PC-Programm. Das µC Programm ist einfach genug, dass da nicht viel 
schief gehen kann. Solange deine Kontrolle durch zb eine LED mitteilt, 
dass gets mit einem String zurückgekommen ist, ist µC seitig soweit 
alles in Butter.

von Karl H. (kbuchegg)


Lesenswert?

Und noch was

> Woher weiß eigentlich das PC-Programm hier
>
>  cout << "GetComReadCount:" << ComGetReadCount(COM1) << endl << endl;
>  iLen=ComRead(COM1,cBuffer,64);
>
> wann es eine Zeile empfangen hat?
> Das wird so nicht funktionieren.

Du scheinst hier anzunehmen, dass die ComTools irgendwie magisch wissen, 
wann ein Text, den du vom µC mittels
puts("no match");
auf den Weg schickst, komplett übertragen wurde.

Das tun sie aber nicht!
Ein Computer kann nicht in die Zukunft schauen, ob da von der 
Schnittstelle noch was kommen wird oder nicht.
ComGetReadCount(COM1) sagt dir, wieviele Zeichen bisher eingetrudelt 
sind. Ob das schon alles war oder nicht, oder ob da noch was kommt oder 
nicht, kann auch ComGetReadCount(COM1) nicht vorhersagen.
Insbsondere hast du keine Garantie dafür, dass ein einziger Aufruf von 
ComRead mit einer kompletten Zeile zurückkommt. Er liefert das, was 
bisher eingetroffen ist und wenn der Sender noch gar nicht alles 
weggeschickt hat, dann liefert er eben nur den Teil, der bisher 
übertragen wurde. Es liegt an dir, dein Programm so zu gestalten, dass 
es damit klar kommt, eine komplette Zeile aus mehreren Übertragungen 
wieder zusammenzusetzen.

von Christian (Gast)


Lesenswert?

Uwe schrieb:
> Dein µC wartet aber auf den String "trs23200"  und senden tust du
> "tttt". Jetzt die Frage was soll da passieren ?

der µcontroller soll "no match" antworten.

Karl Heinz Buchegger schrieb:
> Wozu das \0 Byte?

Ja ich weiß... ich dachte mir, ich probiert das einfach mal aus..

Karl Heinz Buchegger schrieb:
> Hast du auf dem µC neben der UART noch eine andere Möglichkeit um dir
> irgendetwas ausgeben zu lassen? Zb ein LCD?

Nein. Leider nicht. Die Platine ist vorgegeben.

Karl Heinz Buchegger schrieb:
> Woher weiß eigentlich das PC-Programm hier
>
>   cout << "GetComReadCount:" << ComGetReadCount(COM1) << endl << endl;
>   iLen=ComRead(COM1,cBuffer,64);
>
> wann es eine Zeile empfangen hat?
> Das wird so nicht funktionieren.

Natürlich funktioniert das. Ich habe das getestet, indem ich den 
µController per while 1 einfach permanent habe "irgendwas" senden 
lassen.

Die Sache ist doch so: Wenn der PC etwas empfängt, dann liefert 
ComGetReadCount(COM1) einen Wert größer 0. Falls nicht, dann ist der 
Wert gleich 0.

Karl Heinz Buchegger schrieb:
> Wenn du zeilenweise überträgst, was ich dir sehr ans Herz legen würde,
> dann musst du vom µC auch eine Zeile wegschicken.
>   puts("RECIVED1\n");
>
> Jetzt ist es eine Zeile und du kannst am PC anhand des \n feststellen,
> dass du eine Zeile bekommen hast.

In einer früheren Version meines Programms hatte ich das exakt so 
geschrieben und mich dann gewundert, warum ich nach jedem Empfangen in 
meiner Windows-Konsole immer 2(!) Absätze hatte. Ich kann nicht sagen 
warum das so ist, aber puts("RECIVED1"); scheint schon ein "\n" zu 
enthalten...

Karl Heinz Buchegger schrieb:
> Aber lass das erst mal. Deine Problem liegen noch viel einfacher. Erst
> mal sieh zu, dass du die Kommunkation generell hinkriegst.

Wenn ich das µController-Programm, so wie es jetzt ist, mit dem 
Hyperterminal kommunizieren lasse, dann funktioniert es doch schon. Wenn 
ich mein C++ mit dem Hyperterminal kommunizieren lasse, dann 
funktioniert auch das C++ problemlos. Wenn ich zwei Instanzen des C++ 
Programms miteinander kommunizieren lasse, dann geht das auch. NUR, wenn 
ich C++Programm und µController kommunizieren lassen möchte, dann 
passiert garnichts... ^_^

Karl Heinz Buchegger schrieb:
> Das tun sie aber nicht!
> Ein Computer kann nicht in die Zukunft schauen, ob da von der
> Schnittstelle noch was kommen wird oder nicht.
> ComGetReadCount(COM1) sagt dir, wieviele Zeichen bisher eingetrudelt
> sind. Ob das schon alles war oder nicht, oder ob da noch was kommt oder
> nicht, kann auch ComGetReadCount(COM1) nicht vorhersagen.
> Insbsondere hast du keine Garantie dafür, dass ein einziger Aufruf von
> ComRead mit einer kompletten Zeile zurückkommt. Er liefert das, was
> bisher eingetroffen ist und wenn der Sender noch gar nicht alles
> weggeschickt hat, dann liefert er eben nur den Teil, der bisher
> übertragen wurde. Es liegt an dir, dein Programm so zu gestalten, dass
> es damit klar kommt, eine komplette Zeile aus mehreren Übertragungen
> wieder zusammenzusetzen.

Jup. Aber das Programm bevor ich das Programm weiter ausbaue, sollte es 
doch bis hierhin erstmal funktionieren.. :(

von Karl H. (kbuchegg)


Lesenswert?

Christian schrieb:

>> Wenn du zeilenweise überträgst, was ich dir sehr ans Herz legen würde,
>> dann musst du vom µC auch eine Zeile wegschicken.
>>   puts("RECIVED1\n");
>>
>> Jetzt ist es eine Zeile und du kannst am PC anhand des \n feststellen,
>> dass du eine Zeile bekommen hast.
>
> In einer früheren Version meines Programms hatte ich das exakt so
> geschrieben und mich dann gewundert, warum ich nach jedem Empfangen in
> meiner Windows-Konsole immer 2(!) Absätze hatte. Ich kann nicht sagen
> warum das so ist, aber puts("RECIVED1"); scheint schon ein "\n" zu
> enthalten...

Ja, du hast recht. puts hängt von sich aus ein \n an. Zumindest muss es 
das tun, wenn es standardkonform ist.
Daran hab ich nicht mehr gedacht. fputs tut das nämlich nicht und ich 
benutze die puts()/gets() calls praktisch nie, weil mir das eine zu 
unflexibel und das andere zu gefährlich ist.


> NUR, wenn ich C++Programm und µController kommunizieren lassen
> möchte, dann passiert garnichts... ^_^

OK, ok. Ich halt mich schon raus. Wenn du meinst, dass es nicht an 
deinen Programmen liegt, oder der Art und Weise, wie du die Dinge 
gehandhabt hast, dann sei es so.

von Christian (Gast)


Lesenswert?

eigentlich wollte ich damit nur sagen, dass die programme mit dem 
hyperterminal schon funktionieren. du hattest ja vorgeschlagen, simple 
programme mit dem hyperterminal kommunizieren zu lassen.

natürlich liegt der fehler irgendwo in meinen programmen!! wollte dich 
nicht verärgern oder so....

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.