- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
Modérateur : mazertoc
Comme chacun a pu le constater, les fabricants enrobent souvent les composants dans des petits circuits en facilitant l'utilisation, souvent I2S ou USART, ils fournissent alors, en général, des outils logiciels pour Arduino et/ou Raspberry, mais les amateurs de Microchip sont laissés pour compte.
Cette observation m'a donné l'idée de combler ce manque et je vous propose ci-dessous un programme qui met en oeuvre l'USART, il vaut mieux commencer par pas trop compliqué.
L'ensemble du code gérant les différents registres spéciaux et leurs bits est inclus dans le fichier Module USART.inc, l'utilisateur ne voit l'USART qu'en termes de fonctionnalités telles que décrites plus loin.
Le matériel mis en oeuvre sur une platine d'essais:
un Pic 16F884
Un afficheur 7 segments TDSxxx, j'ai utilisé un TDSR316 mais on peut utiliser n'importe quel autre en modifiant une ligne de code si on choisit un TDSX315
8 résistances de 400 à 500 ohm
Le tout deux fois. Les deux pics sont parfaitement indépendants, sauf qu'ils dialoguent par les broches RX/TX. TX de l'un sur RX de l'autre
Le schéma :
On peut noter que, si on veut se simplifier la vie, on peut ne retenir que la moitié du schéma, en connectant les broches RX et TX. C'est seulement un peu moins démonstratif
La réalisation utilisée : voir .jpg en pièce jointe
Le programme (c'est le même qui tourne sur les deux pics) ; description :
Chaque Pic lit le PORTB et affiche le chiffre hexa correspondant à la valeur du quartet de bas poids.
Il se met en attente
1 - soit d'un changement sur le PORTB
2 - soit de la réception d'un caractère sur le port USART
dans le premier cas, il envoie la valeur lue sur le port USART et poursuit son attente
dans le deuxième cas, il affiche le chiffre hexa correspondant à la valeur du quartet de bas poids de l'octet reçu et poursuit son attente.
Le programme ; code :
Code : Tout sélectionner
; TestUSART
; Date création : 02/03/2019
; Auteur : JJE
; Historique
; Version 1 :
;
LIST p=PIC16f884 ; Définition du processeur
include p16f884.inc
#define NbPages 2
include "../../callx/callx.inc"
include "Module USART.INC"
include "Module TDS.inc"
errorlevel -302
__CONFIG _CONFIG1, _INTOSCIO & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _DEBUG_ON & _CP_OFF & _CPD_OFF
; _INTOSCIO oscillator: I/O functionon RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN
; WDT disabled and can be enabled by SWDTEN bit of the WDTCON register end
; PWRT disabled
; BOR disabled
; RB3 pin has digital I/O, HV on MCLR must be used for programming
; In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
; Program memory code protection is disabled
; Data memory code protection is disabled
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
; Write protection off
;******************************************************************
; valeurs initiales des registres spéciaux
;******************************************************************
; valeur initiale de OPTIONREG
OPTIONVAL EQU B'00000010' ; bit 7 = 0 : PORTB pull-ups
; enabled
; bit 6 = 0 : sans objet
; bit 5 = 0 : internal cycle clock
; bit 4 = 0 : sans objet
; bit 3 = 0 : prescaler is assigned
; to TIMER0 module
; bit 2-0=001 : prescaler rate 1:8
; cf page 31 du DataSheet
; valeur initiale de OSCON
OSCONVAL EQU B'01101001' ; bit 7 = 0 sans objet
; bits 6-4 4MH
; bits 3-1 sans objets
; bit 0 Internal oscilateur used
; cf page 64 du DataSheet
; valeur initiale de TRISA
TRISAVAL EQU 0x00 ; tous les ports en sortie
ANSELVAL EQU 0x00 ; pas d'entrée analogique sur PORTA
; valeur initiale de TRISB
TRISBVAL EQU 0x1f ; les ports 0 à 4 en entrée
; valeur initiale de WPUB
WPUBVAL EQU 0x1f ; Pull-up enabled sur les ports
; 0 à 4 de PORTB
; valeur initiale de IOCB
IOCBVAL EQU 0x0f ; IT on change enabled
; sur les bits 0 à 3 de PORTB
TRISCVAL EQU 0x80 ; RC7 en entrée,
; tous les autres en sortie
ANSELHVAL EQU 0x00 ; pas d'entrée analogique sur PORTB
INTCONVAL EQU B'11101000' ; bit 7 = 1 : Enables unmasked
; interrupts
; bit 6 = 1 : Enables all
; peripheral interrupts
; bit 5 = 1 : Enables TMR0 IT
; bit 4 = 0 : Disables
; external interrupt
; bit 3 = 1 : Enables PORTB
; change interrupt
; bit 2-0 = 0 interrupts flags
; cf page 32 du DataSheet
;******************************************************************
; quelques constantes
TIMER0VAL EQU .10 ; valeur initial de TIMER0 pour obtenir
; une IT toutes les 10ms avec un
; prescaler à 8 et une fréquence de 8MH
Nb_ITVAL EQU .20 ; pour simuler unr IT toutes les
; 20.000 microcycles (20ms)
dojobSecondesVAL EQU .50 ; pour simuler unr IT toutes les
; 1.000.000 microcycles (1")
dojob0 EQU 0
;******************************************************************
; MACROS
;******************************************************************
BANK0 macro
bcf STATUS,RP0
bcf STATUS,RP1
endm
BANK1 macro
bsf STATUS,RP0
bcf STATUS,RP1
endm
BANK2 macro
bcf STATUS,RP0
bsf STATUS,RP1
endm
BANK3 macro
bsf STATUS,RP0
bsf STATUS,RP1
endm
;******************************************************************
; DECLARATIONS DE VARIABLES
;******************************************************************
CBLOCK 0x20
; sauvegardes pour l'IT
w_temp : 1 ; W
status_temp : 1 ; STATUS
; FSR_temp : 1 ; FSR
; PCLATH_temp : 1 ; PCLATH
Nb_IT : 1
dojobSecondes : 1 ; compteur utile à déclencher jobSecondes
dojob : 1
wait_temp : 1 ; compteur du ssp wait
Valeur_Lue : 1 ; valeur lue sur PORTB
cmpt1_Test_Segments : 1 ; compteur pour Test_Segments
endc
USART_VAR
ORG 0
goto init
ORG 04
movwf w_temp ; 1 sauver registre W
swapf STATUS,w ; 2 swap status
movwf status_temp ; 3 sauver status swappé
BANK0
btfsc INTCON,T0IE ; 8 tester si interrupt timer
; autorisée
btfss INTCON,T0IF ; 9 oui, tester si interrupt
; timer en cours
goto IT_2 ; 10 non, c'est une autre IT
bcf INTCON,T0IF ; 11 effacer flag interrupt timer
movlw TIMER0VAL ; 12
movwf TMR0 ; 13
nop ; 14
; à ce moment, TIMER0 va compter 984 [(256-10)*4] micro-cycles
; et reviendra au début de ce sous-programme de gestion des IT
; ce qui compte tenu des instructions qui précèdent et des deux
; non décomptées après l'initialisation de TMR0
; ammène bien à 1000 micro-cycles, soit 1000 microsecondes
call IT_TIMER0
goto restaurereg
IT_2
btfsc INTCON,RBIE ; 8 tester si RBIB autorisée
; autorisée
btfss INTCON,RBIF ; 9 oui, tester si RBIB en cours
goto IT_3 ; 10 non, c'est une autre IT
; efface l'IT
movf PORTB, w
movwf Valeur_Lue
bcf INTCON,RBIF
; prévenir le programme principal
bsf dojob, dojob0
goto restaurereg
IT_3
; restaurer les registres
restaurereg
; movf FSR_temp, w ; 4 restaurer FSR avant STATUS
; movwf FSR ; 5
; movf PCLATH_temp, w ; 6
; movwf PCLATH ; 7
swapf status_temp,w ; 2 swap ancien status
movwf STATUS ; 3 restaurer status
swapf w_temp,f ; 6 Inversion L et H de l'ancien W
; sans modifier Z
swapf w_temp,w ; 7 Réinversion de L et H dans W
; W restauré sans modifier status
retfie ; 8 return from interrupt
;;******************************************************************
; Programme principal
; -------------------
;******************************************************************
init
call ClearRam
call InitRegSpec
TDS_Init TDS_CATHODECOMMUNE, PORTA, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
call InitVariables
; définit les constantes du module USART
; voir pages 160 et suivantes du datasheet
; pour un 8MH et 9600 bauds
USART_Init D'52', USART_HIGHBRG
call Test_Segments
; pour faire un affichage au lancement
; bsf dojob, dojob0
movf PORTB, w
andlw 0x0f
CALLX TDS_AfficheWREG
; movwf Valeur_Lue
bcl
btfsc dojob, dojob0
call job0
CALLX USART_IsCarDispo
btfsc STATUS, Z
call job1
goto bcl
;******************************************************************
; job0
;******************************************************************
job0
; un changement a été décelé sur l'une des broche 0 à 3 du PORTB
; la nouvelle valeur lue est dans Valeur_Lue
; l'envoyer sur l'USART
bcf dojob, dojob0
movf Valeur_Lue, w
andlw 0x0f
CALLX USART_Send_Byte
return
;******************************************************************
; job1
;******************************************************************
job1
; une nouvelle donnée vient d'arriver sur le port COMM
; l'afficher
CALLX USART_Recieve_Byte
CALLX TDS_AfficheWREG
return
;******************************************************************
; Test_Segments
;******************************************************************
Test_Segments
; teste le brochage de l'afficheur en affichent successivement
; les segments de a à g puis DP
movlw TDS_chiffreVide
expand
CALLX TDS_SetTDSSegmentsWREG
movlw .1
call wait
clrf cmpt1_Test_Segments
Test_Segments_1
expand
TDS_AfficheSegmentV cmpt1_Test_Segments
movlw .1
call wait
incf cmpt1_Test_Segments, f
btfss cmpt1_Test_Segments, 3
goto Test_Segments_1
movlw TDS_chiffreVide
CALLX TDS_SetTDSSegmentsWREG
movlw .1
call wait
return
;******************************************************************
; Nettoie la RAM
; Spécifique du pic utilisé
; ici 16F883/16F887
;******************************************************************
ClearRam
bcf STATUS, IRP
movlw 0x020 ; initialisation
movwf FSR ; pointeur d'adressage indirect
ClearRam1
clrf INDF ; effacer ram 0x20 à 0x7f
bsf FSR, 7
clrf INDF ; effacer ram 0xa0 à 0xff
bsf STATUS, IRP
bcf FSR, 7
clrf INDF ; effacer ram 0x120 à 0x17f
bcf STATUS, IRP
incf FSR,f ; pointer sur suivant
btfss FSR, 7
goto ClearRam1 ; non, boucler
return
;******************************************************************
; Initialise les registres spéciaux
;******************************************************************
InitRegSpec
BANK1 ; sélectionner banque 1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option
movlw TRISAVAL
movwf TRISA
movlw TRISBVAL
movwf TRISB
movlw IOCBVAL
movwf IOCB ; initialise IOCB
movlw TRISCVAL
movwf TRISC
BANKSEL ANSEL
movlw ANSELVAL
movwf ANSEL
movlw ANSELHVAL
movwf ANSELH
BANK0
movlw INTCONVAL
movwf INTCON ; initialise INTCON
movlw TIMER0VAL
movwf TMR0
return
;******************************************************************
; Initialise les variables
;******************************************************************
InitVariables
movlw Nb_ITVAL
movwf Nb_IT
return
;******************************************************************
; IT_TIMER0
; ---------
;******************************************************************
; appelé toutes les 1ms
IT_TIMER0
decfsz Nb_IT, f
return
; ici, on passe toutes les Nb_ITVAL ms (20ms)
; on réinitialise le compteur d'IT
movlw Nb_ITVAL
movwf Nb_IT
; appelé toutes les 20ms
; on décrémente le compteur de passage dojobSecondes
; qui déclenchera le travail jobSecondes
; en s'annulant, toutes les dojobSecondesVAL*20 ms
; (50*20ms = 1000ms). S'il est déjà nul, on n'y touche pas
movf dojobSecondes,f
btfss STATUS, Z
decf dojobSecondes,f
btfss STATUS, Z
return
movlw dojobSecondesVAL
movwf dojobSecondes
; pour faire fonctionner l'attente wait
; on décrémente wait_temp tant qu'il n'a pas atteint 0
; c'est le sous-programme wait qui la réinitialisera
movf wait_temp, f
btfss STATUS, Z
decf wait_temp, f
return
;******************************************************************
; ROUTINE DE TEMPORISATION
;******************************************************************
; Cette routine introduit un retard de w secondes
wait
; réinitialise dojobSecondes pour compter des secondes entières
; à partir de maintenant
; movlw dojobSecondesVAL
; movwf dojobSecondes
movwf wait_temp
wait_1
movf wait_temp, f
btfss STATUS, Z
goto w ait_1
return
rappel_USART_FERR
return
; introduire le code des modules utilisés
TDS_CODE
USART_CODE
END
Programme ; détails liés à l'utilisation de l'USART :
On commence par informer l'assembleur qu'on utilisera du code à lire dans le fichier Module USART.INC ( l. 14)
Code : Tout sélectionner
include "Module USART.INC"
Deux autre fichiers à inclure sont utilisés qui feront l'objet d'autres post l'un gère les sauts inter-page à la manière BigOnOff, l'autre gère les TDS.
Le modue USART a besoin d'une variable temporaire, c'est le rôle de l'invocation de la macro USART_VAR (l. 137) présente dans le fichier à inclure.
Code : Tout sélectionner
USART_VAR
Remarquons que si l'on voulait positionner cette/ces variables ailleurs, il duffirait de faire précéder la ligne précédente de
Code : Tout sélectionner
CBLOCK 0xa0
endc
pour la/les mettre en début de la Banque 1.
Il faut bien informer le module USART de sa vitesse de fonctionnement. C'est le rôle de l'invocation de cette macro (l. 203) :
Code : Tout sélectionner
USART_Init D'52', USART_HIGHBRG
Remarquons que dans cette première version du module, je n'ai pas pris en charge les possibilités du module USART de ce pic et peut-être des autres de la gestion d'un bit de parité, ni de la possibilité de gérer un bit d'adressage . C'est cette macro qu'il faudrait compléter pour ce faire.
On entre dans la boucle du programme principal qui commence par un test du bit dojob, dojob0. Ce bit est armé dans l'IT qui gère le changement sur l'une des broches RB0 à RB3 du Pic. Si tel est le cas, le job0 fait le travail en ligne 231
CALLX USART_Send_Byte
puis, on interroge le module USART pour savoir si un caractère est disponible (l. 215)
Code : Tout sélectionner
CALLX USART_IsCarDispo
Si tel est le cas, on fait le job1 qui demande au module USART la valeur reçue (l. 240)
Code : Tout sélectionner
CALLX USART_Recieve_Byte
puis l'affiche.
En ligne 377 et 378
Code : Tout sélectionner
rappel_USART_FERR
return
est défini un sous-programme vide qui est appelé par le module USART en cas d'"erreur de framing", libre à l'utilisateur de prendre les décisions qui s'imposent, le module lui, ne fait rien
On pourait de même définir un sous-programme rappel_USART_OERR pour traiter les "erreurs d'overflow"
Enfin, il faut bien introduire le code du module USART, c'est le rôle de l'invocation de la macro USART_CODE (l. 382)
Je sais bien que ce programme n'est pas très ambitieux mais il fait le travail en n'utilisant que sept (+2 facultatives) lignes de code pour ce qui concerne la gestion de l'USART, et ce, sans se préoccuper d'aucun des bits des registres spéciaux liés à ce module
Décrivons maintenant ce module USART.INC, bien qu'on puisse l'utilise comme ci-dessus, en aveugle, mais il dispose de quelques autre fonctionnalités non utilisées dans le programme de test.
Code : Tout sélectionner
; TestUSART
; Date création : 02/03/2019
; Auteur : JJE
; Historique
; Version 1 :
;
LIST p=PIC16f884 ; Définition du processeur
include p16f884.inc
#define NbPages 2
include "../../callx/callx.inc"
include "Module USART.INC"
include "Module TDS.inc"
errorlevel -302
__CONFIG _CONFIG1, _INTOSCIO & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _DEBUG_ON & _CP_OFF & _CPD_OFF
; _INTOSCIO oscillator: I/O functionon RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN
; WDT disabled and can be enabled by SWDTEN bit of the WDTCON register end
; PWRT disabled
; BOR disabled
; RB3 pin has digital I/O, HV on MCLR must be used for programming
; In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
; Program memory code protection is disabled
; Data memory code protection is disabled
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
; Write protection off
; définit les constantes du module USART
; voir pages 160 et suivantes du datasheet
; pour un 8MH et 9600 bauds
; USART_BAUDRATE D'51'
; USART_BRGH
;******************************************************************
; valeurs initiales des registres spéciaux
;******************************************************************
; valeur initiale de OPTIONREG
OPTIONVAL EQU B'00000010' ; bit 7 = 0 : PORTB pull-ups
; enabled
; bit 6 = 0 : sans objet
; bit 5 = 0 : internal cycle clock
; bit 4 = 0 : sans objet
; bit 3 = 0 : prescaler is assigned
; to TIMER0 module
; bit 2-0=001 : prescaler rate 1:8
; cf page 31 du DataSheet
; valeur initiale de OSCON
OSCONVAL EQU B'01101001' ; bit 7 = 0 sans objet
; bits 6-4 4MH
; bits 3-1 sans objets
; bit 0 Internal oscilateur used
; cf page 64 du DataSheet
; valeur initiale de TRISA
TRISAVAL EQU 0x00 ; tous les ports en sortie
ANSELVAL EQU 0x00 ; pas d'entrée analogique sur PORTA
; valeur initiale de TRISB
TRISBVAL EQU 0x1f ; les ports 0 à 4 en entrée
; valeur initiale de WPUB
WPUBVAL EQU 0x1f ; Pull-up enabled sur les ports
; 0 à 4 de PORTB
; valeur initiale de IOCB
IOCBVAL EQU 0x0f ; IT on change enabled
; sur les bits 0 à 3 de PORTB
TRISCVAL EQU 0x80 ; RC7 en entrée,
; tous les autres en sortie
ANSELHVAL EQU 0x00 ; pas d'entrée analogique sur PORTB
INTCONVAL EQU B'11101000' ; bit 7 = 1 : Enables unmasked
; interrupts
; bit 6 = 1 : Enables all
; peripheral interrupts
; bit 5 = 1 : Enables TMR0 IT
; bit 4 = 0 : Disables
; external interrupt
; bit 3 = 1 : Enables PORTB
; change interrupt
; bit 2-0 = 0 interrupts flags
; cf page 32 du DataSheet
;******************************************************************
; quelques constantes
TIMER0VAL EQU .10 ; valeur initial de TIMER0 pour obtenir
; une IT toutes les 10ms avec un
; prescaler à 8 et une fréquence de 8MH
Nb_ITVAL EQU .20 ; pour simuler unr IT toutes les
; 20.000 microcycles (20ms)
dojobSecondesVAL EQU .50 ; pour simuler unr IT toutes les
; 1.000.000 microcycles (1")
dojob0 EQU 0
;******************************************************************
; MACROS
;******************************************************************
BANK0 macro
bcf STATUS,RP0
bcf STATUS,RP1
endm
BANK1 macro
bsf STATUS,RP0
bcf STATUS,RP1
endm
BANK2 macro
bcf STATUS,RP0
bsf STATUS,RP1
endm
BANK3 macro
bsf STATUS,RP0
bsf STATUS,RP1
endm
;******************************************************************
; DECLARATIONS DE VARIABLES
;******************************************************************
CBLOCK 0x20
; sauvegardes pour l'IT
w_temp : 1 ; W
status_temp : 1 ; STATUS
; FSR_temp : 1 ; FSR
; PCLATH_temp : 1 ; PCLATH
Nb_IT : 1
dojobSecondes : 1 ; compteur utile à déclencher jobSecondes
dojob : 1
wait_temp : 1 ; compteur du ssp wait
Valeur_Lue : 1 ; valeur lue sur PORTB
cmpt1_Test_Segments : 1 ; compteur pour Test_Segments
endc
CBLOCK 0xa0
endc
USART_VAR
ORG 0
goto init
ORG 04
movwf w_temp ; 1 sauver registre W
swapf STATUS,w ; 2 swap status
movwf status_temp ; 3 sauver status swappé
BANK0
btfsc INTCON,T0IE ; 8 tester si interrupt timer
; autorisée
btfss INTCON,T0IF ; 9 oui, tester si interrupt
; timer en cours
goto IT_2 ; 10 non, c'est une autre IT
bcf INTCON,T0IF ; 11 effacer flag interrupt timer
movlw TIMER0VAL ; 12
movwf TMR0 ; 13
nop ; 14
; à ce moment, TIMER0 va compter 984 [(256-10)*4] micro-cycles
; et reviendra au début de ce sous-programme de gestion des IT
; ce qui compte tenu des instructions qui précèdent et des deux
; non décomptées après l'initialisation de TMR0
; ammène bien à 1000 micro-cycles, soit 1000 microsecondes
call IT_TIMER0
goto restaurereg
IT_2
btfsc INTCON,RBIE ; 8 tester si RBIB autorisée
; autorisée
btfss INTCON,RBIF ; 9 oui, tester si RBIB en cours
goto IT_3 ; 10 non, c'est une autre IT
; efface l'IT
movf PORTB, w
movwf Valeur_Lue
bcf INTCON,RBIF
; prévenir le programme principal
bsf dojob, dojob0
goto restaurereg
IT_3
; restaurer les registres
restaurereg
; movf FSR_temp, w ; 4 restaurer FSR avant STATUS
; movwf FSR ; 5
; movf PCLATH_temp, w ; 6
; movwf PCLATH ; 7
swapf status_temp,w ; 2 swap ancien status
movwf STATUS ; 3 restaurer status
swapf w_temp,f ; 6 Inversion L et H de l'ancien W
; sans modifier Z
swapf w_temp,w ; 7 Réinversion de L et H dans W
; W restauré sans modifier status
retfie ; 8 return from interrupt
;;******************************************************************
; Programme principal
; -------------------
;******************************************************************
init
call ClearRam
call InitRegSpec
TDS_Init TDS_CATHODECOMMUNE, PORTA, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
call InitVariables
; définit les constantes du module USART
; voir pages 160 et suivantes du datasheet
; pour un 8MH et 9600 bauds
USART_Init D'52', USART_HIGHBRG
call Test_Segments
; pour faire un affichage au lancement
; bsf dojob, dojob0
movf PORTB, w
andlw 0x0f
CALLX TDS_AfficheWREG
; movwf Valeur_Lue
bcl
btfsc dojob, dojob0
call job0
CALLX USART_IsCarDispo
btfsc STATUS, Z
call job1
goto bcl
;******************************************************************
; job0
;******************************************************************
job0
; un changement a été décelé sur l'une des broche 0 à 3 du PORTB
; la nouvelle valeur lue est dans Valeur_Lue
; l'envoyer sur l'USART
bcf dojob, dojob0
movf Valeur_Lue, w
andlw 0x0f
CALLX USART_Send_Byte
return
;******************************************************************
; job1
;******************************************************************
job1
; une nouvelle donnée vient d'arriver sur le port COMM
; l'afficher
CALLX USART_Recieve_Byte
CALLX TDS_AfficheWREG
return
;******************************************************************
; Test_Segments
;******************************************************************
Test_Segments
; teste le brochage de l'afficheur en affichent successivement
; les segments de a à g puis DP
movlw TDS_chiffreVide
expand
CALLX TDS_SetTDSSegmentsWREG
movlw .1
call wait
clrf cmpt1_Test_Segments
Test_Segments_1
expand
TDS_AfficheSegmentV cmpt1_Test_Segments
movlw .1
call wait
incf cmpt1_Test_Segments, f
btfss cmpt1_Test_Segments, 3
goto Test_Segments_1
movlw TDS_chiffreVide
CALLX TDS_SetTDSSegmentsWREG
movlw .1
call wait
return
;******************************************************************
; Nettoie la RAM
; Spécifique du pic utilisé
; ici 16F883/16F887
;******************************************************************
ClearRam
bcf STATUS, IRP
movlw 0x020 ; initialisation
movwf FSR ; pointeur d'adressage indirect
ClearRam1
clrf INDF ; effacer ram 0x20 à 0x7f
bsf FSR, 7
clrf INDF ; effacer ram 0xa0 à 0xff
bsf STATUS, IRP
bcf FSR, 7
clrf INDF ; effacer ram 0x120 à 0x17f
bcf STATUS, IRP
incf FSR,f ; pointer sur suivant
btfss FSR, 7
goto ClearRam1 ; non, boucler
return
;******************************************************************
; Initialise les registres spéciaux
;******************************************************************
InitRegSpec
BANK1 ; sélectionner banque 1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option
movlw TRISAVAL
movwf TRISA
movlw TRISBVAL
movwf TRISB
movlw IOCBVAL
movwf IOCB ; initialise IOCB
movlw TRISCVAL
movwf TRISC
BANKSEL ANSEL
movlw ANSELVAL
movwf ANSEL
movlw ANSELHVAL
movwf ANSELH
BANK0
movlw INTCONVAL
movwf INTCON ; initialise INTCON
movlw TIMER0VAL
movwf TMR0
return
;******************************************************************
; Initialise les variables
;******************************************************************
InitVariables
movlw Nb_ITVAL
movwf Nb_IT
return
;******************************************************************
; IT_TIMER0
; ---------
;******************************************************************
; appelé toutes les 1ms
IT_TIMER0
decfsz Nb_IT, f
return
; ici, on passe toutes les Nb_ITVAL ms (20ms)
; on réinitialise le compteur d'IT
movlw Nb_ITVAL
movwf Nb_IT
; appelé toutes les 20ms
; on décrémente le compteur de passage dojobSecondes
; qui déclenchera le travail jobSecondes
; en s'annulant, toutes les dojobSecondesVAL*20 ms
; (50*20ms = 1000ms). S'il est déjà nul, on n'y touche pas
movf dojobSecondes,f
btfss STATUS, Z
decf dojobSecondes,f
btfss STATUS, Z
return
movlw dojobSecondesVAL
movwf dojobSecondes
; pour faire fonctionner l'attente wait
; on décrémente wait_temp tant qu'il n'a pas atteint 0
; c'est le sous-programme wait qui la réinitialisera
movf wait_temp, f
btfss STATUS, Z
decf wait_temp, f
return
;******************************************************************
; ROUTINE DE TEMPORISATION
;******************************************************************
; Cette routine introduit un retard de w secondes
wait
; réinitialise dojobSecondes pour compter des secondes entières
; à partir de maintenant
; movlw dojobSecondesVAL
; movwf dojobSecondes
movwf wait_temp
wait_1
movf wait_temp, f
btfss STATUS, Z
goto wait_1
return
rappel_USART_FERR
return
; introduire le code des modules utilisés
TDS_CODE
USART_CODE
END
Il commence par la ligne
Code : Tout sélectionner
include "../../CallX/CallX.inc"
qui introduit les macros presque de BigOnOff comme décrit plus haut
puis il définit deux constantes à utiliser comme deuxième paramètre de USART_Init et une troisième facilitant la réception de chaîne de caractères
Code : Tout sélectionner
#DEFINE USART_HIGHBRG 1
#DEFINE USART_LOWBRG 0
#DEFINE USART_ETX 0x03 ; end of text
puis il définit la macro qui sera utilisée pour réserver l'espace mémoire nécessaire au module
Code : Tout sélectionner
USART_VAR macro
CBLOCK
USART_DATA
USART_temp1 : 1
USART_temp2 : 1
endc
if USART_DATA & 0x180 != (USART_DATA+1) & 0x180
messg " "
error "L'espace mémoire du module USART doit résider dans une seule banque"
messg " "
endm
endif
Remarquons la précaution prise d'informer l'utilisateur d'une mauvaise situation. Cette erreur serait sûrement difficile à trouver alors que l'assembleur peut la signaler. Je sais bien qu'ici, la probabilité est très faible mais autant prendre de bonnes habitudes.
Suit la macro qui initialise le module USART
Code : Tout sélectionner
USART_Init macro USART_BaudRate, USART_Brgh
if USART_Brgh!= USART_LOWBRG && USART_Brgh!= USART_HIGHBRG
error ""
error "USART_Init : deuxième paramètre incorrect"
error ""
else
BANK1
bsf TRISC, RC7 ; RX pin en entrée
bcf TRISC, RC6 ; TX pin en sortie
if USART_Brgh == USART_HIGHBRG
bsf TXSTA, BRGH
else
bcf TXSTA, BRGH
endif
if high(USART_BaudRate)!= 0
movlw high(USART_BaudRate)
movwf SPBRGH
else
clrf SPBRGH
endif
movlw low(USART_BaudRate)
movwf SPBRG
bcf TXSTA, SYNC
bcf TXSTA, TX9 ; transmission 8 bits
bsf TXSTA, TXEN
; BANK0
bcf STATUS, RP0 ; repasser en banque 0
movlw b'10010000' ; arme SPEN et CREN désarme RX9
movwf RCSTA
return
endif
endm
Je renvoie le lecteur au Datasheet pour la description de tous ces bits
pour finir, la macro qui introduit le code du module dans le programme. C'est ce code qui donne les fonctionnalités du module.
Code : Tout sélectionner
USART_CODE macro
USART_DEBUT_CODE
USART_Send_Byte
; envoie sur le port USART l'octet contenu dans WREG
; en sortie on est en banque 0
BANK0
; attendre que TXREG soit libre
btfss PIR1, TXIF
goto $-1
; et y transférer la donnée à transmettre
movwf TXREG
return
USART_Send_String
; envoie sur le port TX les octets pointés par FSR et suivants
; jusqu'au premier nul exclu puis un USART_ETX
; FSR inchangé
; la banque mémoire active en sortie est la banque du module
BANKSEL USART_DATA
; sauver FSR pour le remettre dans son état initial en sortie
movf FSR, w
movwf USART_temp1
USART_Send_String1
; traiter l'octet pointé par FSR
movf INDF, w
btfss STATUS, Z
goto USART_Send_String2
call USART_Send_Byte
; traiter le suivant
incf FSR, F
goto USART_Send_String1
USART_Send_String2
; c'est fini, on vient de lire le nul, on envoie l'ETX
movlw USART_ETX
call USART_Send_Byte
BANKSEL USART_DATA
; restaurer FSR
movf USART_temp1, w
movwf FSR
return
; retourne STATUS, Z armé si un caractère est disponible
; en sortie on est en banque 0
USART_IsCarDispo
BANK0
bsf STATUS, Z
btfss PIR1, RCIF
bcf STATUS, Z
return
; retourne dans WREG le premier octet dispo reçu sur le port USART
; rapprelle, éventuellement, l'appelant en cas de frame error et
; d'overrun
; en sortie on est en banque 0
USART_Recieve_Byte
BANK0
btfss RCSTA, FERR
goto USART_Recieve_Byte1
ifdef rappel_USART_FERR
CALLX rappel_USART_FERR
endif
movf RCREG, w ; efface le flag RCSTA, FERR
USART_Recieve_Byte1
btfss RCSTA, OERR
goto USART_Recieve_Byte2
ifdef rappel_USART_OERR
CALLX rappel_USART_OERR
endif
; effacer le flag RCSTA, OERR
bcf RCSTA, CREN
bsf RCSTA, CREN
btfss PIR1, RCIF
goto $-1
USART_Recieve_Byte2
movf RCREG, w
return
USART_Read_String
; reçoit sur RX les octets qu'il range dans l'octet pointé par FSR
; et suivants, jusqu'au premier ETX
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
BANKSEL USART_DATA
movf FSR, w
movwf USART_temp1
USART_Read_String1
call USART_Recieve_Byte
sublw USART_ETX
btfsc STATUS, Z
goto USART_Read_String2
addlw USART_ETX
movwf INDF
incf FSR, f
goto USART_Read_String1
USART_Read_String2
BANKSEL USART_DATA
movf USART_temp1, w
movwf FSR
return
USART_Read
; reçoit sur RX les octets qu'il range dans l'octet pointé par FSR
; et suivants, jusqu'au premier ETX
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
BANKSEL USART_DATA
movf FSR, w
movwf USART_temp1
USART_Read1
call USART_Recieve_Byte
sublw USART_ETX
btfsc STATUS, Z
goto USART_Read2
addlw USART_ETX
movwf INDF
incf FSR, f
goto USART_Read1
USART_Read2
BANKSEL USART_DATA
movf USART_temp1, w
movwf FSR
return
USART_Read_N
; reçoit sur RX N octets(valeur de WREG) qu'il range
; dans l'octet pointé par FSR et suivants
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
BANKSEL USART_DATA
movwf USART_temp2
movf USART_temp2, f
btfsc STATUS, Z
return
movf FSR, w
movwf USART_temp1
USART_Read_N1
call USART_Recieve_Byte
movwf INDF
incf FSR, f
decfsz USART_temp2, f
goto USART_Read_N1
BANKSEL USART_DATA
movf USART_temp1, w
movwf FSR
return
USART_FIN_CODE
if USART_DEBUT_CODE & 0x1800 != (USART_FIN_CODE - 1) & 0x1800
messg " "
error "Le code du module USART doit résider dans une seule page"
messg " "
endif
endm
Je ne décrirai pas ici, ce code en détail, juste, les points d'entrée retenus, au nombre de 6
USART_Send_Byte
; envoie sur le port USART l'octet contenu dans WREG
; en sortie on est en banque 0
USART_Send_String
; envoie sur le port TX les octets pointés par FSR et suivants
; jusqu'au premier nul exclu puis un USART_ETX
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
USART_IsCarDispo
; retourne STATUS, Z armé si un caractère est disponible
; en sortie on est en banque 0
USART_Recieve_Byte
; retourne dans WREG le premier octet dispo reçu sur le port USART
; rapprelle, éventuellement, l'appelant en cas de frame error et
; d'overrun
; en sortie on est en banque 0
C'est dans ce sous-programme qu'on traite les erreurs de réception et que, si l'utilisateur a défini des sous-programmes de traitement, on leur passe la main
USART_Read_String
; reçoit sur RX les octets qu'il range dans l'octet pointé par FSR
; et suivants, jusqu'au premier ETX
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
USART_Read_N
; reçoit sur RX N octets(valeur de WREG) qu'il range
; dans l'octet pointé par FSR et suivants
; FSR inchangé en sortie
; la banque mémoire active en sortie est la banque du module
C'est ce sous-programme qui exploitant les deux variables du module exige qu'elles résident dans la même banque
Comme dans ce module, les goto et call effectués supposent que ce code soit dans une même page, un test est effectué en fin de macro pour s'assurer que c'est bien le cas, l'utilisation d'un tel module devant se faire en aveugle, autant faire travailler l'assembleur et prendre les dispositions qui s'imposent s'il signale un problème.
Remarque finale : Noter que toutes les étiquette commencent par USART_, si l'utilisateur n'utilise jamais ce préfixe, il est assuré de n'avoir pas de conflit. Sans l'avoir testé, je suis assez convaincu que ce programme serait utilisable tel que, en modifiant les quelques premières lignes liées au Pic utilisé et la procédure Clear_Ram sur tout autre Pic Mid-Range au moins disposant d'un module USART.
OUF
- F6FCO
Expert- Messages : 1413
- Âge : 70
- Enregistré en : décembre 2017
- Localisation : Furtif je suis.
- Contact :
Pour le reste du programme de démonstration j'ai un peu de mal avec toutes ces gestions de banques, jeune programmeur PIC que je suis, je suis passé très vite aux 18F pour justement m'en affranchir et j'avoue que j'ai un peu de mal à remettre le nez dedans.
Bravo et merci pour ton travail.
En fait, j'ai commencé par l'I2C,en mode maître, mais, en attendant des circuits pour tester, je me suis rabattu sur l'UASRT, c'était a priori plus facile et me permettait de préciser cette notion de module qui me tient à cœur depuis pas mal de temps et qui a d'ailleurs bien évolué.
DSe mémoire, le programme de test ne fait pas de chgt de banque mémoire sauf dans les routines d'initialisation où il n'a pas le choix. Ce sont les modules utilisés qui s'en chargent en cas de besoin, justement pour décharger l'utilisateur de ces soucis, mais rien ne l’empêche de travailler avec plusieurs banques.
- F6FCO
Expert- Messages : 1413
- Âge : 70
- Enregistré en : décembre 2017
- Localisation : Furtif je suis.
- Contact :
j'essaye de mettre en oeuvre un MCP9808 sur cette carte
Carte d'extension Adafruit 1782 décrite ici, mais le lien ne semble pas marcher
https://www.conrad.fr/p/carte-dextensio ... pe=suggest
en isolant la couche I2C, .../... à suivre
J'ai trouvé une page tout à fait intéressante sur le I2C :
http://fabrice.sincere.pagesperso-orange.fr/cm_electronique/projet_pic/aidememoire/16F876A_bus_I2C/bus_I2C_16F876A.htm
Elle m'a permis de bien avancer mais c'est encore l'échec et je n'arrive pas à utiliser mon PicKit3 (officiel). Il va sans dire que MPLABSIM ne vaut rien pour ce genre de projet
@++
Retourner vers « Langage ASM »
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 54 invités