====== Exercice 2 (TP5) ====== ===== Organigramme ===== {{:fr:supervisors:solutions:didalab:ex2_tp5_organigramme1.png?600|}} ===== 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 #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