PIC Microchip – Manipulateur électronique 12F675 CW Keyer
Depuis plusieurs semaines je parcours la documentation technique des petits processeurs 12F6xx de MICROCHIP. Petits, mais richement dotés à en juger par l’étendue de la documentation qui les accompagne. Poussé par le désir de ne pas en rester à la connaissance purement théorique du sujet et aussi par l’envie de « manger » un peu de code, j’ai cherché un projet qui pourrait me permettre de concrétiser mes acquis. Mon choix s’est porté rapidement sur un manipulateur électronique, petite machine utile à la station. Générer les DIT et les DAH c’est bien mais ce n’est pas tout, moyennant un peu de programmation, quelques fonctions fort utiles peuvent être implémentées. Il est agréable de pouvoir envoyer automatiquement les messages de base CQ CQ CQ DE F8EOZ… et aussi CQ DX et un autre pour les CONTEST. Trois messages enregistrés d’une manière simple au choix de l’utilisateur devraient suffire. Pas besoin de dizaines de mémoires. Il est intéressant d’avoir une écoute locale que l’on peut activer/désactiver ce qui permet d’utiliser le manipulateur pour l’entraînement ou d’utiliser le sidetone de son TRX. Changer la vitesse facilement pour s’adapter à celle de son correspondant est nécessaire. Choisir le mode iambique A ou B pourquoi pas. Enfin une dernière possibilité utile pour régler son antenne, générer une tonalité continue ou à pulsations très rapides. Toutes ces fonction accessibles rapidement et directement par boutons-poussoirs, pas de menus et sous-menus sélectionnés par paddle.
1. Description du projet
1.1. Logiciel
MPLAB IDE v8.92. J’utilise avec satisfaction cet environnement de développement MICROCHIP. A peu de frais, avec mon programmateur maison, il me permet de faire tous les tests de simulation et de débogage.
MPASMWIN v5.51. A priori, je pensais utiliser le langage C. D’une part, j’aurais quand même dû y broder un peu de code assembleur, d’autre part, la taille limitée de la mémoire 1 ou 2K, ont donné la préférence à l’assembleur. Le programme ne comprend pas de calculs compliqués et il n’y a qu’une bonne trentaine d’instructions assembleur à assimiler. Elles sont les mêmes que celles que j’ai utilisées pour le fréquencemètre.
1.2. Matériel
MCU. Les processeurs de la série 12F6 sont dotés de 6 ports mais pas des mêmes possibilités. Je tiens à garder le port GP3 en fonction MCLR (reset) ce qui me laisse 5 ports. Le postulat émis en introduction d’avoir accès aux fonctions directement par boutons-poussoirs m’oriente vers un petit clavier connecté à un port ADC. Je dispose du 12F675 et du 12F683. Je pense que 1K de mémoire devrait suffire à tenir le code du programme et les 128 bytes de l’EEPROM suffisent pour les messages. J’opte finalement pour le 12F675.
Clavier. Les touches de fonctions sont regroupées sur un petit clavier 3×3 réalisé ex nihilo. L’assignation des fonctions est libre et indépendante de la place physique des touches. Cela permet à chacun de choisir la disposition qui lui convient. (personnalisation). L’assignation est faite par des définitions qui font le lien entre le numéro de touche et la fonction.
Ecoute locale. Elle est réalisée par un petit buzzer connecté à un transistor servant de buffer.
Commande du TX. Elle est réalisé par un transistor.
La figure 1 ci-dessous montre le schéma du circuit.
2. Analyse fonctionnelle
2.1. Expression des besoins
En introduction, l’expression fonctionnelle du besoin a permis de définir les fonctions que la machine devra réaliser. Je les rappelle:
- Générer le code Morse en mode Iambique ou Droit,
- Envoyer 3 messages au choix,
- Incrémenter, décrémenter la vitesse,
- Choisir le mode iambique A ou B,
- Choisir l’utilisation de l’écoute locale, BUZZER ON/OFF,
- Générer pour le réglage d’antenne un signal, TUNE Pulse ou Carrier.
2.2. Schéma fonctionnel
Le schéma figure 2 ci-dessous montre le diagramme fonctionnel du manipulateur.
Chacun des blocs mis en évidence fera l’objet d’une description des fonctions principales et des données qu’elles manipulent dans la suite de l’article.
2.2.1. Organes de sortie
Buzzer via un buffer.
Fonction : écoute locale sur option, message de service.
Commutateur Tx: commutateur à transistor.
Fonction : émission en code Morse via le Tx, des messages préenregistrés en clair, émission de la manipulation.
2.2.2. Organes d’entrée
Clef Morse: Iambique (choix du mode A ou B), Droite détectée au setup si le DAH est à la masse.
Fonction : manipulation du message, le DIT sert à avorter (abort) un message préenregistré en cours d’émission.
Clavier matriciel 3×3: organe de commande personnalisable, accessible pendant les temps morts c’est à dire quand la clef Morse reste inactive plus d’une seconde (paramètre).
Fonction: un bouton, une fonction, soit 9 fonctions.
Reset bouton de reset.
Fonction : setup.
2.2.3. Flux de données
Message de service: c’est un message local court destiné à informer l’utilisateur que la commande a été comprise. Il s’agit en général d’un caractère émis en code Morse à la vitesse courante. Il est destiné uniquement au BUZZER même quand celui-ci est OFF. Il est stocké en RAM et personnalisable.
Message préenregistré: c’est un message destiné au TX et au BUZZER s’il est ON. Il est de longueur variable (0 à n caractères), sa limite physique est celle de l’espace disponible dans l’EEPROM compte-tenu de la place prise par les autres messages. Il est muni de 2 propriétés: un identificateur symbolique qui correspond simplement au numéro du bouton qui le commande, un facteur de répétition personnalisable (0 à ∞). Il peut être interrompu par un DIT de la clef Morse. Il est rédigé en clair et transformé en code Morse par la machine. Il est diffusé à la vitesse courante de la machine.
Message manipulé: c’est le message généré par la clef Iambique ou Droite destiné au TX et au BUZZER s’il est ON. Avec la clef Iambique, quand les 2 paddles sont pincés, la répétition automatique des DIT et DAH est commandée en mode A ou en mode B.
2.2.4. Organes internes
Les organes internes de l’automate réalisent les fonctions techniques. Leur conception autonome facilite leur développement et leur mise au point. Ils peuvent ainsi être réutilisés.
KEY INTERFACE: traduit les appuis de la CLEF en DIT et DAH. Le type de clef Iambique ou Droite est déterminé automatiquement au Setup (DAH à la masse = clef Droite). Le mode Iambique A ou B est sélectionnable par une touche du clavier fonctionnant en bascule. L’interface commande l’accès au clavier blocage/déblocage de manière asynchrone par l’interruption TIMER1.
MORSE PLAYER ou PLAYER: joue DIT, DAH et espace entre les mots (GAP) à la demande de la CLEF ou de l’ENCODER. Autrement-dit, il commande les ports de sortie BUZZER et TX au niveau haut et bas à la vitesse courante.
Remarque: le signal PULSE n’est qu’une série de DIT qui se prolonge indéfiniment jusqu’à interruption, CARRIER est un signal continu qui se prolonge indéfiniment jusqu’à interruption.
L’ interrupteur BUZF autorise ou non la sortie BUZZER, l’interrupteur TXF autorise ou non la sortie TX.
Paramètre : unité de temps = durée d’un point à la vitesse courante.
MORSE TIMER: donne l’unité de temps en ms (le point) en fonction de la vitesse (nombre de mots/mn). L’unité de temps peut être incrémentée ou décrémentée par touches successives du clavier. La valeur par défaut est fixée à 12 mots/mn. La dernière valeur utilisée est conservée en EEPROM et reprise ensuite à chaque SETUP.
KEYPAD INTERFACE: gère le clavier matriciel 3×3. L’interface utilise l’ADC du MCU.
Paramètres: description du clavier (assignation des touches aux fonctions), table des seuils de tension analogique, numérique (intervalle numérique réservé à chaque touche).
ENCODER: traduit un caractère, lettre, chiffre, ponctuation, procédure, en code Morse à destination du PLAYER.
Trois entrées possibles : un message préenregistré de l’EEPROM, un message de service stocké en RAM, un message provenant du déroulement du programme.
Le message peut être interrompu par un appui et un relâchement de la clef DIT.
Paramètre: règles de traduction du caractère.
3. Méthode de développement
L’option MPLAB SIM du Debugger de MPLAB IDE permet de vérifier efficacement le bon fonctionnement du programme. Mais le test réel révèle toujours des défauts à corriger. La difficulté est de n’avoir aucun moyen de visualiser, ni de tracer le programme. Quoiqu’ en y réfléchissant, nous avons 2 moyens: nos oreilles et l’EEPROM. L’envoi vers le BUZZER de signaux Morse aux endroits à étudier permet de suivre le programme. L’enregistrement en EEPROM de données partielles permet aussi d’obtenir des indications. Il suffit de replacer le MCU sur le programmateur. PICPgm va relire le contenu de l’EEPROM et l’afficher. Ces traces seront naturellement provisoires (utilisation de define) et disparaissent dans la version Release. Cette observation conditionne la chronologie de développement. J’ai d’abord commencé par produire les sons, ensuite les messages et le reste a suivi.
4. Le clavier matriciel 3×3 touches
4.1. Conception
Je me suis fondé sur le document « Two-wire, four-by-four-key keyboard interface saves power » de « Stefano Salvatori, University of Rome, and Gabriele Di Nucci, EngSistemi, Rome, Italy » paru dans la rubrique designideas de EDN Network.
Le clavier figure 3, ci-dessus, est une matrice 3×3 dans la quelle il est possible de calculer la tension Vout lorsque l’un quelconque des boutons est pressé en appliquant l’équation:
V(x,y) = Vref . Rb/( xRa + yRb + Rb) (1).
L’équation (1) peut s’écrire sous forme d’un rapport de résistances:
V(x,y)/Vref = Rb/( xRa + yRb + Rb) (2).
Posons Rb=Ra/p, l’équation (2) peut s’écrire:
V(x,y)/Vref = (Ra/p)/( xRa + y(Ra/p) + (Ra/p))
ou en multipliant par (p/Ra)/(p/Ra)
on obtient le rapport diviseur de tension quel que soit la touche pressée:
r(x,y) = V(x,y)/Vref = 1 / ( 1 + x.p + y) (3)
dans laquelle p = Ra/Rb représente le rapport entre les résistances de lignes et de colonnes.
On observe facilement que le ratio Rb/Ra<3 donne des doublons et ne convient pas. En prenant une résolution ADC N=10 bits et en choisissant une tolérance T=0,01 pour les résistances Ra et Rb, il est possible de distinguer avec une bonne marge de sécurité 9 valeurs de tension.
J’ai choisi Ra=11K 1% et Rb=33K 1% simplement parce que je les avais en stock. D’autres combinaisons de rapport 1/3 sont possibles : Ra=1,3K et Rb=3,9K ou Ra=1,2K et Rb=3,6K par exemple. Ces dernières valeurs étant, par ailleurs, meilleures que celles que j’ai utilisées car je me suis rendu compte que la documentation MICROCHIP conseille de ne pas dépasser 10K en entrée de l’ADC. En effet, la résistance intervient dans le temps d’acquisition.
Il est maintenant très facile de calculer les valeurs numériques de chaque bouton dans l’intervalle [0, 1023]
AD RESULT = 1023. r(x,y) (4).
On constate un resserrement des valeurs les plus basses mais encore très acceptable. Enfin, cette expression montre que le résultat dépend essentiellement de la qualité des résistances. Dans la réalité, j’ai fixé une petite fenêtre d’examen autour de cette valeur qui laisse une marge d’erreur.
Ces valeurs sont reportées sur la figure ci-dessus. Notre schéma maintenant complet, le clavier peut être programmé et fabriqué.
4.2. Mise en oeuvre de l’ADC
Le clavier est connecté à l’entrée AN0. Cette entrée est lue cycliquement. Le résultat est placé dans un registre ADRES de 10 bits donnant une valeur numérique de 0 à 1023 qui correspond au niveau de tension de la touche pressée. Le clavier n’est qu’un diviseur de la tension Vdd, tension de référence.
Sa mise en oeuvre passe par l’initialisation de quelques registres. Les chapitres 6 et 7 de la documentation technique du 12F675 décrivent le Comparateur et l’ADC.
Le registre ADCON0:
Tout est dit dans le diagramme 7-1 figure 4, ci-dessous, extrait de la documentation.
Le registre ADCON0 met ce circuit en état de fonctionnement. Voici sa définition et son initialisation dans le programme:
;---------------------------------------------------------------------- ; ADC Config #define ADC_CON b'10000001' #define ADC_AN0 b'00000000' #define ADC_AN1 b'00000100' #define ADC_AN2 b'00001000' #define ADC_AN3 b'00001100' ; 1------- ADFM: 1=right justified result ; -0------ VCFG: 0=Vdd is voltage reference ; --xx---- not implemented ; ----00-- 00=select channel 00 (AN0=GP0) ; 01 = Channel 01 (AN1=GP1) ; 10 = Channel 02 (AN2=GP2) ; 11 = Channel 03 (AN3=GP4) ; ------0- GO/NOT DONE Status bit: 0=A/D conversion not started ; -------1 ADON: Conversion Status bit 1=A/D converter module is operating #define ADC_AN_KPAD ADC_AN0 ; assign Keypad to Channel 00 ; set up A/D converter banksel ADCON0 movlw ADC_CON | ADC_AN_KPAD movwf ADCON0
Le registre ANSEL:
Sa fonction est de désigner les ports qui sont affectés au convertisseur et de fixer la fréquence de conversion du cycle A/D. Choisir la fréquence ad hoc, ni trop, ni trop peu. TAD = A/D clock period. Le minimum TAD requis est de 1.6us, paragraphe 7-1-4 de la documentation technique, à 4MHz avec Fosc=8 le minimum TAD = 4MHz/8 = 2us. Les valeurs Fosc inférieures ne conviennent pas puisque TAD<1,6us. La table 7-1 , ci-dessous, extraite de la documentation, résume cela.
Note importante: placer un port en entrée analogique enlève automatiquement les résistances internes de pull-ups. Il faut donc utiliser des résistances externes.
En résumé, voici son initialisation dans le programme:
; set up A/D converter banksel ANSEL movlw b'00010001' ; x------- not implemented ; -001---- ADCS A/D Conversion Clock: 001=Focs/8 Conversion Clock ; -101---- ADCS A/D Conversion Clock: 001=Focs/16 Conversion Clock ; ----0--- ANS3:ANS0: Analog Select bits 0=digital I/O, GP4, Tx output ; -----0-- ANS3:ANS0: Analog Select bits 0=digital I/O, GP2, DIT paddle input ; ------0- ANS3:ANS0: Analog Select bits 0=digital I/O, GP1, DAH paddle input ; -------1 ANS3:ANS0: Analog Select bits 1=analog I/O, GP0, analog input movwf ANSEL
Echantillonage – Calcul du temps d’acquisition minimum:
Un cycle d’échantillonnage comprend 2 phases:
- le temps d’acquisition ou TACQ qui commence après que le canal a été choisi ou qu’un cycle s’achève et que le condensateur interne commence sa charge,
- le temps de conversion qui commence à fin du TACQ et quand le GO bit=1, qui s’achève après 11 TAD.
La résistance d’entrée intervient dans le calcul du temps de charge TC du condensateur interne et par conséquent du TACQ minimum. Avec une résistance de 10K en entrée le TACQ = 19.2us. Comme j’ai utilisé une résistance un peu plus élevée de 33K je calcule
TC = 120 pF(1K+7K+33K)ln0.0004885 = 37.5us
ce qui donne pour TACQ = 40us environ. En y ajoutant 11 * 2us nous obtenons environ 62us. Ce temps est largement inférieur à mon temps de réaction et d’appui sur les touches du clavier… L’équation encadrée, ci-dessus, extraite de la documentation, résume cela.
Le registre CMCON:
Puisque le module comparateur n’est pas utilisé, on choisit l’option « Comparator off ». Voici son initialisation dans le programme:
; set up comparator banksel CMCON movlw b'00000111' ; x------- not implemented ; -0------ COUT: Comparator Output bit: 0 = VIN+ < VIN- When CINV = 0 ; --x----- not implemented ; ---0---- CINV: Comparator Output Inversion bit 0=non-inverted output ; ----0--- CIS: Comparator Input Switch bit When CM2:CM0 = 110 or 101 ; -----111 CM2:CM0: Comparator Mode bits 111=comparator off movwf CMCON
4.3. Programmation
Description du clavier:
La programmation du clavier figure 7, ci-dessous, est réalisée en se fixant 2 objectifs: rendre le module KEYPAD INTERFACE réutilisable pour un autre projet, rendre le clavier personnalisable.
Les touches sont numérotées de 0 à 8 en fonction de leur position x,y, les fonctions liées à ces touches sont assignées ensuite. Pour personnaliser le clavier il suffit de changer l’assignation. J’ai choisi de placer les touches d’envoi des messages sur la première colonne, il serait possible de les assigner à une autre colonne ou une ligne, par exemple. La programmation n’en serait nullement affectée. Voici sa description dans le programme:
; Definition KPAD_00 EQU 0 KPAD_10 EQU 1 KPAD_20 EQU 2 KPAD_01 EQU 3 KPAD_11 EQU 4 KPAD_21 EQU 5 KPAD_02 EQU 6 KPAD_12 EQU 7 KPAD_22 EQU 8 KPAD_FF EQU 0xFF ; no key ; Assign key 3x3 push button ; This allows one to change keypad layout without change algorithm ; My Layout: ; (y2) ; (y1) ; (y0) ; (x2) (x1) (x0) KPAD_SEND0 EQU KPAD_22 KPAD_SEND1 EQU KPAD_21 KPAD_SEND2 EQU KPAD_20 KPAD_SPEED_UP EQU KPAD_12 KPAD_SLOW_DOWN EQU KPAD_11 KPAD_BUZ EQU KPAD_10 KPAD_TUNEC EQU KPAD_02 KPAD_TUNEP EQU KPAD_01 KPAD_MOD EQU KPAD_00
Définition des seuils de tension:
A chaque touche correspond un niveau de tension et un seul. Mais comme rien n’est parfait, il faut attribuer à chaque touche une fenêtre de visée. J’ai défini 9 intervalles [min, max[ disjoints (pas de chevauchement). Pour faciliter la mise au point, les limites min et max sont des paramètres. Voici la description dans le programme:
; Fitted after real analyze #define VTOLPLUS 10 ; tolerance #define VTOLMINUS 1 ; tolerance ; Row 0 (3069=1023*3) #define KPAD_00_MAX (1023+VTOLPLUS) ;key 0,0 (maximum maximorum) #define KPAD_00_MIN (1023-VTOLMINUS) ;key 0,0 #define KPAD_10_MAX ((3069/4)+VTOLPLUS) ;key 1,0 #define KPAD_10_MIN ((3069/4)-VTOLMINUS) ;key 1,0 #define KPAD_20_MAX ((3069/5)+VTOLPLUS) ;key 2,0 #define KPAD_20_MIN ((3069/5)-VTOLMINUS) ;key 2,0 ; Row 1 #define KPAD_01_MAX ((1023/2)+VTOLPLUS) ;key 0,1 #define KPAD_01_MIN ((1023/2)-VTOLMINUS) ;key 0,1 #define KPAD_11_MAX ((3069/7)+VTOLPLUS) ;key 1,1 #define KPAD_11_MIN ((3069/7)-VTOLMINUS) ;key 1,1 #define KPAD_21_MAX ((3069/8)+VTOLPLUS) ;key 2,1 #define KPAD_21_MIN ((3069/8)-VTOLMINUS) ;key 2,1 ; Row 2 #define KPAD_02_MAX ((1023/3)+VTOLPLUS) ;key 0,2 #define KPAD_02_MIN ((1023/3)-VTOLMINUS) ;key 0,2 #define KPAD_12_MAX ((3069/10)+VTOLPLUS) ;key 1,2 #define KPAD_12_MIN ((3069/10)-VTOLMINUS) ;key 1,2 #define KPAD_22_MAX ((3069/11)+VTOLPLUS) ;key 2,2 #define KPAD_22_MIN ((3069/11)-VTOLMINUS) ;key 2,2 ; NO KEY #define KPAD_FF_MAX VTOLPLUS ; no key #define KPAD_FF_MIN 0 ; no key
Remarque: les calculs dans les définitions peuvent réserver des surprises, c'est pourquoi j'ai simplifié la formule en multipliant 1023 par le facteur 3.
Une façon simple de gérer une liste de données, moyennant quelques précautions dans l'implantation mémoire, est d'implémenter une "Lookup Table". Voici sa description dans le programme:
ADC_Vth_TABLE movlw HIGH(ADC_Vth_KEYPAD); PCLATH = HIGH bit address movwf PCLATH ; movf ADCVthPointer,W ; for PCL addwf PCL ,F ; Jump to character pointed to in W register ADC_Vth_KEYPAD ; maximum voltage threshold for keypad: analog to digital convert ; real digit value saved into EEPROM for analyze (use __ADRES_TRON to get result) ; (2) (1) (0) ; 8---- 7---- 6---- (2) ; 01 18 01 34 01 58 ; 5---- 4---- 3---- (1) ; 01 82 01 B8 02 01 ; 2---- 1---- 0---- (0) ; 02 69 03 01 03 FF ; -------xy: digit maximum voltage threshold : digit minimum voltage threshold DT KPAD_FF,(HIGH KPAD_FF_MAX),LOW (KPAD_FF_MAX),(HIGH KPAD_FF_MIN),LOW (KPAD_FF_MIN) DT KPAD_22,(HIGH KPAD_22_MAX),LOW (KPAD_22_MAX),(HIGH KPAD_22_MIN),LOW (KPAD_22_MIN) DT KPAD_12,(HIGH KPAD_12_MAX),LOW (KPAD_12_MAX),(HIGH KPAD_12_MIN),LOW (KPAD_12_MIN) DT KPAD_02,(HIGH KPAD_02_MAX),LOW (KPAD_02_MAX),(HIGH KPAD_02_MIN),LOW (KPAD_02_MIN) DT KPAD_21,(HIGH KPAD_21_MAX),LOW (KPAD_21_MAX),(HIGH KPAD_21_MIN),LOW (KPAD_21_MIN) DT KPAD_11,(HIGH KPAD_11_MAX),LOW (KPAD_11_MAX),(HIGH KPAD_11_MIN),LOW (KPAD_11_MIN) DT KPAD_01,(HIGH KPAD_01_MAX),LOW (KPAD_01_MAX),(HIGH KPAD_01_MIN),LOW (KPAD_01_MIN) DT KPAD_20,(HIGH KPAD_20_MAX),LOW (KPAD_20_MAX),(HIGH KPAD_20_MIN),LOW (KPAD_20_MIN) DT KPAD_10,(HIGH KPAD_10_MAX),LOW (KPAD_10_MAX),(HIGH KPAD_10_MIN),LOW (KPAD_10_MIN) DT KPAD_00,(HIGH KPAD_00_MAX),LOW (KPAD_00_MAX),(HIGH KPAD_00_MIN),LOW (KPAD_00_MIN) ; 5V ; don't remove line below retlw 0xFF ; high value = end of table IF ((HIGH ($)) != (HIGH (ADC_Vth_KEYPAD))) ERROR "ADC_Vth_KEYPAD CROSSES PAGE BOUNDARY!" ENDIF;
Algorithme Keystroke:
Keystroke, figure 8 ci-dessous, est l'algorithme principal de l'interface KEYPAD. Il lance le cycle ADC, récupère son résultat, sélectionne la touche frappée et lance la fonction liée à la touche.
Le code présenté ci-dessous est volontairement abrégé. Il ne montre pas le détail des fonctions liées à chaque touche ni la routine de comparaison CMP_A_B. On se reportera au programme source disponible en téléchargement.
;------------------------------------- ; KPAD_Keystroke process ; Scan ADC KPAD channel until find key ; Execute command associated with key KPAD_Keystroke KPAD_GetADRES movlw ADC_CON | ADC_AN_KPAD ; select channel Keypad call KPAD_GetADCvalue BANK1 ; store ADC result into compare register A movf ADRESL,W ; 8 bits low BANK0 movwf CmpAL movf ADRESH,W ; 2 bits High movwf CmpAH ; point to first ADC table item movlw ADC_Vth_KEYPAD - ADC_Vth_TABLE - 1 -3 -3 ; W = value relative address - 3 movwf ADCVthPointer ; Hold pevious line address KPAD_Lookup ; read one table item incf ADCVthPointer ; skip min value of previous table item incf ADCVthPointer incf ADCVthPointer ; point to current table item call ADC_Vth_TABLE ; lookup voltage scale to find key pressed movwf KeyPadXYtemp ; hold KeyPadXY byte incf ADCVthPointer,f ; Point to next byte call ADC_Vth_TABLE movwf CmpBH ; hold MAX value high byte into compare register B incf ADCVthPointer,f ; Point to next byte call ADC_Vth_TABLE movwf CmpBL ; hold MAX value low byte into compare register B call CMP_A_B ; compare ADC : MAX value btfss UCON1,A_LT_B ; is ADC value < MAX table value ? goto KPAD_Lookup ; no: NEXT item------> ; value is < MAX: then look for MIN value incf ADCVthPointer,f ; Point to next byte call ADC_Vth_TABLE movwf CmpBH ; hold MIN value high byte into compare register B incf ADCVthPointer,f ; Point to next byte call ADC_Vth_TABLE movwf CmpBL ; hold MIN value low byte into compare register B call CMP_A_B ; compare ADC : MIN value btfsc UCON1,A_EQ_B ; is ADC value = MIN table value goto KPAD_GetKey_Found ; yes: Key found------> btfss UCON1,A_GT_B ; is ADC value > MIN table value goto KPAD_GetADRES ; no: value out of voltage span, read again------> KPAD_GetKey_Found movf KeyPadXY,W ; Hold previous key movwf KeyPadXYPre movf KeyPadXYtemp,W ; Hold new key movwf KeyPadXY ;------------------------------- ; only for analyze and benchmark KPAD_Report ifdef __ADRES_TRON ; Report ADRES value into EEPROM for analyse addwf KeyPadXY,W ; pointer = 2*KeyPadXY btfsc STATUS,C ; carry set if key 0xFF goto KPAD_Report_End ; >>>no report sublw LOW(EE_ADRESL0); pointer to LSB BANK1 movwf EEADR ; into EEADR movf ADRESL,W ; ADC value LSB into EEDATA movwf EEDATA call WriteEEPROM ; write one byte to EEPROM BANK1 decf EEADR,f ; pointer to MSB BANK0 movf ADRESH,W ; ADC value MSB into EEDATA BANK1 movwf EEDATA call WriteEEPROM ; write one byte to EEPROM BANK0 endif KPAD_Report_End ;-------------- ; switch case KeyPadXY ; ; case: NO KEY movfw KeyPadXY xorlw KPAD_FF ; Check if no key btfsc STATUS, Z ; Z=0: no next key goto KPAD_Keystroke_End ; Z=1: yes, end key ====> ; ; case: KEY = PREVIOUS KEY movfw KeyPadXY xorwf KeyPadXYPre,W ; Check if equal btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_End ; end key ====> ; ; case: SEND0 movfw KeyPadXY xorlw KPAD_SEND0 ; Check if key Send0 btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_Sendn ; yes, ====> ; ; case: SEND1 movfw KeyPadXY xorlw KPAD_SEND1 ; Check if key Send1 btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_Sendn ; yes, ====> ; ; case: SEND2 movfw KeyPadXY xorlw KPAD_SEND2 ; Check if key Send2 btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_Sendn ; yes, ====> ; ; case: BUZZER movfw KeyPadXY xorlw KPAD_BUZ ; Check if key Buz btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_Buz ; yes, ====> ; ; case: TUNEP movfw KeyPadXY xorlw KPAD_TUNEP ; Check if key Tune PULSE btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_TunP ; yes, ====> ; ; case: TUNEC movfw KeyPadXY xorlw KPAD_TUNEC ; Check if key Tune CARRIER btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_TunC ; yes, ====> ; ; case: MODEAB movfw KeyPadXY xorlw KPAD_MOD ; Check if key Mod btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_Mod ; yes, ====> ; ; case: SPEED UP movfw KeyPadXY xorlw KPAD_SPEED_UP ; Check if key Speed up btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_SpeedUp ; yes, ====> ; ; case: SLOW_DOWN movfw KeyPadXY xorlw KPAD_SLOW_DOWN; Check if key Slow down btfsc STATUS, Z ; Z=0: no goto KPAD_Keystroke_SlowDown ; yes, ====> ; KPAD_Keystroke_End ; End of keypad return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Send message #0,#1,#2 to Tx ;---------------------------- KPAD_Keystroke_Sendn ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Side Tone Buzzer ON/OFF ; Only for TX message ; Not for service message ;------------------------ KPAD_Keystroke_Buz ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Tune mode constant carrier ;--------------------------- KPAD_Keystroke_TunC ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Tune mode pulse 50% duty cycle dits ;------------------------------------ KPAD_Keystroke_TunP ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Toggle mode A or B ;------------------- KPAD_Keystroke_Mod ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Speed up ;--------- KPAD_Keystroke_SpeedUp ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ; Slow down ;---------- KPAD_Keystroke_SlowDown ... return ;>>>>>>>>>>>>>>>>END OF KEYPAD ;---------------------------------------------------------------------- ; KPAD_GetADCvalue ; Convert analog voltage level to 10 bits number ; Input: WREG=AD config with channel number to read ; Output: 10 bit ADC value is read from the pin and returned justified right. ; Please refer data sheet Page 41 (Section 7.1.4) for the AD Conversion ; clock explanation. The 10-BIT ADC in the PIC12F675 are request ; minimum Tad with 1.6uS, and the conversion time need 11 Tad, so the ; mininum conversion time is 1.6uS * 11Tad = 17.6uS. KPAD_GetADCvalue movwf ADCON0 ; AD config channel ANx KPAD_GetADCvalue_Go movlw 15 ; wait for Acquisition time call Delay ; 15*5us=75us ; A/D conversion cycle in progress bsf ADCON0,GO_NOT_DONE ; Init GO_NOT_DONE btfsc ADCON0,GO_NOT_DONE ; return
Réglages:
Pour m’assurer de la qualité de l’intervalle de mesure [min, max[ les résultats sont stockés provisoirement en EEPROM pour être visualisés a posteriori avec PICPgm. La section de code optionnelle encadrée par les étiquettes KPAD_Report et KPAD_Report_End disparaît en version Release. De même, le précieux espace réservé en EEPROM est récupéré en mettant en commentaire la définition __ADRES_TRON . J'ai pu ainsi simplement vérifier que la théorie rejoignait la pratique.
Télécharger le programme source, le fichier .hex et tous les schémas.
5. Encodeur morse – Gestion des messages
5.1. Messages préenregistrés
La quasi totalité de l'EEPROM est réservée à l'enregistrement des messages. Un indicatif et 3 messages peuvent être enregistrés. l'espace est distribué de manière dynamique. Chaque message de longueur variable s'insère dans la place restant disponible comme le montre l'extrait du programme ci-dessous.
;-------------- ; MESSAGE BLOCK ;-------------- ; Your call sign here EE_CALLSIGN ; don't remove this label ; DE "F8EOZ" ; your call sign here CAPS LOCK ONLY DE _EOM ; end of call sign don't remove ;---------------------- ; Prerecorded message#: ; A..Z CAPS LOCK ONLY ; @ alias for CALLSIGN EE_MESSAGE ; don't remove this label ; ; message#0: ; CQ CQ CQ DE F8EOZ F8EOZ... DE _HOM,KPAD_SEND0,0x03 ; Head of message directive: message number (button assign), beacon time (0xFF=infinity) DE "CQ CQ CQ DE @ @ K " DE _EOM ; end of message#0 ; ; message#1: ; CQ DX CQ DX CQ DX DE F8EOZ F8EOZ... DE _HOM,KPAD_SEND1,0x03 ; Head of message directive: message number (button assign), beacon time (0xFF=infinity) DE "CQ DX CQ DX CQ DX DE @ @ K " DE _EOM ; end of message#1 ; ; message#2: ; CQ CQ F8EOZ F8EOZ TEST ... DE _HOM,KPAD_SEND2,0x03 ; Head of message directive: message number (button assign), beacon time (0xFF=infinity) DE "CQ CQ @ @ TEST " DE _EOM ; end of message#2 ;---------------------------------------- ;---------------------------------------- ;----------------------------------------
L'indicatif: il est traité comme un texte pour être inséré dans les messages au moyen d'un alias. Il doit être placé après l'étiquette EE_CALLSIGN. La directive de fin de message _EOM le termine.
Les messages sont placés à la suite de l'indicatif après l'étiquette EE_MESSAGE.
Le message: se compose de 3 parties : l'entête, le texte du message, la fin.
L'entête: comprend les données suivantes:
- directive _HOM (head of message),
- le nom symbolique du bouton qui l'active,
- le facteur de répétition (beacon time) [0, hFF] où FF = infini sachant qu’un message en cours peut toujours être interrompu par un DIT.
Le texte: c’est une chaîne de caractères ASCII et de codes procédure (prosign).
Caractère ASCII: [h20 (espace), h5A (Z)], portion de table comprenant les signes de ponctuation, les chiffres, les lettres majuscules. Les minuscules et tous les autres caractères ne sont pas utilisés.
Le caractère @ est utilisé comme alias de l’indicatif. L’encodeur le reconnaît et effectue son expansion.
Le caractère Espace est utilisé comme espace entre les mots (Word Gap).
Les codes de procédure sont situés dans l’intervalle [h80,hFF]. Les codes _AR,_BT,_SK peuvent être insérés simplement en fractionnant le texte. Exemple:
... DE "TEXTE",_BT,"SUITE..."
La fin du message: directive _EOM (End of Message)
5.2. Messages de service
Le principe reste le même que les messages préenregistrés à la différence que les messages sont stockés dans une table de la RAM. Chaque message est placé derrière l’étiquette qui correspond à l’événement déclencheur.
Personnalisation : dans ma version, le message est constitué d’un seul caractère mais il pourrait être aussi un texte. Pour rendre muet le message il suffit de le remplacer par un espace. L’alias @ ne peut être utilisé. Voici la description de la table:
MSG_TABLE movlw HIGH(MSG_DATA) ; PCLATH = HIGH bit address movwf PCLATH ; movf TabPointer,W ; for PCL addwf PCL ,F ; Jump to character pointed to in W register SERVICE_MESSAGE ; ; SERVICE MESSAGE ; IAMBIC_MSG ; iambic key DT "I",_EOM STRAIGHT_MSG ; straight key DT "S",_EOM SPEED_UP_MSG ; signal for speed change up DT "U",_EOM SLOW_DOWN_MSG ; signal for speed change down DT "D",_EOM MOD_A_MSG ; signal for mode A change DT "A",_EOM MOD_B_MSG ; signal for mode B change DT "B",_EOM BUZ_MSG ; signal for sidetone buzzer on/off DT _AR,_EOM ERROR_HM_NOT_FOUND ; signal for error header message not found DT _ERR,_EOM ; IF ((HIGH ($)) != (HIGH (SERVICE_MESSAGE))) ERROR "MSG_TABLE CROSSES PAGE BOUNDARY!" ENDIF;
5.3. L’encodeur
Le diagramme figure 9 ci-dessous, montre le processus d’encodage.
Registres:
- BitFrame: 8 bits comprenant le code Morse et une clé.
- ControlTape: bande pilote de 8 bits qui commande de gauche à droite l’émission du code Morse (1= émission, 0=fin de code).
- MorseCode: 8 bits de gauche à droite qui représente le code Morse (1 = DAH, 0=DIT).
ControlTape et MorseCode sont en correspondance biunivoque : ControlTape[b8]<->MorseCode[b8],…, ControlTape[b0]<->MorseCode[b0]
Entrée: un caractère ASCII ou un prosign.
Processus:
1) Transcodage:
- Phase 1 : au moyen de la table RAM ENC_BIT_FRAME_TABLE, le caractère ASCII [h20,h5A] est transformé en BitFrame, le prosign passe ce premier filtre sans changement.
- Phase 2 : Le prosign est transformé en Bit Frame. Les prosigns spéciaux passent ce second filtre sans changement.
2) Séparation:
Le BitFrame au moyen de sa clé, est divisé en 2 parties de 8 bits, MorseCode et ControlTape.
3) Encodage:
Enfin, l’encodage du signal morse est réalisé en faisant glisser vers la gauche la bande pilote (rotation gauche avec bit C) qui commande l’émission du signe Morse qui lui est relié.
Télécharger le programme source, le fichier .hex et tous les schémas.
6. Le manipulateur électronique
La boucle principale du programme figure 10 ci-dessous, inclut l’interface de la clé Morse. Au démarrage ou au Reset, le Setup restaure les dernières options de la machine à partir de l’EEPROM :
- le registre UCON (User Control Register)
- la vitesse de manipulation en mots/mn.
La détection du type de clé, Iambique ou Droite, est réalisée au Setup en examinant le port DAH. Voici la description du registre UCON.
;----- UCON Bits ----------------------------------------------------- IAMBIC_KEY EQU 0x00 ; StraightKey=0 Iambic= 1 BUZE EQU 0x01 ; = 1 if side tone buzzer enable TXF EQU 0x02 ; Tx flag = 1 if message sending to Tx MSGF EQU 0x03 ; msg flag = 1 if send message running KPADF EQU 0x04 ; = 1 if keypad unlocked MOD_B EQU 0x05 ; = 1 if keyer mode B, 0 mode A BUZF EQU 0x06 ; buzzer flag = 1 if message sending to buzzer ;----- DEFAULT Options -------------------------------------------------- ; Iambic Key + Buzzer on #define UCON_DEFAULT (1<<IAMBIC_KEY) | (1<<BUZE) | (1<<BUZF)
L’accès au clavier est commandée de manière asynchrone par l’interruption TIMER1 (délai d’une seconde fixé par les paramètres TMR1_INIT et TMR1_OVF_INIT) qui, elle même, est commandée par l’appui sur la clé du maniulateur.
Télécharger le programme source, le fichier .hex et tous les schémas.
7. Réalisation
7.1. Clavier 3×3
Le circuit est réalisé sur une plaque PCB FR4 pastillée étamée à trous métallisés double face de 5x7x0,16 cm. Le MCU et les composants qui l’entourent sont placés sur une seconde plaque identique, placée en dessous et qui s’enfiche à la première plaque. Il y a beaucoup de place. Les boutons poussoirs 6x6x9mm ont été achetés sur Ebay chez Electronics-Salon qui propose des composants d’excellente qualité. L’utilisation d’une plaque double face est très pratique dans ce genre de circuit qui comprend surtout du fil! L’implantation des composants suit exactement le schéma théorique.
Vérification: avant de le connecter au MCU, s’assurer de son fonctionnement sous tension (problème de soudure). Pour ce faire, le relier seul à l’alimentation 5V, connecter le voltmètre à sa sortie, appuyer successivement sur chaque bouton et noter la tension.
Télécharger le programme source, le fichier .hex et tous les schémas.
7.2. Carte principale
7.2.1. Prototype
Le prototype a été réalisé à l’aide du logiciel fritzing. C’est la première fois que je l’utilise. Sa prise en main est facile. Fritzing offre une protoboard dont les dimensions sont réglables. Je n’ai pas trouvé dans sa bibliothèque le 12F675. Qu’à cela ne tienne! l’éditeur de composants permet facilement de créer le sien à partir d’un modèle générique. Trois fichiers SVG sont nécessaires: breadbord.svg (platine d’essai), schematic.svg (schéma), pcb.svg (circuit imprimé). Si vous êtes curieux où si vous souhaitez peaufiner un peu, ces fichiers sont manipulables sous Inkscape. Attention cependant, au préalable, installer les polices de caractères OCR-A et Droid Sans qui sont utilisées par fritzing.
7.2.2. Carte câblée
Les 2 photos ci-dessous, montrent la carte principale cablée. Une diode de protection 1N4001 a été ajoutée en entrée du régulateur 5V. Le clavier s’embroche par dessus. L’ensemble est maintenu par des entretoises coupées dans de simples chevilles en plastique et 4 vis de 3mm provenant de la quincaillerie la plus proche.
Pour conclure, la mise en oeuvre du 12F675 est aisée mais n’oubliez pas: RTFM!
Télécharger le programme source, le fichier .hex et tous les schémas et fichiers Inkscape et fritzing.
Références
Index des articles de la catégorie microcontroleur
- Atmel AVR – Installation des outils de développement logiciel et matériel
- Fréquencemètre à microcontrôleur PIC
- Fréquencemètre à microcontrôleur PIC – Commande de l’afficheur LCD
- Fréquencemètre à microcontrôleur PIC – Description
- Fréquencemètre à microcontrôleur PIC – Mesure
- Fréquencemètre à microcontrôleur PIC – Réalisation
- Fréquencemètre à microcontrôleur PIC – Révision 1
- Fréquencemètre à microcontrôleur PIC – Structure du programme
- Mon premier projet PIC
- Mon premier projet PIC – Programmateur sur port parallèle
- PIC Microchip – Adaptateur pour programmer la série des PIC 12F629/675/683 et 12F1822/1840
- PIC Microchip – Application du 16F88 – Le Bootloader
- PIC Microchip – Installation de la nouvelle version WinPICPgm 1.8.3.0
- PIC Microchip – Manipulateur électronique 12F675 CW Keyer
- PIC Microchip – Manipulateur électronique 16F628 CW Keyer et son interface de liaison série
bel article, bien organsé, felicitations…