Table of Contents

Exemple 3 (TP3)

Sujet:

Faire battre le balai de l'essuie-glace

Objectifs :

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:

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:

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).

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é

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”

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

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)

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) 

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:

→ Définition de variables structurées sous le modèle “Trame”:

Trame T_IRM_Acquisition_FC; 	 // Trame destinée à l’interrogation du module asservissement pour acquérir Fins de Courses.

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

  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; 

Suite à ces définitions, il faudra

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;

#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

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é

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

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:

Programme en "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