# µicrocontroleur sur un port USB



## jfsgeneva (14 Avril 2008)

Voici le code que j'utilise pour lire des valeur sur mon microcontrôleur.
J'arrive à afficher ces valeurs dans une fenêtre (merci le site du zero) avec un renouvellement des valeurs affichées  environ une fois par seconde.
Comment faire pour que cela soit plus rapide ?

J'ai déjà essayé de déplacer Ouverture_port(); et close(fd); , mais mon Mac plante...



```
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL_ttf/SDL_ttf.h>



#include <fcntl.h>
#include <termios.h>   
#include <unistd.h> //write(), read()

using namespace std;

void Output();          // pour envoyer au µcontroleur
void readport();        // pour recevoir de µcontroleur
void init_port();       //initialise le portUSB
void Ouverture_port();  //ouvre le portUSB


char USBPort[1000];            // pour le nom du portUSB
char temps[20] = "";        //pour déterminer le temps
char Temperature [5]={0};    //pour la valeur écrite dans la fenêtre
char table[7]={0};            //pour les valeurs en sortie µcontroleur

int fd = 0;
int continuer = 1;
long Temp,Temp1,Temp2,Temp3 ,Temp4,Temp5  = 0;




int main(int argc, char *argv[])
{
    /******************************************
    détection du port usb
    *******************************************/
    FILE* myPipe=NULL;
    char buffer[1000];
    myPipe = popen("ls /dev/tty.usbserial*", "r");
    if(myPipe==NULL){
        //errorstuff
    }
    while(fgets(buffer, 1000, myPipe)!=NULL){
        (void) printf("\n\nvotre usb est : \n\n%s \n", buffer);
    }    
    
    
    pclose(myPipe);
    
    /*******************************************
    fin de détection
    ********************************************/
            

    
    cout << "Sur quel port est le µcontroleur ?" << endl;
    cout << "Example:\n/dev/tty.usbserial-A70041zl\nor\n/dev/tty.usbserial-A1001N2Y" << endl;    
    
    cin >> USBPort;

    

    SDL_Surface *ecran = NULL, *texte = NULL;
    SDL_Rect position;
    SDL_Event event;
    TTF_Font *police = NULL;
    SDL_Color couleurNoire = {0, 0, 0}, couleurBlanche = {255, 255, 255};


    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();

    ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
    SDL_WM_SetCaption("Mesure de luminosité", NULL);


    /* Chargement de la police */
    police = TTF_OpenFont("angelina.ttf", 65);

 
    while (continuer)
        {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
                close(fd);
                break;
        }

        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));


        
        
        // compteur += 100; // On rajoute 100ms au compteur 
        
    Ouverture_port();
    Output();
    readport();
    close(fd);
        

    //Temp = Temp1*100 + Temp2*10 + Temp3 ; 
    //double strtod(const char *nptr, char **endptr); //pour convertir une chaine en entier
            sprintf(Temperature, "%ld%ld%ld%ld", Temp1, Temp2, Temp3, Temp4);     
     
    
    
    cout<<table[0]<<table[1]<<Temperature<<endl;
            
            sprintf(temps, "Temp : %s", Temperature); /* On écrit dans la chaîne "temps" le nouveau temps */
            SDL_FreeSurface(texte); /* On supprime la surface précédente de la mémoire avant d'en charger une nouvelle (IMPORTANT) */
            texte = TTF_RenderText_Shaded(police, temps, couleurNoire, couleurBlanche); /* On écrit la chaine temps dans la SDL_Surface */
                       

        position.x = 180;
        position.y = 210;
        SDL_BlitSurface(texte, NULL, ecran, &position); /* Blit du texte contenant le temps */
        SDL_Flip(ecran);

        }
    
    
    
        TTF_CloseFont(police);
        TTF_Quit();

        SDL_FreeSurface(texte);
        SDL_Quit();


    return EXIT_SUCCESS;
    }


/**************************************/
/**************************************/


void init_port(int *fd, unsigned int baud) 
    { 
    struct termios options; 
    tcgetattr(*fd,&options); 
    switch(baud) 
    { 
       case 9600: cfsetispeed(&options,B9600); 
    cfsetospeed(&options,B9600); 
    break; 
       case 19200: cfsetispeed(&options,B19200); 
    cfsetospeed(&options,B19200); 
    break; 
       case 38400: cfsetispeed(&options,B38400); 
    cfsetospeed(&options,B38400); 
    break; 
    default:cfsetispeed(&options,B9600); 
    cfsetospeed(&options,B9600); 
    break; 
    } 
    options.c_cflag |= (CLOCAL | CREAD); 
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB; 
    options.c_cflag &= ~CSIZE; 
    options.c_cflag |= CS8; 
    tcsetattr(*fd,TCSANOW,&options); 
    } 
    
    
void Ouverture_port()
        {
        fd = open(USBPort, O_RDWR | O_NOCTTY | O_NDELAY);
    if(fd == -1) 
    perror("open_port: unable to open port"); 

    init_port(&fd,19200);         //set serial port to 9600,8,n,1
    fcntl(fd, F_SETFL,3);
    }


void Output()
    {
    
    write(fd,"&",1);
    }
        
    
void readport()
    {
    char table[7]={0};
    {    
    while(table[6]!='$')
    {
    read(fd,&table,sizeof(table));
    
    Temp1 = table[2]-'0';
    Temp2 = table[3]-'0';
    Temp3 = table[4]-'0';
    Temp4 = table[5]-'0';

    //    if (Temp1 < 0){ fputs("read() of 10 bytes failed!\n", stderr); }    

    }
    }

    }
```


