Results 1 to 7 of 7
Hello everyone,
Sorry for my bad english! (I live in Belgium)
I am asking because my knowledge of C programming is very limited.
I'd like to see the movement of ...
- 05-04-2009 #1Just Joined!
- Join Date
- Apr 2009
- Posts
- 4
Read signal serial mouse RS232 in C
Hello everyone,
Sorry for my bad english! (I live in Belgium)
I am asking because my knowledge of C programming is very limited.
I'd like to see the movement of a RS232 mouse and the time in milli seconds between each increment of displacement
It would appear that:
the mouse RS232 protocol uses 1 start bit, 7 data bits, no parity, 1 stop bit, in a 1200 bits / sec.
The data is sent in packets of 3 bytes, comprising the following telegram:
byte d7 d6 d5 d4 d3 d2 d1 d0
1 X 1 LB RB dy7 dy6 dx7 dx6
2 X 0 dx5 dx4 dx3 dx2 dx1 dx0
3 X 0 dy5 dy4 dy3 dy2 dy1 dy0
LB (left button), RB (right button), is 1 when the button left, right, is pressed.
The movements in x (dx) and y (dy) are coded on 8 bits, whose bits are low on bytes 2 and 3 and the rest in the first byte.
I made a program but I think it is too slow:
After a few values, shift bytes
(the 1 is in position 2, 2 is in position 3 and 3 is in position 1 and so on)
And sometimes I have more than 3 per play while the mouse only sends 3
I wonder if there is an error in my code or if I do not use the right type of transmission (canonical, non-canonical ,...) which is described in this link:Code:046 037 068 000 000 24009 usec 007 035 064 000 000 27987 usec 063 033 065 000 000 23992 usec 007 001 077 000 000 24110 usec 005 062 077 010 005 76173 usec 072 014 039 000 005 15797 usec 075 038 045 000 005 23897 usec 078 062 032 000 005 24002 usec
3xw.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html
I need your help because I do not really know what to do!
A big thank you in advance.
I use Crunchbang linux (ubuntu).
Here is my code:
Code:#include <sys/time.h> //temps #include <unistd.h> //----------------------------------------------------------------------------- #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> // settins du port serie #include <stdio.h> //----------------------------------------------------------------------------- #include <stdlib.h> //fichier //----------------------------------------------------------------------------- #define BAUDRATE B1200 // baudrate settings sont définis dans <asm/termbits.h>, qui est inclus par <termios.h> #define ADRESSE_PORT "/dev/ttyS0" // numero du port #define _POSIX_SOURCE 1 // source conforme à POSIX //---------------- Timer ------------------------------------------------------ struct timeval tv1,tv2; struct timezone tz; long long delta_temps; //----------------- Fichier --------------------------------------------------- int mesure_impulsions; //ecriture ds le fichier char nom_fichier[200] ; // On initialise la variable à 0 //----------------------------------------------------------------------------- volatile int STOP=0; int fd, c, res; struct termios oldtio, newtio; char buf[255]; // nombre max de caracteres dans le buffuer pour une lecture char dep_x, dep_y; int deplacement_x(); int deplacement_y(); //----------------------------------------------------------------------------- // Open modem device pour lecture + écriture et pas comme controleur tty car on ne veut pas etre détruit si on recoit un caractère CTRL-C. main() { printf("Mesure \n\nVeuillez introduire le nom du fichier: "); scanf("%s", &nom_fichier); // On demande d'entrer le nom fd = open(ADRESSE_PORT, O_RDWR | O_NOCTTY );// O_NOCTTY flag dit que ce progr n'est pas un "controlling terminal" pour ce port. Si on ne le spécifie pas, chaque input (such as keyboard abort signals and so forth) va affecter le process. normally a user program does not want this behavior. if (fd <0) {perror(ADRESSE_PORT); exit(-1); } tcgetattr(fd,&oldtio); // sauve config courante bzero(&newtio, sizeof(newtio)); // on initialise la structure à zéro newtio.c_cflag = BAUDRATE | CRTSCTS | CS7 | CLOCAL | CREAD; // BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. // CRTSCTS : contrôle de flux matériel (uniquement utilisé si le câble a les lignes nécessaires. Voir la section 7 du Serial-HOWTO). // CS8 : 8n1 (8bit,no parity,1 stopbit) // CLOCAL : connexion locale, pas de contrôle par le modem // CREAD : permet la réception des caractères newtio.c_iflag = IGNPAR; // IGNPAR : ignore les octets ayant une erreur de parité. // ICRNL : transforme CR en NL (sinon un CR de l'autre côté de la ligne ne terminera pas l'entrée). sinon, utiliser l'entrée sans traitement (device en mode raw). newtio.c_oflag = 0; // positionne le mode de lecture(non-canonical, no echo,...) newtio.c_lflag = 0; // si ICANON : active l'entrée en mode canonique désactive toute fonctionnalité d'echo, et n'envoit pas de signal au programme appelant. // initialize all control characters // default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here newtio.c_cc[VTIME] = 0; // timer inter-caractères non utilisé newtio.c_cc[VMIN] = 3; // read bloquant jusqu'à ce que 3 caractères soient lus // now clean the modem line and activate the settings for the port tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); // la configuration du terminal est faite, à présent on traite les entrées //-------------------------------------------------------------------------------- while (STOP==0) { // boucle jusqu'à condition de terminaison read bloque l'exécution du programme jusqu'à ce qu'un caractère de fin de ligne soit lu, même si plus de 255 caractères sont saisis. //Si le nombre de caractères lus est inférieur au nombre de caractères disponibles, des read suivant retourneront les caractères restants. //res sera positionné au nombre de caractères effectivement lus res = read(fd,buf,255); // returns after xxx chars have been input buf[res]=0; gettimeofday(&tv2, &tz); delta_temps=(tv2.tv_sec-tv1.tv_sec) * 1000000L + (tv2.tv_usec-tv1.tv_usec); //calcul delta temps //-----------------------AFFICHAGE ECRAN-------------------------------------------------------------- //deplacement_x(); //deplacement_y(); gettimeofday(&tv1, &tz); char octet1,octet2,octet3; //octet1=buf[0]; //octet2=buf[1]; //octet3=buf[2]; printf("%03d %03d %03d %03d %03d", buf[0], buf[1], buf[2], buf[3], buf[4]); //printf("%02d %02d %02d", octet1, octet2, octet3);//affiche les deplacamants x et y printf(" %d microsec\n", delta_temps);//affiche le temps //-----------------------ECRITURE FICHIER------------------------------------------------------------ mesure_impulsions = fopen(nom_fichier, "a+");//ecriture ds fichier fprintf(mesure_impulsions,"%03d %03d %03d %03d %03d %d usec\n", buf[0], buf[1], buf[2], buf[3], buf[4], delta_temps); fclose(mesure_impulsions); //--------------------------------------------------------------------------------------------------- if (buf[0]=='z') STOP=1; } tcsetattr(fd,TCSANOW,&oldtio); // restaure les anciens paramètres du port }
- 05-04-2009 #2Linux Guru
- Join Date
- Apr 2009
- Location
- I can be found either 40 miles west of Chicago, or in a galaxy far, far away.
- Posts
- 8,974
I'm not going to take the time needed to fully analyze your code, however I have in the past done just what you are doing when debugging mouse drivers or similar (touch pads for example). I have always found that in such programs, the output to stdout is the biggest performance issue because the mouse generates so much incoming data. This is why routines that deal with the raw mouse data have to apply curve-smoothing algorithms to the data in order to have smooth operation, proper acceleration (if desired), etc. So, take a bunch of samples over some fixed interval of time, and average them out to generate the actual data you report. If you only report a maximum (possible settable on the command line) of 5 or less times per second (exact # needs to be determined experimentally), then you won't get the overflow you are likely experiencing now.
Sometimes, real fast is almost as good as real time.
Just remember, Semper Gumbi - always be flexible!
- 05-07-2009 #3Just Joined!
- Join Date
- Apr 2009
- Posts
- 4
Hello Rubberman,
Thank you for your help.
I will use this program for measure the rotation speed of a roller.
I will do the calculations with the time between each increment of displacement in openoffice calc.
I think the max frequency send for the mouse is 40 send/s.
If my program read 20/s, it's enough for me. But I don't know how make that.
Do you know where I can find help for make that?
Sorry again for my bad english!
Greetings
- 05-07-2009 #4Linux Guru
- Join Date
- Apr 2009
- Location
- I can be found either 40 miles west of Chicago, or in a galaxy far, far away.
- Posts
- 8,974
Even 20 samples / second is more than you can output and keep up with the input. You will still need to average the samples. As for how to limit the reads to 1 each 50ms (20/second), you probably need to use a timer, or usleep( unsigned long microsecs ) in a loop, passing 50000 as an argument, read the mouse, process the data, then sleep again... That would be the Q&D (Quick and Dirty) way to do it. Personally, I would use an interval timer instead, but that's your call.
Sometimes, real fast is almost as good as real time.
Just remember, Semper Gumbi - always be flexible!
- 05-08-2009 #5Just Joined!
- Join Date
- Apr 2009
- Posts
- 4
Hello Rubberman,
I used usleep like that:
When I write that : usleep(50000);Code:#include <sys/time.h> //temps #include <unistd.h> //----------------------------------------------------------------------------- #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> // settins du port serie #include <stdio.h> //----------------------------------------------------------------------------- #include <stdlib.h> //fichier //----------------------------------------------------------------------------- #define BAUDRATE B1200 // baudrate settings sont définis dans <asm/termbits.h>, qui est inclus par <termios.h> #define ADRESSE_PORT "/dev/ttyS0" // numero du port #define _POSIX_SOURCE 1 // source conforme à POSIX //---------------- Timer ------------------------------------------------------ struct timeval tv1,tv2; struct timezone tz; long long delta_temps; //----------------- Fichier --------------------------------------------------- int mesure_impulsions; //ecriture ds le fichier char nom_fichier[200] ; // On initialise la variable à 0 //----------------------------------------------------------------------------- volatile int STOP=0; int fd, c, res; struct termios oldtio, newtio; char buf[255]; // nombre max de caracteres dans le buffuer pour une lecture char dep_x, dep_y; int deplacement_x(); int deplacement_y(); unsigned int usecs; // for sleep //----------------------------------------------------------------------------- // Open modem device pour lecture + écriture et pas comme controleur tty car on ne veut pas etre détruit si on recoit un caractère CTRL-C. main() { printf("Mesure \n\nVeuillez introduire le nom du fichier: "); scanf("%s", &nom_fichier); // On demande d'entrer le nom fd = open(ADRESSE_PORT, O_RDWR | O_NOCTTY );// O_NOCTTY flag dit que ce progr n'est pas un "controlling terminal" pour ce port. Si on ne le spécifie pas, chaque input (such as keyboard abort signals and so forth) va affecter le process. normally a user program does not want this behavior. if (fd <0) {perror(ADRESSE_PORT); exit(-1); } tcgetattr(fd,&oldtio); // sauve config courante bzero(&newtio, sizeof(newtio)); // on initialise la structure à zéro newtio.c_cflag = BAUDRATE | CRTSCTS | CS7 | CLOCAL | CREAD; // BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. // CRTSCTS : contrôle de flux matériel (uniquement utilisé si le câble a les lignes nécessaires. Voir la section 7 du Serial-HOWTO). // CS8 : 8n1 (8bit,no parity,1 stopbit) // CLOCAL : connexion locale, pas de contrôle par le modem // CREAD : permet la réception des caractères newtio.c_iflag = IGNPAR; // IGNPAR : ignore les octets ayant une erreur de parité. // ICRNL : transforme CR en NL (sinon un CR de l'autre côté de la ligne ne terminera pas l'entrée). sinon, utiliser l'entrée sans traitement (device en mode raw). newtio.c_oflag = 0; // positionne le mode de lecture(non-canonical, no echo,...) newtio.c_lflag = 0; // si ICANON : active l'entrée en mode canonique désactive toute fonctionnalité d'echo, et n'envoit pas de signal au programme appelant. // initialize all control characters // default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here newtio.c_cc[VTIME] = 0; // timer inter-caractères non utilisé newtio.c_cc[VMIN] = 3; // read bloquant jusqu'à ce que 3 caractères soient lus // now clean the modem line and activate the settings for the port tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); // la configuration du terminal est faite, à présent on traite les entrées //-------------------------------------------------------------------------------- while (STOP==0) { // boucle jusqu'à condition de terminaison read bloque l'exécution du programme jusqu'à ce qu'un caractère de fin de ligne soit lu, même si plus de 255 caractères sont saisis. //Si le nombre de caractères lus est inférieur au nombre de caractères disponibles, des read suivant retourneront les caractères restants. //res sera positionné au nombre de caractères effectivement lus res = read(fd,buf,255); // returns after xxx chars have been input buf[res]=0; gettimeofday(&tv2, &tz); delta_temps=(tv2.tv_sec-tv1.tv_sec) * 1000000L + (tv2.tv_usec-tv1.tv_usec); //calcul delta temps //-----------------------AFFICHAGE ECRAN-------------------------------------------------------------- //deplacement_x(); //deplacement_y(); gettimeofday(&tv1, &tz); char octet1,octet2,octet3; //octet1=buf[0]; //octet2=buf[1]; //octet3=buf[2]; printf("%03d %03d %03d %03d %03d", buf[0], buf[1], buf[2], buf[3], buf[4]); //printf("%02d %02d %02d", octet1, octet2, octet3);//affiche les deplacamants x et y printf(" %d microsec\n", delta_temps);//affiche le temps //-----------------------ECRITURE FICHIER------------------------------------------------------------ // mesure_impulsions = fopen(nom_fichier, "a+");//ecriture ds fichier // fprintf(mesure_impulsions,"%03d %03d %03d %03d %03d %d usec\n", buf[0], buf[1], buf[2], buf[3], buf[4], delta_temps); // fclose(mesure_impulsions); //--------------------------------------------------------------------------------------------------- usleep(25000); //for sleep and read 20/s if (buf[0]=='z') STOP=1; } tcsetattr(fd,TCSANOW,&oldtio); // restaure les anciens paramètres du port } //----Rassemble les bits des différents octets pour avoir le déplacement total en x------------------- deplacement_x() { int j; char octet1,octet2; octet1=buf[0]; octet2=buf[1]; octet1=octet1 <<3; octet2=octet2 <<2; octet2=octet2 >>2; dep_x=octet1 & octet2; return(dep_x); } //-----Rassemble les bits des différents octets pour avoir le déplacement total en y------------------ deplacement_y() { int j; char octet1,octet3; octet1=buf[0]; octet3=buf[2]; octet1=octet1 <<5; octet1=octet1 >>6; octet1=octet1 <<2; octet3=octet3 <<2; octet3=octet3 >>2; dep_y=octet1 & octet3; return(dep_y); }
the problem of shift bytes is more important.
I have more than 3 Bytes/read. Normally, I should have only 3 bytes.
Code:064 004 012 064 014 50100 microsec 064 028 013 064 025 50099 microsec 064 029 010 064 022 50099 microsec 064 011 000 076 006 50088 microsec 076 000 051 079 053 50087 microsec 079 038 045 079 026 50097 microsec 079 029 054 079 036 50106 microsec 067 049 001 067 060 50120 microsec 064 004 027 064 014 50102 microsec 018 024 064 025 019 50099 microsec 064 030 012 064 024 50097 microsec
When I write: usleep(25000);
It is better but no very good:
I don't understand why there is a shift bytes.Code:064 019 044 000 000 25087 microsec 065 043 002 000 000 25095 microsec 077 005 058 000 000 25099 microsec 076 043 035 079 000 25104 microsec 042 024 078 000 000 27490 microsec 043 057 066 000 000 25087 microsec 004 026 066 000 000 25087 microsec 060 057 071 000 000 25100 microsec 052 005 064 000 000 25106 microsec 000 044 064 000 000 25106 microsec 053 010 077 000 000 25097 microsec
Thank you very much for your help.
- 05-08-2009 #6Linux Guru
- Join Date
- Apr 2009
- Location
- I can be found either 40 miles west of Chicago, or in a galaxy far, far away.
- Posts
- 8,974
Remember that by default, your serial device driver will buffer input - probably up to a couple hundred bytes. You should be able to switch to unbuffered input, or to filter the extra data out. Certainly the mouse outputs some sort of guard-byte so that you can determine what is each input reading? Otherwise, it would be difficult to differentiate between each event.
Sometimes, real fast is almost as good as real time.
Just remember, Semper Gumbi - always be flexible!
- 05-13-2009 #7Just Joined!
- Join Date
- Apr 2009
- Posts
- 4
Hello,
I have find the problem.
I have replaced 255 by 3 and it work good.Code:res = read(fd,buf,255); // returns after xxx chars have been input
Thank you for your help Rubberman.


Reply With Quote