;choisir Tab Size = 10 dans les options de l'éditeur de MPLAB IDE ;pour obtenir un alignement correct du listing ; ;si vous visualisez avec Wordpad, vous aurez des soucis d'alignement... ;choisissez dans les options de Wordpad "pas de retour à la ligne" ;sinon les longues lignes de commentaires seront tronquées ;et passeront dans les colonnes étiquettes et code ;********************************************************************** ; ; ; ;LISTE DES PRINCIPALES PROCEDURES: (Double-clic sur 1 mot puis F3 dans MPLAB, c'est pratique...) ;TESTS ;MACROS ;mot16A macro ;charge AH et AL avec le mot codé sur 16 bits transmis ;mot16B macro ;charge BH et BL avec le mot codé sur 16 bits transmis ;Changements de banques ;R_EEPROM ;W_EEPROM ;CONSTANTES ;VARIABLES_EN_BANQUE0 ;INITIALISATION DES PORTS ;PROGRAMMATION DU REGISTRE OPTION (BANK1) ;PROG DU REGISTRE INTCON (BANK0) ;PROG DU REGISTRE T1CON (BANK0) ;PROG DU REGISTRE T2CON (BANK0) ;PROG DU REGISTRE PR2 (BANK1) ;PROG DU REGISTRE PIE1 (BANK1) ;Initialisation_des_variables ;BOUCLE_PRINCIPALE ;inttimer0 -> le Timer0 est utilisé au sein de l'INT portB0 (voir plus bas) pour mesurer la durée PPM voie GAZ ;inttimer1 -> le Timer1 est utilisé dans l'INT portB4-7 (voir plus bas) pour mesurer la durée PPM voie ANTI-COUPLE ;inttimer2 -> generation du signal de sortie ;intB0 ;intB5 ;convhbin ;conversion sexadécimale -> binaire ;entrée: AA, BB ;resultat: AH,AL = 60*AA+BB ;multi ;mutiplication 8 bits x 8 bits de AA par w (données sur 1 octet) ;resultat (sur 2 octets) dans AH,AL ;divi2 ;division d'une valeur codée sur 16 bits (AH,AL) par 2 ;divi60 ;division d'une valeur codée sur 16 bits (AH,AL) par 60 ;résultat dans w ;reste de la division dans (BH,BL) ;add16A ;addition 16bits résultat dans A ;(AH,AL)+(BH,BL) -> (AH,AL) ;add16B ;addition 16bits résultat dans B ;(AH,AL)+(BH,BL) -> (BH,BL) ;cpl16x ;complément à deux de la variable codée sur 2 octets situés aux adresses w et w+1 permet les soustractions ;compa16p ;comparaison de deux valeurs codées sur 16 bits (AH,AL à BH,BL) ;resultat dans STATUS carry et zéro ;movxA ;mov la variable codée sur 2 octets situés aux adresses w et w+1 dans -> AH,AL ;movAx ;mov AH,AL dans -> la variable codée sur 2 octets situés aux adresses w et w+1 ;movxB ;mov la variable codée sur 2 octets situés aux adresses w et w+1 dans -> BH,BL ;movBx ;mov BH,BL dans -> la variable codée sur 2 octets situés aux adresses w et w+1 ;procédures d'affichage LCD ;cvBDU ;CONVERSION BINAIRE(1) (1 octet incomplet 0..99 et pas 0..255) --> BCD ;nombre à convertir dans AA ;cvBCU ;CONVERSION BINAIRE(2) (1 octet complet 0..255) --> BCD ;resultat dans BB (centaines) et dans AA (unités) ;tp154us ;tp1ms ;tp2ms ;tp10ms ;tp100ms ;vari_vit ;TABLEAUX ; ; ; ;pour Qx=20,000 Mhz ; ; ; ; ;*********************************************************************************************** ; VARIATEUR pour moteur DC (pour hélico Piccolo) : variat2_05.asm ; pour PIC16F628 ; par Silicium 628 ;************************************************************************************************ ;dernière mise à jour: 29/05/2005 ;remarque: suite aux modifications (=améliorations!) certains commentaires peuvent se révéler faux !!! ;j'en suis désolé. Je relis régulièrement les commentaires et essaye de les tenir à jour. ;toutefois il m'arrive de trouver des énormités ! que je corrige... ;------------------------------------------------------------------------------------------------ ;*********************************************** PRINCIPE ***************************************** ;int Extérieure par bit 0 du port B sert à detecter les fronts du signal PPM du récepteur de radio-commande ;on en déduit sa durée (1 à 2,2 ms) ;******************************** REMARQUES GENERALES ********************************************* ;représentation d'un nombre hexadécimal: commence par "0x" ex: 0x20 ;représentation d'un nombre décimal: commence par "." ex: .20 ; ex: 0x20 = .32 ; B'00010000' represente une valeur binaire ;Utiliser une version récente de MPLAB afin que le PIC16F628 soit pris en compte (ma version= 5.70.00 ) ;voir sur le site de Microchip(R): http://www.microchip.com ;*************************************************************************************************** ;---------------------------------------------------------------------- list p=16f628 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _LVP_OFF ; '__CONFIG' précise les paramètres encodés dans le processeur au moment de ; la programmation du processeur. Les définitions sont dans le fichier include. ; Voici les valeurs et leurs définitions : ; _CP_ON Code protection ON : impossible de relire ; _CP_OFF Code protection OFF ; _PWRTE_ON Timer reset sur power on en service ; _PWRTE_OFF Timer reset hors-service ; _WDT_ON Watch-dog en service ; _WDT_OFF Watch-dog hors service ; _LP_OSC Oscillateur quartz basse vitesse (32 Bank 0, 1 (00h - FFh) ;=1 -> Bank 2, 3 (100h - 1FFh) BANK0 ;pour l'adressage direct ;*********************************************************************** ;ZONE de TESTS de procédures ; mot16B .61000 ; movlw .335 ; call divi16_8 ; nop ; movlw .200 ; movwf rapcyc2 ;G ;la movlw .255 ; movwf BB ;mancheAC ; call calc_AC ; movlw .10 ; addwf rapcyc2,f ; goto la ;*********************************************************************** call tp100ms clrwdt ;*********************************************************************** ; INITIALISATION DES PORTS ;*********************************************************************** ;RA0=entrée: signal du capteur magnétique (détection de la phase du rotor) ;RA1=entrée: signal en provenance du circuit de détection de vitesse faible ou nulle suite à décrochage du moteur ;RA2=entrée: détection tension alim faible ( "BEC" ) ;RA3=sortie: LED alim faible ;RA3= ;RB0=entrée: signal PPM du récepteur de radio-commande, voie 'gaz' ;RB1= ;RB2=sortie: commande MOSFET canal N ;RB3= ;RB4= ;RB5=s ;RB6=s ;RB7= BANK0 movlw 0x07 movwf CMCON ; PORT A en E/S numériques (BANK0) BANK1 movlw B'00000000' ;0=sortie 1=entree attention RA4 =drain ouvert movwf TRISA ;config du port A (TRISA en page 1) movlw B'00101001' movwf TRISB ;config du port B bcf OPTION_REG,7 ;Enable PORTB pull-ups ;---------------------------------------------------------------------- ;PROGRAMMATION DU REGISTRE OPTION (BANK1) - voir datasheet p:20 du datasheet PIC16F62X.pdf ;bit7: RBPU =0 -> R tirage à Vdd du port B ;bit6: INTEDG=1 -> INT sur front montant ou descendant de RB0 ; 1 = Interrupt on rising edge of RB0/INT pin ; 0 = Interrupt on falling edge of RB0/INT pin ;bit5: T0CS = 0 -> TMR0 Clock Source Select bit ; 1 = Transition on RA4/T0CKI pin (Fonctionnement en mode compteur) ; 0 = Internal instruction cycle clock (CLKOUT) (Fonctionnement en mode timer) ;bit4: RTE = 0 -> inc sur front montant ;bti3: PSA = 0 -> prédiv affecté au timer0 ;bits2,1,0:PS2,1,0 ;Bit Value TMR0 Rate WDT Rate ;000 1 : 2 1 : 1 ;001 1 : 4 1 : 2 ;010 1 : 8 1 : 4 ;011 1 : 16 1 : 8 ;100 1 : 32 1 : 16 ;101 1 : 64 1 : 32 ***** ICI 100b -> Timer0 = 1/64 ***** ;110 1 : 128 1 : 64 ;111 1 : 256 1 : 128 BANK1 ; nº bits: '76543210' movlw B'01000101' movwf OPTION_REG ;---------------------------------------------------------------------- ;PROG DU REGISTRE INTCON (BANK0) - voir datasheet p:21 ;bit7 GIE =0 -> INT GLOBALE interdite. (voir + bas) ;bit6 PEIE=1 -> INT PERIPHERIQUES autorisées. (timer1 en fait partie) ;bit5 T0IE=0 -> INT par debordement Timer0 autorisée. ;bit4 INTE=0 -> INT de RB0/INT autorisées (INTERRUPTIONS EXTERNES) ;bit3 RBIE=1 -> INT du port RB4 à RB7 autorisées. ;bit2 T0IF=x (flag mis à 1 par débordement du Timer0) ;bit1 INTF=x (flag mis à 1 par une INT provoquée par la libne RB0/INT du port B) ;bit0 RBIF=x (flag mis à 1 si changement d'état des entrées RB4 à RB7 du port B. attention RB1 à RB3 -> pas d'INT) BANK0 ; nº bits: '76543210' movlw B'01111000' movwf INTCON ;---------------------------------------------------------------------- ;PROG DU REGISTRE T1CON (BANK0) ;bit7 : Inutilisé : lu comme « 0 » ;bit6 : Inutilisé : lu comme « 0 » ;bit5 : T1CKPS1 : Timer 1 oscillator ClocK Prescale Select bit 1 ;bit4 ; T1CKPS0 : Timer 1 oscillator ClocK Prescale Select bit 0 ;bit3 : T1OSCEN : Timer 1 OSCillator ENable control bit (oscillateur interne) ;bit2 : T1SYNC : Timer 1 external clock input SYNChronisation control bit ;bit1 : TMR1CS : TiMeR 1 Clock Source select bit (0=internal clock) ;bit0 : TMR1ON : TiMeR 1 ON bit BANK0 ; nº bits: '76543210' movlw B'00110001' ;prescale Timer1=1/8 movwf T1CON ;---------------------------------------------------------------------- ;PROG DU REGISTRE T2CON (BANK0) ;bit 7: Unimplemented: Read as '0' ;bit 6-3: TOUTPS3:TOUTPS0: Timer2 Output Postscale Select bits ;0000 = 1:1 Postscale ;0001 = 1:2 Postscale ;0010 = 1:3 Postscale ;0011 = 1:4 Postscale ;0100 = 1:5 Postscale etc... (valeur binaire +1) ;1111 = 1:16 Postscale ;bit 2: TMR2ON: Timer2 On bit =1 : Timer2 is on ;bit 1-0: T2CKPS1:T2CKPS0: Timer2 Clock Prescale Select bits ;00 = Prescaler = 1 ;01 = Prescaler = 4 ;1x = Prescaler = 16 (valeur choisie ici) BANK0 ; nº bits: '76543210' movlw B'00000110' movwf T2CON ;---------------------------------------------------------------------- ;PROG DU REGISTRE PR2 (BANK1) ;utilisé par timer2 BANK1 movlw .64 movwf PR2 ;---------------------------------------------------------------------- ;PROG DU REGISTRE PIE1 (BANK1) ;bit7 : PSPIE b7 : Toujours 0 sur PIC 16F876 ;bit6 : ADIE : masque int convertisseur A/D ;bit5 : RCIE : masque int réception USART ;bit4 : TXIE : masque int transmission USART ;bit3 : SSPIE : masque int port série synchrone ;bit2 : CCP1IE: masque int CCP1 ;bit1 : TMR2IE: masque int TMR2 = PR2 ;bit0 : TMR1IE: masque int débordement tmr1 BANK1 ; nº bits: '76543210' movlw B'00000011' ;enable INT TIMER1 - enable INT TIMER2 - disable int réception USART (port série) movwf PIE1 ;---------------------------------------------------------------------- ;Initialisation_des_variables initvar clrwdt BANK0 movlw B'00000001' ;STOP moteur ! movwf mesflags clrf count2 clrf DDD movlw .200 movwf TMR0 clrf TMR1L clrf TMR1H movlw .128 movwf TMR2 movlw .5 movwf T_PPM_G movlw .128 movwf T_PPM_A movlw .1 movwf rapcyc1 movwf rapcyc2 bsf INTCON, GIE ;->INT GLOBALE autorisée ;----------------------------------------------------------------------- ; clrwdt ;RAZ LCD ; call dspclr ; call home ; call fset ; call setmod0 ; call dsp10 ; movlw "V" ; call ecrire ; movlw "a" ; call ecrire ; movlw "r" ; call ecrire ; movlw "i" ; call ecrire ; movlw "a" ; call ecrire ; movlw "t" ; call ecrire ; call tp100ms ;------------------------------------------------------------------------------------------------------------------ ;BOUCLE_PRINCIPALE boucle1 BANK0 call tp10ms ;DETERMINE LA VITESSE DE REPONSE ; btfss PORTB,3 ; call ecrireEE ;pour test uniquement ;CES AFFICHAGES SONT DESTINES A UN AFFICHEUR LCD INTERFACE SUR LE PORT A ;pour la phase de mise au point uniquement. (Ralentit la réponse globale) ; movlw 00h ;affiche en ligne1 du LCD ; call ddras ; movf rapcyc2,w ; call affiw ; movlw 40h ;affiche en ligne2 du LCD ; call ddras ; comf rapcyc1,w ; call affiw ;------------------------------------------------------------------------------------------------------------------ ;ajustement du rapport cyclique en fonction du signal ' VOIE GAZ' ;T_PPM est calculé dans la procédure durée du signal PPM VOIE GAZ ;(T_PPM = 84..173 avec un Qx=20MHz) ;arret moteur en dessous d'une valeur palier movlw .88 ;valeur de T_PPM au dessous de laquelle on va stopper le moteur subwf T_PPM_G,w ;w:= T_PPM - 88 (result -> w : ne touche pas à T_PPM) btfsc STATUS,0 ;c=0 ? (c=0 si f < 5 ) goto test2 bsf mesflags,0 ;oui: ARRET D'URGENCE (si manche + trim gaz au mini) goto tppm1 test2 movlw .5 ;valeur de rapcyc2 au dessous de laquelle on va stopper le moteur subwf rapcyc2,w ;w:= rapcyc2 - 5 (result -> w : ne touche pas à rapcyc2) btfss STATUS,0 ;c=0 ? (c=0 si f < 5 ) goto stop ;oui goto go ;non stop bsf mesflags,0 ;oui: STOP ; clrf butcyc2 ; clrf rapcyc2 goto tppm1 go btfsc STATUS,0 ;même question bcf mesflags,0 ;non: pas STOP ;calcul du rapport cyclique tppm1 movf T_PPM_G,w movwf memo1 movlw .84 ; T_PPM_G mini CETTE VALEUR EST A AJUSTER EN FONCTION DE VOTRE RADIO subwf memo1,f ; T_PPM_G:= T_PPM_G - 84 (pré-ofset) btfss STATUS,0 ;débordement ? clrf memo1 ;oui rlf memo1,w ; w:= 2 x T_PPM_G addwf memo1,w ; w:= 3 x T_PPM_G btfsc STATUS,0 ;débordement ? (résult > 255 ?) movlw .253 ;oui, butée haute movwf butcyc2 ;calibrage final movlw .253 ;valeur max de rapcycl admissible (attention: si > 253 -> int Timer2 = HS) ;avec prediv =1/16 (voir T2CON) subwf butcyc2,w ;w:= rapcycl - 240 (result -> w : ne touche pas à rapcycl) d=f-w btfss STATUS,0 ;c=0 ? rapcycl < 240 ? (c=0 si w > f ) goto fincal ;oui movlw .253 ;non alors on bloque à butée max movwf butcyc2 fincal nop ;progressivité de la réponse (pour éviter de casser les dents de la roue dentée en plastique sur l'arbre rotor) ;on fait tendre progressivement rapcyc2 vers butcycl2 ;------------------------------- rapvari movf rapcyc2,w subwf butcyc2,w btfsc STATUS,2 ;z goto finrapv btfss STATUS,0 ;c goto moins goto plus moins decf rapcyc2,f ; movlw .2 ; call tx10ms ;décroissance lente goto finrapv plus incf rapcyc2,f finrapv nop ;------------------------------------------------------------------------------------------------------------------ ;ajustement du rapport cyclique en fonction du signal ' voie ANTI-COUPLE' ;T_PPM est calculé dans la procédure durée du signal PPM voie ANTI-COUPLE ;========================================= ;RAPPEL: ;les valeurs du rapport cycliques sont codées sur un octet ;le rapport cyclique varie entre 0% et 100% c.a.d. en analogique [0..1] ce qu'on code ici sur un octet [0..255] ;il y a donc 256 pas possibles ;VOICI LE MIXAGE UTILISE: ;AC=(G*G/256 * Manche_AC /170 + G)/2 qui s'annule pour GAZ=0 mais pas pour AC=0 ;ou son équivalent qui évite 1 débordement: ;AC=G*G/256/2*Manche_AC/170 + G/2 ;cette courbe du second degré (gaz " au carré") a été déterminé empiriquement ;Les calculs se font sur deux octets mais les résultats sont réencodés sur un octet ;========================================= ;calcul du signal voie ANTI-COUPLE tppm2 movf T_PPM_A,w ;manche anti-couple movwf memo1 movlw .84 ; T_PPM_A mini CETTE VALEUR EST A AJUSTER EN FONCTION DE VOTRE RADIO subwf memo1,f ; T_PPM_A:= T_PPM_A - 84 (pré-ofset) btfss STATUS,0 ;débordement ? clrf memo1 ;oui rlf memo1,w ; w:= 2 x T_PPM_A addwf memo1,w ; w:= 3 x T_PPM_A btfsc STATUS,0 ;débordement ? (résult > 255 ?) movlw .250 ;oui, butée haute movwf BB ;non, on garde le résultat obtenu BB=AntiCouple ;calcul du rapport cyclique (mixage de la valeur obtenue avec celle de la voie "GAZ") calc_AC movf rapcyc2,w ;w=GAZ movwf AA call multi ;w*AA -> AH,L = GAZ*GAZ =GAZ^2 ; AL=GAZ^2/256 movf BB,w ;w=manche AntiCouple movwf AA ;AA=manche AntiCouple bcf STATUS,0 ;RAZ c rrf AH,w ;w=G*G/256/2 call multi ;w*AA -> AH,L = G*G/256/2 * Manche_AC movlw AH ;w=adresse du registre AA call movxB ;BH,L = AH,L donc BH,L := G*G/256/2 * Manche_AC movlw .170 ;dividende call divi16_8 ; w:=BH,L / 170 = G*G/256/2 * Manche_AC / 170 movwf AA ;AA:=BH,L / 170 = G*G/256/2 * Manche_AC / 170 bcf STATUS,0 ;RAZ c rrf rapcyc2,w ;w:=G/2 addwf AA,f ;AA:=G*G/256/2 * Manche_AC / 170 +G/2 btfss STATUS,0 ;c dépassement ? goto clc2 ;non movlw 0xFF ;oui, on force à 255 movwf AA clc2 comf AA,w ;pour agir dans le bon sens (les 2 moteurs doivent accélérer en même temps) movwf rapcyc1 ;rapcyc1=resultat ; comf rapcyc1,f ;POUR TEST SEULEMENT ; return ;POUR TEST SEULEMENT ;calibrage final movlw .250 ;valeur max de rapcycl admissible (attention: si > 250 -> int Timer2 = HS) ;avec prediv =1/8 (voir T1CON) subwf rapcyc1,w ;w:= rapcycl - 240 (result -> w : ne touche pas à rapcycl) d=f-w btfss STATUS,0 ;c=0 ? rapcycl < 240 ? (c=0 si w > f ) goto finbcl1 ;oui movlw .250 ;non alors on bloque à butée max movwf rapcyc1 ;------------------------------------------------------------------------------------------------------------------ finbcl1 goto boucle1 ;----------------------------------------------------------------------- ;DEBUT DES PROCEDURES ;----------------------------------------------------------------------- ;*********************************************************************** ; SOUS-ROUTINES d'INTERRUPTIONS ;*********************************************************************** ;int timer0 ;en principe ne déborde jamais ici. ;est utilisé au sein de l'INT portB0 (voir plus bas) pour mesurer la durée PPM voie GAZ inttimer0 fintimer0 return ;---------------------------------------------------------------------- ;int timer1 ;génération du signal de sortie voie ANTI-COUPLE ;ce timer fonctionne ici suivant 2 alternances consécutives de durées inégales, mais dont la somme est constante ;on obtient dont une fréquence constante avec un rapport cyclique variable ;valeur max de rapcycl admissible =253 (avec prediv =1/8 (voir T1CON)) inttimer1 movlw B'00000010' xorwf mesflags,f ;inverse le flag de phase btfsc mesflags,1 ;test du flag de phase goto int1_a movf rapcyc1,w ;ici w=rapcycl sublw .255 ;ici w=255-rapcycl movwf TMR1L movlw 0xFF ;pour utiliser le timer1 sur 8 bits seulement movwf TMR1H goto int1_b int1_a movf rapcyc1,w movwf TMR1L movlw 0xFF movwf TMR1H btfsc mesflags,0 ;STOP ? goto int1_b ;oui, on va bloquer le MOSFET bsf PORTB,1 ;SORTIE PHYSIQUE sur le port B pour commander le MOSFET voie ANTI-COUPLE return int1_b bcf PORTB,1 ;SORTIE PHYSIQUE sur le port B pour commander le MOSFET voie ANTI-COUPLE fin_int1 return ;---------------------------------------------------------------------- ;int timer2 ;génération du signal de sortie VOIE GAZ ;ce timer fonctionne ici suivant 2 alternances consécutives de durées inégales, mais dont la somme est constante ;on obtient dont une fréquence constante avec un rapport cyclique variable ;valeur max de rapcycl admissible =253 (avec prediv =1/16 (voir T2CON)) ;attention: si prediv<1/16 ou si rapcycl > 253 alors-> int Timer2 = HS (pas le temps de réinitialier PR2) inttimer2 movlw B'00000100' xorwf mesflags,f ;inverse le flag de phase btfsc mesflags,2 ;test du flag de phase goto int2_a movf rapcyc2,w ;ici w=rapcycl sublw .255 ;ici w=255-rapcycl BANK1 movwf PR2 ;PR2 = registre 8bits de période du Timer2 situé en banque1 BANK0 goto int2_b int2_a movf rapcyc2,w BANK1 movwf PR2 ;PR2 = registre 8bits de période du Timer2 BANK0 btfsc mesflags,0 ;STOP ? goto int2_b ;oui, on va bloquer le MOSFET bsf PORTB,2 ;SORTIE PHYSIQUE sur le port B pour commander le MOSFET VOIE GAZ return int2_b bcf PORTB,2 ;SORTIE PHYSIQUE sur le port B pour commander le MOSFET VOIE GAZ fin_int2 return ;---------------------------------------------------------------------- ;int Extérieure par bit 0 du port B ;sert à detecter les fronts du signal PPM du récepteur de radio-commande, voie GAZ ;et à mesurer la durée du signal à 1 intB0 btfss mesflags,4 ;quel front vient-on de détecter ? goto frontD0 ;le front descendant frontM0 clrf TMR0 ;le front montant. RAZ Timer0 BANK1 bcf OPTION_REG,6 ;Interrupt on falling edge of RB0/INT pin (détectera le front descendant) BANK0 bcf mesflags,4 ;pour éviter une lecture en bank1 au début de cette procédure, on testera ce flag return frontD0 movf TMR0,w ;le timer0 à compté (l'horloge du PIC) depuis le front montant précédent movwf T_PPM_G ;MEMORISATION DE LA MESURE DU SIGNAL PPM voie GAZ pour le reste du programme BANK1 bsf OPTION_REG,6 ;(détectera le front montant) BANK0 bsf mesflags,4 clrf TMR0 return ;---------------------------------------------------------------------- ;int Extérieure par bit5 du port B ;sert à détecter les fronts du signal PPM du récepteur de radio-commande, voie ANTI-COUPLE ;et à mesurer la durée du signal à 1 ;REMARQUE: contrairement à l'intRB0, les INT RB4-7 sont déclenchées par les fronts montants ET descendants ;sans que l'on puisse choisir lequel ;Mais en fait ceci aboutit à simplifier la procédure ;lorsque l'int est déclenchée, il suffit de tester l'état du port pour savoir si elle a été déclenchée par un ;front montant ou descendant. ;REMARQUE2: Cette procédure utilise volontairement LE MEME timer (le Timer0) que la précédente (intB0) ;ceci est possible car les signaux PPM des différentes voies ne sont jamais simultanés, mais sont succéssifs. ;Donc les comptages des temps par le Timer0 ne se chevauchent pas (voir plus bas la précaution à prendre) ;ET AINSI ON GAGNE UN TIMER ! ;(on peut éenddre ce principe pour un plus grand nombre de voies ! avec 1 seul timer, on peut mesurer ;autant de périodes de temps qu' on veut, pourvu qu' elles soient disjointes) ;************* ATTENTION **************** ;Pour éviter un RAZ intempéstif du Timer0 d'une voie par l'autre, ;LES VOIES GAZ ET ANTI-COUPLE NE DOIVENTS PAS ETRE 2 VOIES CONSECUTIVES SUR LA RADIO !!! ;choisir par exemple les voies 2et4 MAIS PAS les voies 3et4 ou 2et3 pour l'anti-couple et les gaz. ;**************************************** intB5 btfss PORTB,5 ;quel front vient-on de détecter ? goto frontD5 ;le front descendant frontM5 clrf TMR0 ;le front montant. RAZ Timer0 return ;le timer1 à compté (l'horloge du PIC) depuis le front montant précédent frontD5 movf TMR0,w ;le timer0 à compté (l'horloge du PIC) depuis le front montant précédent movwf T_PPM_A ;MEMORISATION DE LA MESURE DU SIGNAL PPM voie A.Couple pour le reste du programme clrf TMR0 return ;------------------------------------------------------------------------ ;Pour test seulement: mémorise en EEPROM les valeurs simultanées de la vitesse Rotor et AntiCouple ;afin d'étudier la courbe obtenue (sous Excel par exemple) ecrireEE movf adrEE,w movwf DDD movf rapcyc2,w W_EEPROM incf adrEE,f movf adrEE,w movwf DDD comf rapcyc1,w W_EEPROM incf adrEE,f call tp100ms ;anti-rebond call tp100ms call tp100ms call tp100ms call tp100ms return ;************************************************************************ ;début des procédures d'affichage LCD (utilisent le portA) ;************************************************************************ ;FUNCTION SET fset bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .56 ;(32+16+8) movwf dtlcd call dt_out ;transmission série vers 4015 -> DATA // LCD call impuls return ;---------------------------------------------------------------------- ;DISPLAY CLEAR dspclr bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .1 movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;RETURN HOME home clrf PORTA movlw .2 movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;ENTRY MODE SET 0 ;le curseur se déplace setmod0 bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .6 ;( 4+2 sens inverse si 4+0 ) movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;ENTRY MODE SET 1 ;curseur gelé setmod1 bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .7 ;( 4+2+1 ) movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;DISPLAY ON OFF dsp10 bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .12 ;( 8+4 ) movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;DDRAM ADRESS SET (A) ;w doit contenir l'adresse (position d'affichage. voir doc) ddras bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 addlw .128 movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;CURSOR OR DISPLAY SHIFT ;DEFILEMENT DU TEXTE shiftT bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .24 ;( 16+8 ) movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;CURSOR OR DISPLAY SHIFT ;DEFILEMENT DE LA POSITION D'AFFICHAGE (CURSEUR) shiftC bcf PORTA,2 ;E=0 bcf PORTA,3 ;R/S=0 movlw .16 ;( 16 ) movwf dtlcd call dt_out call impuls return ;---------------------------------------------------------------------- ;ECRIRE ;w doit contenir lavaleur ASCII du caractère à afficher ecrire bcf PORTA,2 ;E=0 bsf PORTA,3 ;R/S=1 movwf dtlcd call dt_out bsf PORTA,2 ;impuls E à 1 avec RS=1 call tp10ms bcf PORTA,2 ;fin impulsion call tp10ms return ;---------------------------------------------------------------------- ;impulsion E à 1 avec RS=0 impuls bcf PORTA,3 ;R/S=0 bsf PORTA,2 ;impulsion E à 1 call tp10ms bcf PORTA,2 ;fin impulsion call tp10ms return ;---------------------------------------------------------------------- ;SORTIE DATA (8 bits) en série sur PA0 vers CD4015. PA1=Clock 4015. dt_out movlw .8 movwf bitn dtbcl rlf dtlcd,f bcf PORTA,0 ;bit = 0 (à priori) btfsc STATUS,0 ;test carry bsf PORTA,0 ;non, bit = 0 out bsf PORTA,1 ;clock 4015 call tp154us bcf PORTA,1 ;fin clock call tp154us decfsz bitn,f goto dtbcl return ;------------------------------------------------------------------------ affi4 movf aff4,w addlw .48 ;code ASCII de zéro call ecrire affi3 movf aff3,w addlw .48 ;code ASCII de zéro call ecrire affi2 movf aff2,w addlw .48 ;code ASCII de zéro call ecrire movf aff1,w addlw .48 ;code ASCII de zéro call ecrire return ;------------------------------------------------------------------------ ;nb decimaux dans AA(unités) et BB(centaines) au préalable affdeci movf BB,w movwf CC ;memo BB danc CC because cvBDU utilise BB call cvBDU movf AA,w ;ld A,V movwf aff1 ;ld Aff1,A movf BB,w ;ld A,W movwf aff2 ;ld Aff2,A movf CC,w ;ld A,BB ;0..99 movwf AA call cvBDU movf AA,w movwf aff3 movf BB,w movwf aff4 return ;----------------------------------------------------------------------- ;affiche un octet complet sur aff1..4 (4 TIL 702) ;W doit contenir l'octet à afficher affiw movwf AA call cvBDU ;BB=18 et AA=4 movf AA,w movwf aff1 ;aff1=4 movf BB,w ;w=18 movwf AA ;AA=18 call cvBDU ;BB=1 et AA=8 movf AA,w movwf aff2 ;aff2=8 movf BB,w movwf aff3 ;aff3=1 clrf aff4 call affi4 return ;----------------------------------------------------------------------- ;affichage nombre 0..9999 ;AH et AL contiennent un nb 0..9999 affnb movf AL,w ;ld A,AL movwf AA call cvBCU ;convertit period0 en BCD ;résultat dans AA(unités) et BB(centaines) ;on va ajouter valbin1 x 256 movf AH,w ;ld A,AH movwf DD ;ld memo3,A pour'pas toucher period1 incf DD,f ;hors boucle afn1 decfsz DD,f goto saut1 ;jrnz ici1 goto suitef ;ld A,AA saut1 movlw .56 addwf AA,f ;addi A,56 (+56) retenue decimale possible movf AA,w sublw .99 ;carry =0 si AA>99 btfsc STATUS,0 ;bit de carry goto st1 ;donc saut->conv3 si carry=1, c.a.d si A>99 ;jrc st1 movlw .100 subwf AA,f incf BB,f ;ajout retenue decimale st1 movlw .2 addwf BB,f ;(+200) soit en tout +256 goto afn1 suitef call affdeci return ;------------------------------------------------------------------------ ;CONVERSION BINAIRE(1) (1 octet incomplet 0..99 et pas 0..255) --> BCD ;nombre à convertir dans AA ;resultat dans BB (dizaines) et dans AA (unités) ;ex: AA=237 -> BB=23 et AA=7 ;ex2 AA=84 -> BB=8 et AA=4 cvBDU clrf BB conv2 movlw .10 subwf AA,w ;w=AA-10 positionne le bit de carry si A<10 btfss STATUS,0 ;bit de carry goto conv3 ;donc saut ->conv3 si carry=1, c.a.d si A<10 movlw .10 subwf AA,f ;en boucle : revient à diviser A par 10 incf BB,f goto conv2 ;9 passages au max si nb <= 99 conv3 return ;-------------------------------------------------------------------- ;CONVERSION BINAIRE(2) (1 octet complet 0..255) --> BCD ;nombre à convertir dans AA ;resultat dans BB (centaines) et dans AA (unités) ;ex: AA=237 -> BB=23 et AA=7 cvBCU clrf BB conv4 movlw .100 subwf AA,w ;w=AA-100 positionne le bit de carry si A<100 btfss STATUS,0 ;bit de carry goto conv5 ;donc saut ->conv3 si carry=1, c.a.d si A<100 movlw .100 subwf AA,f ;en boucle : revient à diviser A par 100 incf BB,f goto conv4 ;9 passages au max si nb <= 999 conv5 return ;-------------------------------------------------------------------- ;*********************************************************************** ; ROUTINES MATH ;*********************************************************************** ;------------------------------------------------------------------------ ;conversion sexadécimale -> binaire ;entrée: AA, BB ;resultat: AH,AL = 60*AA+BB convhbin movlw .60 call multi ;AA contient la donnée à multiplier movf BB,w addwf AL,f btfsc STATUS,0 ;carry incf AH,f return ;------------------------------------------------------------------------ ;mutiplication 8 bits x 8 bits de AA par w (données sur 1 octet) ;d'après note AN526 Microchip ;resultat (sur 2 octets) dans AH,AL (poids fort et poids faible) multi clrf AH movwf AL movlw .8 movwf count1 movf AL,w clrf AL bcf STATUS,0 ;RAZ carry loop rrf AA,f btfsc STATUS,0 addwf AH,f rrf AH,f rrf AL,f decfsz count1,f goto loop return ;------------------------------------------------------------------------ ;division d'une valeur codée sur 16 bits (AH,AL) par 2 divi2 bcf STATUS,0 ;RAZ carry c=0 rrf AH,f ;le bit de poids faible tombe dans -> c ; le bit de poids fort de AH devient nul rrf AL,f ;le bit de poids faible de AH devient le bit de poids fort de AL return ;------------------------------------------------------------------------ ; addwf AL,f ;(f+w) -> dest ; c=1 si retenue (à traiter) btfsc STATUS,0 ;c incf BH,f ;ajout retenue movf BH,w addwf AH,f ;(f+w) -> dest ; c=1 si retenue return ;------------------------------------------------------------------------ ;addition 16bits ;(AH,AL)+(AH,AL) -> (BH,BL) ;remarque seule la destination (B) est différente par rapport à la procédure add16A add16B movf AL,w addwf BL,f ;(f+w) -> dest ; c=1 si retenue (à traiter) btfsc STATUS,0 ;c incf AH,f ;ajout retenue movf AH,w addwf BH,f ;(f+w) -> dest ; c=1 si retenue return ;------------------------------------------------------------------------ ;complément à deux de la variable codée sur 2 octets situés aux adresses w et w+1 cpl16x movwf FSR comf INDF,f ;w=complément (H) incf FSR,f comf INDF,f ;w=complément (L) incf INDF,f ;w=complément à 2 de L btfss STATUS,2 ;z return decf FSR,f ;pointe H incf INDF,f ;retenue return ;------------------------------------------------------------------------ ;division 16bits par 8 bits résultat sur 8 bits : BH,L / w -> w ;par approximations succésives sur les 8 bits (méthode rapide, 8 passages max dans la boucle) ;ATTENTION si le résultat est >255 il sera retourné = 255 ;il est évident par exemple que 65535 / 1 = 65535 ne tient pas sur 1 octet ;toutefois dans ce programme, le résultat est borné sur 1 octet ; x/0 donne 255 ; 0/0 donne 255 ; 0/x (x<>0) donne 0 divi16_8 movwf CC ;CC contient le diviseur clrf BB movlw B'10000000';masque du bit testé movwf DD movwf BB divi1 movf CC,w movwf AA movf BB,w call multi ;AH,L=AA*w = diviseur * BB ;ne touche pas call compar16p ;ne touche pas AA ni BB btfss STATUS,0 goto trop ;test bit suivant goto pastrop decf BB,w ;résultat return trop movf DD,w xorwf BB,f ;éteint le bit précédent bcf STATUS,0 rrf DD,f ;bit suivant btfsc STATUS,0 ;c c'était le dernier ? goto findiv ; oui movf DD,w iorwf BB,f ;allume le bit suivant goto divi1 pastrop bcf STATUS,0 rrf DD,f ;bit suivant btfsc STATUS,0 ;c c'était le dernier ? goto findiv ; oui movf DD,w iorwf BB,f ;allume le bit suivant goto divi1 findiv movf BB,w return ;------------------------------------------------------------------------ ;mov la variable codée sur 2 octets situés aux adresses w et w+1 dans -> AH,AL movxA movwf FSR movf INDF,w movwf AH incf FSR,f movf INDF,w movwf AL return ;------------------------------------------------------------------------ ;mov AH,AL dans -> la variable codée sur 2 octets situés aux adresses w et w+1 movAx movwf FSR movf AH,w movwf INDF incf FSR,f movf AL,w movwf INDF return ;------------------------------------------------------------------------ ;mov la variable codée sur 2 octets situés aux adresses w et w+1 dans -> BH,BL movxB movwf FSR movf INDF,w movwf BH incf FSR,f movf INDF,w movwf BL return ;------------------------------------------------------------------------ ;mov BH,BL dans -> la variable codée sur 2 octets situés aux adresses w et w+1 movBx movwf FSR movf BH,w movwf INDF incf FSR,f movf BL,w movwf INDF return ;------------------------------------------------------------------------ ;comparaison de deux valeurs codées sur 16 bits (AH,AL à BH,BL) ;resultat dans STATUS carry et zéro ;les valeurs doivent représenter des nombres tous deux positifs (pas ok si valeurs codées en complément à 2) ;sauf pour le test d'égalité STATUS,2 ('z') ;16p-> p comme positifs compar16p movf AH,w subwf BH,w ;c=0 si AH>BH btfss STATUS,2 ;z=1 si AH=BH il faut alors comparer AL à BL return movf AL,w subwf BL,w ;z=1 si AL=BL et comme on sait déjà que AH=BH, si z=1 -> A=B return ;------------------------------------------------------------------------ ;*********************************************************************** ; TEMPOS GENERALES ;*********************************************************************** ; Qx = 20,000 Mhz ;TEMPO 154us pile ;tiens compte du call de l'appelant et du return final tp154us movlw .255 ;1 cycle movwf t1 ;1 cycle t3loop1 decfsz t1,f ;1 cycle goto t3loop1 ;2 cycles return ;2 cycles ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz ; 2,0004ms ;tiens compte du call de l'appelant et du return final tp2ms movlw .13 movwf t1 t4loop1 movlw .255 movwf t2 t4loop2 decfsz t2,f goto t4loop2 decfsz t1,f goto t4loop1 return ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz ; 1,000ms ;tiens compte du call de l'appelant et du return final tp1ms movlw .11 movwf t1 t5loop1 movlw .150 movwf t2 t5loop2 decfsz t2,f goto t5loop2 decfsz t1,f goto t5loop1 return ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz ; 9,998ms ;tiens compte du call de l'appelant et du return final tp10ms movlw .65 movwf t1 t1loop1 movlw .255 movwf t2 t1loop2 decfsz t2,f goto t1loop2 decfsz t1,f goto t1loop1 return ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz tp100ms clrwdt movlw .10 movwf t3 t2loop2 clrwdt call tp10ms decfsz t3,f goto t2loop2 return ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz ;tempo n x 10ms ;charger w avec n avant l'appel de cette procédure ; tx10ms movwf t3 txlp2 call tp10ms decfsz t3,f goto txlp2 return ;---------------------------------------------------------------------- ; Qx = 20,000 Mhz ;tempo n x 1ms ;charger w avec n avant l'appel de cette procédure ; tx1ms movwf t3 txlp3 call tp1ms decfsz t3,f goto txlp3 return ;*********************************************************************** ; TABLEAUX DE DONNEES ;*********************************************************************** ;NOTE: les tableaux doivent se situer chacun sur 1 seule page d'adresse codée sur 8 bits (longueur<=255, 00FF h) ;c.a.d qu'un tableau ne doit pas être à cheval sur dex pages ;verifier sur le listing absolu obtenu après compilation. ;je le place en page6 ;NOTE: en exa, chaque page de 256octets = 100 (noté 0x100) ;RAM page1=0000 à 00FF ;RAM page2=0100 à 01FF ;RAM page3=0200 ;etc... jusqu'à ;RAM page8=0700 à 07FF (8 pages de 256 octets pour le PIC16F628, soit 2kO RAM) org 07C0h ;Le datasheet de Microchip précise ceci: ;A computed GOTO is accomplished by adding an offset ;to the program counter (ADDWF PCL). When doing a table ;read using a computed GOTO method, care should be ;exercised if the table location crosses a PCL memory ;boundary (each 256 word block). Refer to the application ;note "Implementing a Table Read" (AN556). ;--------------------------fin des tableaux en FLASH ----------------------------------- ;======================================================================================= ;DATA EN EEPROM ;======================================================================================= ORG 0x2100 ; zone EEPROM ;======================================================================================= end