----------



## tatouille (15 Avril 2008)

tu es en usb 1?


----------



## jfsgeneva (16 Avril 2008)

USB 2.0

Voici ce qui figure dans information système :

Bus USB à grande vitessse
   USB 2.0 Hub
       FT232R USB UART


----------



## tatouille (16 Avril 2008)

jfsgeneva a dit:


> USB 2.0
> 
> Voici ce qui figure dans information système :
> 
> ...




ok ca ne devrait pas etre aussi lent quand tu select ton baud quel est la valeur retournee?
et les specs de ton materiel ? c est quoi ton um?


----------



## jfsgeneva (16 Avril 2008)

En changeant de Baud, la vitesse d'affichage des valeurs ne varie pas.

J'ai l'impression que c'est le fait d'ouvrir et de fermer le port Usb à chaque boucle qui crée cette lenteur, mais je ne sais pas comment modifier mon code pour changer ça sans plantage.

Actuellement les valeurs sont affichées à un rythme d'environ une seconde, j'aimerais approcher le 1/100 ou mieux, le 1/1000 si possible.

J'utilise un Arduino Diecimila avec une alim 12 volts extérieure, le logiciel pour coder le µU est Arduino 010.



```
int CaptPin05 = 5;
//int Temp1 = 0;
char incoming = 0;
void setup()
{
pinMode(CaptPin05,INPUT);
  Serial.begin(9600);
}



void loop () {
//Temp1 = analogRead(CaptPin05);

//Temp1 =123; 

incoming=Serial.read();
if (incoming = '&')
{
Serial.print("ok");
//Serial.print("yes");
/* mise à niveau des chiffres */
if(analogRead(CaptPin05)<1000)
{
  Serial.print("0");
}
if(analogRead(CaptPin05)<100)
{
  Serial.print("0");
}
if(analogRead(CaptPin05)<10)
{
  Serial.print("0");
}
/* fin de mise à niveau */

Serial.print(analogRead(CaptPin05));
Serial.print("$");
incoming = 0 ;
}
}
```


----------



## tatouille (16 Avril 2008)

ha ok tu veux un datastream je n'avais regarde en details
tu doit lire un stream, pas besoin d ouvrir et de ferme a chaque fois

creer un handler dans un subthread pour eviter d occuper ton main


----------



## jfsgeneva (17 Avril 2008)

Je débute en C et je ne comprend pas tout ce que tu expliques 

Ce que tu proposes c'est de faire une partie de code qui fonctionne en parallèle au Main pour le libérer ?

Le main ouvrirait le port et cette partie parallèle le lirait en boucle ?



