ENSSAT |
Dan Truong |
TP Interfacage : Programmation directe du PC en C
Ports d'E/S
p@ 40H Timer: 3 voies
Fréquence de base 1.19318MHz
Voie 2 fréquence du HP
p@ 61H Haut Parleur:
les 2 bits de poid faible à 1 allument le HP
p@ 70H Horloge temps réele:
70H: Sélection du registre accédé (64 possible)
71H: Accès au registre de l'horloge sélectionné
Registres disponibles: Heures, Min, Sec, An, Mois, Jour, Date, Etat A, Etat B, Mémoire étendue, Mémoire de base...
ex: outportb(0x70,0x16); c = inportb(0x71) ; lit le poids fort de la taille de la mémoire basse dans x.
p@ XXH Registres du port parallèle
Par exemple 378H~37FH pour LPT1
@+0: donnée
@+1: état (sont notamment cablés Ack, Str, Ini, Busy, Dsl, OfOn)
@+2: contrôle
p@ XXH Registres du port série
Par exemple 3F8H~3FFH pour COM1 ou 2F8H~2FF pour COM2
Registres obtenu par l'interruption BIOS bIRQ 14
@+0 ETAT @+1 CONTROLE
caractère reçu 7/8 bits
caractère éffacé 7/8 bits
erreur parité 1 ou 2 bits stop
erreur protocole parité sans/pair/impair
canal interrompu parité sans/pair/impair
registre données vide bauds 110, 150, 600
registre à décalage vide 1200, 2400,
time out 4800, 9600
p@ 20H PIC #1
Contrôleur d'interruption
@+1: registre de masquage des interruptions (mettre le bit correspondant à l'IRQ à 0 pour l'activer)
p@ A0H PIC #2
Contrôleur d'interruption
Infos en mémoire basse (BIOS)
ram@ 40:13, 40:14 Mémoire de base disponible
ram@ 40:08 ~ 40:0E Pointeurs d'adresse des ports parallèles
L'adresse est codée sur 16 bits
ram@ 40:10 Configuration des ports parallèles
Peu fiable sous Windows.
ram@ 40:00 ~ 40:06 Pointeurs d'adresse des ports séries
Les interruptions
La table d'interruption
Située en mémoire entre 000H et 3FFH, elle contient des vecteurs (pointeurs) de 4 octets (32 bits) sur les routines de gestion des interruptions (il est prévu jusqu'a 256 interruptions, donc la table fait 1KO).
Le numéro d'interruption (INT) permet de trouver dans la table le pointeur (vecteur) vers la routine de gestion de l'interruption (handler). Les routines d'interruptions logicielles (ex: les INT DOS) sont exécutées lorsqu'un programme (ou l'OS) y fait appel explicitement (par exemple vous avec int86() ). Les routines d'interruptions matérielles sont exécutées sur un évennement matériel externe (les IRQ) de façon assynchrone. En général, on ne les appelle donc pas ; par contre on peut modifier ces handlers (ex: INT 1CH dans le TP) pour exécuter des tâches spécifiques quand l'interruption arrive (ex: ajout d'un driver souris sur COM1).
On note INT les interruptions logicielles, et IRQ les interruptions matérielles déclenchées par l'un des 2 PIC ou le CPU.
Il y a 4 types d'interruption (cf. une table des interruptions complète):
INT Vecteur
0H~7H 00H~01FH IRQ CPU, etc (souvent NMI)
8H~FH 020H~03FH IRQ matérielles 0 à 7 du 1er PIC
70H~77H 1C0H~1DFH IRQ matérielles 8 à 15 du 2nd PIC
10H~46H 040H~11BH INT du BIOS
21H 084H Appel des INT DOS
47H~49H 11CH~127H INT définissable par l'utilisateur
Pour utiliser une routine d'interruption
Il suffit d'initialiser les registres pour passer les paramêtres à la routine d'interruption, et d'exécuter l'INT (par exemple, en appelant la routine adécquate en Turbo C, ou en exécutant une instruction d'INT en assembleur).
Les interruptions matérielles n'utilisent pas de paramètres, car exécutées automatiquement sur des signaux matériels.
Pour changer une routine d'interruption
Désactiver les INT.
Sauvegarder l'ancien vecteur d'interruption.
Connecter la routine d'INT en modifiant le vecteur correspondant dans la table d'interruption.
Réactiver les INT.
Note: on peut désactiver toutes les INT sur le CPU (sauf les NMI) ou une seule IRQ matérielle par le PIC.
Ecriture d'une routine d'interruption matérielle
Par défaut, les IRQ sont désactivées dans les PIC. Il faut donc les activer (mettre à 0 le bit correspondant dans le registre de masquage des IRQ du PIC).
Si une IRQ est déja activée, il y a une routine d'interruption installée. Il faut donc l'appeler dans la routine d'interruption, et vérifier que l'IRQ s'est déclenchée pour nous. Sinon, il ne faut pas appeler l'ancienne routine d'interruption.
ex: Routine typique d'interruption matérielle
void Routine_IT( void ) {
enable(); /* Réactive les interruptions INT */
(code de gestion)...
outportb(0x20, 0x20);
/* Réactive les IRQ du PIC 0 */outportb(0xA0, 0x20);
/* Réactive les IRQ du PIC 1 (gestion des IRQ > 8 */}
interruptions Matérielles
Leur numérotation correspond à l'ordre dans les PIC.
IRQ 0 Timer Interruption 18,2Hz
Corresponds à l'INT matérielle 8H, vecteur 20H dans la table.
IRQ matérielle déclenchée par le canal 1 du timer.
Il est préférable de ne pas modifier cette INT, mais plutôt INT 1CH.
IRQ 3 Interruption du port série COM2
Corresponds à l'INT matérielle BH, vecteur 2CH.
Elle est active par exemple si une souris est connectée et que son driver est installé.
IRQ 4 Interruption du port série COM1
IRQ 7 Interruption port LPT1
Corresponds à l'INT matérielle FH, vecteur 3CH.
Active si le contrôle du port LPT1 active les envois d'irq.
L'IRQ est lancée à la réception d'un signal Ack.
interruptions BIOS
INT 11H Détermination de la configuration
AX contient la congifuration.
bits 2~3: taille mémoire basse (160, 320, 480 ou 640 KO)
bits 9~11: nb. de liaisons RS232
bits 14~15: nb. de ports parallèles
Peu fiable.
bIRQ 12H Mémoire de base disponible
AX: mémoire basse disponible en KO
bIRQ 14 Interruption des ports série
AH=0: Initialise le port spécifié en DX, avec les paramètres dans AL
AH=1: emmet le caractère dans AL sur le port spécifié dans DX
AH=2: Lit un caractère dans AL (si AH passe à 0 au retour) sur le port spécifié dans DX
bIRQ 17H interruption pour l'imprimante
AH = 0: envois le caractère dans AL
AH=1: initialisation
AH=2: état de l'imprimante
(voir ram@ 40:10)
bIRQ 1CH Exécutée 18,2 fois par secondes.
voir hIRQ 8H.
Est appelée par l'IRQ 8 matérielle
le vecteur de cet IRQ est dans la table à l'adresse 70H (i.e. 1C*4)
interruptions DOS
Toutes les interruptions DOS sont accessible en lançant l'interruption DOS 21h, vecteur 084H.
Le numéro de la fonction DOS choisie est écrite dans le registre AH.
Le premier paramètre de l'interruption est le plus souvent écrit dans BX ou DX.
Les résultats sont le plus souvent retournés dans AL ou AX.
Les interruptions DOS donnent accès à toutes les fonctionnalités de base de l'OS DOS (formatage de disquettes, gestion de l'écran, de l'imprimante,etc.)
Routines DOS spécifiques au Turbo C
Ces routines ne sont disponible qu'avec Borland C++.
pour appeler les interruptions:
Inclus dans DOS.H :
union REGS structure d'accès aux registres de données AX,BX,CX,DX, DI, SI, CFLAGS
struct SREGS structure d'accès aux registres de segment ES, CS, SS, DS.
intdosx( ®s, ®s, &stack_regs);
int86(#int, ®s, ®s);
ex: union REGS regs; regs.h.al =0xFF; regs.h.ah =0xFF; regs.x.ax = 0xFF00;
Accès au segment et à l'offset d'un pointeur: FP_SEG(ptr) FP_OFF(ptr). Génération d'un pointeur: MK_FP(segment, offset);
pour modifier les interruptions:
Définir un pointeur de fonction pour stocker l'ancienne routine d'interruption, écrire la nouvelle routine d'interruption, et la brancher dans la table d'interruption.
exemple:
void interrupt (*old_int)();
/* note: en C++, mettre ... comme paramètres de fonction */void interrupt new_int(void) {
enable();
... ;
old_int();
}
main() {
disable();
old_int = getvect(int#);
setvect(int#, new_int);
enable();
...
disable();
setvect(int#, old_int);
enable();
}
Pour les IRQ matérielles, il faut en plus vérifier le masque d'interruption du PIC ( 0x21 ou 0xA1) lors de la mise en place de la routine pour savoir si il faut exécuter l'ancienne interruption. Il faut aussi éventuellement activer l'interruption en modifiant le masque. En quittant, il faut remettre l'ancien vecteur d'interruption, et désactiver l'interruption si elle n'était pas active précédemment.
Dans la routine d'interruption il faut de plus écrire le registre d'acquittement du PIC ( 0x20 ou 0xA0) pour réenclancher le circuit.
pour utiliser les ports d'E/S
Inclus dans DOS.H :
unsigned char inportb( int port# );
/* lit un octet */int inport( int port# );
/* lit un mot 16 bits */void outportb( int port#, unsigned char data );
/* écrit un octet */void outport( int port#, int data );
/* écrit un mot 16 bits */
pour lire la mémoire
On peut utiliser un pointeur, et l'initialiser evec l'adresse requise
ex: far int * Ptr = MK_FP(40,08); printf("adresse de LPT1: %X\n", *Ptr);
ou mieux, pour s'affranchir des problèmes lorsqu'on compile les programmes en mode tiny ou small:
int peek(segment,offset)
unsigned char peekb(segment,offset)
poke(segment,offset, data)
pokeb(segment,offset, data)
Fonctions C utiles
Dans CONIO.H, Borland propose plusieurs fonctions utiles pour tester les programmes. Ces fonctions ne sont pas standard. Elles ne sont pas disponibles avec d'autres compilateurs (Microsoft, Watcom...), ni d'autres OS (Unix, OS2...).
int kbhit();
/* retourne 0 si aucune touche du clavier est pressée, 1 sinon */delay
(millisecondes); /* pour attendre.. */char getc();
/* lit un caractère sur clavier sans echo */char getche();
/* lit un caractère sur clavier + echo */clrscr
(); /* éfface l'écran */