Réception sur port série d'un PC en C standa

Fermé
KIMFAF - 13 janv. 2008 à 01:26
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 - 6 févr. 2008 à 16:53
Bonjour,

je débute en C , j'aimerai recevoir une trame GPS (4800 bauds en ASCII) par
l'intermédiaire du port COM de mon PC (windows XP)

Une bonne âme pourrait-elle m'aider, ou au moins m'aiguiller afin de m'indiquer la procédure et/ou instructions à suivre pour recevoir les caractères sur le PC et les stocker (code C, librairies a insérer,...)?

Merci
A voir également:

14 réponses

damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
29 janv. 2008 à 00:09
Salut,

1) config_ com est le nom que j'ai donné à la variable de type DCB. Ds ton programme tu aura donc

/*Déclaration des variable*/
DCB config_com; /*(ou un autre nom)*/
...


2)HANDLE est un type de variable qui contient en fait un entier qui est attribué à un fichier lors de son ouverture. Utilisation :

/*Déclaration des variable*/
HANDLE hcom1; /*(ou un autre nom)*/
/*Ouverture du port COM1*/
hcom1 = CreateFile("COM1",autres paramètres(voir aide));


3)Toutes ces fonctions sont dans : stdio.h, windows.h stdlib.h. Je sais plus quelles fonctions dans quel .h mais en tout cas avec ces 3 .h tu les as toutes.


4)Si j'ai mis a chaque fois DCB xxxx c'est parce que pour décrire une fonction en C on fait souvent figurer les paramètres de la fonction avec leurs types. Bien sur dans un programme tu as d'abords une partie de déclaration des variables et ensuite dans les fonctions tu utilises juste le nom des variables. Par exemple ici :

/*Déclaration des variable*/
DCB config_com; /*(ou un autre nom)*/
HANDLE hcom1; /*(ou un autre nom)*/

/*Ouverture du port COM1*/
hcom1 = CreateFile("COM1",autres paramètres(voir aide));

/*Récupération de la config du port*/
SetCommState(hcom1,config_com);
etc...

voilou. Chao
2
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
13 janv. 2008 à 02:11
Salut,

La fonction bioscom de bios.h permet de communiquer avec un port série.
Va voir sa syntaxe sur : http://www.delorie.com/djgpp/doc/libc/libc_486.html

Par contre qu' entens-tu par transmission en ASCII ? Pour un communication série il te faut les infos de bit de stop de bit de parite...
Du moins si on travaille avec bioscom.

++
1
Bonsoir,
tout d'abord, merci de m'avoir répondu (c'est la 1ère fois que je viens sur un forum)
je suis allé à l'adresse indiquée et voici ce que j'ai trouvé:

bioscom(0, 0xe3, 0); /* 9600 baud, no parity, one stop, 8 bits */
for (i=0; buf[i]; i++)
bioscom(1, buf[i], 0);

si j'ai bien compris la 1ère ligne: Nous sommes en * initialisation
* 9600 bds etc...
* sur COM1

Pour la boucle, on est en écriture (1) et je suppose que buf (i) est une
chaine de caractère que l'on envoie sur COM1, ais je raison?

Pour ce qui est du status:

Return Value

The return value is a sequence of bits that indicate the port status and,
for cmd=0 and 3, the modem status.
For read/write operations, the lower eight bits are the character read.

1111 1100 0000 0000
5432 1098 7654 3210 Meaning

Cela veut-il dire que chaque caractére envoyé/recu est en 3 octets
(2 pour le status et 1 pou le caractère (ASCII pour moi)?

Merci

++
1
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
16 janv. 2008 à 00:01
Salut,

La syntaxe de bioscom est la suivante :

int bioscom(int cmd, char abyte, int port)

où abyte est, si cmd=0, une combinaison OR (OU logique) des bits spécifiant la configuration du port et si cmd=1, le caractère a transmettre. abyte est ignoré si cmd =2 ou 3.
Donc buf[i] est un char cad un caractère et non pas un chaine de caractère.

La fonction bioscom renvoie un entier sur seize bits : les 8 bits de poids fort forment le statut et les huit bits de poids faible forment le caractère recu, si cmd=2.

Pour utilisé le port en reception il faut tester si un caractère a été recu par le port c-a-d on regarde si le bit 8 du mot recu est a 1 : les huit premiers bits correspondent alors au caractères recu. On peut également tester d'autres bits de statut comme le bit 10 (parity error) si une detection d'erreur de parité est souhaité.
Ce qui donne, par exemple

bioscom(0, 0xe3, 0); /* 9600 baud, no parity, one stop, 8 bits , COM1 par exemple */
while( ( mot_recu = bioscom(1,0,1) ) && (0x0100) ) != 0x10){
//attendre
}
caractere_recu = mot_recu && 0x00FF


explications :
&& : ET logique bit à bit
0x0100 = 0000 0001 0000 0000
Donc while( ( mot_recu = bioscom(1,0,1) ) && (0x0100) ) != 0x10) equivaut à : tant que le bit 8 n'est pas a 1 on continue de lire le port.

