Principes de programmation

Posté le 26 avril 2000

Voici quelques indications sur la façon de de commander par programme un port parallèle.

Attention : ce qui suit ne s’applique qu’à la commande des ports natifs, et non au ports réalisés à travers des convertisseurs USB-parallèle.

Ça ne s’applique aussi qu’au mode SPP, et avec les limitations exposées sur la page précédente: pas de relecture des registres A0 et A2, pas d’utilisation des interruptions.

Langage et système d’exploitation

Le langage utilisé doit permettre de manipuler des octets et d’accéder aux adresses d’entrée/sortie : instructions IN et OUT en assembleur, INP et OUT en BASIC, fonction et instruction PORT en Pascal, etc.

Le système d’exploitation doit autoriser cet accès direct, ou bien il faut se procurer le composant logiciel capable de faire le travail: pilote, DLL pour Windows 9x, etc.

Les exemples suivants sont donnés en QuickBASIC sous DOS, et en VisualBASIC sous Windows 95, mais bien évidemment on peut faire la même chose en assembleur, en Pascal ou en C, sous Linux, BeOS ou autre, en utilisant les outils de programmation adaptés.

Détermination de l’adresse du port parallèle

Rappelons qu’un port parallèle de PC utilise trois adresses consécutives A0, A1, A2 de l’espace d’entrée-sortie.
L’adresse de base A0 peut prendre 3 valeurs différentes, suivant le nombre de ports installés, le type de carte supportant le port, les réglages du BIOS et des cavaliers, etc.

Heureusement il existe une méthode simple pour connaître ces adresses: le BIOS ayant fait le travail pour nous, il suffit d’aller lire ces adresses en mémoire, sur 2 octets, à partir de l’adresse hexa 40:0008h.

Exemple en BASIC, pour un PC n’ayant qu’un seul port parallèle:
DEFINT A-Z             ‘toutes les variables sont entières

DEF SEG=&h40           ‘chargement du pointeur de segment
A0=PEEK(8)+256*PEEK(9) ‘lecture de la valeur entière sur 2 octets
DEF SEG                ‘restauration du pointeur de segment
A1=A0+1: A2=A1+1       ‘calcul des adresses des 2 autres registres

Lorsqu’il y a plusieurs ports parallèles, les adresses sont à la suite à partir de 40:0008h (LPT1, puis LPT2, puis LPT3).
Un exemple de détermination du nombre et de l’adresse des ports, ainsi que du choix d’un port, est donné dans les programme « moniteur de port parallèle », au bas de cette page.

Bits et octets

On ne peut lire et écrire dans les registres que des octets entiers, alors qu’on cherche le plus souvent à manipuler des bits. Il faut donc convertir les valeurs binaires en valeurs décimales ou hexadécimales. Les exemples ci-après sont en décimal.

Commande du registre A0 :

Le plus souvent, on peut de contenter de calculer les huit bits de ce registre en une seule opération. Il suffit de les convertir en une valeur décimale, de façon classique :

bit 7
(D7)
bit 6
(D6)
bit 5
(D5)
bit 4
(D4)
bit 3
(D3)
bit 2
(D2)
bit 1
(D1)
bit 0
(D0)
 décimal 
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
0
1
0
1
0
0
1
2
3
4
 
 
 
 
 
 
 
 
etc
1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
1
254
255

Exemple en BASIC:
DEFINT A-Z ‘idem

‘On souhaite mettre D1 et D4 à 1, et les autres fils à 0.
ValeurA0=34      ’34 décimal = 00100010 binaire (D1 et D4 à 1)
OUT A0, ValeurA0 ‘écriture dans le registre A0

Commande du registre A2 :

Ici, il suffit de commander les 4 bits de poids faible, et d’ignorer les autres, qui peuvent donc être laissés à 0.
Comme précédemment, on peut utiliser la correspondance binaire-décimal classique, limitée aux 16 premières valeurs :

bit 7
(n.u.)
bit 6
(n.u.)
bit 5
(n.u.)
bit 4
(n.u.)
bit 3
(C3-)
bit 2
(C2+)
bit 1
(C1-)
bit 0
(C0-)
 décimal 
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
0
1
0
1
0
0
1
2
3
4
 
 
 
 
 
 
 
 
etc
0
0
0
0
0
0
0
0
1
1
1
1
1
1
0
1
14
15


Par contre, contrairement à A0, on va avoir besoin de commander les fils indépendamment les uns des autres.
Ceci peut-être fait en suivant deux règles simples :

  • mémorisation de l’état du port dans une variable globale
  • modification d’un bit dans la variable et ré-écriture de celle-ci dans le registre lors de la commande.

Exemple en BASIC (en BASIC, les opérateurs logiques s’appliquent directement aux variables numériques):
DEFINT A-Z ‘Toutes les variables sont entières

‘suite à une commande précédente, l’état du port est mémorisé dans la variable ValeurA2


‘On veut mettre le fil C2+ à l’état 1:
Bit=2                      ‘rang du bit en commençant à 0
ValeurA2=ValeurA2 OR 2^Bit ‘mise à 1 du bit C2
OUT A2,ValeurA2            ‘écriture de l’octet dans le registre A2


