;********************************************************************** ; * ; NOM: LB - http://www.chez-todd.fr * ; Date: 25/12/2006 * ; Version: 1.04 * ; Circuit: Commande de RX 2.4 GHZ Comtech (PLL SP5055) * ; * ; Evolutions: * ; * ; V1.04 - Le 01/12/08: Correction du bug de la V1.03. * ; La décrémentation du PAS 125k vers 10M entrainait un * ; Reset au mieux du PIC suite à une erreur à la fin de * ; "set_step_50" qui effectuait un goto au lieu d'un call* ;********************************************************************** ; * ; Fichier requis: P16F84a.inc * ; * ; * ; * ;********************************************************************** ; * ; Notes: Fonctionne avec un quartz de 4MHz. * ; Toutes les temporisations sont basées sur cette fréquence. * ; Pour changer le débit I2C, éditer wait_i2c. * ; Affichage LCD 2 lignes de 16 caractères (type HITACHI 44780) * ; L'adresse I2C de la PLL est 0xC2, voir RX_ADDR si PLL différente * ; * ; Merci à BIGONOFF pour ses merveilleux cours! * ; http://www.bigonoff.org * ; * ; Le système d'affichage des messages sur le LCD est réalisé en * ; utilisant la routine de Damien Dspix et Jean-François B. * ; disponible sur l'excellent site de BIGONOFF, sur la page * ; "Trucs, astuces, librairies, et aides". * ; * ; CE CODE SOURCE VOUS EST FOURNI TEL QUEL, IL EST SUFFISAMMENT * ; COMMENTE POUR COMPRENDRE SON FONCTIONNEMENT. JE NE REPONDRAI * ; DONC PAS AUX QUESTIONS DONT LA REPONSE SE TROUVE DANS LES * ; COMMENTAIRES. * ; CE FICHIER EST RESERVE A UNE UTILISATION NON COMMERCIALE. * ; ME CONTACTER LE CAS ECHEANT A L'ADRESSE INDIQUEE SUR CETTE PAGE: * ; http://www.chez-todd.fr/fr/contact.html * ;********************************************************************** LIST p=16F84a ; Définition de processeur #include ; Définitions des constantes __CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC ; '__CONFIG' précise les paramètres encodés dans le processeur au moment de ; la programmation. 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 ; _XT_OSC Oscillateur quartz moyenne vitesse ; _HS_OSC Oscillateur quartz grande vitesse ; _RC_OSC Oscillateur à réseau RC ;********************************************************************* ; ASSIGNATIONS * ;********************************************************************* OPTIONVAL EQU b'01000000' ; Valeur registre option ; Résistance pull-up ON ; Interrupt flanc montant RB0 ; Préscaler timer à 2 (exemple) INTERMASK EQU b'00000000' ; Masque d'interruption ; Pas d'interruption RX_ADDR EQU b'11000010' ; Adresse I2C de la PLL du RX Comtech: 0xC2 ; le LSB est à 0 pour définir l'écriture vers la PLL ; le mettre à 1 pour lire la PLL RX_VALID EQU b'10001110' ; octet de validation de la donnée transmise au RX ;********************************************************************* ; DEFINE * ;********************************************************************* ; sorties ; ------- #DEFINE SDA PORTA,2 #DEFINE SCL PORTA,3 ; entrées ; ------- #DEFINE FUNC PORTA,1 #DEFINE SCAN PORTA,0 #DEFINE UP PORTB,7 #DEFINE DN PORTB,6 ;********************************************************************* ; VARIABLES BANQUE 0 * ;********************************************************************* ; Zone de 36 octets ; ----------------- ; banque 0 CBLOCK 0x0C ; Début de la zone cmpt : 1 ; registre utilisé pour les temporisations w_temp : 1 ; Sauvegarde du registre W status_temp : 1 ; Sauvegarde du registre STATUS empty : 1 retenue : 1 ; retenue de la division par 10 repeat_loop : 1 ; sert à définir le nombre de répétitions d'une boucle repeat_loop2 : 1 ; idem repeat_loop3 : 1 FSR_temp : 1 ; mémo du pointeur de FSR FSR_temp2 : 1 ; idem i2c_buffer : 1 ; donnée à envoyer sur l'I2C freq_L : 1 ; valeur basse de la fréquence freq_H : 1 ; valeur haute de la fréquence step : 1 ; pas d'incrémentation/décrémentation de la fréquence: ; 0x01 = pas de 125kHz ; 0x02 = pas de 250kHz ; 0x04 = pas de 500kHz ; 0x08 = pas de 1MHz ; 0x50 = pas de 10MHz bufferLCD : 1 ; donnée à transmettre au LCD commands : 1 ; bits de sélection de mode de comm avec le LCD LCDline : 1 ; adresse de la ligne du LCD LCDcol : 1 ; colonne de la ligne du LCD I2C_speed : 1 ; utilisé pour savoir quel est le débit I2C sélectionné (seul un des 8 bits est à 1) I2C_ERR : 1 ; compteur de NO ACK (on affiche ERR si différent de 0) ADDRL_MSG : 1 ; Pointeur bas de la chaine de caractères à envoyer au LCD ADDRH_MSG : 1 ; Pointeur haut de la chaine de caractères à envoyer au LCD ENDC CBLOCK 0x3B udg : 1 ; digits de la fréquence en décimal cdm : 1 ; aussi utilisé pour stocker la ddm : 1 ; fréquence codée en hexa avant udm : 1 ; la récupération des quartets cdk : 1 ; lors des divisions par 0x0A ddk : 1 udk : 1 quartet1 : 1 ; quartets après division par 10 de la fréquence en hexadécimal quartet2 : 1 quartet3 : 1 quartet4 : 1 quartet5 : 1 quartet6 : 1 quartet7 : 1 ENDC ; Fin de la zone ;********************************************************************* ; MACRO * ;********************************************************************* BANK0 macro bcf STATUS,RP0 ; passer banque0 endm BANK1 macro bsf STATUS,RP0 ; passer banque1 endm ;********************************************************************** ; DEMARRAGE SUR RESET * ;********************************************************************** org 0x000 ; Adresse de départ après reset goto init ; Adresse 0: initialiser ;********************************************************************** ; ROUTINE INTERRUPTION * ;********************************************************************** ;sauvegarder registres ;--------------------- org 0x004 ; adresse d'interruption ; pas d'intéruption gérée par ce logiciel ! ;********************************************************************* ; INITIALISATIONS * ;********************************************************************* init bsf SDA bsf SCL ; le BUS I2C est libre clrf PORTB ; sorties portB à 0 clrf EEADR ; permet de diminuer la consommation BANK1 ; passer banque1 movlw OPTIONVAL ; charger masque movwf OPTION_REG ; initialiser registre option movlw b'00000011' movwf TRISA ; PORTA 4:2 en sortie (I2C) ; PORTA 1:0 en entrée (UP/DN) movlw b'11000000' movwf TRISB ; PORTB 7:6 en entrée (FUNC/SCAN) ; PORTB 5:0 en sortie (LCD) BANK0 ; passer banque0 movlw INTERMASK ; masque interruption movwf INTCON ; charger interrupt control goto start ; sauter programme principal ;************************************************************************ ; ROUTINES I2C * ;************************************************************************ i2c_start bcf SDA call wait_i2c bcf SCL call wait_i2c return i2c_stop bcf SDA ; le maître force l'état de SDA à 0 avant que l'esclave ne le fasse au prochain passage à 1 de SCL nop ; (avant d'arriver au stop, le dernier bit transmis était forcément un ACK, donc SDA = 0) bsf SCL call wait_i2c bsf SDA call wait_i2c return i2c_write movwf i2c_buffer ; la valeur stockée dans W est envoyée dans le buffer d'envoi I2C movlw D'08' movwf repeat_loop3 ; la boucle sera répetée 7 fois, le premier décalage à lieu dès le départ bcf SCL ; SCL mis à 0, on peut changer la valeur de SDA i2c_writeloop call wait_i2c rlf i2c_buffer,f ; MSB d'I2C_buffer envoyé dans C btfss STATUS,C ; C vaut 1? bcf SDA ; non, on met SDA à 0 btfsc STATUS,C ; C vaut 0? bsf SDA ; non, on met SDA à 1 nop ; on attend que le signal SDA se stabilise à sa valeur finale (temps de montée) bsf SCL ; SCL mis à 1, on valide la valeur de SCL pour que l'esclave puisse la lire call wait_i2c bcf SCL ; SCL mis à 0, l'esclave ne scrute plus SDA, on peut donc changer sa valeur à nouveau decfsz repeat_loop3,f goto i2c_writeloop bsf SDA ; le BUS est libre, l'esclave peut répondre call i2c_sack return i2c_sack ; attente de l'ACK provenant de l'esclave BANK1 bsf TRISA,2 ; SDA devient une entrée BANK0 call wait_i2c bsf SCL ; SCL mis à 1, l'esclave peut envoyer son ACK call wait_i2c ; attente du changement d'état de SDA par l'esclave btfsc SDA ; SDA mis à 0 par l'esclave? incf I2C_ERR,f ; non, compteur d'érreurs incrémenté BANK1 bcf TRISA,2 ; SDA redevient une sortie BANK0 bcf SCL ; SCL remis à 0 pour l'envoi éventuel d'un stop ; SDA reste inchangé du coté de l'esclave tant qu'il n'y a pas de remise à 1 de SCL call wait_i2c return ;***************************************************************************** ; ROUTINES DE TEMPORISATIONS * ;***************************************************************************** wait_128us movlw D'31' goto short_loop wait_500us movlw D'250' short_loop movwf cmpt movlw D'1' movwf repeat_loop goto loop_wait wait_1ms movlw D'01' movwf repeat_loop goto wait wait_2ms movlw D'02' movwf repeat_loop goto wait wait_5ms movlw D'05' movwf repeat_loop goto wait wait_30ms movlw D'30' movwf repeat_loop goto wait wait_125ms movlw D'125' movwf repeat_loop goto wait wait_255ms movlw D'255' movwf repeat_loop goto wait wait_1s movlw 0x04 movwf repeat_loop3 goto loop_wait_xs wait_2s movlw 0x08 movwf repeat_loop3 loop_wait_xs movlw D'255' movwf repeat_loop call wait decfsz repeat_loop3,f goto loop_wait_xs return wait movlw 0xFF movwf cmpt loop_wait clrwdt decfsz cmpt,f goto loop_wait decfsz repeat_loop,f goto wait return wait_i2c ; Tempo à éditer en fonction du débit désiré sur le BUS I2C movf I2C_speed,w ; valeur du débit I2C movwf w_temp ; dans w_temp wait_i2c_loop bcf STATUS,C ; C mis à 0 rrf w_temp,f ; décalage vers la droite de w_temp btfsc STATUS,C ; test de C return ; C = 1 Fin de la boucle de temporisation I2C call wait_500us ; C = 0 On ajoute 500µs à chaque fois pour réduire le débit goto wait_i2c_loop ; retour au début de la boucle tant que C différent de 1 ;***************************************************************************** ;***************************************************************************** ; ROUTINES EEPROM * ;***************************************************************************** ;***************************************************************************** ; LECTURE * ;***************************************************************************** read_EEP movwf EEADR ; adresse à lire, doit être mise dasn W juste avant d'appeler cette routine BANK1 bsf EECON1,RD ; lecture wait_read_end clrwdt btfsc EECON1,RD ; fin de lecture? goto wait_read_end ; non BANK0 movf EEDATA, W ; valeur lue envoyée dans W return ;***************************************************************************** ; ECRITURE * ;***************************************************************************** write_EEP ; la donnée à écrire doit être stockée dans EEDATA avant d'appeler cette routine movwf EEADR call wait_1ms BANK1 bcf INTCON, GIE ; désactiver les interuptions bsf EECON1, WREN ; activer l'écriture movlw 0x55 movwf EECON2 ; début de la séquence d'init d'écriture movlw 0xAA ; movwf EECON2 ; fin de la séquence bsf EECON1,WR wait_write_end clrwdt btfsc EECON1,WR ; fin d'écriture? goto wait_write_end ; non bsf INTCON, GIE ; oui, réactiver les intéruptions BANK0 return ;***************************************************************************** ;***************************************************************************** ; ROUTINES LCD * ;***************************************************************************** ;***************************************************************************** ; INITIALISATION DU LCD * ;***************************************************************************** ; Gestion des données à transmettre pour l'init du LCD ; Rappel des bits: ; PORTB,0 = D5 ; 1 = D6 ; 2 = D7 ; 3 = D8 ; 4 = E commands = 0x10 si E=1 ; 5 = RS commands = 0x20 si RS=1 lcdstart clrf commands call wait_30ms initlcd movlw 0x03 ; données d'init envoyées à l'envers 30 -> 03, etc... call initstl call wait_5ms movlw 0x03 call initstl call wait_5ms movlw 0x03 call initstl call wait_5ms movlw 0x02 call initstl call wait_1ms movlw 0x28 call inits4b clearscreen clrf commands movlw 0x0C call inits4b movlw 0x01 call inits4b movlw 0x06 call inits4b movlw 0x20 movwf commands ; envoi de caractères call wait_2ms return ;***************************************************************************** ; MASQUAGE LCD 4 BITS * ;***************************************************************************** ; 1) mémorisation de la valeur à transmette ; 2) masquage de son MSB qui sera envoyé par un sous programme ; 3) swap des deux quartets puis retour à 1) ; 4) fin du découpage en 2 quartets de la donnée à transmettre inits4b movwf w_temp ; mémorisation de la valeur à transmettre sous forme de 2 quartets movlw 0x02 movwf repeat_loop2 ; envoi de deux quartets send4bits clrwdt movf w_temp,w ; récupération de la valeur à envoyer, mémorisée précédement andlw 0xF0 ; masquage pour garder le quartet de poids fort movwf bufferLCD swapf bufferLCD,w ; le quartet de poids fort devient quartet de poids faible call initstl ; envoi au LCD (gère l'horloge E) swapf w_temp,f ; échange des deux quartets decfsz repeat_loop2,f ; test si les deux quartets ont été envoyés goto send4bits ; envoi du second quartet return ;***************************************************************************** ; ENVOI AU LCD AVEC GESTION DE E * ;***************************************************************************** initstl movwf bufferLCD ; mémorisation de la valeur à transmettre dans bufferLCD sendtolcd movwf PORTB ; Donnée à transmettre au LCD mise sur le PORT B nop addwf commands,w movwf PORTB ; mise à 1 de RS nop ; attente de 800ns environ (@20MHz) addlw 0x10 ; mise à 1 de E pendant 3.2µs environ movwf PORTB nop ; cycle de E défini à environ 500ns andlw 0x2F ; mise à 0 de E pendant au moins 150µs movwf PORTB call wait_128us return ;********************************************************************* ; CHANGEMENT DE LIGNE * ;********************************************************************* line1 movlw 0x80 ; adresse du premier caractère de la ligne 1 goto gotolonex line2 movlw 0xC0 ; adresse du premier caractère de la ligne 2 gotolonex movwf LCDline linex call wait_128us clrf commands movf LCDline,w addwf LCDcol,w call inits4b movlw 0x20 movwf commands return ;********************************************************************* ; MESSAGES * ;********************************************************************* envoi_msg movwf ADDRL_MSG envoi_msg_1 call index_msg ; Récupération dans W du caractère à afficher addlw D'0' btfsc STATUS, Z ; Est-ce la fin ? return ; Oui, tout le message a donc été affiché call inits4b ; Envoi du caractère à l'afficheur LCD incf ADDRL_MSG, F ; Passage au caractère suivant btfsc STATUS, Z ; Changement de bloc de 256 octets ? incf ADDRH_MSG, F ; Oui : donc on incrémente également l'adresse haute de ce caractère suivant goto envoi_msg_1 ; --> On boucle jusqu'à la fin de l'envoi de tous les caractères du message donné index_msg movf ADDRH_MSG, W movwf PCLATH movf ADDRL_MSG, W movwf PCL ; Remarque : le return est fait par le retlw contenu dans msg_"n" msg_1 ; message d'accueil dt "FM2400RTIM V1.04", 0 msg_2 dt "2-2.7GHz SP5055", 0 msg_3 ; messages fixes écrits après le message d'accueil dt "Pas: I2C:", 0 msg_4 dt ". kHz", 0 msg_5 dt "Defaut sur l'I2C", 0; message d'info si la lisison I2C échoue avec le débit le plus faible msg_6 dt "VFO:", 0 ; info mode VFO msg_7 dt "SCAN", 0 ; info mode SCAN msg_8 dt "MEMO", 0 ; info MEMO du VFO en EEPROM interne msg_9 dt "ERR", 0 ; défaut de liaison I2C, pas d'ACK reçu msg_10 dt " OK", 0 ; liaison I2C correcte, l'esclave (PLL) a tout reçu (4 trames de 8 bits) msg_11 dt "125k", 0 ; pas d'incrémentation/décrémentation msg_12 dt "250k", 0 msg_13 dt "500k", 0 msg_14 dt " 1M", 0 msg_15 dt " 10M", 0 ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - welcomemsg clrf LCDcol call line1 movlw high msg_1 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_1 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg call line2 movlw high msg_2 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_2 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return background clrf LCDcol call line1 movlw high msg_3 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_3 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg movlw 0x09 movwf LCDcol call line2 movlw high msg_4 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_4 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg VFOmenu clrf LCDcol call line2 movlw high msg_6 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_6 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return scanmenu clrf LCDcol call line2 movlw high msg_7 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_7 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return storemenu clrf LCDcol call line2 movlw high msg_8 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_8 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg call wait_1s goto VFOmenu NACK movlw D'13' ; affichage du message ERR movwf LCDcol call line1 movlw high msg_9 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_9 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg bcf STATUS,C rlf I2C_speed,f ; changement du débit I2C btfss STATUS,C goto NACK_save_newspeed ; message d'érreur si le problème d'I2C persiste à 70Hz call clearscreen ; effacement de l'écran movlw high msg_5 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_5 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg movf freq_H,w ; sauvegarde des données avant reboot movwf EEDATA movlw 0x00 call write_EEP movf freq_L,w movwf EEDATA movlw 0x01 call write_EEP movlw 0x01 movwf EEDATA movlw 0x03 call write_EEP call wait_2s ; tempo d'affichage du message d'érreur infiniteloop ; boucle sans reset du watchdog pour rebooter le programme goto infiniteloop NACK_save_newspeed movf I2C_speed,w movwf EEDATA movlw 0x03 call write_EEP return ACK movlw D'13' movwf LCDcol call line1 movlw high msg_10 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_10 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg bcf STATUS,C ; RAZ de C pour sauter l'appel à NACK (si C est passé à 1 entre temps) return ;***************************************************************************** ;***************************************************************************** ; CALCULS ET CONVERSION DES DONNEES * ;***************************************************************************** ;***************************************************************************** ; Voilà comment ça marche. ; On veut aller de 2GHz à 2.7GHz, les valeurs à envoyer au RX sont les suivantes (en tenant compte de la FI infradyne de 479,5 MHz): ; (2000 - 479.5) * 8 = 12164 soit 0x2F84 en hexa ; (2700 - 479.5) * 8 = 17764 soit 0x4564 en hexa ; Tout ça donne la possibilité d'utiliser 5600 fréquences, puisqu'elles sont espacées de 125kHz chacunes (le pas minimum de la PLL). ; ; Pour simplifier la conversion hexa vers décimal (afin d'afficher la fréquence sur le LCD), voici la suite de calculs effectués: ; - Prenons comme exemple la fréquence 2468.125MHz, qui sera affichée de cette façon sur le LCD: 2468125 ; [La valeur hexadécimale envoyée à la PLL est additionnée à la fréquence de la FI puis multipliée par 0x7D (125 en décimal)] ; -> (2468.125 - 479.5) * 8 = 15909, soit 0x3E25 en hexa. <- valeur envoyée à la PLL ; -> 479.5 * 8 = 3836, soit 0xEFC en hexa. ; ; 1) Addition de la valeur envoyée à la PLL avec la valeur de la FI: ; --> 3E25 + EFC = 4D21 <- fréquence réellement reçue ; ; 2) Multiplication par le pas minimum de la PLL (125kHz), soit par 125 (0x7D en hexa). ; --> 4D21 * 7D = 25A91D, soit 2468125 en décimal <-- On sait donc retrouver la fréquence en fonction de la valeur envoyée à la PLL. ; ; Puisque le PIC ne sait pas faire cette conversion hexadécimal vers décimal, il faut la gérer avec le logiciel. Voici la méthode utilisée: ; [Utilisez la calculatrice de Windows si vous avez du mal à suivre :)] ; ; 3) On récupère le quartet de poids faible du résultat obtenu précédemment, ; on le divise ensuite par 0x0A, ; chaque résultat de division par 0x0A est redivisé par 0x0A autant de fois qu'il y a de chiffres dans la fréquence, ; on récupère à chaque fois le quartet de poids faible du résultat. ; Exemple: ; 25A91D -> on garde le quartet de poids faible D ; 25A91D / A = 3C41C -> on garde le quartet de poids faible C ; 3C41C / A = 6069 -> on garde le quartet de poids faible 9 ; 6069 / A = 9A4 -> on garde le quartet de poids faible 4 ; 9A4 / A = F6 -> on garde le quartet de poids faible 6 ; F6 / A = 18 -> on garde le quartet de poids faible 8 ; 18 / A = 2 -> on garde le quartet de poids faible 2 ; On a donc 7 quartets, mais la fréquence est fausse! Pas de panique, la conversion n'est pas terminée. ; ; 4) Fin des divisions, maintenant on effectue le calcul suivant: quartet - ((A * quartet précédent) & 0x0F) = chiffre de la fréquence ; "& 0x0F" indique qu'il faut masquer le quartet de poids fort du résultat de la soustraction. ; Le dernier quartet récuperé n'est pas utilisé pour le calcul, il est déja prêt à l'emploi pour la valeur décimale. ; ; Exemple: ; dernier quartet récupéré = 2 ; (0x08 - (0x02 * 0x0A)) & 0x0F = (8 - 14) & 0x0F = 4 ; (0x06 - (0x08 * 0x0A)) & 0x0F = (6 - 50) & 0x0F = 6 ; (0x04 - (0x06 * 0x0A)) & 0x0F = (4 - 3C) & 0x0F = 8 ; (0x09 - (0x04 * 0x0A)) & 0x0F = (9 - 28) & 0x0F = 1 ; (0x0C - (0x09 * 0x0A)) & 0x0F = (C - 5A) & 0x0F = 2 ; (0x0D - (0x0C * 0x0A)) & 0x0F = (D - 78) & 0x0F = 5 ; ; CQFD! Et tout ça ne prendra que 4.67ms @ 4MHz! Maintenant, au boulot! ; Première étape: Additionner la donnée envoyée à la PLL avec la valeur de la FI ; En deux étapes car la donnée envoyée à la PLL est sur 16bits et le PIC ne fonctionne que sous 8bits (+1 bit pour la retenue Carry). ; 0xEFC = 0x0EFC, l'octet de poids fort 0x0E est additionné avec freq_H et mémorisé temporairement dans udg, ; l'octet de poids faible 0xFC est additionné avec freq_L et mémorisé temporairement dans cdm. ; L'éventuelle retenue de l'addition précécdente est ajoutée au résultau de l'addition (0x0E + freq_H) contenu dans udg addition_EFC ; on ajoute la FI à la fréquence envoyée à la PLL movf freq_H,w movwf udg movf freq_L,w movwf cdm movlw 0x0E addwf udg,f ; freq_H + 0x0E movlw 0xFC bcf STATUS,C addwf cdm,f ; freq_L + 0xFC = cdm btfsc STATUS,C incf udg,f ; udg + 1 = udg si dépassement lors du calcul précédent return ; Deuxième étape: multiplier le résultat de l'addition avec 0xEFC de la donnée anvoyée à la PLL avec le pas minimum de la PLL: 125kHz. ; Le mot binaire formé par udg (octet de poids fort) et cdm (octet de poids faible) est décalé vers la gauche à travers C bit par bit. ; Le résultat de la multiplication tient sur 3 octets: cdk (l'octet de poids fort), ddk et udk (l'octet de poids faible). ; Ces 3 octets vont être décalés eux aussi vers la gauche en même temps que udg et cdm. ; A chaque fois que le bit lu dans C vaudra 1 (résultant d'un décalage vers la gauche de udg et cdm) on ajoutera 0x7D à udk. ; Un dessin pour mieux comprendre: ; ; cdk ddk udk ; _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ ; | | | | | | | | | <- | | | | | | | | | <- | | | | | | | | | ; ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ; ^ Addition si C ; | vaut 1 ; _ _ _ _ _ _ _ _ ; 0x7D: |0|1|1|1|1|1|0|1| ; ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ; ; C udg cdm ; _ rlf _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ ; |X| <- | | | | | | | | | <- | | | | | | | | | ; ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ; ; On décale autant de fois qu'il y a de bits à tester dans udg et cdm, soit 16 fois. multiplication_7D movlw D'16' movwf repeat_loop ; on va tester les 16 bits du multiplicande contenu dans udg et cdm clrf cdk clrf ddk clrf udk loop_mult_7D bcf STATUS,C rlf cdk,f ; décalage d'un cran vers la gauche de cdk bcf STATUS,C rlf ddk,f ; décalage d'un cran vers la gauche de ddk btfsc STATUS,C ; MSB de ddk à 1? incf cdk,f ; oui, ajouté au LSB de cdk bcf STATUS,C rlf udk,f ; décalage d'un cran vers la gauche de udk btfsc STATUS,C ; MSB de udk à 1? incf ddk,f ; oui, ajouté au LSB de ddk bcf STATUS,C rlf udg,f ; MSB de udg dans C btfsc STATUS,C ; C = 1? call add_7D ; oui bcf STATUS,C ; non rlf cdm,f ; MSB de cdm dans C btfsc STATUS,C ; C = 1? incf udg,f ; oui, envoi de la retenue dans le LSB de udg decfsz repeat_loop,f ; les 16 bits ont été testé? goto loop_mult_7D ; non return ; oui add_7D movlw 0x7D bcf STATUS,C addwf udk,f ; ajout de 0x7D btfss STATUS,C ; on a dépassé 0xFF suite à l'addition? return ; non bcf STATUS,C ; oui, il faut ajouter 1 à ddk movlw 0x01 addwf ddk,f btfss STATUS,C ; on a dépassé 0xFF suite à l'addition? return ; non incf cdk,f ; oui return ; Troisième étape: récupération du quartet de la fréquence codée en hexadécimal et division par 10 (0x0A en hexa). ; ; udm cdk ddk udk Carry ; _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ rlf _ _ _ _ _ _ _ _ rlf _ ; | | | | | | | | | <- | | | | | | | | | <- | | | | | | | | | <- | | | | | | | | | <- |C| ; ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ¯ ; _ _ _ _ | ; - |1|0|1|0| 0x0A ^ ; ¯ ¯ ¯ ¯ | ; ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ | ; W ------------>--------------------->-------------------->------------+ ; ; Voir http://www.ift.ulaval.ca/~marchand/ift17583/Support/Arithm.html pour comprendre le fonctionnement de la division. conversion_hexa_dec nop division_0A movlw 0x42 movwf FSR_temp ; début de la zone où seront mémorisés les quartets récupérés movlw D'7' movwf repeat_loop ; nombre de quartets à récupérer goto recup_quartet ; récupération du premier quartet sans faire de division redivision_0A movlw D'25' movwf repeat_loop2 ; nombre de décalages vers la gauche à effectuer pour une division par 0x0A clrf retenue ; retenue de la soustraction mise à 0 clrf udm loop_div_0A bcf STATUS,C rlf udm,f ; udm décalé d'un cran vers la gauche, prêt à reçevoir le MSB de cdk bcf STATUS,C rlf cdk,f ; cdk décalé d'un cran vers la gauche btfsc STATUS,C ; envoyer son MSB dans le LSB d' udm? incf udm,f ; oui bcf STATUS,C ; non rlf ddk,f ; ddk décalé d'un cran vers la gauche btfsc STATUS,C ; envoyer son MSB dans le LSB de cdk? incf cdk,f ; oui bcf STATUS,C ; non rlf udk,f ; udk décalé d'un cran vers la gauche btfsc STATUS,C ; envoyer son MSB dans le LSB de ddk? incf ddk,f ; oui movf retenue,w ; non, on prépare l'ajout d'une éventuelle retenue si la soustraction a eu lieu addwf udk,f ; addition de la retenue dans udk clrf retenue ; retenue remise à 0 pour la prochaine soustractrion bcf STATUS,C movlw 0x0A subwf udm,w ; udm - 0x0A = W btfss STATUS,C ; résultat positif ou égal à 0 (si C = 1)? goto test_fin_div_0A ; non, on continue les décalages sans toucher à la valeur d' udm et sans mettre la retenue à 1 movwf udm ; oui, le résultat de la soustraction écrase l'ancienne valeur d' udm movlw 0x01 movwf retenue ; la retenue est mise à 1 test_fin_div_0A decfsz repeat_loop2,f ; les 24 bits ont été décalés? goto loop_div_0A ; non, on continue à les décaler d'un cran vers la gauche ; oui, la ligne précédente est sautée et on passe à la récupération du quartet de poids faible du résultat de la division par 0x0A ; Récupération du quartet de poids faible: recup_quartet movf udk,w ; récupération de l'octet de poids faible andlw 0x0F ; masquage de son quartet de poids fort movwf ddm ; résultat stocké temporairement dans ddm movf FSR_temp,w ; lecture de la valeur de la case mémoire à pointer movwf FSR ; case mémoire pointée movf ddm,w ; chargement de la valeur à mémoriser movwf INDF ; valeur mémorisée incf FSR_temp,f ; prêt à pointer la case suivante decfsz repeat_loop,f ; tous les quartets ont été récupérés? goto redivision_0A ; non, on repart pour une division de cdk, ddk et udk ; oui, on passe à la dernière étape ; Quatrième étape: conversion des quartets en digits de la fréquence ; On récupère les quartets dans le sens inverse: de l'avant dernier au premier mémorisé. Le dernier quartet mémorisé est déjà prêt à l'emploi. movlw 0x48 movwf FSR_temp ; zone où sont stockés les quartets (le dernier mémorisé est à l'adresse 0x48) movlw 0x3C movwf FSR_temp2 ; zone où sont stockés les digits de la fréquence (le premier digit est à l'adresse 0x3B) movlw 0x06 movwf repeat_loop ; il n'y a que 6 digits à décoder, le septième est déja prêt à l'emploi movf quartet7,w ; dernier quartet mémorisé movwf udg ; stocké directement dans le premier digit (unité de gigahertz) multiplication_quartets ; multiplication par 0x0A du quartet, avant d'éffectuer une soustraction avec le quartet précédent clrwdt movf FSR_temp,w ; chargement du pointeur FSR dans la zone des mémoires des quartets movwf FSR movf INDF,w ; récupération du quartet movwf w_temp ; le quartet est dans temp ; début de la multiplication par 10 (0x0A) bcf STATUS,C ; effacement de la retenue Carry, pour ne pas être géné lors de la multiplication par 0x0A rlf w_temp,f movf w_temp,w rlf w_temp,f rlf w_temp,f addwf w_temp,w ; fin de la multiplication par 10 ; andlw 0x0F ; masquage du quartet de poids fort movwf w_temp ; temp = 0x0A * buffer quartet ; soustraction decf FSR_temp,f ; décrémentation du pointeur de quartet vers le précédent movf FSR_temp,w ; movwf FSR movf INDF,w ; récupération du quartet précédent movwf retenue ; retenue = quartet précédent movf w_temp,w ; Wreg = résultat de la multiplication précédente par 0x0A subwf retenue,f ; (quartet précédent) - (A * quartet) = retenue ; mémorisation du résultat movf FSR_temp2,w ; pointeur de case mémoire de digit de la fréquence movwf FSR movf retenue,w ; envoi du résultat dans la case mémoire andlw 0x0F ; masquage d'un éventuel 'F' si (A * quartet) inférieur à (quartet précédent) movwf INDF incf FSR_temp2,f ; pointage de la case mémoire suivante pour y stocker le résultat de cette multiplication & soustraction decfsz repeat_loop,f ; encore une multiplication & soustraction à effectuer? goto multiplication_quartets ; oui return ; non, c'est fini ;********************************************************************* ;********************************************************************* ; PROGRAMME PRINCIPAL * ;********************************************************************* ;********************************************************************* start call lcdstart ; init LCD call welcomemsg ; affiche le message d'accueil btfss FUNC ; test si FUNC est appuyé au boot call FUNC_reset ; RAZ paramètres "d'usine" movlw 0x00 ; récupération des paramètres mémorisées en EEPROM interne call read_EEP movwf freq_H movlw 0x01 call read_EEP movwf freq_L movlw 0x02 call read_EEP movwf step movlw 0x03 call read_EEP movwf I2C_speed ; fin de la récupération call wait_1s ; encore un peu de temps avant l'effacement du message d'accueil call clearscreen ; effacement de l'écran call background ; affichage des données fixes call display_freq ; affichage de la fréquence call display_step ; affichage du pas call send_freq ; envoi de la fréquence au module COMTECH wait_release ; on attend que tous les boutons soient relachés clrwdt movf PORTB,w andlw b'11000000' movwf w_temp movf PORTA,w andlw b'00000011' iorwf w_temp,w sublw b'11000011' ; résultat précédent - la valeur au repos btfss STATUS,Z ; résultat égal à 0 (toutes les touches sont relachées)? goto wait_release ; non call wait_30ms ; anti-rebond logiciel wait_action ; oui, on attend qu'un bouton soit pressé clrwdt btfss UP goto UP_ btfss DN goto DN_ btfss FUNC goto FUNC_ btfss SCAN goto SCAN_ goto wait_action ;********************************************************************* ; UP * ;********************************************************************* UP_ ; incrémentation de la fréquence en fonction du pas sélectionné movf step,w bcf STATUS,C addwf freq_L,f ; octet bas de la fréquence en héxa + step = freq_L btfsc STATUS,C ; valeur supérieure à 0xFF? incf freq_H,f ; oui call check_overflow ; non, on teste si la fréquence paut être gérée par la PLL call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_125ms ; anti-rebond logiciel btfsc UP goto wait_release ; si UP est relaché, on attend qu'une autre touche soit pressée call wait_1s ; sinon on attends le temps d'une petite tempo tant que UP reste pressé btfsc UP goto wait_release ; dernier test, si au bout de 0.5s la touche est restée enfoncée on lance l'incrémentation automatique loop_UP_ movf step,w bcf STATUS,C addwf freq_L,f ; octet bas de la fréquence en héxa + step = freq_L btfsc STATUS,C ; valeur supérieure à 0xFF? incf freq_H,f ; oui call check_overflow ; non, on teste si la fréquence paut être gérée par la PLL call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_30ms ; attente avant la prochaine incrémentation btfsc UP goto wait_release ; fin de la fonction, on retourne au scan des boutons poussoir goto loop_UP_ check_overflow movlw 0xBA bcf STATUS,C addwf freq_H,w ; freq_H max vaut 0x45, si sa valeur est supérieure on sort de la plage de la PLL donc il faut repartir au début btfsc STATUS,C ; freq_H + 0xAB supérieur à 0xFF? goto min_freq ; oui movlw 0xBB ; non addwf freq_H,w ; freq_H max vaut 0x45, si sa valeur est égale à 0x54 on teste freq_L, sinon on peut terminer le test btfss STATUS,C ; freq_H + 0xAC supérieur à 0xFF? return ; non, la fréquence peut être transmise à la PLL bcf STATUS,C ; oui movlw 0x9B addwf freq_L,w ; freq_L max vaut 0x64, si sa valeur est supérieure on sort de la plage de la PLL donc il faut repartir au début btfss STATUS,C ; freq_L + 0x9B supérieur à 0xFF? return ; non, la fréquence peut être transmise à la PLL ; oui, la ligne précédente est donc sautée et le programme va continuer tout seul avec reset_freq, on a gagné une ligne de code :) min_freq ; rechargement des valeurs les plus basses acceptables par la PLL movlw 0x2F movwf freq_H movlw 0x84 movwf freq_L return ; prêt à transmettre la fréquence de départ (la plus basse) à la PLL ;********************************************************************* ; DOWN * ;********************************************************************* DN_ ; décrémentation de la fréquence en fonction du pas sélectionné movf step,w bcf STATUS,C subwf freq_L,f ; octet bas de la fréquence en héxa - step = freq_L btfss STATUS,C ; valeur inférieure à 0x00? decf freq_H,f ; oui call check_underflow ; non, on teste si la fréquence paut être gérée par la PLL call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_125ms ; anti-rebond logiciel btfsc DN goto wait_release ; si DN est relaché, on attend qu'une autre touche soit pressée call wait_1s ; sinon on attends le temps d'une petite tempo tant que DN reste pressé btfsc DN goto wait_release ; dernier test, si au bout de 0.5s la touche est restée enfoncée on lance la décrémentation automatique loop_DN_ movf step,w bcf STATUS,C subwf freq_L,f ; octet bas de la fréquence en héxa - step = freq_L btfss STATUS,C ; valeur inférieure à 0x00? decf freq_H,f ; oui call check_underflow ; non, on teste si la fréquence paut être gérée par la PLL call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_30ms ; attente avant la prochaine décrémentation btfsc DN goto wait_release ; si DN est relaché, on attend qu'une autre touche soit pressée goto loop_DN_ check_underflow movlw 0xD1 bcf STATUS,C addwf freq_H,w ; freq_H min vaut 0x2F, si sa valeur est inférieure on sort de la plage de la PLL donc il faut repartir à la fin btfss STATUS,C ; freq_H + 0xD2 supérieur à 0xFF? goto max_freq ; non, freq_H est inférieur à sa valeur min movlw 0xD0 ; oui addwf freq_H,w ; freq_H min vaut 0x2F, si sa valeur est égale à 0x2F on teste freq_L, sinon on peut terminer le test btfsc STATUS,C ; freq_H + 0xD1 supérieur à 0xFF? return ; oui, freq_H est supérieur à sa valeur min bcf STATUS,C ; non, freq_H est égal à sa valeur min movlw 0x7D addwf freq_L,w ; freq_L min vaut 0x84, si sa valeur est inférieure on sort de la plage de la PLL donc il faut repartir à la fin btfsc STATUS,C ; freq_L + 0x80 supérieur à 0xFF? return ; oui, freq_L est supérieur ou égal à sa valeur min ; non, freq_L est inférieur à sa valeur min max_freq ; rechargement des valeurs les plus basses acceptables par la PLL movlw 0x45 movwf freq_H movlw 0x64 movwf freq_L return ; prêt à transmettre la fréquence de départ (la plus basse) à la PLL goto wait_release ;********************************************************************* ; ENVOI I2C DE LA FREQUENCE * ;********************************************************************* send_freq clrf I2C_ERR call i2c_start movlw RX_ADDR call i2c_write movf freq_H,w call i2c_write movf freq_L,w call i2c_write movlw RX_VALID call i2c_write call i2c_stop movlw 0xFF ; test si il y a eu un NoACK bcf STATUS,C addwf I2C_ERR,w btfss STATUS,C call ACK btfsc STATUS,C call NACK return ;********************************************************************* ; AFFICHAGE DE LA FREQUENCE * ;********************************************************************* display_freq call addition_EFC call multiplication_7D call conversion_hexa_dec movlw 0x05 movwf retenue ; on affiche le point après le 4e digit affiché movlw 0x3B movwf FSR_temp movlw 0x07 movwf repeat_loop3 ; repeat_loop est utilisé pour les tempos et repeat_loop2 est utilisé par la routine d'affichage LCD movlw 0x05 movwf LCDcol call line2 loop_display decfsz retenue,f goto next_digit goto jump_dot next_digit movf FSR_temp,w movwf FSR movf INDF,w addlw 0x30 call inits4b incf FSR_temp,f incf LCDcol,f ; colonne suivante sur la ligne (utilisé pour sauter le point uniquement) decfsz repeat_loop3,f goto loop_display return jump_dot ; saut du point des kHz movlw 0xff movwf retenue ; pas d'autre point par la suite incf LCDcol,f ; sauter le point call line2 ; curseur placé après le point goto next_digit ; Fonction FUNC_: ; RAPPEL: ; 0x01 = pas de 125kHz ; 0x02 = pas de 250kHz ; 0x04 = pas de 500kHz ; 0x08 = pas de 1MHz ; 0x50 = pas de 10MHz ; ; pour le UP_ on décale d'un cran vers la gauche l'octet step et on le vérifie après: ; - soit le quartet de poids fort vaut 0, donc il n'y a rien de plus à faire, ; - soit le quartet de poids fort vaut plus de 5, dans ce cas il faut mettre step à 0x01, ; - soit le quartet de poids fort est inférieur à 5, dans ce cas il faut mettre step à 0x50. ; ; pour le DN_ on décale d'un cran vers la droite l'octet step et on le vérifie après: ; - soit le quartet de poids fort vaut 0, on teste alors le quartet de poids faible, si il vaut 0 on met step à 0x50, ; - soit le quartet de poids fort est inférieur à 5, dans ce cas il faut mettre step à 0x08. ; ; Après avoir effectué un UP_ ou DN_, on teste la valeur de l'octet step pour savoir quoi afficher sur la première ligne du LCD. ; La façon la plus simple est de ne vérifier que le quartet de poids faible de step, si aucun de ses bits n'est à 1 on est forcément en mode 10MHz. release_FUNC_ ; on attend que les boutons UP/DN soient relachés clrwdt movf PORTB,w andlw b'11000000' sublw b'11000000' ; résultat précédent - la valeur au repos btfss STATUS,Z ; résultat égal à 0 (toutes les touches sont relachées)? goto release_FUNC_ ; non call wait_30ms ; anti-rebond logiciel FUNC_ ; on va rester dans cette boucle tant que le bouton FUNC sera pressé clrwdt btfss UP goto STEP_UP_ btfss DN goto STEP_DN_ btfss SCAN goto STORE_ ; ici la touche SCAN sert à mémoriser la fréquence dans l'EEPROM interne du PIC btfsc FUNC ; FUNC toujours pressé? goto wait_action ; non, on sort de ce menu goto FUNC_ ; oui, on reboucle STEP_UP_ call wait_30ms ; anti-rebond logiciel bcf STATUS,C rlf step,f ; step décalé d'un cran vers la gauche movf step,w movwf w_temp ; octet copié dans w_temp pour les tests bcf STATUS,C addlw 0xF0 btfss STATUS,C ; quartet égal à 0? goto call_display_step ; oui, pas besoin d'aller plus loin dans les tests movf w_temp,w ; non, il faut tester si le décalage à gauche nécéssite une mise à 0x01 ou 0x50 de step bcf STATUS,C addlw 0xA0 ; si w_temp inférieur à 0x50, C restera à 0 movlw 0x01 ; on part sur la supposition que w_temp est supérieur à 0x50 btfss STATUS,C ; si C vaut 0, on saute la ligne suivante movlw 0x50 ; si C vaut 1, on ne saute pas cette ligne movwf step call display_step goto release_FUNC_ STEP_DN_ call wait_30ms ; anti-rebond logiciel bcf STATUS,C rrf step,f btfsc STATUS,C ; le décalage à droite a mis la retenue à 1? goto set_step_50 ; oui movf step,w movwf w_temp ; non, il faut savoir si step valait 0x50 avant le décalage bcf STATUS,C addlw 0xE0 ; si step valait 0x50 avant le décalage, il vaut 0x20 après. 0x20 + 0xE0 = 0x100 (C = 1) btfss STATUS,C ; C=1? goto call_display_step ; non, step ne valait pas 0x50 avant le décalage movlw 0x08 ; oui, il faut redéfinir la valeur de step movwf step call_display_step call display_step goto release_FUNC_ set_step_50 movlw 0x50 movwf step goto call_display_step display_step movf step,w movwf EEDATA movlw 0x02 call write_EEP movlw 0x04 movwf LCDcol call line1 ; curseur placé au bon endroit sur le LCD movf step,w movwf w_temp ; on recopie la valeur corrigée (si nécéssaire) de step dans w_temp bcf STATUS,C rrf w_temp,f ; w_temp décalé d'un cran vers la droite, test du bit envoyé dans la retenue btfsc STATUS,C ; octet à 1? goto display_125k ; oui bcf STATUS,C ; non, on continue... rrf w_temp,f btfsc STATUS,C goto display_250k bcf STATUS,C rrf w_temp,f btfsc STATUS,C goto display_500k bcf STATUS,C rrf w_temp,f btfsc STATUS,C goto display_1M goto display_10M ; par déduction, si ce n'est pas les 4 autres possibilités... c'est forcément celle-ci display_125k movlw high msg_11 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_11 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return display_250k movlw high msg_12 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_12 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return display_500k movlw high msg_13 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_13 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return display_1M movlw high msg_14 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_14 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return display_10M movlw high msg_15 ; Adresse haute du message à envoyer -> ADDRH_MSG movwf ADDRH_MSG movlw low msg_15 ; Adresse basse du message à envoyer -> ADDRL_MSG call envoi_msg return STORE_ call wait_30ms ; anti-rebond logiciel movf freq_H,w movwf EEDATA movlw 0x00 call write_EEP movf freq_L,w movwf EEDATA movlw 0x01 call write_EEP call storemenu goto release_FUNC_ SCAN_ call scanmenu release_SCAN_ clrwdt movf PORTB,w andlw b'11000000' movwf w_temp movf PORTA,w andlw b'00000001' iorwf w_temp,w sublw b'11000001' ; résultat précédent - la valeur au repos btfss STATUS,Z ; résultat égal à 0 (toutes les touches sont relachées)? goto release_SCAN_ ; non call wait_30ms ; anti-rebond logiciel wait_SCAN_ clrwdt btfss UP goto SCAN_UP_ btfss DN goto SCAN_DN_ btfss SCAN goto end_SCAN_ goto wait_SCAN_ SCAN_UP_ clrwdt btfss SCAN goto release_SCAN_ ; si la touche SCAN est appuyée, le scan est stoppé btfss DN goto SCAN_DN_ ; si la touche DN est appuyés, le scan décrémente la fréquence movf step,w bcf STATUS,C addwf freq_L,f ; octet bas de la fréquence en héxa + step = freq_L btfsc STATUS,C ; valeur supérieure à 0xFF? incf freq_H,f ; oui call check_overflow call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_125ms ; pause de 125ms goto SCAN_UP_ SCAN_DN_ clrwdt btfss SCAN goto release_SCAN_ ; si la touche SCAN est appuyée, le scan est stoppé btfss UP goto SCAN_UP_ ; si la touche DN est appuyés, le scan décrémente la fréquence movf step,w bcf STATUS,C subwf freq_L,f ; octet bas de la fréquence en héxa - step = freq_L btfss STATUS,C ; valeur inférieure à 0x00? decf freq_H,f ; oui call check_underflow call send_freq ; envoi de la fréquence à la PLL call display_freq ; affichage de la fréquence sur le LCD call wait_125ms ; pause de 125ms goto SCAN_DN_ end_SCAN_ call wait_30ms ; anti-rebond logiciel call VFOmenu goto wait_release ;********************************************************************* ; RESET * ;********************************************************************* FUNC_reset movlw 0x3C ; fréquence remise à 2400MHz movwf EEDATA movlw 0x00 call write_EEP movlw 0x04 movwf EEDATA movlw 0x01 call write_EEP movlw 0x04 ; step à 500kHz movwf EEDATA movlw 0x02 call write_EEP movlw 0x01 ; débit I2C remis au max (environ 33.33kHz) movwf EEDATA movlw 0x03 call write_EEP return ; on reprend le cours normal du programme END ; directive fin de programme