pic16f628A, hitech et les timers...
Répondre à la discussion
Affichage des résultats 1 à 20 sur 20

pic16f628A, hitech et les timers...



  1. #1
    invite45724da5

    Unhappy pic16f628A, hitech et les timers...


    ------

    Hello

    Bon j'ai encore besoin de votre aide, ça fait un moment que je cherche mais je ne trouve pas le pourquoi du comment: j'utilise le timer0 et le timer2 pour générer une impulsion pour servo moteur sur RA1.

    Le timer0 a son prescaler à 16 (pour avoir une impulsion entre 0.5 et 2.5ms), le timer2 divise par 160 (10*16) avec PR2 à 124 pour avoir une impulsion toutes les 20ms (1µs*(124+1)*10*16=tpscycle*(P R2+1)*prescaler*postscaler=20m s).

    Donc le fonctionnement des ITs en rapide:
    si IT du timer2: RA1 = 1, chargement valeur dans TMR0 et T0IE activé pour l'impulsion
    si IT timer0: RA1 = 0, T0IE désactivé: fin de l'impulsion

    Mon code:
    Code:
    static void interrupt timer(void){
    	
    	if(TMR2IF){
    		
    		RA1 = 1;
    		
    		TMR0 = 256 - impulsion;
    		T0IE = 1;
    					
    		TMR2IF = 0;
    		}
    		
    	if(T0IF){
    	
    		RA1 = 0;
    		T0IE = 0;
    		
    		T0IF = 0;
    		}	
    }
    	
    void main(void){
    	
    	TRISA = 0b00100000; //RA5 en entrée
    	TRISB = 0b00000000;	// Tout le Port B en sortie
    	CMCON = 0x07;		// Désactivation module comparateur
    	PORTA = 0;			// Reset ports
    	PORTB = 0;
    	
    	OPTION = 0b00000011;//0b00000011; //Osc/4, prédisviseur = 16
    	GIE = 1;			// IT autorisées
    	T0IE = 0;			// IT du Timer0 non autorisées		
    	PEIE = 1;			// IT autorisées
    	TMR2IE = 1;             //iT timer2 activées
    	PR2 = 124;
    	TMR0 = 94;		
    	T2CON = 0b01001010;	// 0b01001010 prescaler = 10 (0b1001: 10-1)), postscaler = 16(0b1x): division par 16
    	TMR2ON = 1;			// IT du Timer2 autorisée
    		
    	
    	
    
    	while(1){
    		
    		if(!z){  //z=1 ici, donc condition fausse: saut
    			addat = readCAN();
    			addat = (addat*15)/32+35;	//ajustement pour les IT
    			impulsion = addat;		
    			addat = (addat*8)/5; 	//ajustement pour l'affichage
    			
    			}
    		//affichage7Seg(addat);   //affichage de la valeur sur aff 7seg ("désactivé" pour être sur que ça n'interfère pas)
    		
    		
    		}
    }
    après compil avec hitechpicc lite et prog avec winpic800, le signal n'est pas bon, mon servo (qui fonctionne correctement) va directement en butée (et force). Et je n'ai pas d'oscillo pour voir, cependant avec une led en sortie elle s'allume légèrement.

    Voila là je vois vraiment pas ce qu'il ne va pas!! (si ça continu je vais encore tout casser ça m'énerve... )

    Merci d'avance pour votre aide précieuse

    crdlt,
    Benj

    -----

  2. #2
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    Et puis Joyeux noël à tous...

  3. #3
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Bonsoir,

    la gestion des interruptions pose problème.
    On n'active pas une interruption dans une interruption.

    Code:
    if(TMR2IF){
    		
    		RA1 = 1;
    		
    		TMR0 = 256 - impulsion;
    		T0IE = 1;					
    		TMR2IF = 0;
    		}
    		
    	if(T0IF){
    	
    		RA1 = 0;
    		T0IE = 0;
    		
    		T0IF = 0;
    		}

  4. #4
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Une solution consiste à utiliser une variable (flag) qui sera modifiée dans l'interruption et prise en compte dans le main().
    Attention cette variable doit obligatoirement être déclarée avec le préfixe volatile.

    Ensuite dans le while(1) tu détectes si ce flag est actif et tu fais ce qui doit être fait en n'oubliant pas de remettre ce flag à 0 en sortant.

    Et joyeux Noël à toi aussi.

    @+

  5. A voir en vidéo sur Futura
  6. #5
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    Ah d'accord... dommage j'aurais une petite perte de précision suivant où je suis dans mon programme à l'interruption!

    je met donc bien "volatile int flagTMR0 = 0;" par exemple?
    Ça apporte quoi?

    En fait il va me falloir 2 flags, vu qu'il faut que je détecte quand est-ce que je dois mettre T0IE à 1 et à 0!

    Si je remplace T0IE dans l'IT par une variable "flagTMR0"(avec le volatile) et que dans le while je met "T0IE = flagTMR0;", ben ça marche pas... il va en butée directement comme avant.

    Je vais revérifier les réglages puis je verrais.

    Merci de ton aide!
    Benj

  7. #6
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    Me revoila!
    J'espère que noël s'est bien passé pour tout le monde avec plein de cadeaux (si vous avez été sage ) , moi impec j'ai même eu le temps de me repencher sur mon montage:
    Le code suivant fonctionne, même en activant le timer0 dans l'IT! (alors HULK ? )
    J'ai juste désactivé le prédiviseur (PSA = 1)

    Code:
    static void interrupt timer(void){
    	
    	if(TMR2IF){
    		
    		RA1 = 1;
    		
    		TMR0 = 256 - impulsion;
    		T0IE = 1;
    					
    		TMR2IF = 0;
    		}
    		
    	if(T0IF){
    	
    		countimp++;
    		if(countimp == 10){
    		      RA1 = 0;
    		      T0IE = 0;
    		      countimp = 0;
    		}else{
    			TMR0 = 256 - impulsion;
    			}
    		
    		T0IF = 0;
    		}	
    }
    	
    void main(void){
    	
    
    	
    	TRISA = 0b00100000; //RA5 en entrée
    	TRISB = 0b00000000;	// Tout le Port B en sortie
    	CMCON = 0x07;		// Désactivation module comparateur
    	PORTA = 0;			// Reset ports
    	PORTB = 0;
    	
    	OPTION = 0b00001011;//pas de prédiv!
    	GIE = 1;			// IT autorisées
    	T0IE = 0;			// IT du Timer0 non autorisées		
    	PEIE = 1;			// IT autorisées
    	TMR2IE = 1;
    	PR2 = 124;
    	TMR0 = 128;		
    	T2CON = 0b01001010;	// 0b01001010 prescaler = 10 (0b1001: 10-1)), postscaler = 1(0b00): divison par 10
    	TMR2ON = 1;			// IT du Timer2 autorisée
    		
    	
    	
    
    	while(1){
    		
    		if(z == 0){
    			addat = readCAN();
    			addat = (addat*15)/32+35;	//ajustement pour les IT
    			
    			impulsion = addat;		
    			addat = (addat*8)/5; 	//ajustement pour l'affichage
    			
    			}
    		affichage7Seg(addat);
    		
    		
    		}
    }
    Par contre si j'active juste le prédiviseur du timer0 (PSA=0)( à 16 ici, mais peu importe), le servo part en butée. Je vois pas d'où ça peut venir, le prédiviseur du timer0 est partagé uniquement avec le watchdog qui n'est pas utilisé, et mes calculs sont corrects!!

    Help!

    merci
    @+
    Benj

  8. #7
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Citation Envoyé par MofK Voir le message
    Le code suivant fonctionne, même en activant le timer0 dans l'IT! (alors HULK ? )
    Ben alors continu à faire comme ça.

  9. #8
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    j'aurais préféré que tu me dises ce qu'il ne va pas...
    mais bon moi non plus je trouve pas... je vais devoir me passer du prédiviseur je crois bien!

  10. #9
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Moi je veux bien mais tu n'écoutes pas mes conseils.

    Je vois plusieurs choses qui ne vont pas trop, comme par exemple la variable "impulsion" qui n'est pas initialisée, que représente z un BP?

    Donc si ce BP n'est pas activé "impulsion" n'a pas de valeur préfixée lorsque tu entres dans l'interruption:

    TMR0 = 256 - impulsion;

    Je vais regarder à quoi correspondent les valeurs que tu as rentré pour les Timers.

    @+

  11. #10
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    Mais si j'écoute mais mon truc marche (j'ai testé les 2!) aussi et c'est plus simple...
    Si, "impulsion" est initialisé (et à la bonne valeur), mais le code n'est pas là car ya plein de trucs entre encore... "char impulsion = 94;"

    z est une variable qui sert pour l'affichage, lorsqu'elle vaut zéro on est dans un nouveau cycle d'affichage, donc nouvelle valeur à afficher, donc lecture du CAN. Ca évite de perdre du temps et saccader l'affichage.

    Je vais encore regarder ça de plus près...

    merci
    @+
    Benj

  12. #11
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    A priori je vois une erreur dans le contenu du registre OPTION:

    Tu mets: OPTION = 0b00001011;

    tu as mis PSA à 1 donc le prescaler (1:8) est attribué au watchdog.

    Il faut écrire:

    OPTION = 0b00000011;

    Ainsi tu as un prescaler de 1:16 attribué au timer.
    @+

  13. #12
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    J'attends que tu es fini de chercher, et ensuite je te dirai comment faire normalement.

  14. #13
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    Ok pour le prescaler, mais là je l'avais désactivé pour justement ne pas prédiviser, et incrémenter ttes les µs. Si je met OPTION = 0b00000011; en modifiant

    if(T0IF){
    RA1 = 0;
    T0IE = 0;

    T0IF = 0;
    }

    ben le servo part en butée... comme si le temps haut était trop court.
    Pourtant 1µs*16*94=1504µs= 1.5ms...

    Faire normalement??

  15. #14
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Faire normalement c'est prendre le problème par le bon bout.

    Il faut utiliser les ressources du PIC, utiliser des timers c'est bien mais utiliser le module CCPx associé avec le timer1 c'est mieux, on gagne 1 timer.

    Voyons dans un premier temps le cahier des charges qui doit permettre d'activer un servo de gauche à droite.

    Les données:
    On prend un quartz de 4MHz pour l'exemple.

    1/ La période doit être de 20ms maximum durant laquelle un pulse variable doit être généré pour réaliser une commande dite en largeur d'impulsion.
    Ce pulse doit calibré selon la position à obtenir:

    -> 1,5ms -> position centrale
    -> 1ms -> -90°
    -> 2ms -> +90°

    On va utiliser les interruptions CCP1IF pour produire le rapport cyclique variable, et TMR1IF pour générer la période de 20mS.

    CCPR1 contiendra la valeur pour générer un rapport cyclique en fonction de la position du servo choisie, c'est donc ce contenu qui va varier en fonction de la variable "impulsion" qui sera récupérée de readCAN().

    CCP1CON est le registre de contrôle de CCP1, on le règle avec 0b00001010 pour seulement utiliser l'interruption CCPxIF qui permettra d'activer la sortie de notre choix.

    T1CON est le registre de contrôle du Timer1, on va y inscrire la valeur qui va nous permettre de fixer le pas d'incrémentation du compteur.

    Avec un quartz de 4MHz on a un temps de base (tick) de 1µs (4/Fosc), le timer1 en mode 16 bits déborde naturellement tous les 65536 ticks (65536µs), il n'est donc pas nécessaire de prédiviser pour obtenir une période de 20ms (20000µs).

    Nous devons donc pré-charger le Timer1 d'une valeur d'offset pour obtenir une période exact de 20ms:

    65535-20000=45535 => soit 0xB1DF en Hexa

    TMR1H=0xB1
    TMR1L=0xDF

    Calcul de CCPR1 pour obtenir le rapport cyclique pour servo à -90°:

    rapport cyclique 1mS: 1000µs/1µs=1000 donc 45535+1000= 46535 -> en hexa 0xB5C7.
    => CCPR1H=0xB5; CCPR1L=0xC7;

    Calcul de CCPR1 pour obtenir le rapport cyclique pour servo à 0° (centre):
    rapport cyclique 1,5mS: 1500µs/1µs=1500 donc 45535+1500= 47035, en hexa 0xB7BB.
    => CCPR1H=0xB7; CCPR1L=0xBB;

    Calcul de CCPR1 pour obtenir le rapport cyclique pour servo à +90°:
    rapport cyclique 2mS: 2000µs/1µs=2000 donc 45535+2000= 47535, en hexa 0xB9AF.
    => CCPR1H=0xB9; CCPR1L=0xAF;

    Bon maintenant on a tout, il ne faut pas oublier de configurer T1CON:

    TMR1CS=0 (internal clock)
    T1CKPS1~T1CKPS0=00 (prediv=1:1)
    Soit T1CON=0;

    Nous allons voir ensuite comment intégrer tout ça dans un programme fonctionnel.
    @+

  16. #15
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Le registre CCP1CON va être configuré pour permettre la comparaison de CCPR1 avec le contenu de Timer1, afin de pouvoir activer n'importe quelle sortie nous allons uniquement détecter le flag CCP1IF qui rend compte du "match" des 2 registres comparés.
    Pour cela nous avons à configurer les 4 bits de poids faible de CCP1CON -> CCP1M3~CCP1M0=1010

    Soit:
    CCP1CON=0b00001010;

    Nous voulons que la sortie RA1 soit activé donc il faut initialiser les sortie du portA en digital et désactiver les comparateurs.

    Soit:

    CMCON=0x07;

    Au besoin configurer ADCON1 en digital si le PIC possède des A/D.
    TRISA=0 -> tout en sortie.

    Le programme gérant cette première étape:

    La gestion des interruptions:

    Code:
    //==============================================================================
    //                         Traitement des interruptions
    //==============================================================================
    
    static void interrupt inter(void)
    
    {
    if(TMR1IF) // traite l'interruption générée par le débordement de TMR1
    	    {
    	    RA1=1;   // Sortie activée 			      
    	    TMR1H=0xB1; TMR1L=0xDF;	// On recharge Timer1 avec l'offset pour avoir T=20ms
    	    TMR1IF=0; // on efface le flag		
    	    }
    
    	if(CCP1IF) // traite l'interruption du résultat de comparaison
    	    {		  		
    	    RA1=0;   // La sortie est désactivée 	
    	    CCP1IF=0; // on efface le flag
    	    }
    
    }
    Remarque: Aucune interruption n'est validée ou dévalidée durant ce traitement, les instructions y sont courtes.

    On initialise le PIC:

    Code:
    void init_pic (void)
    {   
        ADCON1= 6 ;	      // port A digital (-> inutile pour le PIC16F628A)
        CMCON=0x07;    // Comparateurs off
        TRISA = 0 ;	      // Config port A en sortie
           
        CCP1CON = 0b00001010 ;  // compare mode CCP1
        
        T1CON = 0b00000001 ;    //Prescaler=1:1 Timer1=on
    
        CCP1IE = 1 ;	// Interupt mode compare CCPx enable
        TMR1IE = 1 ;	// Interupt Timer1 enable
        GIE = 1;	// global interrupt enable
        PEIE = 1 ;
        T1CON = 0b00000001 ;    //Prescaler=1:1 Timer1=on
    
    }
    A suivre.

  17. #16
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    Voici le prog dans son entier:

    Code:
    #define   SERVO_G        0xB5C7
    #define   SERVO_CENTRE   0xB7BB
    #define   SERVO_D        0xB9AF
    
    // Déclaration des prototypes des fonctions
    
    void init_pic (void);
    void Config_rapport_cyclique(unsigned int impulsion);
    
    
    //==============================================================================
    //                         Traitement des interruptions
    //==============================================================================
    
    static void interrupt inter(void)
    
    {
    if(TMR1IF) // traite l'interruption générée par le débordement de TMR1
    	    {
    	    RA1=1;   // Sortie activée 			      
    	    TMR1H=0xB1; TMR1L=0xDF;	// On recharge Timer1 avec l'offset pour avoir T=20ms
    	    TMR1IF=0; // on efface le flag		
    	    }
    
    	if(CCP1IF) // traite l'interruption du résultat de comparaison
    	    {		  		
    	    RA1=0;   // La sortie est désactivée 	
    	    CCP1IF=0; // on efface le flag
    	    }
    
    }
    
    void Config_rapport_cyclique(unsigned int impulsion)
    {	
    unsigned int new_impulsion;
    
    new_impulsion = 0xB1DF + impulsion ;
    CCPR1L=new_impulsion; 
    CCPR1H=new_impulsion>>8;	
    }
    
    
    void init_pic (void)
    {   
        ADCON1= 6 ;	  // port A digital (-> inutile pour le PIC16F628A)
        CMCON=0x07;   // Comparateurs off
        TRISA = 0 ;	  // Config port A en sortie
           
        CCP1CON = 0b00001010 ;  // compare mode CCP1
        
        T1CON = 0b00000001 ;    //Prescaler=1:1 Timer1=on
        TMR1H=0xB1;
        TMR1L=0xDF;
        CCP1IE = 1 ;	// Interupt mode compare CCPx enable
        TMR1IE = 1 ;	// Interupt Timer1 enable
        GIE = 1;	// global interrupt enable
        PEIE = 1 ;
        T1CON = 0b00000001 ;    //Prescaler=1:1 Timer1=on
    
    }
    
    void main(void)
    {
    init_pic();
    Config_rapport_cyclique(SERVO_CENTRE);
    
    while(1)
    {
    ................ // on modifie et récupère ici la nouvelle valeur de "impulsion" 
    Config_rapport_cyclique(impulsion);
    }
    Je remarque que dans ton code précédent tu utilisais readCan() or le PIC16F628 ne possède pas d'ADC.

    @+

  18. #17
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    woaw chapeau!!
    Je savais pas trop comment m'en servir mais là c'est bon je suis blindé!!
    Moi j'irai de 0.5ms à 2.5ms, certains servos ont plus de débattement.

    par contre je vois pas comment on arrive à avoir une plage de 1ms (1ms <=> 2ms) avec ce code:
    Code:
    void Config_rapport_cyclique(unsigned int impulsion)
    {	
    unsigned int new_impulsion;
    
    new_impulsion = 0xB1DF + impulsion ;
    CCPR1L=new_impulsion; 
    CCPR1H=new_impulsion>>8;	
    }
    impulsion varie de 0 à 256, donc on arrive pas aux valeurs extrêmes qui on été calculées?!?
    et une variable int est sur 8 bits? je croyais que c'était 1 bit... on en apprend tous les jours!!


    Pour le readCAN() j'utilise un convertisseur externe 8bits (TLC549)...

    et merci pour cette super explication!! (et pour la suite... )
    je vais essayer.
    @+
    Benj

  19. #18
    invite45724da5

    Re : pic16f628A, hitech et les timers...

    ah non je confond int et bit... autant pour moi.

  20. #19
    invite5637435c

    Re : pic16f628A, hitech et les timers...

    8 bits = 1 BYTE = 1 octet

    int -> 2 octets

    Selon la valeur de "impulsion", il faudra peut-être réaliser une mise à l'échelle pour avoir un débattement maximum.

    Du genre scale=x*AdcRead()/y avec x et y à fixer par des #define.
    @+

  21. #20
    invite45724da5

    Re : pic16f628A, timers: signal pour servomoteur modelisme [résolu]

    Génial ça marche du tonnerre!!!
    Bravo et merci!
    j'ai changé un peu le code sur cette partie:
    Code:
    //===============================================
    //========== Config du rapport cyclique =========
    //====================================
    
    void Config_rapport_cyclique(unsigned int impulsion){
    	
    	CCPR1L = impulsion; 
    	CCPR1H = impulsion >> 8;	
    }
    
    
    
    //=======================================
    //========= Programme principal =========
    //=======================================
    	
    void main(void){
    		
    	init_pic();
    	Config_rapport_cyclique(SERVO_CENTRE);
    	
    
    	while(1){
    		
    		if(z == 0){ //z == 0 
    			addat = readCAN();
    			addattemp = (addat*125)/16+45885;	//ajustement pour l'impulsion: [0.35ms;2.5ms]
    			impulsion = addattemp;		
    			addat = (addat*43)/51+35; 	//ajustement pour l'affichage: [35;250]
    			
    			}
    		Config_rapport_cyclique(impulsion);  //maj de l'impulsion
    		
    		affichage7Seg(addat); //affichage de addat sur les 3 segments
    		
    		
    		}
    }
    Ensuite je verrai dans mon lycée pour le calibrage, avec un oscillo.
    Je vais quand même de 0.35ms à 2.5ms pour avoir le débattement max sur mon servo!!
    Il me reste encore la mesure d'impulsion à faire et mon montage sera fini!! (avc typon et tout...) Je reviendrais si j'ai des problèmes!

    Merci encore à toi Hulk.
    @+
    Benj

Discussions similaires

  1. Les timers sur 16f628
    Par invite45724da5 dans le forum Électronique
    Réponses: 2
    Dernier message: 25/11/2008, 18h39
  2. timers sur AVR
    Par inviteeddea82a dans le forum Électronique
    Réponses: 1
    Dernier message: 03/10/2007, 19h37
  3. Problème avec MPlab et Hitech PICC18
    Par invite36ee2dcb dans le forum Électronique
    Réponses: 3
    Dernier message: 07/03/2007, 21h15
  4. besoin d'aide sur la programmation des TIMERs du PIC svp !!!
    Par invite17e62166 dans le forum Électronique
    Réponses: 6
    Dernier message: 03/04/2006, 00h24
  5. Comment les gènes interragissent-ils les uns avec les autres ?
    Par invitef31b56f9 dans le forum Biologie
    Réponses: 19
    Dernier message: 26/02/2005, 11h48
Dans la rubrique Tech de Futura, découvrez nos comparatifs produits sur l'informatique et les technologies : imprimantes laser couleur, casques audio, chaises gamer...