‘On veut mettre le fil C2+ à l’état 0:
Bit=2                           ‘idem…
ValeurA2=ValeurA2 AND NOT 2^Bit ‘mise à 0 du bit C2
OUT A2,ValeurA2                 ‘écriture de l’octet dans le registre A2


‘On veut mettre le fil C0- à l’état 0:
Bit=0                      ‘idem…
ValeurA2=ValeurA2 OR 2^Bit ‘mise à 1 du bit, car cette ligne est inversée
OUT A2,ValeurA2            ‘écriture de l’octet dans le registre A2

Lecture du registre A1 :

On cherche en général à détecter un changement d’état, d’où la nécessité de conserver l’ancien état du registre dans une variable.
Lorsqu’on a détecté un changement d’état, il faut calculer quel fil(s) a(ont) changé d’état, d’où la nécessité de conserver l’ancien état de chaque bit dans une autre variable (ça n’est pas indispensable, mais c’est plus simple).

bit 7
(I7-)
bit 6
(I6+)
bit 5
(I5+)
bit 4
(I4+)
bit 3
(I3+)
bit 2
(n.u.)
bit 1
(n.u.)
bit 0
(n.u.)
 décimal 
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
0
1
0
1
0
0
1
2
3
4
 
 
 
 
 
 
 
etc
1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
1
254
255

Exemple en BASIC:
DEFINT A-Z ‘idem

‘l’état du registre est dans la variable ValeurA1
‘l’état de chaque bit est dans le tableau Bit()

Boucle: ‘boucle de scrutation permanente
   ValeurLue=INP(A1) ‘il est nécessaire de mémoriser la valeur lue
   IF ValeurLue<> ValeurA1 THEN GOSUB TraitementA1
   ‘ici, autres évènements à traiter cycliquement,
   ‘y compris les conditions de sortie de boucle
GOTO Boucle 

TraitementA1: ‘traitement du changement d’état du registre
   FOR I=3 to 7 ‘seuls ces bits nous intéressent
      IF (ValeurA1 AND 2^I) <> (2^I)*Bit(I)) THEN ‘ce bit a changé d’état
         IF (ValeurA1 AND 2^I)=0 THEN Bit(I)=0 ELSE Bit(I)=1
         GOSUB TraitementBit
      END IF
   NEXT
   ValeurA1=ValeurLue ‘mémorise que le changement d’état a été traité
RETURN

TraitementBit: ‘traitement du changement d’état…
               ‘du bit I qui vient de prendre la valeur Bit(I)
   ‘traitement souhaité…
RETURN

Note : ceci n’est qu’un exemple, et il y a de nombreuses autres façons de réaliser ce genre de fonction. Il est notamment souhaitable d’accélérer le programme en évitant les calculs répétés d’expression du style 2^I.

Un moniteur de port parallèle

Voici un petit moniteur écrit en QuickBASIC, qui permet de d’écrire bit à bit sur les ports A0 et A2, et de lire et d’afficher les données présentes sur A1.

Un exemple en VisualBASIC

VisualBASIC étant dépourvu d’instructions d’entrée/sortie physique, il faut faire appel à une DLL fournissant ces fonctions.

On trouve sur Internet un certain nombre de telles DLL, en tant que shareware ou freeware. Parmi ces dernières, nous avons choisi InpOut32, sur l’excellent site de Jan Axelson, que nous vous conseillons absolument de visiter.

Une fois en possession de cette DLL, l’écriture d’un programme simple ne pose guère de problème. Noter toutefois l’usage qui est fait de l’instruction DoEvents pour réaliser une scrutation permanente.

Attention : ce moniteur ne fonctionne pas exactement comme le précédent :

  • le contenu des registres de sortie A0 et A2 est préparé bit à bit en mémoire, avant d’être affiché sur le port sur commande de l’utilisateur (alors que dans MONPAR, le registre de sortie est mis à jour au fur et à mesure des modifications)
  • le bit de bidirectionnalité (D5 de A2) est traité.

    Commentaires : On peut se demander s’il est bien judicieux d’utiliser VisualBASIC pour le contrôle d’un réseau de train électrique ou autre application du même style.
    En fait, c’est plus précisément l’utilisation du système d’exploitation Windows pour réaliser une gestion de processus multitâche temps réel, qui est tout à fait discutable, car Windows n’est pas fait pour cela, et son utilisation dans ce contexte pose plusieurs problèmes:

    • Perte de performance. Il est vrai que les ordinateurs actuels sont surpuissants. Cependant, si l’on veut utiliser pour son train un vieux PC dédié à cet usage, on aura intérêt à se passer de Windows, soit que celui-ci ralentisse trop l’ordinateur, soit qu’il soit tout bonnement impossible de l’installer sur une machine antédiluvienne.
    • Difficulté de réaliser certaines fonctions sans être un programmeur de haut niveau: temps réel pointu, gestion des interruptions, programmation synchrone, etc.

    Windows présente par contre d’autres avantages, comme la gestion graphique de l’écran en haute résolution, ou la facilité d’utilisation de la souris.

    Programmation sous W7, 9, 64 bits,etc

    En attendant la réfection de cette page, vous pouvez nous contacter par mail.

    Recherche dans les Tutoriels

    0 commentaires

    Soumettre un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Dans la même catégorie