Le probleme de cette methode est que pendant qu'on boucle on ne peut rien faire d'autre (notament faire du traitment sur le caractère recu). Heuresement il existe les interruptions. A toi de voir ce dont tu as besoin.

Chao
1
Bonsoir,

merci de ton aide , cela fait toujours plaisir d'avoir un coup de pouce.
Je commence a y voir plus clair dans mon problème mais juste une précsion:

Dan l'instruction suivante: while( ( mot_recu = bioscom(1,0,1) ) && (0x0100) ) != 0x10) pouquoi
y-a-t-il 1 en non 2 alors qu l'on est en reception?

Dans l'instruction caractere_recu = mot_recu && 0x00FF, FF sert à récupérer le caractère
recu, mais existe t-il une instructio permettant de récupérer juste l'octet du caractère?

Merci

@+
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
bonsoir,
merci de poursuivre cette discussion,

1) Dans l'instruction ci-dessous, cmd devrait être= 2 pour réception comme l'indique ton"mea culpa", mais vu que l'on test si un
caractère est présent ne faudrait-il pas mettre cmd =3 afin de tester le status comme dans FIG.1-i ?

mot_recu = bioscom(1,0,1) ) && (0x0100) ) != 0x10

FIG.1

a---- ---- ---- ---1 CTS change
b---- ---- ---- --1- DSR change
c---- ---- ---- -1-- ring change
d---- ---- ---- 1--- carrier detect change
e---- ---- ---1 ---- CTS present
f---- ---- --1- ---- DSR present
g---- ---- -1-- ---- ring present
h---- ---- 1--- ---- carrier detect
i---- ---1 ---- ---- data ready
j---- --1- ---- ---- overrun error

2) Puisque l'on fait un ET logique entre abyte et 0x0100 (sur 32 bits) , comment arrive t-on à Ox10 (sur 16 bits) ?
3) Existe t-il une librairie pir une reception en USB?
4) Quand tu parles d'interruption, comment la déclenche t-on (avec data ready)?

merci

@+
1
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
21 janv. 2008 à 01:00
Bonjour,

1) En fait, ça marche que tu mettes cmd=2 ou cmd =3 puisque quelque soit la valeur de cmd les huit bits de poids fort représentent le statut. Et comme data ready fait partie de ces huit bits c'est bon. Avec cmd = 3 tu as juste en plus les huit bis de statut de poids faibles (a,b,c,d,e,f,g et h). En mettant cmd = 2, ca t'évite juste de refaire un bioscom pour réceptionner le caractère que tu aurait détecter avec cmd=3.

2)J'ai fait une erreur (encore une...) puisqu'on cherche a savoir si le bit i est a 1 (en reprenant tes notations) il faut écrire
( mot_recu = bioscom(1,0,1) ) && (0x0100) ) != 0x0100
Soit dit en passant on peut aussi mettre 0x100 puisqu'ici c'est des nombre que l'on compare et 0x0100 = 0x100 donc ca revient au même.

3)Je sais pas, mais je pense que faire du l'usb en C doit être assez compliqué vu que le langage est plus vieux que l'usb.

