Préambule
Il peut être parfois utile d'avoir à forcer une entrée ou une sortie à un état ou une valeur.
Par exemple lorsqu'un capteur ne donne plus la bonne information et elle est indispensable pour l'exécution du programme et la maintenance a tout pris en compte pour que malgré cette information manquante, toutes les sécurités de fonctionnement soit validées.
Lorsqu'on l'on doit activer une sortie alors que les conditions requises par le programme nous en empêchent.
Et comment doit on réaliser un forçage ? En général, il faut ouvrir le logiciel de programmation, se connecter sur l'automate et forcer les informations désirées.
Cette opération qui peut paraître simple comporte pourtant de nombreux risques.
En effet, nous ne sommes pas à l'abris de faire, sans le vouloir, une modification de programme, de forcer une information qui n'est pas la bonne, simplement parce que nous nous sommes perdus dans le flux d'informations fournies dans le programme.
Cette solution n'est pas viable, nous pouvons nous passer de cela si notre programme a été bien construit. Si nous savons que quelqu'un pourra avoir besoin de forcer certaines informations, alors pourquoi ne pas le prévoir dès la conception du programme et donner l'accès à cette fonctionnalité sans avoir à rentrer dans le code, par exemple, depuis une visualisation.
Mise en place des informations nécessaires
Si nous voulons travailler de cette manière, il va falloir changer quelque peu notre façon de construire notre programme.
La première chose à faire est de ne plus travailler directement avec les entrées et les sorties de notre automate. Cela peut paraitre surprenant, mais cette méthode est utilisée depuis de nombreuses années dans bons nombres de programmes d'automates industriels.
Comment faire puisque mon programme a besoin de ses entrées et ses sorties pour pouvoir gérer mon process ?
Tout simplement en passant par une table image des entrées et une table image des sorties.
Notre programme va donc utiliser ces informations "images" et il faudra faire un lien entre les entrées et les images puis les images et les sorties.
Mais ca va me prendre plus de temps, plus de ressources que si je travaillais directement !
La réponse est oui. Mais la réponse est plus précisément : oui, maintenant. non, plus tard.
La nouvelle structure pourrait ressembler à cela. L'avantage est de s'affranchir de la configuration matérielle telle qu'elle a été définie et fournie pour une application. Notre programme pouvant être un programme "générique", les seuls points qui peuvent nous empêcher de le rendre totalement générique, ce sont les tables d'entrées et les tables de sorties qui peuvent et sont, très certainement, différentes d'une application à une autre.
Cette structuration du programme permet, en outre de pouvoir inverser une information (un capteur normalement ouvert à la place d'un capteur initialement prévu en normalement fermé par exemple) sans avoir à modifier notre programme et surtout garder la même logique de raisonnement pour toutes les informations similaires, quelques que soient les informations reçues au niveau des entrées.
Cela permet aussi d'avoir une structure de programme prévue pour pouvoir gérer la plus grande de nos installations et ce sans avoir à tout modifier.
Bien sûr les tables images d'entrées et de sorties peuvent être découpées en plus petites tables, regroupant par exemple des fonctionnalités identiques (des mesures de températures, des retours de marche moteur... )
Réalisation de la fonction de forçage
Une fonction simple pour le forçage peut être réalisée de la manière suivante :
FUNCTION fuForcageTOR : BOOL
VAR_INPUT
xIn:BOOL; // Information booléenne à utiliser
bForcage:BYTE; // Valeur utilisée pour le forçage (0 : Forçage à FALSE, 1 : Forçage à TRUE, Autres : Valeur xIn)
END_VAR
VAR
END_VAR
CASE bForcage OF
0:
fuForcageTOR:=FALSE;
1:
fuForcageTOR:=TRUE;
ELSE
fuForcageTOR:=xIn;
END_CASE
Cette fonction sera appelée lors du lien entre l'entrée et l'image d'entrée ou entre l'image de sortie et la sortie
Exemple d'utilisation :
PROGRAM PLC_PRG
VAR
axIN:ARRAY[1..200] OF BOOL;
xMonEntree1Physique:BOOL;
xMonEntree2Physique:BOOL;
xMonEntree3Physique:BOOL;
abForcage:ARRAY[1..200] OF BYTE;
END_VAR
axIN[1]:=fuForcageTOR(xMonEntree1Physique,abForcage[1]);
axIN[10]:=fuForcageTOR(xMonEntree2Physique,abForcage[10]);
axIN[12]:=fuForcageTOR(xMonEntree3Physique,abForcage[12]);
L'utilisation peut être optimisée, nous aborderons ce sujet dans un autre article concernant la configuration matérielle
Il faut penser à sauvegarder, d'une manière ou d'une autre le tableau abForcage pour que lors d'un redémarrage automate, les valeurs de ce tableau soient toujours égales à celles qui étaient présentes avant le redémarrage (soit en plaçant le tableau dans une liste de variables persistantes, soit en stockant ces informations dans une base de données, dans un fichier csv à chaque changement de valeur et en allant relire ces informations au démarrage du programme)
En l'état actuel, cette fonction simplifie simplement la notion de forçage, mais elle nécessite toujours une connexion à l'automate et une modification des valeurs des variables de forçage pour être utilisable.
Réalisation d'une visualisation de forçage et utilisation
Afin de faciliter l'intégration des visualisations, nous allons reprendre quelques peu la manière dont nous avons écrit notre fonction.
Création de la structure :
TYPE DUTTOR :
STRUCT
xIn:BOOL;
bForcage:BYTE;
xOut:bool;
END_STRUCT
END_TYPE
Modification de la fonction fuForcageTOR :
FUNCTION fuForcageTOR : BOOL
VAR_INPUT
DUTTor:DUTTor;
END_VAR
VAR
END_VAR
CASE DUTTor.bForcage OF
0:
fuForcageTOR:=FALSE;
1:
fuForcageTOR:=TRUE;
ELSE
fuForcageTOR:=DUTTor.xIn;
END_CASE
Modification du programme d'utilisation :
PROGRAM PLC_PRG
VAR
xMonEntree1Physique:BOOL;
xMonEntree2Physique:BOOL;
xMonEntree3Physique:BOOL;
aDUTTOR:ARRAY[1..200] OF DUTTOR;
i:DINT;
END_VAR
aDUTTOR[1].xIN:=xMonEntree1Physique;
aDUTTOR[10].xIN:=xMonEntree2Physique;
aDUTTOR[12].xIN:=xMonEntree3Physique;
FOR i:=1 TO UPPER_BOUND(aDUTTOR,1) DO
aDUTTOR[i].xOut:=fuForcageTOR(aDUTTOR[i]);
END_FOR
Pourquoi ces modification sont elles intéressantes ? Comme nous allons renseigner les variables de forçage depuis une visualisation, nous allons pouvoir, avec cette modification, créer une visualisation générique pour une structure et nous pourrons ensuite utiliser cette visualisation générique pour tous nos éléments.
Création de la visualisation générique
Cette visualisation pourrait ressemble à l'exemple suivant :
Tous les éléments de cette visualisation travailleront avec la variable DUTTOR Définie en VAR_IN_OUT de la visualisation.
Une fois notre visualisation générique créée, il ne nous reste qu'à l'appeler dans notre visualisation de gestion de forçage
Il faudrait faire de même avec toutes les informations de notre tableau de DUTTOR.
Fastidieux ! Oui !
Afin de rendre cette navigation plus modulaire, nous allons réaliser quelques petites modifications.
Modification du programme d'utilisation :
PROGRAM PLC_PRG
VAR
xMonEntree1Physique:BOOL;
xMonEntree2Physique:BOOL;
xMonEntree3Physique:BOOL;
aDUTTOR:ARRAY[1..200] OF DUTTOR;
i:DINT;
iIndex:INT;
xPrecedent:BOOL;
xSuivant:BOOL;
iPas: INT := 4;
END_VAR
aDUTTOR[1].xIN:=xMonEntree1Physique;
aDUTTOR[10].xIN:=xMonEntree2Physique;
aDUTTOR[12].xIN:=xMonEntree3Physique;
FOR i:=1 TO UPPER_BOUND(aDUTTOR,1) DO
aDUTTOR[i].xOut:=fuForcageTOR(aDUTTOR[i]);
END_FOR
IF iIndex<1 THEN
iIndex:=1;
END_IF
IF xPrecedent THEN
xPrecedent:=FALSE;
IF iIndex>=1+iPas THEN
iIndex:=iIndex-iPas;
END_IF
END_IF
IF xSuivant THEN
xSuivant:=FALSE;
IF iIndex<=TO_INT(UPPER_BOUND(aDUTTOR,1))-iPas THEN
iIndex:=iIndex+iPas;
END_IF
END_IF
Ces nouvelles informations nous permettront de placer un bouton "Précédent" et un bouton "Suivant" sur la visualisation et ainsi de parcourir notre tableau de DUT en affichant les différents informations.
La variable iPas doit être initialisée en fonction du nombre de visualisations génériques qui seront insérées (dans notre cas, 4).
Modification de la visualisation de forçage
Paramétrage des deux boutons précédent et suivant
Notre visualisation est maintenant opérationnelle et permet de parcourir notre tableau de DUT en appuyant sur les boutons précédent et suivant et ce qu'elle que soit la taille de notre tableau.
Améliorations réalisables
Il pourrait être judicieux de stocker aussi dans notre structure le nom de l'entrée ou de la sortie pour ensuite l'afficher dans notre visualisation et savoir à quelle entrée/sortie correspondent les informations affichées.
Il pourrait aussi être judicieux de définir une variable globale constant pour y stocker la borne supérieure du tableau de structures.
Nous pourrions aussi rendre invisible les boutons précédent et suivant lorsqu'ils n'ont plus d'action réalisable (par exemple lorsque la valeur d'index est inférieure à la valeur du pas pour le bouton précédent).
Nous pourrions aussi déplacer le tableau de structure dans une liste de variables globales et déplacer la zone d'affectation des .xIN dans un programme spécifique. Ce programme serait la zone d'échange entre les entrées / sorties et les tables images.