Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
fr:examples:can:wiper:tp3 [2010/03/12 16:51] sdeniaudfr:examples:can:wiper:tp3 [2020/07/20 12:00] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +====== TP3 - Exemple 3 ======
 +===== Sujet: =====
 +**Faire battre le balai de l'essuie-glace**
 +
 +==== Objectifs : ====
 +
 +  * Définir les différentes trames interrogatives ou de commande à faire transiter par le réseau CAN en fonction d'une action souhaitée.
 +
 +  * Commander un actionneur électrique (moteur à courant continu), dans les deux sens de rotation par l'intermédaire d'un pré-actionneur commandable par réseau CAN.
 +
 +  * Acquérir l'état de capteurs TOR (fins de course) acessibles par réseau CAN et en déduire les actions à mener pour satisfaire un cahier des charges imposé.
 +
 +==== Cahier des charges : ====
 +
 +Après avoir fait tourner le moteur dans le sens positif (déplacement à droite) jusqu'à atteindre l'action sur le fin de course droit, l'essuie glace réalise le cycle continu suivant:
 +
 +  * déplacement à gauche jusqu'à action sur le fin de course gauche
 +  * déplacement à droite jusqu'à action sur le fin de course droite
 +  * etc
 +
 +
 +===== Eléments de solution =====
 +==== Analyse ====
 +
 +**Principe:**
 +Le module d'interface CAN mis en œuvre dans ce TP est le module repéré "Asservissement".
 +Ce module permet la commande d'un moteur à courant continu 24V/ 1A, dans les deux sens de rotation, en mode "PWM" (modulation de largeur d'impulsion). Cette possibilité a été expérimentée dans le TP5.
 +Il permet d'acquérir 3 entrées TOR sur lesquelles on pourra connecter les capteurs de fin de courses:
 + → fcd  (fin de course droit) relié à l'entrée GP5 du contrôleur CAN 
 + → fcg  (fin de course gauche) relié à l'entrée GP6 du contrôleur CAN
 + → fs  (fin de surcource) relié à l'entrée GP7 du contrôleur CAN
 +Le cycle demandé conduit au diagramme des états suivant:
 +
 +{{  :fr:examples:can:wiper:diag_etats.png  |}}
 +
 +**Configurations du module "Asservissement" pour l'utilisation envisagée:**
 +Comme dans l'exemple n°2, il faut envoyer un certain nombre de "Trames" afin de configurer le module "Asservissement"
 +
 +**Trame n°1**   →  pour définir les entrées et sorties du module "Asservissement"
 +Il faut initialiser le registre GPDDR ("Data Direction Register") -> Idem TP Exemple n°2
 +
 +**Trame n°2**   → pour initialiser la sortie GP2 en sortie PWM1 (commande  du moteur dans le sens positif) → Idem TP Exemple n°2
 +
 +**Trame n°3**   →  pour définir la fréquence de la  sortie PWM1: → Idem TP Exemple n°2
 +
 +**Trame n°4**   →  pour définir le rapport cyclique de la sortie PWM1 (module de la commande donc de la vitesse du moteur) → Idem TP Exemple n°2
 +
 +**Trame n°5**   → pour initialiser la sortie GP3 en sortie PWM2 (commande  du moteur dans le sens négatif)
 +D'après la notice technique du circuit MCP25050 (pages 30 à 32), la génération du signal PWM2 se fait à partie du "Timer2" et la fréquence de ce signal est choisie grâce au registre "T2CON" d'adresse 06H  (page 15 Doc MCP25050).
 +<code c>
 +bit 7 =1  TMR2ON Validation du "Timer 2"
 +bits 5:4 seront mis à 0 pour avoir un coefficient de division de fréquence égal à 1 ("TMR2 prescaler value" = 1)
 +T_IM_Asservissement.data[0]=0x22; // Adresse du registre T1CON en écriture (doc MCP25050 p15) 06H + décalage = 06H + 1CH = 22H
 +T_IM_Asservissement.data[1]=0xB3; // Masque sur le registre (doc MCP25050 p32) 
 +T_IM_Asservissement.data[2]=0x80; // Valeur à charger dans le registre adressé
 +</code>
 +Suite à ces définitions, il faudra envoyer la trame puis attendre la réponse de type "Ack".  
 +
 +**Trame n°6**   →  pour définir la fréquence de la  sortie PWM2:
 +Cette fréquence dépend de la valeur chargée dans le registre "PR2"
 +<code c>
 +T_IM_Asservissement.data[0]=0x24; // adresse du registre PR2 en écriture (doc MCP25050 p15) 08H + décalage = 08H + 1CH = 24H
 +T_IM_Asservissement.data[1]=0xFF; // Masque sur le registre (doc MCP25050 p32) 
 +T_IM_Asservissement.data[2]=0xFF; // On chargera 255 dans le registre
 +</code>
 +La fréquence du quartz implanté sur la carte "asservissement" étant égale à 16Mhz, la fréquence du signal PWM2 sera donc égale à :     FPWM = 16.106/(4.256) = 15,6 KHz
 +Ce qui est une fréquence correcte pour piloter un moteur en PWM (fréquence sensiblement inaudible).
 +Suite à ces définitions, il faudra envoyer la trame puis attendre la réponse de type "Ack".
 +
 +**Trame n°7**   →  pour définir le rapport cyclique de la sortie PWM2 (module de la commande donc de la vitesse du moteur)
 +<code c>
 +T_IM_Asservissement.data[0]=0x25; //adresse du registre PWM2DCH en écriture (doc MCP25050 p15) 0AH + décalage = 0AH + 1CH = 26H
 +T_IM_Asservissement.data[1]=0xFF; //masque sur le registre (doc MCP25050 p33)
 +T_IM_Asservissement.data[2]=0x00; // Commande = 0 (0xFF=255 pour la commande Maxi) 
 +</code>
 +Suite à ces définitions, il faudra envoyer la trame puis attendre la réponse de type "Ack".
 +
 +**Acquisition de l'état des fins de course:**
 +
 +Définition de la trame interrogative permettant de connaître l'état des fins de course:
 +Dans ce cas, la trame envoyée par le contrôleur CAN (Circuit SJA1000 sur carte CAN_PC104) sera vue par le récepteur (circuit MCP25050 sur module) comme une IRM ''Information Request Message'', avec la fonction ''Read register'' (voir documentation  technique du MPC25025 pages 22). 
 +
 +D’après le tableau donné page 22 de la notice du MCP25050, l’identificateur lui-même contiendra l’adresse du registre lu. Cette adresse est placée sur les bits  ID15 à ID8 de l’identificateur en mode étendu (bits qui seront réceptionnés et placés dans le registre RXBEID8). Le registre concerné est GPPIN d’adresse ''1Eh'' (voir documentation  technique du MPC25025 pages 37).
 +D’autre part, les trois bits de poids faibles de l’identificateur en mode étendu devront être positionnés à 1.
 +L’identificateur défini dans le chapitre 1 devra donc être complété comme suit:
 +{{  :fr:examples:can:wiper:acquisition.png?600  |}}
 +
 +→ Définition de variables structurées sous le modèle  "Trame":
 +<code c>
 +Trame T_IRM_Acquisition_FC; // Trame destinée à l’interrogation du module asservissement pour acquérir Fins de Courses.
 +</code>
 +Remarque:  La variable structurée ''T_IRM_Acquisition_FC'' comportera 5 octets utiles seulement, 1octet pour trame_info et  4 octets pour l'identificateur en mode étendu (qui comprendra l'adresse du registre concerné par la lecture.
 +
 +→ Accès et définition des différents éléments de la variable structurée ''Lecture_FC'' 
 +<code c>
 +  T_IRM_Acquisition_FC.trame_info.registre=0x00;  //On initialise tous les bits à 0
 +  T_IRM_Acquisition_FC.trame_info.champ.extend=1; //On travaille en mode étendu
 +  T_IRM_Acquisition_FC.trame_info.champ.dlc=0x01; //Il y aura 1 octet de données demandé
 +  T_IRM_Acquisition _FC.ident.extend.identificateur.ident=0x00841E07; 
 +</code>
 +Suite à ces définitions, il faudra 
 +  * envoyer la trame par la fonction ''Ecrire_Trame(Acquisition _FC)''
 +  * puis attendre la réponse de type "OM"  en utilisant la fonction  ''Lire_Trame(&T_Recue)''
 +
 +D'après la définition des identificateurs donnée en Annexe, une trame de réponse à une IRM a le même identificateur que la trame interrogative qui en a été à l'origine. 
 +Vu du module (du MCP25050), la réponse à un "IRM" (Information Request Message) est un "OM" (Output Message). 
 +La différence avec la trame interrogative origine est que cette trame réponse comporte le paramètre ''value'' (au rang 0 de la partie "data" de la trame de réponse). Ce paramètre est l'image des entrées. On récupère donc l'état des différents capteurs.
 +
 +**Définition de variables structurées images de l'état des fins de course**
 +
 +La trame reçue en réponse à cette trame interrogative comportera en data[0], l'état des fins de course. On recopie cette donnée reçue dans une variable image.
 +union byte_bits FC;
 +<code c>
 +#define Etats_FC FC.valeur // Pour l'ensemble des états fins de courses
 +#define fs FC.bit.b7  // Pour fin de surcourse
 +#define fcg FC.bit.b6 // Pour fin de course gauche
 +#define fcd FC.bit.b5 // Pour fin de course droit
 +</code>
 +
 +Afin de pouvoir détecter les changements d'état des capteurs, on mémorise l'état dans une deuxième variable structurée -> Etat_mémorisé 
 +<code c>
 +union byte_bits FC_Mem; // Pour fins de courses mémorisés
 +#define Etats_FC_Mem FC_Mem.valeur  // Pour l'ensemble des états mémorisés
 +</code>
 +Si l'état d'une variable acquise est différente de sa valeur mémorisée, c'est qu'il y a eu un changement d'état. On en déduit alors les actions à mener.
 + 
 +
 +==== Organigramme: ====
 +
 +{{  :fr:examples:can:wiper:orga_3.png  |}}
 +
 +==== Programme en "C" ====
 +
 +<code c>
 +/************************************************************************************
 +*       TPs sur  EID210 / Réseau CAN - VMD  (Véhicule Multiplexé Didactique)
 +*************************************************************************************
 +*       APPLICATION: Commande Essuie-glace à distance
 +*************************************************************************************
 +*   TP Exemple n°3:   Battement essuie glace avant 
 +*------------------------------------------------------------------------------------ 
 +*   CAHIER DES CHARGES :      
 +*  *********************      
 +*  On souhaite que l'essuie glace réalise le cycle suivant:
 +* - rotation droite jusqu'à atteindre le fin de course droit  
 +* - arrêt sur fin de course droit et démarrage en rotation gauche
 +* - rotation gauche jusqu'à atteindre le fin de course gauche  
 +* - arrêt sur fin de course gauche et démarrage en rotation droite
 +* etc ...
 +*  La structure de programme sera de type "boucle de scrutation"
 +*  On affichera à l'écran, dans quel état on est.
 +*-------------------------------------------------------------------------------------
 +*  NOM du FICHIER :  TP_Exemple 3.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éclaration des variables 
 +// Pour les Indicateurs divers (variables binaires)
 +union byte_bits Indicateurs,FC,FC_Mem; // 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 fins de course
 +#define Etat_FC FC.valeur // Pour l'ensemble des fins de course
 +#define fs FC.bit.b7 // Pour fin de surcourse
 +#define fcg FC.bit.b6 // Pour fin de course gauche
 +#define fcd FC.bit.b5 // Pour fin de course droit
 +#define Etat_FC_Mem FC_Mem.valeur // Pour la mémorisation des fins de courses
 +// Déclarations des diverses trames de communication
 +Trame Trame_Recue; // Pour la trame qui vient d'etre reçue par le controleur
 +#define Ident_Trame_Recue Trame_Recue.ident.extend.identificateur.ident
 +// Trmes de type "IM" (Input Message -> trame de commande)
 +Trame T_IM_Asservissement; // Pour la commande du moteur
 +Trame T_IRM_Acquisition_FC; // Pour l'acquisition de l'état des fins de courses EG
 +// Déclaration constantes
 +#define Module_Vitesse 100
 +
 +//======================
 +// FONCTION PRINCIPALE
 +//======================
 +main()
 +{
 +//  INITIALISATIONS
 +//------------------
 +// Déclaration de variables locales à la fonction principale
 +int Cptr_Affichage=0,Cptr_TimeOut;
 +
 +Init_Aton_CAN();
 +clsscr();
 +// 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; 
 +I_Message_Pb_Affiche=0;
 +do {Ecrire_Trame(T_IM_Asservissement); // C'est la première trame envoyée
 +   Cptr_TimeOut=0;
 + do{Cptr_TimeOut++;}while((Lire_Trame(&Trame_Recue)==0)&&(Cptr_TimeOut<2000));
 + if(Cptr_TimeOut==2000)
 + { gotoxy(2,12);
 +   printf(" Pas de reponse a la trame de commande en initialisation \n");
 +   printf(" Couper et/ou  remettre    alimentation 12 V  \n");
 +   do{}while(Lire_Trame(&Trame_Recue)==0); // On attend les trames  "On Bus"
 +              for(Cptr_TimeOut=0;Cptr_TimeOut<100000;Cptr_TimeOut++);
 +              Ecrire_Trame(T_IM_Commodo_EG);  // Renvoyer trame IM sur réseau CAN
 +   Cptr_TimeOut=0;
 +   do{Cptr_TimeOut++;}while((Lire_Trame(&Trame_Recue)==0)&&(Cptr_TimeOut<2000));
 +   if(Cptr_TimeOut==2000)
 + { gotoxy(2,12);
 +     printf(" Pas de reponse a la trame de commande en initialisation \n");
 +   printf("  Modifier le programme et recommencer  \n");
 +         do{}while(1); // On reste bloqué, on ne continue pas
 +
 + }
 +// 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 définir sortie GP3 en PWM2  
 +T_IM_Asservissement.data[0]=0x22; // Adresse du registre T2CON
 +T_IM_Asservissement.data[1]=0xB3; // Masque -> seuls bit 7;5;4;1;0 consernés
 +T_IM_Asservissement.data[2]=0x80; // Valeur ->  TMR2ON=1; Prescaler2=1
 +Ecrire_Trame(T_IM_Asservissement);
 +do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
 +// Pour définir fréquence signal sortie PWM2  
 +T_IM_Asservissement.data[0]=0x24; // Adresse du registre PR2
 +T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont consernés
 +T_IM_Asservissement.data[2]=0xFF; // Valeur ->  PR2=255
 +Ecrire_Trame(T_IM_Asservissement);
 +do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
 +// Pour initialiser rapport cyclique PWM1 
 +T_IM_Asservissement.data[0]=0x25; // Adresse du registre PWM1DC
 +T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont consernés
 +T_IM_Asservissement.data[2]=Module_Vitesse; // Valeur ->  PWM1DC 
 +Ecrire_Trame(T_IM_Asservissement);
 +do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
 +// Pour initialiser rapport cyclique PWM2 à 0
 +T_IM_Asservissement.data[0]=0x26; // Adresse du registre PWM2DC
 +T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont consernés
 +T_IM_Asservissement.data[2]=0; // Valeur ->  PWM2DC=0 
 +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 ->  ValidIP=1
 +Ecrire_Trame(T_IM_Asservissement);
 +do{}while(Lire_Trame(&Trame_Recue)==0); // Attendre réponse
 +// Masque pour les commandes IM futures
 +T_IM_Asservissement.data[1]=0xFF; // Masque -> tous les bits sont consernés
 +// Pour acquérir l'état des fin de course
 +// Trame de type "IRM" (trame interrogative): Données d'identification
 +T_IRM_Acquisition_FC.trame_info.registre=0x00;
 +T_IRM_Acquisition_FC.trame_info.champ.extend=1;
 +T_IRM_Acquisition_FC.trame_info.champ.dlc=1;
 +T_IRM_Acquisition_FC.trame_info.champ.rtr=1;
 +T_IRM_Acquisition_FC.ident.extend.identificateur.ident=Ident_T_IRM1_Asservissement;
 + Ecrire_Trame(T_IRM_Acquisition_FC); // Envoi trame pour acquérir états fins de course
 +do{}while(Lire_Trame(&Trame_Recue)==0); //On attend la réponse
 + Etat_FC=~Trame_Recue.data[0]; // On récupére l'état des fin de course
 + Etat_FC_Mem=Etat_FC; // On le mémorise
 +// Initialisation des variables diverses
 + I_Sens_Rotation=0;
 +
 +// Pour afficher titre
 +gotoxy(1,6);
 +printf(" ****************************************************************** \n");
 +printf("  TPs sur Reseau CAN  Application: Commande Essui-glace a distance  \n");
 +printf(" ------------------------------------------------------------------ \n");
 +printf("   TP Exemple n°3    Battement du BALAI D'ESSUI GLACE               \n");
 +printf(" ******************************************************************* \n");
 +
 +// BOUCLE PRINCIPALE
 +//*******************
 +while(1)
 + {
 + // Pour "Acquérir l'état des fins de course"
 + Ecrire_Trame(T_IRM_Acquisition_FC); // Envoi trame pour acquérir états fins de course
 + Cptr_TimeOut=0;
 + do{Cptr_TimeOut++;}while((Lire_Trame(&Trame_Recue)==0)&&(Cptr_TimeOut<10000));
 + if(Cptr_TimeOut==10000)
 + {clsscr(),gotoxy(2,10);
 + printf(" Pas de reponse a la trame interrogative pour fins de courses \n");
 + printf("  Il faut recharger et relancer le programme \n");
 + do{}while(1);} // Stop
 + else { if(Trame_Recue.ident.extend.identificateur.ident==Ident_T_IRM1_Asservissement)
 + // Si identificateur attendu
 + {Etat_FC=~Trame_Recue.data[0]; // On récupére l'état des fin de course
 + if(Etat_FC!=Etat_FC_Mem) // S'il y a eu une modification 
 + // de l'état des fin de courses -> on traite
 + {Etat_FC_Mem=Etat_FC; // Mémorisation du nouvel état
 +       // Traiter le changement de l'état
 + if(I_Sens_Rotation) // Si on tourne en négatif
 + {if(fcg) // Si on est arrivé en fin de course gauche
 + {T_IM_Asservissement.data[2]=0; // On arrête la rotation négative
 + T_IM_Asservissement.data[0]=0x26; // Adresse du registre PWM2DC
 + Ecrire_Trame(T_IM_Asservissement);
 + while(Lire_Trame(&Trame_Recue)==0){}; // On attend la réponse
 + T_IM_Asservissement.data[2]=Module_Vitesse; // On commande la rotation positive
 + T_IM_Asservissement.data[0]=0x25; // Adresse du registre PWM1DC
 +   Ecrire_Trame(T_IM_Asservissement);
 + while(Lire_Trame(&Trame_Recue)==0){}; // On attend la réponse
 + I_Sens_Rotation=!I_Sens_Rotation; // On change d'état  
 + }}
 + else {// On tourne en positif
 + if(fcd) // Si on est arrivé en fin de course droit
 + {T_IM_Asservissement.data[2]=0; // On arrête la rotation positive
 + T_IM_Asservissement.data[0]=0x25; // Adresse du registre PWM1DC
 + Ecrire_Trame(T_IM_Asservissement);
 + while(Lire_Trame(&Trame_Recue)==0){}; // On attend la réponse
 + T_IM_Asservissement.data[2]=Module_Vitesse; // On commande la rotation négative
 + T_IM_Asservissement.data[0]=0x26; // Adresse du registre PWM2DC
 +   Ecrire_Trame(T_IM_Asservissement);
 + while(Lire_Trame(&Trame_Recue)==0){}; // On attend la réponse
 + I_Sens_Rotation=!I_Sens_Rotation; // On change d'état  
 + }}
 + }}} // Fin "Traiter changement d'état"
 + } //  Fin boucle principale
 +} // Fin fonction principale
 +</code>
  
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0