I. Avant-propos▲
Dans les applications industrielles et domotiques, nous avons souvent besoin d'allier un système électronique à une application logicielle via un port d'entrée/sortie de l'ordinateur. Ce peut être le port parallèle, le port série ou même l'USB. Par exemple un modem externe, sur le port série ou une imprimante avec le port parallèle. Ceci dans un but d'allègement des montages électroniques et de commodité pour tout ce qui est calcul. Bien que ce ne soit pas toujours possible, par exemple pour des systèmes embarqués, ou là l'emploi d'un micro contrôleur est inévitable.
Ce tutoriel à pour but de voir, quelques méthodes de ce composant, pour l'écriture, la lecture, les mises à 1 des niveaux sur certaine broche, voir l'état des entrées etc... sur le port série.
II. Généralité sur le port série▲
II-A. Le brochage vue de face▲
Affectation :
Nom | C++ Builder | Broche | Sens |
DCD | RLSD | Broche n°1 | Entrée |
RxD | Rx | Broche n°2 | Entrée |
TxD | Tx | Broche n°3 | Sortie |
DTR | DTR | Broche n°4 | Entrée |
Masse | -- | Broche n°5 | -- |
DSR | DSR | Broche n°6 | Entrée |
RTS | RTS | Broche n°7 | Sortie |
CTS | CTS | Broche n°8 | Entrée |
RI | RING | Broche n°9 | Entrée |
Description des signaux:
- Broche 1 : DCD ou RLSD (Data Carrier Detect) ou (Receive Line Signal Detect) cette ligne est une entrée active à l'état haut. Elle signale à l'ordinateur qu'une liaison a été établie avec un correspondant ;
- Broche 2 : RxD (Receive Data) cette ligne est une entrée. C'est ici que transitent les informations du correspondant vers l'ordinateur ;
- Broche 3 : TxD (Transmit Data) cette ligne est une sortie. Les données de l'ordinateur vers le correspondant sont véhiculées par son intermédiaire ;
- Broche 4 : DTR (Data Terminal Ready) cette ligne est une sortie active à l'état haut. Elle permet à l'ordinateur de signaler au correspondant que le port série a été libéré et qu'il peut être utilisé s'il le souhaite ;
- Broche 5 : GND (Ground) c'est la masse ;
- Broche 6 : DSR (Data Set Ready) cette ligne est une entrée active à l'état haut. Elle permet au correspondant de signaler qu'une donnée est prête ;
- Broche 7 : RTS (Request To Send) cette ligne est une sortie, qui quand elle est active est à l'état haut. Elle indique au correspondant que l'ordinateur veut lui transmettre des données ;
- Broche 8 : CTS (Clear To Send) cette ligne est une entrée active à l'état haut. Elle indique à l'ordinateur que le correspondant est prêt à recevoir des données ;
- Broche 9 : RI ou RING (Ring Indicator) cette ligne est une entrée active à l'état haut. Elle permet à l'ordinateur de savoir qu'un correspondant veut initier une communication avec lui.
D'un point de vue électronique, les signaux TX et RX en sortie des prises répondent aux normes RS232, c'est à dire: 1 logique compris entre -3 et -25V et 0 logique compris entre +3 et +25V.
Bien sur, nous pouvons utiliser les broches comme bon nous semble, c'est à dire par exemple, se servir de CTS autrement que pour signaler à l'ordinateur que le périphérique est prêt à recevoir, mais il vaut quand même mieux respecter la norme.
III. Format des données▲
La communication série nécessite trois fils au minimum: une masse pour référencer les signaux, un fil émetteur et un fil récepteur. Notre liaison série est en effet full-duplex, c'est à dire que l'on peut émettre et recevoir en même temps (comme le téléphone par exemple). La différence principale entre le port parallèle et le port série est que les informations ne sont pas transmises simultanément sur des fils séparés (D0 à D7) mais les unes après les autres sur un même fil. Cela amène une économie de câble (un fil au lieu de 8) mais un montage décodeur devient nécessaire pour retransformer les données sérialisées.
Il est bon de rappeler que le port série, lors d'une écriture par exemple, envoi le bit de poids faible (LSB) en premier.
La liaison série est totalement asynchrone. Aucune horloge n'est transmise. Il faut donc se mettre d'accord sur la vitesse de transfert des bits et rajouter des bits de synchronisation. Voici un petit résumé des différents paramètres rentrant en jeu lors d'une communication série:
- Longueur de mot : sur le PC, le BIOS ne permet une longueur de mot que de 7 ou 8 bits ;
- Parité : le mot transmis peut être suivi d'un bit de parité qui sert à détecter les erreurs éventuelles de transmission. Il existe deux parités: la parité paire et la parité impaire. Dans le cas de la parité paire, et pour le mot 10110101 contenant 5 états à 1, le bit de parité sera 1 amenant ainsi le nombre total de 1 à un nombre pair (6). Dans le cas de la parité impaire, le bit de parité aurait été 0 car le nombre total de 1 est déjà impair. L'intérêt de ce rajout est le suivant: si jamais lors de la transmission un état 1 est transformé en état 0 (perturbation du canal par des parasites par exemple) le nombre total de 1 change et donc le bit de parité recalculé par le récepteur ne correspond plus à celui reçu. L'erreur est donc détectée. Évidemment, si deux états à 1 passent à 0, l'erreur ne sera pas détectée mais la probabilité pour que cela arrive est très faible ;
- Bit de start : lorsque rien ne circule sur la ligne, celle-ci est à l'état haut. Pour indiquer qu'un mot va être transmis, la ligne passe à bas avant de commencer le transfert. Cette précaution permet de resynchroniser le récepteur ;
- Bits de stop : ces bits signalent la fin de la transmission. Selon le protocole utilisé, il peut y avoir 1, 1.5, ou 2 bits de stop (ces bits sont toujours à 1) ;
- Vitesse de transmission : la plupart des cartes série permettent de choisir une vitesse entre 300 et 9600 bauds (par exemple à 300 bauds, un bit est transmis tout les un trois-centième de seconde). Les cartes récentes proposent des vitesses jusqu'à 115200 bauds. Ces vitesses ne vous paraissent peut-être pas énormes mais il faut garder à l'esprit que la liaison série est avant tout pensée pour les liaisons téléphoniques par modems, dont la bande passante est très limitée.
IV. Le composant TcomPort▲
IV-A. Ouverture du port▲
On définit préalablement, le port COM1, 2, 3 ou 4 dans l'inspecteur d'objets, (propriété Port).
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
ComPort1->
Connected=
true
; //Ouverture du port (prêt à communiquer)
}
//-------------------------------------------------------
Le port et maintenant ouvert et prêt à communiquer avec un périphérique externe.
IV-B. Fermeture du port▲
//-------------------------------------------------------
void
__fastcall TForm1::Button2Click
(
TObject *
Sender)
{
ComPort1->
Connected=
false
; //Fermeture du port (arrêt des communications)
}
//-------------------------------------------------------
Le port série est fermé, toutes tentatives de lecture, d'écriture ou autre, déclenchera une erreur.
IV-C. Changement de niveau sur les sorties RTS et DTR▲
Il peut être nécessaire d'envoyer un signal au montage relié au port du PC par une sortie. Admettons que celui ci ai besoin d'une impulsion pour diverses raisons. Nous pouvons faire ceci via RTS.
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
ComPort1->
SetRTS
(
true
); //Mise à +15V de RTS
ComPort1->
SetRTS
(
false
); //Mise à -15V de RTS
}
//-------------------------------------------------------
Ou par DTR comme cela.
c | 0 | 1 | |||
---|---|---|---|---|---|
//------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ComPort1->SetDTR(true); //Mise à +15V de DTR ComPort1->SetDTR(false); //Mise à -15V de DTR } //------------------------------------------------------- |
IV-D. État d'une broche d'entrée, CTS, DSR, RLSD▲
Il peut être utile de savoir quelle est le niveau sur une broche d'entrée.
Il faut pour cela, agir dans les événements, des ces broches. Prenons un exemple avec CTS.
//-------------------------------------------------------
void
__fastcall TForm1::ComPort1CTSChange
(
TObject *
Sender, bool OnOff)
{
if
(
OnOff ==
true
)
Button1->
Caption =
"
État haut sur CTS
"
; //État haut = +15V
else
Button1->
Caption =
"
État bas sur CTS
"
; //Etats bas = -15V
}
//-------------------------------------------------------
Si le Caption du TButton indique "États haut sur CTS", c'est que le niveau sur celle ci est +15V.
Nous pouvons procéder de même pour les autres événements, DSR et RLSD (DCD).
IV-E. Écrire une chaîne de caractères sur TxD▲
Vous serez peut être amené à envoyer des caractères ASCII vers le correspondant.
Voilà un petit exemple de la manière à procéder pour faire cela.
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
AnsiString Phrase;
Phrase =
Edit1->
Text;
ComPort1->
WriteStr
(
Phrase); //Écrit toute la chaîne "Phrase" sur le port série
}
//-------------------------------------------------------
IV-F. Écrire une valeur sur TxD▲
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
unsigned
char
tableau[7
] =
{
'
V
'
, '
i
'
, '
n
'
, '
c
'
, '
e
'
, '
n
'
, '
t
'
}
;
ComPort1->
Write
(
tableau, 7
); //Ecrit 7 octets de "tableau" sur le port série
}
//-------------------------------------------------------
IV-G. Lecture d'une chaîne de caractères sur RxD▲
Après avoir envoyé une chaîne de caractères sur la ligne TxD, il serait bien de savoir comment la recevoir. Écrivons dans l'événement OnRxChar :
//-------------------------------------------------------
void
__fastcall TForm1::ComPort1RxChar
(
TObject *
Sender, int
Count)
{
AnsiString Phrase2;
ComPort1->
ReadStr
(
Phrase2, Count);
//Lit les "Count" octet(s) présent(s) dans le buffer d'entrée et le(s) place dans Phrase2
}
//-------------------------------------------------------
La phrase reçut est stockée dans le buffer d'entrée du port, qui cela dit en passant est paramétrable en taille dans l'inspecteur d'objets, propriété Buffer / Input et OutputSize.
Dans cette exemple, nous remarquons bien que la lecture se fait caractère par caractère, ReadStr vient effacer le caractère dans le buffer, puis il passe au suivant et refait de même. Une lecture peut se faire, aussi, en dehors de l'événement OnRxChar.
IV-H. Lecture d'une valeur sur RxD▲
Toujours dans l'événement OnRxChar :
//-------------------------------------------------------
void
__fastcall TForm1::ComPort1RxChar
(
TObject *
Sender, int
Count)
{
unsigned
char
*
Buf =
new unsigned
char
[Count];
ComPort1->
Read
(
Buf, Count);
//Lit "Count" octet(s) présent(s) dans le buffer d'entrée et le(s) place dans "Buf"
delete [] Buf;
Buf =
NULL
;
}
//-------------------------------------------------------
Une lecture peut aussi se faire hors de cette événement.
IV-I. Vérifier les erreurs sur le port série▲
Il est possible, via l'événement OnError, de savoir si une erreur a eu lieu sur le port série.
//-------------------------------------------------------
void
__fastcall TForm1::ComPort1Error
(
TObject *
Sender, TComErrors Errors)
{
if
(
Errors.Contains
(
ceFrame))
{
// Une erreur de frame a eu lieu, mauvaise vitesse de communication !?
}
if
(
Errors.Contains
(
ceOverrun))
{
// Une erreur d'overrun a eu lieu, la donnée suivante est erronée !?
}
// voir l'aide de TComPort sur "LastErrors" pour continuer la gestion des erreurs
}
//-------------------------------------------------------
IV-J. Nombre d'octets présents dans le buffer d'entrée▲
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
int
NbrBits;
NbrBits =
ComPort1->
InputCount
(
);
}
//-------------------------------------------------------
Chaque fonction de lecture Read, ReadStr etc... décrémente InputCount.
IV-K. Vider les buffers d'entrée et de sortie▲
Nous pouvons effacer les Buffers, si une donnée est jugée inexploitable pour quelques raisons que se soit.
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
ComPort1->
ClearBuffer
(
true
, false
); // buffer d'entrée vidé, celui de sortie intacte
}
//-------------------------------------------------------
IV-L. Attendre un événement pour exécuter une action▲
Lors d'un dialogue, il est parfois nécessaire d'attendre une réponse du correspondant avant de lui envoyer une commande.
//-------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
ComPort1->
Events =
TComEvents
(
); // Effacer tous les évenements
ComPort1->
Connected =
true
;
TComEvents Ev;
Ev <<
evRxChar;
ComPort1->
WaitForEvent (
Ev, 0
, 5000
);
// Attend un événement OnRxChar ou 5 secondes avant de continuer
if
(
Ev.Contains
(
evRxChar))
{
// Executer une action, une donnée est arrivée
}
else
{
// Executer autre action, les 5 secondes se sont écoulées
}
}
//-------------------------------------------------------
L'utilisation de WaitForEvent se fait de la manière suivante :
- on efface tous les événements de la propriété Events de TComPort. Ce qui implique qu'aucun thread n'est créé ;
- on ouvre le port série ;
- on déclare les événements déclencheurs de l'application ;
- on appel la méthode WaitForEvent avec comme paramètre, les événements déclencheurs, 0 puis le timeout en ms. Il est possible de remplacer le timeout par "WaitInfinite" ;
- on test le(s) événement(s) qui ont déclenché(s).
IV-M. Changer les paramètres du port▲
La première possibilité est d'appeler la méthode ShowSetupDialog.
//---------------------------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
ComPort1->
ShowSetupDialog (
);
}
//---------------------------------------------------------------------------
La seconde est de placer par exemple un TComRadioGroup et d'affecter ses propriétés :
- "AutoApply" à true ;
- "ComPort" sur le port voulu, ComPort1, ComPort2 etc... ;
- "ComProperty" sur le paramètre à regler, cpPort pour le port, cpBaudRate pour la vitesse etc...
La même technique peut être employé pour un TcomComboBox.
IV-N. Stocker les paramètres du port dans un fichier .ini▲
Lors de la fermeture de l'application nous pouvons écrire.
//---------------------------------------------------------------------------
void
__fastcall TForm1::FormClose
(
TObject *
Sender, TCloseAction &
Action)
{
ComPort1->
StoreSettings (
stIniFile, GetCurrentDir
(
) +
"
\\
mon_fichier.ini
"
);
ComPort2->
StoreSettings (
stIniFile, GetCurrentDir
(
) +
"
\\
mon_fichier.ini
"
);
}
//---------------------------------------------------------------------------
Attention à prendre les précautions nécessaire en cas d'échec d'écriture !
IV-O. Lire les paramètres du port depuis un fichier .ini▲
Lors de la création de l'application nous pouvons écrire.
//---------------------------------------------------------------------------
void
__fastcall TForm1::FormCreate
(
TObject *
Sender)
{
ComPort1->
LoadSettings (
stIniFile, GetCurrentDir
(
) +
"
\\
mon_fichier.ini
"
);
ComPort2->
LoadSettings (
stIniFile, GetCurrentDir
(
) +
"
\\
mon_fichier.ini
"
);
ComRadioGroup1->
UpdateSettings (
); // si vous avez placé un TComRadioGroup
// avec la méthode expliquée en 2.12
}
//---------------------------------------------------------------------------
On peut procéder de la même manière pour un TcomComboBox.
IV-P. Gestion des exceptions▲
Il est possibles de gérer les exceptions provoquées par le composant TcomPort.
//---------------------------------------------------------------------------
void
__fastcall TForm1::Button1Click
(
TObject *
Sender)
{
AnsiString msg =
""
;
try
{
ComPort1->
Connected =
true
;
}
catch (
EComPort &
e)
{
switch
(
e.Code)
{
case
CError_OpenFailed : msg =
"
Votre port série est déjà ouvert
"
; break
;
case
CError_WriteFailed : msg =
"
Erreur d'écriture sur le port série
"
; break
;
// voir l'aide de TComPort sur "Error codes" pour continuer la gestion des erreurs
}
ShowMessage
(
msg);
}
}
//---------------------------------------------------------------------------
V. Conclusion▲
Attention le composant TComPort se révèle être inactif sans l'emploi des TComLed, il vous suffit de placer 3 TComLed et d'attribuer leurs propriétés :
- "ComPort" sur le port voulu, ComPort1 ou ComPort2 etc... ;
- "LedSignal" une sur IsConn pour l'ouverture du port, l'autre sur IsRx pour la ligne RxD et enfin une sur IsTx pour TxD.
Malheureusement le port série tend à disparaître sur les ordinateurs actuels pour laisser place aux ports USB. Referez vous aux liens ci dessous pour savoir où et comment installer le composant TcomPort.
VI. Liens▲
Nos articles C++ Builder™ :
- Piloter le port série avec C++ Builder™ :
- le composant TComPort, description,
- le composant TComPort, installation ;
- Piloter le port parallèle avec C++ Builder™ :
- le composant TDLPortIO, description,
- le composant TDLPortIO, installation.
Sans oublier :