Bienvenue aux nouveaux arrivants sur FantasPic !

- 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 ---
Forum général sur l'Assembleur !

Modérateur : mazertoc

Utiliser l'USART
JJE
Passioné
Passioné
Messages : 399
Âge : 83
Enregistré en : novembre 2017
Localisation : Picardie

#1 Message par JJE » ven. 22 mars 2019 17:51

Bonjour à chacun,
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 :
Shéma.pdf

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 :sad:

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 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 :idea: . 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

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 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 :-D
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Cordialement

JJE

C'est pas parcequ'on n'a rien à dire qu'il faut fermer sa G....e

Utiliser l'USART
F6FCO
Avatar de l’utilisateur
Expert
Expert
Messages : 1413
Âge : 70
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#2 Message par F6FCO » sam. 23 mars 2019 19:37

Ouf ! ça fait de quoi assimiler tout çà :wink:, j'ai parcouru mais c'est à relire à tête reposée. C'est une super bonne idée de faire une sorte de librairie pour l'USART (et pour l'I2C pourquoi pas). Je vais tester tes routines pour cette utilisation.
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.
Une porte nand prend 2 bits en entrée... la cochonne !!! :langue:

Utiliser l'USART
JJE
Passioné
Passioné
Messages : 399
Âge : 83
Enregistré en : novembre 2017
Localisation : Picardie

#3 Message par JJE » dim. 24 mars 2019 06:06

Salut FCFCO,
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.
Cordialement

JJE

C'est pas parcequ'on n'a rien à dire qu'il faut fermer sa G....e

Utiliser l'USART
F6FCO
Avatar de l’utilisateur
Expert
Expert
Messages : 1413
Âge : 70
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#4 Message par F6FCO » mer. 27 mars 2019 19:04

Je suis en train de travailler sur l'I2C aussi de mon coté mais sans me préoccuper des changements de banques, avantage des 18F. Mais pour l'instant je fais çà en dilettante sans m'y plonger vraiment sérieusement dedans car je voudrais faire aboutir mon soft CNC avant de passer à autre chose. Je dirai plutôt que je me fais une culture :wink:
Une porte nand prend 2 bits en entrée... la cochonne !!! :langue:

Utiliser l'USART
JJE
Passioné
Passioné
Messages : 399
Âge : 83
Enregistré en : novembre 2017
Localisation : Picardie

#5 Message par JJE » mer. 27 mars 2019 19:26

je dois dire que ce n'est pas tout à fait évident.
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
Cordialement

JJE

C'est pas parcequ'on n'a rien à dire qu'il faut fermer sa G....e

Utiliser l'USART
JJE
Passioné
Passioné
Messages : 399
Âge : 83
Enregistré en : novembre 2017
Localisation : Picardie

#6 Message par JJE » jeu. 28 mars 2019 19:12

Bonsoir à tous, en particulier à F6FCO.
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
Cordialement

JJE

C'est pas parcequ'on n'a rien à dire qu'il faut fermer sa G....e

Utiliser l'USART
venom
Avatar de l’utilisateur
Confirmé
Confirmé
Messages : 953
Âge : 38
Enregistré en : avril 2016
Localisation : Klyntar
Contact :

#7 Message par venom » jeu. 28 mars 2019 21:09

Je suis aussi tomber sur cet excellent tuto sur l'I2C. Il me semble que c'est paulfjujo qu'il me l'avait partager.






@++
Mon site web
Mon discord : venom#4888

Utiliser l'USART
F6FCO
Avatar de l’utilisateur
Expert
Expert
Messages : 1413
Âge : 70
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#8 Message par F6FCO » sam. 30 mars 2019 20:15

Bonjour tous,
Merci pour le lien, je l'avais aussi remarqué et chargé mais pas encore lu . Je suis un peu au ralenti niveau pic en ce moment. :wink:
Une porte nand prend 2 bits en entrée... la cochonne !!! :langue:


Retourner vers « Langage ASM »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 33 invités