Au fait, merci de t'attarder sur ce topic.



Edit : j'ai trouvé ce tuto :

http://http://www.siteduzero.com/tuto-3-21581-1-les-threads-et-les-mutex.html


----------



## jfsgeneva (18 Avril 2008)

En simplifiant le code j'arrive à avoir 130 mesures affichées par seconde, mais c'est dans la console.


```
int main(int argc, char *argv[]) 
{    
   cout << "what USB port is your Arduino Board pluged into?" << endl; 
   cout << "Example:\n/dev/tty.usbserial-A70041zl\nor\n/dev/tty.usbserial-A1001N2Y" << endl;    
    
   cin >> USBPort; 
    
   Ouverture_port(); 
    
         
       
      while(Q!=8000) 
      { 
 
    
   //Output(); 
   readport(); 
    
       
     
   sprintf(Temperature, "%ld%ld%ld%ld", Temp1, Temp2, Temp3, Temp4);     
      
    
    
   cout<<Temperature<<endl; 
        Q++; 
      }     
              
    
   close(fd); 
    return EXIT_SUCCESS; 
   }
```

Là ça ne plante pas même en fermant la console au milieu d'un processus.


----------



## jfsgeneva (18 Avril 2008)

Pour la suite j'ai essayé de faire un thread pour l'affichage, mais la lib SDL m'affiche une fenêtre noire pendant quelques secondes puis disparait et me sort de l'application.
La console m'affiche ça :

2008-04-18 20:51:49.144 digit[646] *** _NSAutoreleaseNoPool(): Object 0x455700 of class NSView autoreleased with no pool in place - just leaking
2008-04-18 20:51:49.168 digit[646] *** _NSAutoreleaseNoPool(): Object 0x455ca0 of class NSIdEnumerator autoreleased with no pool in place - just leaking
2008-04-18 20:51:49.168 digit[646] *** _NSAutoreleaseNoPool(): Object 0xa72fc2c0 of class NSCFString autoreleased with no pool in place - just leaking


Comment éviter ces "fuites" ?


----------



## ntx (18 Avril 2008)

jfsgeneva a dit:


> Pour la suite j'ai essayé de faire un thread pour l'affichage, mais la lib SDL m'affiche une fenêtre noire pendant quelques secondes puis disparait et me sort de l'application.


Si tu veux faire des threads dans une application graphique, ça ne se fait pas n'importe comment. Toute la GUI doit être gérée dans le thread principal, les autres threads ne doivent servir qu'aux calculs, il ne faut pas s'y amuser à modifier des éléments graphiques.


----------



## jfsgeneva (19 Avril 2008)

Donc dans mon cas la fenêtre graphique doit être ouverte dans le main, et l'ouverture et lecture de mes ports usb dans des threads ?


----------



## jfsgeneva (19 Avril 2008)

Effectivement ça à l'air de marcher... les affichages ont l'air rapide, mais je n'ai pas encore mesuré la cadence.

Merci pour les tuyaux


----------



## jfsgeneva (19 Avril 2008)

Avec l'affichage graphique j'ai 50 mesures par seconde si je n'utilise que la console pour afficher j'ai 130 mesures par seconde.

Est-ce possible d'avoir plus rapide ?

Si je mets les Bauds au delà de 19200 ça plante.


----------



## tatouille (19 Avril 2008)

jfsgeneva a dit:


> Avec l'affichage graphique j'ai 50 mesures par seconde si je n'utilise que la console pour afficher j'ai 130 mesures par seconde.
> 
> Est-ce possible d'avoir plus rapide ?
> 
> Si je mets les Bauds au delà de 19200 ça plante.


 yep scuse j etais un peu deconnecte du fil, oui ca c est normale si tu veux lire au dela de la capacite de lecture 

la tu es confronté a un probleme d optimisation de code, peut etre que tu dois avoir un deamon de lecture, et tu le popen,   comme je le dis 1 phrase plus haut, c'est vraiment un choix de devel a faire, c est comme cela que l on apprend on a une idee theorique mais souvent l implementation n est pas satisfaisante en terme d'efficacité et il faut souvant revoir sa copie et comment on envie-sage le bignou


