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( &regs, &regs, &stack_regs);

int86(#int, &regs, &regs);

 

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 */