|
A.M.F.N. |
|
Association
des Modélistes Ferroviaires de Nice
Le
port parallèle: principes de programmation
(page
en cours de réfection)
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.
fichiers proposés:
- MONPAR.BAS:
source du programme (nécessite QuickBASIC),
- MONPAR.EXE:
programme compilé (exécutable sous DOS). |
|
téléchargement |
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.
fichiers proposés:
- MONPARVB.FRM,
MONPARVB.VBP ET MONPARVB.VBW:
sources
du programme (nécessite VisualBASIC 5.0),
- MONPARVB.EXE:
programme compilé (exécutable sous Windows). |
|
téléchargement
|
Conformément
aux usages, nous ne vous proposons pas la DLL en téléchargement.
Vous pouvez vous la procurer
sur Internet, par
exemple ici.
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 Windows 7, 8, 64 bits, etc:
En attendant la réfection
de cette page, vous pouvez nous contacter par mail.
Page
suivante: utilisation des lignes de sortie.
Retour
à la page d'accueil |