µicrocontroleur sur un port USB

jfsgeneva

Membre confirmé
12 Mars 2006
33
1
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...


Bloc de code:
#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); }    

    }
    }

    }
 
USB 2.0

Voici ce qui figure dans information système :

Bus USB à grande vitessse
USB 2.0 Hub
FT232R USB UART
 
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.


Bloc de code:
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 ;
}
}
 
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
 
:siffle:
Je débute en C et je ne comprend pas tout ce que tu expliques :D

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
 
  • J’aime
Réactions: p4bl0
En simplifiant le code j'arrive à avoir 130 mesures affichées par seconde, mais c'est dans la console.

Bloc de code:
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.
 
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" ?
 
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.
 
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 ?
 
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 :up:
 
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.
 
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 :D

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
 
Non justement elle doit être décochée :D



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 :

Bloc de code:
void deamonize (void)
Au lieu de :

Bloc de code:
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 ?