----------



## jfsgeneva (19 Avril 2008)

Intéressant tout ça... faut que j'essaye.


----------



## jfsgeneva (20 Avril 2008)

J'ai essayé de faire un démon, mais la console me renvoie ça :



> ZeroLink: unknown symbol '__Z9daemonizev'


----------



## tatouille (20 Avril 2008)

jfsgeneva a dit:


> J'ai essayé de faire un démon, mais la console me renvoie ça :



zerolink debug mode


----------



## jfsgeneva (20 Avril 2008)

Si c'est la case Zerolink qui doit être cochée c'est le cas.


----------



## ntx (20 Avril 2008)

jfsgeneva a dit:


> Si c'est la case Zerolink qui doit être cochée c'est le cas.


Non justement elle doit être décochée


----------



## jfsgeneva (20 Avril 2008)

ntx a dit:


> Non justement elle doit être décochée





Si je fais ça, je n'arrive pas à compiler et j'ai deux erreurs stipulant que SDK n'arrive pas à être linké ... ou un truc comme ça :rateau:.


Arrrfff.... :rose: j'ai simplement deux lettres qui étaient inversées dans la déclaration de ma fonction :


```
void deamonize (void)
```
Au lieu de  :


```
void daemonize (void)
```
J'ai trouvé le code source sur cppfrance.com et j'avais fait un copié-collé.

Maintenant ça passe.

Est-ce qu'un démon se construit comme un thread lors de la déclaration ?

Si le démon est "détaché" comment renvoie t'il les valeurs qu'il va lire au main ?


----------



## jfsgeneva (21 Avril 2008)

Voici ou j'en suis avec mon code qui fonctionne (sans démon, avec le thread):


```
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL_ttf/SDL_ttf.h>

#include <pthread.h>

#include <fcntl.h>
#include <termios.h>   
//#include <memory.h>
#include <unistd.h> //write(), read()

using namespace std;

void Output();          // pour envoyer à l'arduino
void readport();        // pour recevoir de l'arduino
void init_port();       //initialise le portUSB
bool Ouverture_port();  //ouvre le portUSB
bool RecherchePort();

void* monThread(void*);//thread de lecture de portUSB

char USBPort[1000];            // pour le nom du portUSB
char temps[20] = "";        //pour déterminer le temps
char Temperature [5]={0};    //pour la valeur écrite dans la fenêtre
char table[7]={0};            //pour les valeurs en sortie d'arduino

int Q=0;  //fait la boucle de lecture du portUSB
int continuer = 1; //boucle de fenêtre graphique
int fd = 0;

long Temp,Temp1,Temp2,Temp3,Temp4,Temp5  = 0;
long *pointeurTemp = &Temp,*pointeurTemp1 = &Temp1,*pointeurTemp2 = &Temp2,*pointeurTemp3 =&Temp3,*pointeurTemp4 = &Temp4,*pointeurTemp5  = &Temp5;


int main(int argc, char *argv[])
{

/******************************************
    détection du port usb
    *******************************************/
 RecherchePort();
 if(!RecherchePort()) return 0;
    /*******************************************
    fin de détection
    ********************************************/
    
    
    cout << "what USB port is your Arduino Board pluged into?" << endl;
    cout << "Example:\n/dev/tty.usbserial-A70041zl\nor\n/dev/tty.usbserial-A1001N2Y" << endl;    
    
    cin >> USBPort;
    
    Ouverture_port();
    if(!Ouverture_port()) return 0;
                
    
pthread_t thread;
pthread_create (&thread, NULL, monThread, NULL);
        
        
    SDL_Surface *ecran = NULL, *texte = NULL;
    SDL_Rect position;
    SDL_Event event;
    TTF_Font *police = NULL;
    SDL_Color couleurNoire = {0, 0, 0}, couleurBlanche = {255, 255, 255};


    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();

    ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
    SDL_WM_SetCaption("Mesure de luminosité", NULL);


    /* Chargement de la police */
    police = TTF_OpenFont("angelina.ttf", 65);

 
    while (continuer)
        {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                
                continuer = 0;
                
                break;
        }

        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));


            sprintf(temps, "Temp : %s", Temperature); /* On écrit dans la chaîne "temps" le nouveau temps */
            SDL_FreeSurface(texte); /* On supprime la surface précédente de la mémoire avant d'en charger une nouvelle (IMPORTANT) */
            texte = TTF_RenderText_Shaded(police, temps, couleurNoire, couleurBlanche); /* On écrit la chaine temps dans la SDL_Surface */
                       

        position.x = 180;
        position.y = 210;
        SDL_BlitSurface(texte, NULL, ecran, &position); /* Blit du texte contenant le temps */
        SDL_Flip(ecran);

        }
    
    

        TTF_CloseFont(police);
        TTF_Quit();

        SDL_FreeSurface(texte);
        SDL_Quit();


        pthread_join(thread, NULL);
  
        return EXIT_SUCCESS;
}
```


