IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants VCL Delphi Discussion :

Probleme gestion port parallele


Sujet :

Composants VCL Delphi

  1. #1
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut Probleme gestion port parallele
    Bonjour
    J'ai un petit soucis avec l'utilisation du port parallele, si les commandes sont bien envoyees les delais sont par contre tres long.
    Je precise qu'a l'origine je ne suis pas un programmeur Delphi
    Le poste utilise est sous XP Pack2 l'uc un Atlon 1800+, les seuls logiciels installes sont BCB6 et Delphi7, a l'origine le BIOS etait configure port parallele en SPP, je l'ai mis en EPP ce qui correspond a un port capable de fonctionner plus rapidement (pas d'amelioration sensible)
    Voici les grandes lignes de la gestion du port parallele

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    uses
    DLPortOCXControl1_TLB // dll installee
    // port selectionne
    AB : integer; {adresse du port parallèle sélectionné}
    AB := $378;
    // initialisation
    {ouverture du driver port parallele}
    DLPortOCX1.OpenDriver;
    {initialisation du port parallele a zero}
    DLPortOCX1.WritePort(AB, 0);
    // teste arret urgence
    {Vérifie si les butées sur les Chariots X, Y, Z sont activées}
    repeat
         n1 := DLPortOCX1.ReadPort(AB + 1);
         n2 := DLPortOCX1.ReadPort(AB + 1);
    until (n1 = n2);
    procedure TForm1.deplacement
              (choix_moteur, choix_sens : integer; tempo : word; choix_pas : integer);
    var
    { Thread }
    inc_x, inc_y, inc_z : integer;
    begin
    moteur := choix_moteur;
    sens := choix_sens;
    attente := trunc(tempo);
    pas := choix_pas;
    inc_x := 0; inc_y := 0; inc_z := 0; inc_pas := 0;
     {Tri pour déterminer le sens de rotation de chaque moteur}
    case choix_moteur of mx,mx+my,mx+mz,mx+my+mz :
         begin
         case choix_sens of sx,sx+sy,sx+sz,sx+sy+sz : inc_x := 1; end;
         case choix_sens of 0,sy,sz,sy+sz : inc_x := -1; end;
         end;
    end;
    case choix_moteur of my,my+mx,my+mz,my+mx+mz :
         begin
         case choix_sens of sy,sy+sx,sy+sz,sy+sx+sz : inc_y := 1; end;
         case choix_sens of 0,sx,sz,sx+sz : inc_y := -1; end;
         end;
    end;
    case choix_moteur of mz,mz+mx,mz+my,mz+mx+my :
         begin
         case choix_sens of 0,sx,sy,sx+sy : inc_z := 1; end;
         case choix_sens of sz,sz+sx,sz+sy,sz+sx+sy : inc_z := -1; end;
         end;
    end;   {Sélections des sens de rotations}
    repeat {Mise en rotation des moteurs}
          DLPortOCX1.WritePort(AB, choix_sens);
          DLPortOCX1.WritePort(AB, choix_sens + choix_moteur);
          Sleep(1);
          DLPortOCX1.WritePort(AB, 0);
          total_inc_x := total_inc_x + inc_x;
          total_inc_y := total_inc_y + inc_y;
          total_inc_z := total_inc_z + inc_z;
          inc(inc_pas);
          Application.ProcessMessages;
    until (inc_pas = choix_pas) or (aru = true);
    end;
    // fermeture
    {initialisation a zero du port parallele}
    DLPortOCX1.WritePort(AB, 0);
    {fermeture du driver port parallele}
    le programme calcul les donnees a envoyer a la fonction deplacement
    Pour environ 97000 donnees envoyees le temps mis est de environ 12minutes ce qui correspond a un deplacement de 1cm, c'est beaucoup trop long
    Quelqu'un a t'il deja eu ce genre de probleme, le code est'il mal concu y a t'il un oubli de ma part, doit on mettre la fonction deplacement dans un Thread
    --
    Plutot que d'essayer de réinventer la roue, apprenons à nous en servir

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Sleep(1); dure souvent 1.995 ms !
    Donc au final 12 minutes = 720 000 ms, ça donnerait un choix_pas autour de 360000 ? tu ne fais une si grosse boucle ?
    Est-ce ton 97000 ?

    97000 est-ce le nombre de boucle ?
    ça ferait 5 ms par boucle (hors Sleep)

    97000 est-ce le nombre d'octet ?
    le LPT c'est bien plus que le débit du COM ?
    97 000 ça prendrait au pire quelques secondes sur un COM
    Alors sur un LPT, ça doit être instantané,
    Tu envoie bcp de petit paquet cela doit être plus lent que d'envoyer une grosse trame d'un coup
    mais 12 secondes ça serait déjà énorme alors 12 minutes


    Application.ProcessMessages; peut-être aussi couteux, surtout si tu dessin est fait à l'écran

    fait gaffe aussi au vilain effet de bord sur les sorties boucle

    until (inc_pas = choix_pas) or (aru = true); passe le en until (inc_pas >= choix_pas) or aru;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Merci de ta reponse ShaiLeTroll
    Le programme n'est pas de moi mais j'ai le source il a ete modifie pour fonctionner avec DLPortOCXControl, a l'origine il etait prevu pour fonctionner avec W95, W98 et Millenium je crois.
    Si j'enleve Sleep(1); ca ne fonctionne plus, je n'ai pas trouve pourquoi, pareil pour Application.ProcessMessages;
    until (inc_pas = choix_pas) or (aru = true); passe le en until (inc_pas >= choix_pas) or aru;
    je vais modifier la boucle, j'en ai aussi partout dans le programme, quels sont les effet indesirable de la boucle originale.

    le programme permet de commander des moteurs pas a pas pour commander une fraiseuse 3 axes.

    Pour ce qui est des pas ce n'est qu'une partie de ce qui doit etre envoye, je dois ajouter un moteur.

    Je ne vois pas comment faire pour savoir si c'est la partie deplacement des moteurs ou le code d'envoi des commandes qui ralenti le code
    --
    Plutot que d'essayer de réinventer la roue, apprenons à nous en servir

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Citation Envoyé par blondelle Voir le message
    Si j'enleve Sleep(1); ca ne fonctionne plus, je n'ai pas trouve pourquoi, pareil pour Application.ProcessMessages;
    tente un Sleep(0) qui dure quelques centaines de micro sec (µs)

    Probablement que le composant DLPortOCXControl utilise un thread, le sleep lui permet d'agir
    Pour ProcessMessages, peut-il qu'il utilise des messages Windows, idem cela peut lui permettre de réagir !
    C'est le même principe avec le TServerSocket en mode nonBlocking, si l'on utilise dans un thread sans avoir de TForm, il faut écouter CM_SOCKETMESSAGE, CM_DEFERFREE et CM_LOOKUPCOMPLETE

    Citation Envoyé par blondelle Voir le message
    je vais modifier la boucle, j'en ai aussi partout dans le programme, quels sont les effet indesirable de la boucle originale.
    Avec un integer est 2^31, peu de risque de débordement mais sur un word en 2^15, cela peut survenir, comme on a pas la déclaration de inc_pas, je préfère me méfier !
    Cela peut se produire aussi sur une boucle en pas irrégulier, on l'on ne tombe pas pil sur la limite
    C'est encore plus flagrant sur un flottant, une erreur d'arrondi pouvant provoquer une boucle infinie parce que zéro =~ 0.000...001 ou 0.999...998
    C'est juste une habitude pour éviter le cas où un jour ça foire !

    Il te faut mesurer avec QueryPerformanceCounter le temps de chaque étape
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Merci pour ta reponse ShaiLeTroll
    J'ai essaye Sleep(0); mais c'est trop rapide les infos n'on pas le temps d'arriver aux moteurs.
    Si je supprime ProcessMessages je n'ai plus la main sur le programme je ne peu meme plus l'arreter.
    il faut écouter CM_SOCKETMESSAGE, CM_DEFERFREE et CM_LOOKUPCOMPLETE
    Je vais faire des recherches sur ses commandes.
    Pour les teste de boucles je vais les verifier et corriger par securite.
    Je ne connaissais pas " QueryPerformanceCounter ".
    A la suite de tes reponses j'ai teste une solution bancale qui permet plus de reglage que l'utilisation de Sleep(x);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    DLPortOCX1.WritePort(AB, choix_sens + choix_moteur);
    repeat
    inc(instruction);
    until(instruction >= 1000000); // ici on va ajouter ou retirer valeur TrackBar Vitesse
    instruction := 0;
    Il y a peut etre une autre maniere plus propre de faire, mais la je vois pas.
    Il y a aussi une chose que je ne sais pas ou chercher pour savoir les delais d'une commande comme Sleep ou d'un suite d'instructions de boucle.
    En tout cas ton aide ma permis d'avoir d'avoir un fonctionnement a peu pres correcte
    --
    Plutot que d'essayer de réinventer la roue, apprenons à nous en servir

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Citation Envoyé par blondelle Voir le message
    Merci pour ta reponse ShaiLeTroll
    J'ai essaye Sleep(0); mais c'est trop rapide les infos n'on pas le temps d'arriver aux moteurs.
    le Sleep(1) va te côuter presque 2ms à chaque itération, c'est à prendre en compte !

    Citation Envoyé par blondelle Voir le message
    Si je supprime ProcessMessages je n'ai plus la main sur le programme je ne peu meme plus l'arreter.
    Ne le retire pas complètement mais appel le moins souvent genre toutes les 10 ou 100 pas !

    il faut écouter CM_SOCKETMESSAGE, CM_DEFERFREE et CM_LOOKUPCOMPLETE
    Je vais faire des recherches sur ses commandes.
    Tu as mal lu, je faisais une comparaison avec TServerSocket qui a besoin d'un ProcessMessages pour réagir !

    ProcessMessages est souvent utilisé comme une méthode magique qui résoud les problèmes que l'on ne comprend pas !
    tu sembles l'utiliser que pour l'interactivité avec l'IHM

    C'est peut-être l'occasion d'utiliser un TThread pour séparer l'IHM de ton envoie de données au Moteur


    Citation Envoyé par blondelle Voir le message
    Je ne connaissais pas " QueryPerformanceCounter "..
    C'est l'occasion, c'est une sorte de GetTickCount mais qui n'a pas le bug des 49,7 jours mais plutôt au bout de 100 ans, QueryPerformanceCounter est entre 100 et 10 000 de fois plus précis que GetTickCount selon le processeur, cela permet de mesurer en µs voire même en ns !

    ...inc(instruction);... est consommateur CPU, sur un mono c'est 100%, un dual 50%, quad 25% ...

    Citation Envoyé par blondelle Voir le message
    Il y a peut etre une autre maniere plus propre de faire, mais la je vois pas.
    Fait une boucle genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    repeat
      Inc(instruction);
      Sleep(0);
    until(instruction >= 1000); ... TrackBar ...
    Cela consommera moins de CPU

    Regarde les property du DLPort, a-t-il des éléments pour déterminer que l'écriture est bloquante ou asynchrone, des events pour savoir ce qui a été écrit
    Selon ce que tu décrits, c'est asynchrone WritePort rend la main sans attendre que les données soit reçues
    Je n'ai fait que du Port COM avec un débit moindre ou alors via des library comme Modbus, je n'ai pas trop de notion sur LPT et son comportement

    J'utilise beaucoup de thread, j'essaye d'utiliser plutôt de privilégier de l'Attente passive avec TCriticalSection, des TEvent ou WaitMultipleObject

    Mais j'en ai aussi qui utilise Sleep et de vilaine attente active (souvent plus simple à coder), un peu dans les mêmes problématiques où je dois dialoguer avec du périphérique

    Voici un commentaire dans une unité avec 3 classes de TThread

    // Rappel sur le temps d'un Sleep (valeurs mesurées pouvant varier selon l'OS et le PC)
    // Sur un Pentium D 3Ghz - XP SP3 (processeur datant de 2005-2006)
    // - Sleep(0) dure en moyenne 1 µs peut varier de 1,028 µs et 8,837 µs
    // - Sleep(1) dure en moyenne 1.955 ms peut varier de 1,054 ms et 3,023 ms
    // - Sleep(2) dure en moyenne 2,929 ms peut varier de 2,572 ms et 4,155 ms
    // - Sleep(5) dure en moyenne 5,860 ms peut varier de 5,498 ms et 7,152 ms
    // - Sleep(10) dure en moyenne 10,743 ms peut varier de 10,125 ms et 12,901 ms
    // - Sleep(100) dure en moyenne 100,593 ms peut varier de 99,669 ms et 102,485 ms
    Ce sont des observations, mais ça donne une idée !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Merci pour tes reponse ShaiLeTroll

    Le ProcessMessages est appele a la sortie de la boucle de temporisation

    DLPort existe en deux versions soit en version printer soit port // simple, la version simple n'attend pas de reponse (de toute facon la carte receptrice ne renvoie rien) les donnees envoyees sont gerees a partir de l'ordinateur

    J'ai teste QueryPerformance, apparement on peut meme recuperer la frequence du processeur
    A l'aide de ton exemple j'ai essaye ceci, le code semble fonctionner, je ne pense pas avoir fait d'erreur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    unit Unit1;
    interface
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
    var
      Form1: TForm1;
      BeginTime,EndTime,TickPerSec : Int64;
      tempo, instruction : integer;
      Result : double ;
    implementation
    {$R *.dfm}
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if Not QueryPerformanceFrequency(TickPerSec) then
    begin
      exit;
    end;
    QueryPerformanceCounter(BeginTime);
    { placer le Delay a tester }
    // Sleep(100); { millisecondes }
    // ou
    repeat
      inc(instruction);
    until(instruction >= 100000);
      instruction := 0;
      QueryPerformanceCounter(EndTime);
      Result := (EndTime - BeginTime) / TickPerSec * 1000;
      Edit1.Text := FloatToStr(Result); // milliseconds
    end;
    end.
    --
    Plutot que d'essayer de réinventer la roue, apprenons à nous en servir

  8. #8
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Le code est maintenant fonctionnel je marque ce post resolu
    --
    Plutot que d'essayer de réinventer la roue, apprenons à nous en servir

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Probleme port parallele
    Par iMaTh dans le forum C++
    Réponses: 10
    Dernier message: 10/02/2008, 19h04
  2. Réponses: 3
    Dernier message: 10/10/2005, 18h30
  3. Utiliser le port parallele pour simuler un digicode
    Par nonoRedDevils dans le forum Assembleur
    Réponses: 8
    Dernier message: 30/12/2003, 13h23
  4. [debutant]servlet probleme de port
    Par noOneIsInnocent dans le forum Servlets/JSP
    Réponses: 14
    Dernier message: 04/09/2003, 16h33
  5. Port parallele
    Par Phoneus dans le forum C
    Réponses: 2
    Dernier message: 05/05/2002, 23h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo