Vcl8254.pas

UNIT Vcl8254;
{-----------------------------------------------------------------------------
  NOM DE L'UNITE : VCL8254.PAS
  BUT            : Composant VCL 8254 renfermant tout les contrôles du PIT
  AUTEUR         : S.Claus / M.Amarantidis
  DATE           : Février 1997
 
  MODIFIE LE     :
  RAISON         :
 
  REMARQUES      : - Pour la configuration du 8254, la structure du mot de
                     commande qu'il faut écrire à l'adresse de contrôle est la
                     suivante:
 
   0  0  1  1  0  1  1  0    Cnt 0 - Géné    36
   0  1  1  1  0  1  1  0    Cnt 1 - Géné    76
   1  0  1  1  0  1  1  0    Cnt 2 - Géné    B6
 
  D7 D6 D5 D4 D3 D2 D1 D0
   ¦  ¦  ¦  ¦  ¦  ¦  ¦  ¦
   ¦  ¦  ¦  ¦  +--+--+  +-- BCD -> 1 ou Binaire -> 0
   ¦  ¦  ¦  ¦        ¦
   ¦  ¦  ¦  ¦        +----- Mode : 0 = 000   1 = 001   2 = X10
   ¦  ¦  +--+                      3 = X11   4 = 100   5 = 101
   ¦  ¦     ¦
   ¦  ¦     +-------------- Read/Write : 00 Counter Latch Command
   ¦  ¦                                  01 R/W byte de poids faible uniquement
   ¦  ¦                                  10 R/W byte de poids fort uniquement
   ¦  ¦                                  11 R/W byte de poids faible en premier
   +--+                                     puis le byte de poids fort ensuite
      ¦
      +-------------------- Sélection du compteur : 00 = Compteur 0
                                                    01 = Compteur 1
                                                    10 = Compteur 2
                                                    11 = Read Back
 
 -----------------------------------------------------------------------------}
 
 
{=============================================================================}
INTERFACE   {============================================== I N T E R F A C E }
{=============================================================================}
 
 
USES
  WinTypes, WinProcs, Classes, SysUtils;
 
 
CONST
  versionvcl            = '1.00';                            { Version du VCL }
  adressebase           = $308;                     { Adresse de base du 8254 }
  frquartz              = 6000000.0;                    { Fréquence du quartz }
 
TYPE
  TModeCompteur = (mcIndefini, mcGenerateur);            { Etat des compteurs }
 
  TPIT8254 = CLASS(TComponent)
    PRIVATE { Private-déclarations ---------------------------------- PRIVATE }
 
      {-- Divers }
      FVersion         : STRING;
      FAdresseBase8254 : WORD;
      AdresseCtrl,
      AdresseCnt0,
      AdresseCnt1,
      AdresseCnt2      : WORD;
      FCanWrite        : BOOLEAN;
 
      {-- Paramètres généraux }
      FFrequenceQuartz : EXTENDED;
 
      {-- Configuration des compteurs }
      FModeCnt0,
      FModeCnt1,
      FModeCnt2        : TModeCompteur;
 
      {-- Valeur des différents compteurs }
      FCnt0,
      FCnt1,
      FCnt2            : WORD;
 
      {-- Divers }
      PROCEDURE AjusteAdresses;
      PROCEDURE SetAdresseBase(Adresse:WORD);
      PROCEDURE SetCanWrite(WriteEnabled:BOOLEAN);
 
      {-- Configuration des compteurs }
      PROCEDURE SetModeCnt0(Mode:TModeCompteur);
      PROCEDURE SetModeCnt1(Mode:TModeCompteur);
      PROCEDURE SetModeCnt2(Mode:TModeCompteur);
 
      {-- Valeur des différents compteurs }
      PROCEDURE SetCnt0(Valeur: WORD);
      PROCEDURE SetCnt1(Valeur: WORD);
      PROCEDURE SetCnt2(Valeur: WORD);
 
    PUBLIC { Public-déclarations ------------------------------------- PUBLIC }
      CONSTRUCTOR Create(AOwner:TComponent); OVERRIDE;
      DESTRUCTOR Destroy; OVERRIDE;
 
    PUBLISHED { Published declarations ---------------------------- PUBLISHED }
 
      {-- Divers }
      PROPERTY Enabled : BOOLEAN READ FCanWrite WRITE SetCanWrite;
      PROPERTY Adresse : WORD READ FAdresseBase8254 WRITE SetAdresseBase;
      PROPERTY Version : STRING READ FVersion;
      PROPERTY Quartz  : EXTENDED READ FFrequenceQuartz WRITE FFrequenceQuartz;
 
      {-- Configuration des compteurs }
      PROPERTY ModeCompteur0 : TModeCompteur READ FModeCnt0 WRITE SetModeCnt0
                 DEFAULT mcIndefini;
      PROPERTY ModeCompteur1 : TModeCompteur READ FModeCnt1 WRITE SetModeCnt1
                 DEFAULT mcIndefini;
      PROPERTY ModeCompteur2 : TModeCompteur READ FModeCnt2 WRITE SetModeCnt2
                 DEFAULT mcIndefini;
      PROPERTY Compteur0 : WORD READ FCnt0 WRITE SetCnt0 DEFAULT 0;
      PROPERTY Compteur1 : WORD READ FCnt1 WRITE SetCnt1 DEFAULT 0;
      PROPERTY Compteur2 : WORD READ FCnt2 WRITE SetCnt2 DEFAULT 0;
 
  END; {CLASS TPIT8254}
 
PROCEDURE Register;    { Enregistrement de l'objet dans l'inspecteur d'objets }
 
 
{=============================================================================}
IMPLEMENTATION   {================================= I M P L E M E N A T I O N }
{=============================================================================}
 
 
USES
  Forms, Dialogs;
 
 
CONST
  Poids : ARRAY[0..7] OF WORD = (1, 2, 4, 8, 16, 32, 64, 128);
 
 
TYPE
  bbit = 0..7;                                        { Pour l'accés aux bits }
 
 
{-----------------------------------------------------------------------------}
{ INITIALISATIONS ------------------------------------------- Initialisations }
{-----------------------------------------------------------------------------}
 
 
CONSTRUCTOR TPIT8254.Create;
{ BUT: Initialisation du composant }
BEGIN
  {-- Toujours appeler le constructeur reçu en héritage }
  INHERITED Create(AOwner);
  {-- Version}
  FVersion := versionvcl;
  {-- Interdiction d'écrire sur tous les ports }
  FCanWrite        := FALSE;
  {-- Fréquence du quartz }
  FFrequenceQuartz := frquartz;
  {-- Valeur par défaut des adresses }
  SetAdresseBase(adressebase);
  {-- Valeurs des différents compteurs }
  FCnt0 := 0;
  FCnt1 := 0;
  FCnt2 := 0;
  {-- Tous les compteurs sont dans un état indéfini }
  FModeCnt0 := mcIndefini;
  FModeCnt1 := mcIndefini;
  FModeCnt2 := mcIndefini;
END; {CONSTRUCTOR Create}
 
 
DESTRUCTOR TPIT8254.Destroy;
{ BUT: Tout remettre en ordre quand on a fini }
BEGIN
  { Toujours appeler le destructor hérité }
  INHERITED Destroy;
END; {DESTRUCTOR Destroy}
 
 
{-----------------------------------------------------------------------------}
{ ACCES BAS NIVEAU ----------------------------------------- Accés bas niveau }
{-----------------------------------------------------------------------------}
 
 
FUNCTION InPortB(LePort:WORD):BYTE;
{ BUT: Lecture de l'état d'un port }
VAR
  Valeur : BYTE;
BEGIN
  ASM
    PUSH DX
    MOV  DX, LePort
    IN   AL, DX
    MOV  Valeur, AL
    POP  DX
  END; {ASM}
  InPortB := Valeur;
END; {FUNCTION InPortB}
 
 
PROCEDURE OutPortB(LePort:WORD; Value:BYTE); ASSEMBLER;
{ BUT: Ecriture sur un port }
ASM
  PUSH  DX
  MOV   DX, LePort
  MOV   AL, Value
  OUT   DX, AL
  POP   DX
END; {PROCEDURE OutPortB}
 
 
PROCEDURE SetBitB(VAR B : Byte; bit : bbit);
{ BUT: Mise à 1 d'un bit }
BEGIN
  B := B OR Poids[bit]
END; {PROCEDURE SetBitB}
 
 
PROCEDURE ClearBitB(VAR B : Byte; bit : bbit);
{ BUT: Mise à 0 d'un bit}
BEGIN
  B := B AND NOT Poids[bit];
END; {PROCEDURE ClearBitB}
 
 
{-----------------------------------------------------------------------------}
{ UTILITAIRES --------------------------------------------------- Utilitaires }
{-----------------------------------------------------------------------------}
 
 
PROCEDURE Register;
{ BUT: Ajoute ce composant dans la palette des composants de Delphi}
BEGIN
  RegisterComponents('More...', [TPIT8254]);
END; {PROCEDURE Register}
 
 
{-----------------------------------------------------------------------------}
{ METHODES DU COMPOSANT ------------------------------- Méthodes du composant }
{-----------------------------------------------------------------------------}
 
 
PROCEDURE TPIT8254.SetCanWrite(WriteEnabled:BOOLEAN);
{ BUT: Autorise ou non l'écriture sur les ports }
BEGIN
  FCanWrite := WriteEnabled;
END; {PROCEDURE SetCanWrite}
 
 
PROCEDURE TPIT8254.AjusteAdresses;
{ BUT: Ajuste toutes les adresses du 8254 en fonction de l'adresse de base }
BEGIN
  AdresseCnt0 := FAdresseBase8254 + 0;
  AdresseCnt1 := FAdresseBase8254 + 1;
  AdresseCnt2 := FAdresseBase8254 + 2;
  AdresseCtrl := FAdresseBase8254 + 3;
END; {PROCEDURE AjusteAdresses}
 
 
PROCEDURE TPIT8254.SetAdresseBase(Adresse:WORD);
{ BUT: Configuration de l'adresse de base }
BEGIN
  FAdresseBase8254 := Adresse;
  AjusteAdresses;
END; {PROCEDURE SetAdresseBase}
 
 
{-----------------------------------------------------------------------------}
{ COMPTEUR 0 ----------------------------------------------------- Compteur 0 }
{-----------------------------------------------------------------------------}
 
 
PROCEDURE TPIT8254.SetCnt0(Valeur: WORD);
{ BUT: Change la valeur du compteur 0 }
BEGIN
  IF FCanWrite AND (FModeCnt0 <> mcIndefini) THEN BEGIN
    { On ne change la valeur que si le composant est activé et que le compteur
      a déjà été configuré }
    FCnt0 := Valeur;                                    { MAJ de la propriété }
    CASE FModeCnt0 OF
      mcGenerateur : BEGIN                                   { - GENERATEUR - }
                       IF FCnt0 < 2 THEN FCnt0 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $36);            { Choix du mode }
                       OutPortB(AdresseCnt0, Lo(FCnt0));   { Facteur division }
                       OutPortB(AdresseCnt0, Hi(FCnt0));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetCnt0}
 
 
PROCEDURE TPIT8254.SetModeCnt0(Mode:TModeCompteur);
{ BUT: Initialisation du mode de fonctionnement du compteur 0 }
VAR
  ValeurControle : BYTE;
BEGIN
  IF FCanWrite AND (Mode <> mcIndefini) THEN BEGIN
    { On ne change le mode de fonctionnement que si le composant est activé
      et qu'on choisi un mode de fonctionnement (logique, non?) }
    FModeCnt0 := Mode;                                  { MAJ de la propriété }
    CASE FModeCnt0 OF
      mcGenerateur : BEGIN                                   { - GENERATEUR - }
                       IF FCnt0 < 2 THEN FCnt0 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $36);            { Choix du mode }
                       OutPortB(AdresseCnt0, Lo(FCnt0));   { Facteur division }
                       OutPortB(AdresseCnt0, Hi(FCnt0));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetModeCnt0}
 
 
{-----------------------------------------------------------------------------}
{ COMPTEUR 1 ----------------------------------------------------- Compteur 1 }
{-----------------------------------------------------------------------------}
 
 
PROCEDURE TPIT8254.SetCnt1(Valeur: WORD);
{ BUT: Change la valeur du compteur 1 }
BEGIN
  IF FCanWrite AND (FModeCnt1 <> mcIndefini) THEN BEGIN
    { On ne change la valeur que si le composant est activé et que le compteur
      a déjà été configuré }
    FCnt1 := Valeur;                                    { MAJ de la propriété }
    CASE FModeCnt1 OF
      mcGenerateur : BEGIN
                       IF FCnt1 < 2 THEN FCnt1 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $76);            { Choix du mode }
                       OutPortB(AdresseCnt0, Lo(FCnt1));   { Facteur division }
                       OutPortB(AdresseCnt0, Hi(FCnt1));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetCnt1}
 
 
PROCEDURE TPIT8254.SetModeCnt1(Mode:TModeCompteur);
{ BUT: Initialisation du mode de fonctionnement du compteur 1 }
VAR
  ValeurControle : BYTE;
BEGIN
  IF FCanWrite AND (Mode <> mcIndefini) THEN BEGIN
    { On ne change le mode de fonctionnement que si le composant est activé
      et qu'on choisi un mode de fonctionnement (logique, non?) }
    FModeCnt1 := Mode;                                  { MAJ de la propriété }
    CASE FModeCnt1 OF
      mcGenerateur : BEGIN
                       IF FCnt1 < 2 THEN FCnt1 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $76);            { Choix du mode }
                       OutPortB(AdresseCnt1, Lo(FCnt1));   { Facteur division }
                       OutPortB(AdresseCnt1, Hi(FCnt1));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetModeCnt1}
 
 
{-----------------------------------------------------------------------------}
{ COMPTEUR 2 ----------------------------------------------------- Compteur 2 }
{-----------------------------------------------------------------------------}
 
 
PROCEDURE TPIT8254.SetCnt2(Valeur: WORD);
{ BUT: Change la valeur du compteur 2 }
BEGIN
  IF FCanWrite AND (FModeCnt2 <> mcIndefini) THEN BEGIN
    { On ne change la valeur que si le composant est activé et que le compteur
      a déjà été configuré }
    FCnt2 := Valeur;                                    { MAJ de la propriété }
    CASE FModeCnt2 OF
      mcGenerateur : BEGIN
                       IF FCnt2 < 2 THEN FCnt2 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $B6);            { Choix du mode }
                       OutPortB(AdresseCnt0, Lo(FCnt2));   { Facteur division }
                       OutPortB(AdresseCnt0, Hi(FCnt2));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetCnt2}
 
 
PROCEDURE TPIT8254.SetModeCnt2(Mode:TModeCompteur);
{ BUT: Initialisation du mode de fonctionnement du compteur 2 }
VAR
  ValeurControle : BYTE;
BEGIN
  IF FCanWrite AND (Mode <> mcIndefini) THEN BEGIN
    { On ne change le mode de fonctionnement que si le composant est activé
      et qu'on choisi un mode de fonctionnement (logique, non?) }
    FModeCnt2 := Mode;                                  { MAJ de la propriété }
    CASE FModeCnt2 OF
      mcGenerateur : BEGIN
                       IF FCnt2 < 2 THEN FCnt2 := 2;               { ! Limite }
                       OutPortB(AdresseCtrl, $B6);            { Choix du mode }
                       OutPortB(AdresseCnt2, Lo(FCnt2));   { Facteur division }
                       OutPortB(AdresseCnt2, Hi(FCnt2));
                     END; {BRANCH OF CASE}
    END; {CASE OF}
  END; {IF}
END; {PROCEDURE SetModeCnt2}
 
 
{-----------------------------------------------------------------------------}
{ THAT'S ALL -------------------------------------------------------- The end }
{-----------------------------------------------------------------------------}
 
 
INITIALIZATION
END. {UNIT Vcl8254}