Les fonctions :


```
void init_port(int *fd, unsigned int baud) 
    { 
    struct termios options; 
    tcgetattr(*fd,&options); 
    switch(baud) 
    { 
       case 9600: cfsetispeed(&options,B9600); 
    cfsetospeed(&options,B9600); 
    break; 
       case 19200: cfsetispeed(&options,B19200); 
    cfsetospeed(&options,B19200); 
    break; 
       case 38400: cfsetispeed(&options,B38400); 
    cfsetospeed(&options,B38400); 
    break; 
    default:cfsetispeed(&options,B9600); 
    cfsetospeed(&options,B9600); 
    break; 
    } 
    options.c_cflag |= (CLOCAL | CREAD); 
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB; 
    options.c_cflag &= ~CSIZE; 
    options.c_cflag |= CS8; 
    tcsetattr(*fd,TCSANOW,&options); 
} 
    
    
bool Ouverture_port()
     {
     fd = open(USBPort, O_RDWR | O_NOCTTY | O_NDELAY);
     if(fd == -1){
          perror("open_port: unable to open port");
          return FALSE;
     }
     init_port(&fd,19200);         //set serial port to 9600,8,n,1
     fcntl(fd, F_SETFL,3);
     
     return TRUE;
}



void Output()
    {
    
    write(fd,"&",1);
}
        
    
void readport()
    {
    char table[7]={0};
    {    
    while(table[6]!='$')
    {
    read(fd,&table,sizeof(table));
    
    Temp1 = table[2]-'0';
    Temp2 = table[3]-'0';
    Temp3 = table[4]-'0';
    Temp4 = table[5]-'0';
    
    //    if (Temp1 < 0){ fputs("read() of 10 bytes failed!\n", stderr); 
    }    

    }
    }
}
    

bool RecherchePort(){
    FILE* myPipe=NULL;
    char buffer[1000];
    bool found=FALSE;
    myPipe = popen("ls /dev/tty.usbserial*", "r");
    if(myPipe==NULL){
      //errorstuff
      printf("Aucune carte trouvée !\n");
      return FALSE;
   }
   while(fgets(buffer, 1000, myPipe)!=NULL){
      printf("\n\nvotre usb est : \n\n%s \n", buffer);
      found=TRUE;
   }   
   
   
    pclose(myPipe);
   if(!found) printf("Aucune carte trouvée !\n");
    return found;
} 
    
    
    
void* monThread(void*)
    {
    while(Q!=4000)
    {  

    //Output();
    readport();
     
    //double strtod(const char *nptr, char **endptr); //pour convertir une chaine en entier
            
    sprintf(Temperature, "%ld%ld%ld%ld", *pointeurTemp1, *pointeurTemp2, *pointeurTemp3, *pointeurTemp4);//affiche dans la fenêtre     
    
    printf("%ld%ld%ld%ld\n", *pointeurTemp1, *pointeurTemp2, *pointeurTemp3, *pointeurTemp4); //affiche dans la console
    
    Q++;
           
    }    
   
    close(fd);
        
    return EXIT_SUCCESS;
}
```


J'avoue avoir été également sur Mactronique.com pour chercher un peu d'aide à propos des microcontroleurs en USB .


----------