4)En fait, avec cette méthode on fait ce qu'on appelle un transfert de données par test du mot d'état (ou statut). Comme je te l'ai dit l'inconvénient de cette méthode c'est la boucle while : pendant que tu teste le mot d'état (ou statut) tu es bloqué dans la boucle et tu ne peux rien faire d'autre.
Il existe une autre méthode : le transfert de données par interruption. Lors de l'arrivée d'un caractère sur le port COM, ce dernier peut envoyer une interruption (sil on l'a autorisé à le faire).Une interruption est un signal envoyer au CPU pour qu'il exécute une tâche (un programme) contenu en mémoire. L'idée est de modifier ce programme par notre programme qui va lire le caractère reçu. Ainsi pas besoin de boucler pour lire le statut, le port COM nous préviens lui même quand un caractère est arrivé. Par contre les fonctions à utiliser sont très différentes; on utilise des fonctions qui écrivent directement dans les registres des ports sans passer par l'intermédiaire du bios comme le fait bioscom.

voilou, Chao
1
bonsoir, c'est encore moi qui viens à la rescousse, voila, voici une ébauche de programme de lecture de trame GPS
en simulant la reception au clavier mais en introduisant quand même la fonction bios.h

l'objectif est de tester si un caractère est recu sur COM1, en attendant de connecter un GPS je veux simuler l'entrée des caractère avec le clavier et tester si on reçoit un '$' (1er caractère d'une trame GPS)
Le Problème est
1)Apparament le compilateur ne trouve pas bios.h en lignes 5 et 23 d'où ma demande d'aide de ta part
2) ligne 38, je ne comprend pas le message


#include <stdio.h>
//#include <stdlib.h>
#include <conio.h>
#include <string.h>
5 #include <bios.h>
#define COM1 0
#define DATA_READY 0x0100 //bit 8 à 1
#define TRUE 1
#define FALSE 0
#define SETTINGS 0xC3 //reception à 4800 bauds
#define INIT_PORT 0 //COM1
#define RECEP 2 //reception
//#define $ 0x24 // code ASCII de $ ( début d'une trame GPS)
int main()
{
char sim_carac_recu;
char mot_recu;
int LONG_TRAME; longueur de la trame
char carac1_recu[LONG_TRAME]; //tableau recevant la trame
char carac_recu[LONG_TRAME]; //tableau recevant la simulation au clavier du caractère recu
//clrscr(); clear screen (n'existe pas en C ?)
23 bioscom(INIT_PORT,SETTINGS,COM1);//initialisation du port série COM1
printf("entrez la longueur de la trame GPS\n");
scanf("%d",&LONG_TRAME); // entrée de la longueur de la trame pour simulation
printf("la longueur de la trame est: %c ", LONG_TRAME);

while ((mot_recu = bioscom(RECEP,0,COM1))&(DATA_READY)!= 0x10)
{
printf("attendre réception caractères GPS\n");

}
attente_$:
for (i= 0;i<LONG_TRAME;i++)
{
scanf("%c",&sim_carac_recu);
// carac_recu[i]=mot_recu&0x00FF; //masque pour avoir le caractère recu
carac1_recu[i]=sim_carc_recu; //tableau recevant le caractère recu simulé
38 while (carac1_recu[i]!="$") //boucle d'attente de '$'

{
goto attente_$;
}
printf("caractère '$' recu\n)"); //sortie de la boucle et arr^t de la simulation
break;
}
}

