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

Turbo Pascal Discussion :

[TP] Gestion du temps sous Pascal - aquisition en temps réel


Sujet :

Turbo Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut [TP] Gestion du temps sous Pascal - aquisition en temps réel
    Bonjour
    Je cherche à créer un programme sous dos d'aquisition de signal via port parallèle (pour une expérience physique). Je voudrais chronométrer chaque interval de temps entre chaque changement d'état du port (des durées de l'ordre de 100ms qui doivent être calculée pour être stockée dans des listes). Je ne veux pas faire appel à chaque fois à un nouveau "chrono", mais plutot utiliser une variable de temps "globale", c'est à dire un choromètre qui "s'allume" au lancement et qui reste le même pour touts les cycles de mesures (pour ne pas cumuler des petits décalages entre chaque changement du port).

    Voici ce que j'ai déja fait en programme de test et qui ne convient pas (utilisation de l'unité sdelay plus performante que le delay de ctr)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    program etatport;
    uses  Sdelay;
    var n:real;
    begin
       n:=0  ;
       while (PORT[$379] = 63) do  MilliDelay(500)  ; 
       while (PORT[$379] = 127) do  MilliDelay(500) ; 
       while (PORT[$379] = 63) do begin  MilliDelay(500); n:=n+5 end  ; 
       while (PORT[$379] = 127) do begin  MilliDelay(500); n:=n+5 end ;
     
       writeln(n);   {renvoi une période en milliseconde}
    end.
    J'ai fait ce programme pour tester la précision de mesure:
    j'ai branché un bouton poussoir avec une resistance entre le port 10 et la masse, le programme est scendé mesuré la durée durant laquelle:
    1) on appuie sur l'interupteur (127->63)
    2) on relache (63->127)
    3) on réapui (127->63)

    Resulat: la durée mesurée par le programme (sous dos bien sur!) est différente à quelques dizaines de pourcents de la durée réelle

    Sous windows avec Delphi, j'avais la viable Gettickcount qui simplifie le problème (le resultat est moyen car windows perturbe le fonctionnement en temp réel), sous turbo pascal je n'ai rien trouvé de tel...

    Que faire?


    Merci d'avance pour vos conseils

    Etienne

  2. #2
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    Avril 2002
    Messages
    2 466
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Avril 2002
    Messages : 2 466
    Par défaut
    Tu es sous Dos, tu as donc accès aux interruptions réelles (merci le mode réel !!). Tu peux récupérer le nombre de Ticks depuis minuit si je me rappelle bien, en allant farfouiller dans une zone de la mémoire. C'est une valeur DWord stockée dans la mémoire du BIOS à l'adresse 0040h:006Ch

    Cette valeur est mise à jour par l'interruption 08h 18,2 fois par secondes soit à peu près toutes les 55 millisecondes. Tu peux changer changer cette valeur en reprogrammant le PIT, regarde du côté du port 40

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut
    J'avais vu en effet cette piste, mais c'est le passage en code pascal qui ma bloqué.
    Une explication détaillé est ici dans le paragraphe "the dos clock"
    http://209.85.135.104/search?q=cache...k/pas-time.htm

    Mais que faut t'il taper dans le code source pour acceder à la valeur de l'adresse 0040h:006Ch?? PORT[0040h:006Ch]???

    Sinon il faudrais que je reparametre le nombre de ticks par seconde car 18.2 ce n'est pas assez, il me faudrait plutot environ du 1000 par seconde pour s'approcher de la miliseconde.

    sur un autre sujet j'ai trouvé ca:
    j.p.mignot
    28/06/2005, 19h22
    si la clock à 18.20648.. Hz, if est aussi possible de la changer.
    En fait il s'agit d'1 clock à 1193181.667 HZ dont on définit le diviseur entre 1 et $FFFF. avec FFFF on trouve les 18.206... Hz. en le changeant et en redefinissant l'interrupt 1C par exemple Il est tres facile de creer des actions jusqu'à quelques dizaines de kHz en tache de fond comme acquisition sur un port, ...
    Il faut noter qu'1 tel changement déregle l'heure du PC et à la restitution de FFFF il faut calculer l'erreur sur time pour corriger.
    Il faudrai donc que je remplace le facteur par défaut FFFF=65535 (ou plutot 1000=65536? les 2 sources divergent sur ce point) par 04A9=1193 pour avoir une fréquence de clock à environ 1000Hz ce qui me fait un pit toute les miliseconde (+une petite erreur qu'il suffira de corriger)


    Le problème qu'il me reste est donc juste un problème de syntaxe:
    1)Comment redefinir l'interrupt 1C (pour y mettre la valeur 04A9)
    2) Comment acceder à la valeur en 0040h:006Ch

    Merci d'avance!

    Etienne

  4. #4
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    Avril 2002
    Messages
    2 466
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Avril 2002
    Messages : 2 466
    Par défaut
    Pour la valeur en mémoire, tu peux y accéder avec le tableau Mem (Mem[$0040:$006C], si je me souviens bien).

    Comme tout ça est un peu loin dans ma mémoire, tu peux jeter un coup d'oeil à l'unité d'HDD34, disponible ici: http://pascail.developpez.com/utilitaires/?unite=timer

    Elle permet de reprogrammer le PIT assez précisément. Tu pourras certainement t'en inspirer.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 16
    Par défaut
    Merci à wormful_sickfoot pour ses réponses!

    Ca semble marcher: j'ai fait un programme tout simple que affiche la valeur Mem[$0040:$006C] et en l'executant environ toute les seconde, on voit que le résultat qui apparait augmente bien de environ 18.2 toute les secondes.
    Mais la valeure donnée semble être toujours dans l'intervalle 0 ou 1? jusque 255 ou 256. Après ca repart au début. (exemple si j'ai eut 249 et une seconde après 15)


    Donc ca risque de poser problème:
    Si j'arrive à régler le pit à 1000hz, je ne pourrai mesurer que des durée de 256 millisecondes au maximum. ou alors la durée mesuré sera modulo 256...

    Il faudrai donc ajouter dans les "while" de detection du port parrallèle une boucle if qui incrémente le modulo 256 (if writeln(Mem[$0040:$006C]< (Mem[$0040:$006C] mesuré juste avant) then x:=x+1)
    Avec le risque de perdre une bouble si le programme n'est pas assez rapide.

    Voici un test avec cette methode
    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
    program tt;
    var p,n,n1: integer   ;
    begin
      p:=0 ;
      writeln('appuyer sur touche pour démarrer chrono de 28sec (256*2)/18.2');
      readln  ;
      n:=Mem[$0040:$006C];
      while p<>2 do
        begin  while Mem[$0040:$006C]>=n do ;
               while Mem[$0040:$006C]<=n do ;
               p:=p+1;
        end;;
      writeln('fin chrono')
     
    end.
    résultat : l'ordi chronomètre parfaitement bien, même un vieux portable 386!

    Ne reste plus qu'a changer la fréquence de pit

    Le programme de hdd34 semble assez compliqué a comprendre, surtout le code assembleur!
    Je viens de trouver ceci: http://www.qzx.com/pc-gpe/pit.txt
    on y retrouve des passages de hdd34 mais il n'y a que l'essentiel.

    J'ai simplifié quelques truc (rentrer directement la fréquence à 1000hz soit un diviseur de 1193) et j'ai mis ca dans une unité pour la suite...
    Voici ce que ca donne:

    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
    unit pitsetup;
    interface
     
       procedure SetTimer(TimerHandler : pointer);
       procedure CleanUpTimer;
     
    implementation
     Uses Crt, Dos;
     var BIOSTimerHandler : procedure;
         counter : longint;
        procedure SetTimer(TimerHandler : pointer);
        begin
               counter := 1193;
              { Store the current BIOS handler and set up our own }
              GetIntVec(TIMERINTR, @BIOSTimerHandler);
              SetIntVec(TIMERINTR, TimerHandler);
              { Set the PIT channel 0 frequency }
               Port[$43] := $34;
               Port[$40] := counter mod 256;
               Port[$40] := counter div 256;
               end;
     
         procedure CleanUpTimer;
         begin
               { Restore the normal clock frequency }
               Port[$43] := $34;
               Port[$40] := 0;
               Port[$40] := 0;
     
               { Restore the normal ticker handler }
               SetIntVec(TIMERINTR, @BIOSTimerHandler);
         end;
    begin
     
    end.
    Je n'ai pas compris l'interet et le fonctionnement du pointer TimerHandler et ce que représente TIMERINTR.
    Ne voulant pas faire d'erreur je l'ai laissé, mais je ne sais pas avec quoi je vais appeler Settimer...

    Est-ce que je risque d'endomager l'ordinateur??? Est-ce que les modifications apportées subsistent même après un redémarrage ?
    Si oui j'ai interet à faire gaffe, donc j'attend vos avis...

  6. #6
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    Avril 2002
    Messages
    2 466
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Avril 2002
    Messages : 2 466
    Par défaut
    Ca semble marcher: j'ai fait un programme tout simple que affiche la valeur Mem[$0040:$006C] et en l'executant environ toute les seconde, on voit que le résultat qui apparait augmente bien de environ 18.2 toute les secondes.
    Mais la valeure donnée semble être toujours dans l'intervalle 0 ou 1? jusque 255 ou 256. Après ca repart au début. (exemple si j'ai eut 249 et une seconde après 15)


    Donc ca risque de poser problème:
    Si j'arrive à régler le pit à 1000hz, je ne pourrai mesurer que des durée de 256 millisecondes au maximum. ou alors la durée mesuré sera modulo 256...

    Il faudrai donc ajouter dans les "while" de detection du port parrallèle une boucle if qui incrémente le modulo 256 (if writeln(Mem[$0040:$006C]< (Mem[$0040:$006C] mesuré juste avant) then x:=x+1)
    Avec le risque de perdre une bouble si le programme n'est pas assez rapide.
    Attention, c'est un DWord à cette adresse, donc un entier stocké sur 4 octets ! Normal que tu obtiennes un modulo 256 si tu lis avec MEM Tu peux utiliser MEMW (qui lit des Word) et faire un petit calcul pour transformer en DWord. Seul problème, TP ne dispose pas de type entier non signé sur 64 bits, il faudra passer par un longint en vérifiant qu'il n'y ai pas de problème de dépassement. Ou sinon passer par les registres étendus 32 bits...

    Le programme en bas sert pour détourner l'interruption, probablement la 8 qui est appelée par le PIT à chaque tick (il me semble !). On récupère d'abord le vecteur d'interruption d'origine (GetIntVec), qu'on remplace par le notre (SetIntVec). Ainsi c'est notre routine qui est appelée et pas celle du BIOS. TIMERINTR doit être une constante dont la valeur est 8. A la fin on nettoie tout en remettant la bonne interruption, celle du BIOS. Tu peux faire ces changements, c'est pas rédibitoire puisque la table des vecteurs d'interruptions est remise dans l'état d'origine à chaque reboot (par le BIOS).

    Have fun

Discussions similaires

  1. La gestion du temps sous Oracle
    Par zaidouni dans le forum Oracle
    Réponses: 1
    Dernier message: 18/11/2011, 14h06
  2. Gestion de temps sous access
    Par K4mu1 dans le forum Modélisation
    Réponses: 17
    Dernier message: 25/06/2008, 16h59
  3. [TP] Gestion carte graphique sous ms-dos en Turbo Pascal
    Par mulfycrowh dans le forum Turbo Pascal
    Réponses: 4
    Dernier message: 04/08/2007, 13h13
  4. [LG]Menu déroulant sous Pascal
    Par Apprenti Sorcier dans le forum Langage
    Réponses: 8
    Dernier message: 26/03/2004, 13h29
  5. Routines de gestion des ports sous Windows XP
    Par wiccanhelios dans le forum Windows
    Réponses: 2
    Dernier message: 14/11/2003, 08h02

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