Exercice 2 (TP5)
Organigramme
Programme
/************************************************************************************************
* TPs sur EID210 / Réseau CAN - VMD (Véhicule Multiplexé Didactique)
*************************************************************************************************
* APPLICATION: Commande Essuie-glace à distance
*************************************************************************************************
* TP Exercice n°2: Réguler la vitesse du moteur essuie-glace avec correcteur P
*-----------------------------------------------------------------------------------------------
* CAHIER DES CHARGES :
* *********************
* Réguler la vitesse du moteur EG avec pour consigne, l'entrée analogique du commodo E.G.
* La commande du moteur se fait boucle fermé avec correcteur à action proportionnelle
* Commande = Kp*Ecart = Kp * (Consigne - Mesure)
*------------------------------------------------------------------------------------------------
* NOM du FICHIER : TP_Exercice 2.C
* *****************
*************************************************************************************************/
// Déclaration des fichiers d'inclusion
#include <stdio.h>
#include"Structures_Donnees.h"
#include"cpu_reg.h"
#include "eid210_reg.h"
#include "CAN_vmd.h"
#include "Aton_can.h"
// Déclarations des diverses trames de communication
Trame Trame_Recue; // Pour la trame qui vient d'etre reçue par le controleur
// Trmes de type "IM" (Input Message -> trame de commande)
Trame T_IM_Asservissement; // Pour la commande du moteur
Trame T_IM_Commodo_EG;
Trame T_IRM_Commodo_EG; // Pour l'acquisition des entrées Commodo EG
// Déclaration des variables
// Pour les Indicateurs divers (variables binaires)
union byte_bits Indicateurs; // Structures de bits
#define I_Sens_Rotation Indicateurs.bit.b0
#define I_Attente_Reponse_IRM Indicateurs.bit.b1
#define I_Message_Pb_Affiche Indicateurs.bit.b2
// Pour les résultats de conversion
unsigned short S_Mesure_Vitesse,S_Consigne,S_Temp;
unsigned char AN0H,AN1H,AN10L;
// Pour régulateur de vitesse
int Ecart,Resultat_Calcul;
unsigned char Cde_Moteur;
// Déclaration constante pour régulation
#define Kp 6 // Coefficient d'action proportionnelle -> Ce doit etre un entier
//en fait valeur réelle Kp/16 = 6/16
//======================
// FONCTION PRINCIPALE
//======================
main()
{
// INITIALISATIONS
//------------------
// Déclaration de variables locales à la fonction principale
// Les différents compteurs
unsigned int Cptr_Affichage,Cptr_TimeOut,Ctpr_Acquisition;
// Initilisation carte controleur réseau CAN
Init_Aton_CAN();
// Effacer l'écran
clsscr();
// Pour initialiser les liaison en entrées du noeud "Commodo Essuie-Glace"
T_IM_Commodo_EG.trame_info.registre=0x00;
T_IM_Commodo_EG.trame_info.champ.extend=1; // On travaille en mode étendu
T_IM_Commodo_EG.trame_info.champ.dlc=0x03; // Il y aura 3 données de 8 bits (3 octets envoyés)
T_IM_Commodo_EG.ident.extend.identificateur.ident=Ident_T_IM_Commodo_EG;
T_IM_Commodo_EG.data[0]=0x1F; // première donnée -> "Adresse" du registre concernée
//(GPDDR donne la direction des I/O) adresse = 1Fh page 16
T_IM_Commodo_EG.data[1]=0x7F; // deuxième donnée -> "Masque"
//-> Tous les bits concernés sauf GP0 (voir doc page 16)
T_IM_Commodo_EG.data[2]=0x7F; // Valeur -> 1 si Entrée et 0 si Sortie (Toutes en entrées)
// Pour envoyer trame et test si réponse (avec Time Out
I_Message_Pb_Affiche=0;
do {Ecrire_Trame(T_IM_Commodo_EG); // C'est la première trame envoyée
Cptr_TimeOut=0; // On teste si le module répond bien
do{Cptr_TimeOut++;}while((Lire_Trame(&Trame_Recue)==0)&&(Cptr_TimeOut<500));
if(Cptr_TimeOut==500)
{if(I_Message_Pb_Affiche==0)
{I_Message_Pb_Affiche=1;
gotoxy(2,10);
printf(" Pas de reponse a la trame de commande en initialisation \n");
printf(" Verifier si alimentation 12 V est OK ... PUIS \n");
printf(" FAIRE un Reset de la carte processeur EID 210 ... PUIS \n");
printf(" RECHARGER le programme et RELANCER \n");
do{}while(1);}}
}while(Cptr_TimeOut==500);
// La première tramme est bien passée ... on peut continuer!
clsscr();
// Pour afficher titre
gotoxy(1,2);
printf(" ******************************************************************** \n");
printf(" TPs sur Reseau CAN Application: Commande Essui-Glace \n");
printf(" -------------------------------------------------------------------- \n");
printf(" TP Exercice n°2: REGULER LA VITESSE DU MOTEUR Essuie-Glace \n");
printf(" ******************************************************************** \n");
printf(" - en agissant sur l'entree analogique 0 sur module Commodo_EG \n");
printf(" - en boucle fermee en mode proportionnel Sr = Kp(Consigne -Mesure) \n");
printf(" ******************************************************************** \n");
// Pour activer les conversions Ana -> Num
T_IM_Commodo_EG.data[0]=0x2A; // Adresse du registre ADCON0
T_IM_Commodo_EG.data[1]=0xF0; // Masque -> bits 7..4 concernés
T_IM_Commodo_EG.data[2]=0x80; // Valeur -> ADON=1 et "prescaler rate"=1:32
Ecrire_Trame(T_IM_Commodo_EG);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour définir le mode de conversion
T_IM_Commodo_EG.data[0]=0x2B; // Adresse du registre ADCON1
T_IM_Commodo_EG.data[1]=0xFF; // Masque -> tous les bits sont concernés
T_IM_Commodo_EG.data[2]=0x0C; // Valeur -> voir doc MCP25050 page 36
Ecrire_Trame(T_IM_Commodo_EG);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Trame de type "IRM" (trame interrogative): Données d'identification du commodo EG
T_IRM_Commodo_EG.trame_info.registre=0x00;
T_IRM_Commodo_EG.trame_info.champ.extend=1;
T_IRM_Commodo_EG.trame_info.champ.dlc=0x08; // On demande les valeurs de 8 rgistres
T_IRM_Commodo_EG.trame_info.champ.rtr=1;
T_IRM_Commodo_EG.ident.extend.identificateur.ident=Ident_T_IRM8_Commodo_EG; //
// Initialisation des différentes trames et envoi aux modules "Asservissement"
// Trame de type "IM" (trame de commande): Données d'identification
T_IM_Asservissement.trame_info.registre=0x00;
T_IM_Asservissement.trame_info.champ.extend=1;
T_IM_Asservissement.trame_info.champ.dlc=0x03;
T_IM_Asservissement.trame_info.champ.rtr=0;
T_IM_Asservissement.ident.extend.identificateur.ident=Ident_T_IM_Asservissement;
// Pour définir des Entrées/Sorties
T_IM_Asservissement.data[0]=0x1F; // Adresse du registre GPDDR (direction de E/S)
// doc MCP25050 Page 16
T_IM_Asservissement.data[1]=0xEF; // Masque -> Bit 7 non concerné
T_IM_Asservissement.data[2]=0xE3; // Valeur -> 1 si Entrée et 0 si Sortie
// GP7=fs Entrée; GP6=fcg Entree; GP5=fcd Entrée; GP4=ValidIP Sortie;
// GP3=PWM2 Sortie; GP2=PWM1 Sortie; GP1=AN1 Entrée; GP0=AN0 Entrée;
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour mettre à 0 les sorties
T_IM_Asservissement.data[0]=0x1E; // Adresse du registre GPLAT (Registre I/O)
T_IM_Asservissement.data[1]=0x1C; // Masque -> sorties GP4,3,2 sont consernées
T_IM_Asservissement.data[2]=0x00; // Valeur -> les 3 sorties à 0
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour définir sortie GP2 en PWM1
T_IM_Asservissement.data[0]=0x21; // Adresse du registre T1CON
T_IM_Asservissement.data[1]=0xB3; // Masque -> seuls bit 7;5;4;1;0 consernés
T_IM_Asservissement.data[2]=0x80; // Valeur -> TMR1ON=1; Prescaler1=1
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour définir fréquence signal sortie PWM1
T_IM_Asservissement.data[0]=0x23; // Adresse du registre PR1
T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont consernés
T_IM_Asservissement.data[2]=0xFF; // Valeur -> PR1=255
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour Valider le circuit de puissance
T_IM_Asservissement.data[0]=0x1E; // Adresse du registre GPLAT (Registre I/O)
T_IM_Asservissement.data[1]=0x10; // Masque -> sortie GP4 (ValidIP) est conserné
T_IM_Asservissement.data[2]=0x10; // Valeur ->
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour initialiser le rapport cyclique (valeur initiale)
T_IM_Asservissement.data[0]=0x25; // Adresse du registre PWM1DC (Charger cde vitesse)
T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont concernés
T_IM_Asservissement.data[2]=0; // Valeur -> Commande vitesse à 0
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour activer les conversions Ana -> Num
T_IM_Asservissement.data[0]=0x2A; // Adresse du registre ADCON0
T_IM_Asservissement.data[1]=0xF0; // Masque -> bits 7..4 concernés
T_IM_Asservissement.data[2]=0x80; // Valeur -> ADON=1 et "prescaler rate"=1:32
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour définir le mode de conversion
T_IM_Asservissement.data[0]=0x2B; // Adresse du registre ADCON1
T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont concernés
T_IM_Asservissement.data[2]=0x0C; // Valeur -> voir doc MCP25050 page 36
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour valider le séquenceur
T_IM_Asservissement.data[0]=0x2C; // Adresse du registre STON
T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont concernés
T_IM_Asservissement.data[2]=0xD2; // Valeur -> voir doc MCP25050 page 24
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Pour valider le séquencement sur entrées analogiques 0 et 1
T_IM_Asservissement.data[0]=0x2C; // Adresse du registre STON
T_IM_Asservissement.data[1]=0x03; // Masque -> tous les bits sont concernés
T_IM_Asservissement.data[2]=0x03; // Valeur -> voir doc MCP25050 page 24
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
Cptr_Affichage=0;
Ctpr_Acquisition=0;
Cptr_TimeOut=0;
// BOUCLE PRINCIPALE
//*******************
while(1)
{// Un trame donnant les états est recue à intervalles de temps réguliers
// Fonction 'Scéduleur' du module 'Asservissement' est activée
if(Lire_Trame(&Trame_Recue)!=1) // Un trame résultat n'est pas arrivée ?
{Cptr_TimeOut++;
if(Cptr_TimeOut==10000)
{clsscr(),gotoxy(2,10);
printf(" Pas de trame resultats de conversion depuis trop longtemps\n");
printf(" Il faut recharger et relancer le programme \n");
do{}while(1);}} // Stop
else {Cptr_TimeOut=0;
if(Trame_Recue.ident.extend.identificateur.ident==Ident_T_OB_Asservissement)
// On teste si l'identificateur est correct
{AN1H =Trame_Recue.data[3]; // On récupére les MSB de la mesure vitesse
AN10L =Trame_Recue.data[4]; // On récupére les LSB AN1 et AN0
// Traiter les données et reconstituer les résultats
S_Mesure_Vitesse=(unsigned short)(AN1H); //Transfert avec transtypage
S_Mesure_Vitesse=S_Mesure_Vitesse<<2; // Décaler de 2 bits vers poids forts
S_Temp=(unsigned short)(AN10L&0xC0); // Pour ne récupérer que les 2 bits AD1 et AD0
S_Mesure_Vitesse=S_Mesure_Vitesse|(S_Temp>>6);
// Calculer la grandeur de commande
Ecart = S_Consigne - S_Mesure_Vitesse;
Resultat_Calcul = (Kp*Ecart)>>4;
if(Resultat_Calcul>255)Resultat_Calcul=255;
if(Resultat_Calcul<0)Resultat_Calcul=0;
Cde_Moteur=(unsigned char)(Resultat_Calcul);
T_IM_Asservissement.data[0]=0x25; // Adresse du registre PWM1DC (Charger cde vitesse)
T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont concernés
T_IM_Asservissement.data[2]=Cde_Moteur; // Valeur -> Commande vitesse
Ecrire_Trame(T_IM_Asservissement);
do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
// Acquisition de la consigne
Ecrire_Trame(T_IRM_Commodo_EG);
do{}while(Lire_Trame(&Trame_Recue)==0);
if(Trame_Recue.ident.extend.identificateur.ident==Ident_T_IRM8_Commodo_EG)
{AN0H =Trame_Recue.data[2]; // On récupére les MSB entree analogique Commodo EG
AN10L =Trame_Recue.data[4]; // On récupére les LSB AN1 et AN0
// Traiter les données et reconstituer les résultats
S_Consigne=(unsigned short)(AN0H); //Transfert avec transtypage
S_Consigne=S_Consigne<<2; // Décaler de 2 bits vers poids forts
S_Temp=(unsigned short)(AN10L&0x0C); // Pour ne récupérer que les 2 bits AD1 et AD0
S_Consigne=S_Consigne|(S_Temp>>2);
}
}} // Fin acquisition et traitement
Cptr_Affichage++;
if(Cptr_Affichage==20000)
{Cptr_Affichage=0;
gotoxy(1,12);
printf(" Valeur de l'entree Consigne: \n");
printf(" Valeur de l'entree Mesure vitesse: \n");
printf(" Ecart = Consigne - Mesure: \n");
printf(" Valeur de la Commande moteur: \n");
// Afficher grandeurs
gotoxy(1,12);
printf(" Valeur de l'entree Consigne: %d\n",S_Consigne);
printf(" Valeur de l'entree Mesure vitesse: %d\n",S_Mesure_Vitesse);
printf(" Ecart = Consigne - Mesure: %d\n",Ecart);
printf(" Valeur de la commande moteur:%d\n",Cde_Moteur);
printf(" On doit verifier la relation:\n");
printf(" Commande moteur = (Kp*Ecart)/16 avec Kp= %d\n",Kp);}
} // Fin boucle principale
} // Fin fonction principale