voici ce que me répond le compilateur:
5 bios.h:No such file or directory
23 error:'bioscom' undeclared (first use this function)
23 error:(Each undeclared identifier is reported only once for each function it appears
38 error: ISO C++ forbds comparison between pointer and integer


merci

@+
1
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
19 janv. 2008 à 01:39
Salut,

T'as raison c'est bien 2 mea culpa.
Pour la deuxième question : je me suis aussi trompé && est le ET des conditions ( if(i>3 && i<5) par ex ) le ET Logique bit à bit c'est un & tous seul. . Et pour récupérer l'octet du caractère, l'instruction caractere_recu =(char) mot_recu suffit, avec caractere_recu défini comme un char puisque un char étant défint sur un octet, la conversion est automatique.
Pour en savoir plus www.commentcamarche.net/c/ctype.php3

Chao ++
0
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
24 janv. 2008 à 15:33
Salut,

1)
bios.h ne fonctionne que sous DOS (j'aurais peut être du le préciser avant dsl).
Sous windows il y a d'autres fonctions :
CreateFile("COM1",autres paramètres(voir aide)) : Cette fonction ouvre le port com comme un fichier.Elle renvoie le HANDLE du com1
GetCommState(HANDLE hcom1,DCB config_com) : Stocke la config du port com pointé par hcom1, dans config_com.
Modif de la config :
config_com.BaudRate = CBR_2400;
config_com.ByteSize = 8;
config_com.Parity = NOPARITY;
config_com.Stopbits = ONESTOPBIT; (par exemple)
SetCommState(HANDLE hcom1,DCB config_com) Ecrit la nvelle config sur le port.
ReadFile(HANDLE hcom1,char*caractere_recu,autre parametre (voir aide)). Lit le port com1 comme si c'était un fichier

2) Pour l'erreur de la ligne 38 essaye while (carac1_recu[i]!='$')

A+
0
Bonsoir, sympa de me mettre sur une nouvelle voie (windows au lieu de DOS)

1) Dans ton message ci-dessous tu utilises "config_com" : Est-ce un fichier du C ou un nom de fichier perso?
2) J'ai cherché un peu partout mais n'arrive pas a trouver une définition exacte de HANDLE, peux-tu m'éclairer la dessus SVP?
3) Pour HANDLE hcom1, dans quel librairie le trouve t-on ?
4) Dans d'autre programmes je vois souvent DCB xxxxx, est-ce une initialisation ?

CreateFile("COM1",autres paramètres(voir aide)) : Cette fonction ouvre le port com comme un fichier.Elle renvoie le HANDLE du com1
GetCommState(HANDLE hcom1,DCB config_com) : Stocke la config du port com pointé par hcom1, dans config_com.
Modif de la config :
config_com.BaudRate = CBR_2400;
config_com.ByteSize = 8;
config_com.Parity = NOPARITY;
config_com.Stopbits = ONESTOPBIT; (par exemple)
SetCommState(HANDLE hcom1,DCB config_com) Ecrit la nvelle config sur le port.
ReadFile(HANDLE hcom1,char*caractere_recu,autre parametr

merci encore

@+
0
salut, je vais encore avoir besoin de tes lumières:

voila: J'ai trouvé ce bout de code sur un forum, qui correspond aux instructions que tu m'as indiqué.

J'aimerai le tester, mais Pb:

ReadCOM : lecture de données sur le port COM.
entrée : buffer : buffer où mettre les données lues.
nBytesToRead : nombre max d'octets à lire.
pBytesRead : variable qui va recevoir le nombre d'octets lus.
retour : vrai si l'opération a réussi, faux sinon.
-------------------------------------------------------------------------------
Remarques : - la constante MAX_WAIT_READ utilisée dans la structure
COMMTIMEOUTS permet de limiter le temps d'attente si aucun
caractères n'est présent dans le tampon d'entrée.
- la fonction peut donc retourner vrai sans avoir lu de données.
******************************************************************************/

BOOL ReadCOM(void* buffer, int nBytesToRead, int* pBytesRead)

{

return ReadFile(g_hCOM, buffer, (DWORD)nBytesToRead, (DWORD*)pBytesRead, NULL);

}


1) Après la compilation (GNU GCC compiler avec code::blocks windows XP) j'ai le message suivant:

File line Message
ld.exe cannot find _lbios.h


et ce, quelque soit le programme (même très simple), as tu une idée ?

2) Dans les lignes du début de ce programme, il y a :

BOOL OpenCOM (int nId);
BOOL CloseCOM ();
BOOL ReadCOM (void* buffer, int nBytesToRead, int* pBytesRead);
BOOL WriteCOM (void* buffer, int nBytesToWrite, int* pBytesWritten);

Que signifie : BOOL ?

merci encore

@+
0
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
3 févr. 2008 à 00:57
Salut,

1) As-tu bien fait l'include de windows.h et stdio.h ? J'ai essayé juste un main avec un appel a la fonction ReadCOM j'ai pas eu d'erreur de compilation ni d'exécution (j'utilise l'IDE Dev-C++ qui utilse le compilateur gcc). tu devrais me poster le script du petit prog que tu as fait.

2) BOOL est un type représentant un booléen cad un int qui vaut 0 ou 1 (FAUX ou VRAI). Ici toute les fonction renvoient un booléen qui faux 0 si la fonction à rencontrer une erreur et 1 si tout c'est bien passé. C'est pour te permettre de faire un programme avec gestion d'erreur.

A+
0
Bonsoir, suite de mon Pb, si tu as un peu de temps:
voilà, mon Pb initial est toujours de traiter une trame GPS.

En utilisant l'IDE Dev-C++ qui utilse le compilateur gcc, cela va mieux pour le script de reception sur COM1 qui doit être sensé me retourner une chaine de caractères (trame GPS), j'aprofondirai ce Pb plus tard quand j'aurai résolu (avec ton aide si possible) la question suivante:.

Maintenant que la trame est sensée avoir été recue, il faut la découper pour la traiter, voici donc le script
que j'essaie de « pondre »
#include <stdio.h>
#include <string.h>
#include <windows.h>
char TRAME[10]; //Tableau recevant les morceaux de la trame recue par COM1
int i=0;
int main ()
{
char str[ ] ="$GPRMC,211335.260,A,4546.6428,N"; //str= chaine de caract de COM1
//(une partie ici)

char *pch; //pointeur de « découpage
printf ("%s \n\n\n",str);//affichage de la trame GPS
pch = strtok (str,",");//découpage de la trame par rapport à la « , »
while (pch != NULL) //boucle
{
TRAME[i]=*pch;// j'ai aussi essayé avec TRAME[i]=pch;
i++;
printf ("%s\n",pch); //affichage des « morceaux « de la trame//jusqu'ici c'est OK
//sprintf(TRAME[i], "%s \n",pch);//essai d'ecrire dans la chaine mais non OK
printf ("Decoupage trame TRAME[%d] du GPS: bloc %d = %s\n",i,i, TRAME[i]);//c'est ici que cela ne va pas apparament
//car rien n'apparait pour le contenu de TRAME[i]
//printf("%s",TRAME);

pch = strtok (NULL, ",");
}
system("PAUSE");
return 0;
}
voilà le résultat: Je n'arrive pas a afficher (pour un futur traitement des infos GPS) les valeurs
du tableau « TRAME », j'ai juste <NULL> dans les cases de mon tableau « TRAME[ ]

$GPRMC,211335.260,A,4546.6420,N
$GPRMC
Decoupage trame TRAME[1] du GPS: bloc 1= <null>

etc... Pourquoi ce <null> à la place de la valeur de la trame découpée?
voilà, voilou merci
@+
0
damlegone32 Messages postés 74 Date d'inscription lundi 11 septembre 2006 Statut Membre Dernière intervention 31 mai 2011 29
6 févr. 2008 à 16:53
Salut,

Apparament, tu veux sauvegarder chaque morceau de chaîne de caractère découpé dans un tableau. Tu doit donc déclarer un tableau de chaine de caractères. Or toi du déclare seulement une chaine de 10 caractères (char TRAME[10]).
Il faut déclarer "char TRAME[n][p]" où n et le nombre de chaines maxi que tu peux stocker et p le nombre maxi de caractère de chaque chaine.
Ensuite pour chaque itération tu fais strcpy(TRAME[i],pch) pour recopier tous les caractères dans ton tableau. Si tu fait juste TRAME[i] = pch tu ne fais que recopier l'adresse de la chaine pch dans TRAME[i] et a l'itération suivante les caractère seront écrasés vu que l'addresse de pch ne change pas.
Enfin pour afficher c'est simplement printf("%s",TRAME[i]);

@+
0