; Carte d'acquisition 7 entrées analogiques 0 à 5 V ; Fréquence d'échantillonnage 2560 Hz (Te = 390,6 µs) ; Communication via RS232 ; Utilisation de l'USART du 16F88 avec interruptions ; 9600 bauds/s 8 bits de données Pas de bit de parité ; 1 bit de STOP Pas de contrôle de flux ; Utilisation du module ADC 10 bits avec interruption de fin de conversion ; (C) Fabrice Sincère, octobre 2007 ; IUT Nancy-Brabois ; http://perso.orange.fr/fabrice.sincere ; version 1.0.1 ; microcontrôleur PIC 16F88 ; langage : assembleur ; développé avec Microchip MPLAB IDE Errorlevel-302 ; Supprime le message "Ensure that bank bits are correct" List p=16F88 ; processeur utilisé #include ;Program Configuration Register 1 __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC ;bits de configuration : ; Code protection OFF ; CCP1 function on RB0 ; In-Circuit Debugger OFF ; FLASH Program Memory Write protection OFF ; Data EE Memory Code Protection OFF ; Low Voltage Programming OFF ; Brown-out Reset ON ; RA5/MCLR pin function is MCLR ; Power-up Timer ON ; Watchdog Timer OFF ; HS oscillator (quartz 20 MHz) ;Program Configuration Register 2 __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF ;bits de configuration : ;Internal External Switch Over mode OFF ;Fail-Safe Clock Monitor OFF ;xxxxxx ; macro ;xxxxxx bank1 macro ; passage en banque 1 bsf STATUS,RP0 bcf STATUS,RP1 endm bank0 macro ; passage en banque 0 bcf STATUS,RP0 bcf STATUS,RP1 endm ;xxxxxxxxxxxxxxxxxxxxxxxxxx ; Déclaration des variables ;xxxxxxxxxxxxxxxxxxxxxxxxxx CBLOCK 0x070 ; début de la zone des registres d'usage général du 16F88 ; (banque quelconque : 0,1,2 ou 3) ; 0x070 - 0x07F : 16 variables STATUS_TEMP : 1 ; sauvegarde du registre STATUS (routine d'interruption) W_TEMP : 1 ; sauvegarde du registre W (routine d'interruption) octet_rx : 1 ; octet reçu (broche RX de l'UART) ; contient le numéro de canal à échantillonner(0x00 à 0x06) octet1_tx : 1 ; 1er octet à transmettre : contient les 2 bits de poids fort ; de la sommme des 256 mesures (0 0 0 0 0 0 b17 b16) octet2_tx : 1 ; 2ème octet à transmettre : (b15 ... b8) octet3_tx : 1 ; 3ème octet à transmettre : (b7 ... b0) nb_octet_transmis : 1 ; compteur du nombre d'octets transmis (0, 1, 2 ou 3) nb_mesures : 1 ; compteur du nombre de conversion réalisées (0x01 à 0x00 = 256) adresh_bak : 1 ; sauvegarde du registre ADRESH adresl_bak : 1 ; sauvegarde du registre ADRESL ENDC ;xxxxxxxxxxxxxxxxxxxx ; Démarrage sur reset ;xxxxxxxxxxxxxxxxxxxx org 0x0000 goto initialisation ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Routine d'interruption ; 4 sources d'interruption : ; - réception (UART) ; - émission (UART) ; - module ADC (interruption de fin de conversion) ; - timer1 (période d'échantillonnage de 390,6 µs) ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx org 0x0004 ; vecteur d'interruption movwf W_TEMP swapf STATUS,W movwf STATUS_TEMP ; sauvegarde du registre W puis du registre STATUS bank1 btfss PIE1, RCIE goto int1 bank0 btfsc PIR1, RCIF goto reception int1 bank1 btfss PIE1, TXIE goto int2 bank0 btfsc PIR1, TXIF goto emission int2 bank1 btfss PIE1, ADIE goto int3 bank0 btfsc PIR1, ADIF goto adc int3 bank1 btfss PIE1, TMR1IE goto int4 bank0 btfsc PIR1, TMR1IF goto timer1 int4 goto restauration ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; traitement de l'interruption de réception de l'USART ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx reception bank0 movf RCREG , W ; N.B. le flag RCIF est remis à 0 par une lecture du registre RCREG movwf octet_rx ; les 8 bits de données sont transférés dans (octet_rx) ; on teste s'il s'agit du canal 0 movlw .0 ; W = .0 subwf octet_rx , W ; W = (octet_rx) - .0 btfss STATUS, Z ; test du bit Z goto canal1 ; Z = 0 c'est-à-dire (octet_rx) != .0 ; (octet_rx) = .0 (canal 0) ; Sélection du canal 0 bcf ADCON0 , CHS2 ; CHS2 = 0 bcf ADCON0 , CHS1 ; CHS1 = 0 bcf ADCON0 , CHS0 ; CHS0 = 0 goto activation_timer1 canal1 ; on teste s'il s'agit du canal 1 movlw .1 ; W = .1 subwf octet_rx , W ; W = (octet_rx) - .1 btfss STATUS, Z ; test du bit Z goto canal2 ; Z = 0 c'est-à-dire (octet_rx) != .1 ; (octet_rx) = .1 (canal 1) ; Sélection du canal 1 bcf ADCON0 , CHS2 ; CHS2 = 0 bcf ADCON0 , CHS1 ; CHS1 = 0 bsf ADCON0 , CHS0 ; CHS0 = 1 goto activation_timer1 canal2 movlw .2 ; W = .2 subwf octet_rx , W ; W = (octet_rx) - .2 btfss STATUS, Z ; test du bit Z goto canal3 ; Z = 0 c'est-à-dire (octet_rx) != .2 ; (octet_rx) = .2 (canal 2) ; Sélection du canal 2 bcf ADCON0 , CHS2 ; CHS2 = 0 bsf ADCON0 , CHS1 ; CHS1 = 1 bcf ADCON0 , CHS0 ; CHS0 = 0 goto activation_timer1 canal3 movlw .3 ; W = .3 subwf octet_rx , W ; W = (octet_rx) - .3 btfss STATUS, Z ; test du bit Z goto canal4 ; Z = 0 c'est-à-dire (octet_rx) != .3 ; (octet_rx) = .3 (canal 3) ; Sélection du canal 3 bcf ADCON0 , CHS2 ; CHS2 = 0 bsf ADCON0 , CHS1 ; CHS1 = 1 bsf ADCON0 , CHS0 ; CHS0 = 1 goto activation_timer1 canal4 movlw .4 ; W = .4 subwf octet_rx , W ; W = (octet_rx) - .4 btfss STATUS, Z ; test du bit Z goto canal5 ; Z = 0 c'est-à-dire (octet_rx) != .4 ; (octet_rx) = .4 (canal 4) ; Sélection du canal 4 bsf ADCON0 , CHS2 ; CHS2 = 1 bcf ADCON0 , CHS1 ; CHS1 = 0 bcf ADCON0 , CHS0 ; CHS0 = 0 goto activation_timer1 canal5 movlw .5 ; W = .5 subwf octet_rx , W ; W = (octet_rx) - .5 btfss STATUS, Z ; test du bit Z goto canal6 ; Z = 0 c'est-à-dire (octet_rx) != .5 ; (octet_rx) = .5 (canal 5) ; Sélection du canal 5 bsf ADCON0 , CHS2 ; CHS2 = 1 bcf ADCON0 , CHS1 ; CHS1 = 0 bsf ADCON0 , CHS0 ; CHS0 = 1 goto activation_timer1 canal6 movlw .6 ; W = .6 subwf octet_rx , W ; W = (octet_rx) - .6 btfss STATUS, Z ; test du bit Z goto canal_erreur ; Z = 0 c'est-à-dire (octet_rx) != .6 ; (octet_rx) = .6 (canal 6) ; Sélection du canal 6 bsf ADCON0 , CHS2 ; CHS2 = 1 bsf ADCON0 , CHS1 ; CHS1 = 1 bcf ADCON0 , CHS0 ; CHS0 = 0 goto activation_timer1 canal_erreur ; (octet_rx) a une valeur non valide ; (liste des valeurs valides : 0, 1, 2, 3, 4, 5 et 6) goto overrun ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Activation du TIMER1 (16 bits) ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx activation_timer1 bcf PIR1 , TMR1IF ; on efface le drapeau de l'interruption clrf nb_mesures clrf octet1_tx clrf octet2_tx clrf octet3_tx clrf TMR1H bank1 bsf PIE1 , TMR1IE ; autorisation de l'interruption du TIMER1 (16 bits) bank0 bsf PIR1 , TMR1IF ; on force à 1 le drapeau de l'interruption ; => interruption provoquée goto overrun ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx overrun ; test d'une erreur d'overrun bank0 btfss RCSTA , OERR goto restauration ; traitement de l'erreur d'overrun bcf RCSTA , CREN ; on efface le bit OERR bsf RCSTA , CREN ; on relance la réception goto restauration ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Traitement de l'interruption du Timer1 ; on arrive ici toutes les 390,6 µs (période d'échantillonnage) ; 390,6 µs = 1953 cycles (avec un quartz de 20MHz) ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx timer1 incf nb_mesures , f ; incrémentation du compteur ; le timer1 est incrémenté de 0xF866 = 63590 (65536 - 1953 + 7 instructions) bcf T1CON , TMR1ON ; Stops TIMER1 movlw 0x66 addwf TMR1L , f ; (TMR1L) = (TMR1L) + 0x66 btfsc STATUS, C ; test du bit C (Carry) incf TMR1H , f movlw 0xF8 addwf TMR1H , f ; (TMR1H) = (TMR1H) + 0xF8 bsf T1CON , TMR1ON ; Enables TIMER1 ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Attente pendant la phase d'acquisition (environ 19,7 µs) ; 19,7 µs = 98 cycles (avec un quartz 20 MHz) acquisition movlw .158 ; 256 - 98 movwf TMR0 ; (TMR0) = .158 bcf INTCON , TMR0IF ; on efface le drapeau du timer0 attente btfss INTCON , TMR0IF goto attente ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Lancement de la phase de conversion de l'ADC bsf ADCON0 , GO ; GO = 1 bcf PIR1 , TMR1IF ; on efface le drapeau de l'interruption Timer1 goto restauration ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Traitement de l'interruption de fin de conversion du module ADC ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx adc ; Attente avant une nouvelle acquisition (2 TAD = 3,2 µs) ; 3,2 µs = 16 cycles (avec un quartz 20 MHz) movlw .240 ; 256 - 16 movwf TMR0 ; (TMR0) = .240 bcf INTCON , TMR0IF ; on efface le drapeau du timer0 attente1 btfss INTCON , TMR0IF goto attente1 ; lecture et sauvegarde du résultat de la conversion movf ADRESH , W ; W = (ADRESH) movwf adresh_bak ; (adresh_bak) = (ADRESH) bank1 movf ADRESL , W ; W = (ADRESL) movwf adresl_bak ; (adresl_bak) = (ADRESL) bank0 ; sommme = ; (octet1_tx) (octet2_tx) (octet3_tx) = nombre de 18 bits ; (000000 b17 b16 ... b0) ; resultat de conversion = ; (adresh_bak) (adresl_bak) = nombre de 10 bits ; (000000 d9 ... d0) ; somme = somme + resultat de conversion movf adresl_bak , W ; W = (adresl_bak) addwf octet3_tx , f ; (octet3_tx) = (octet3_tx) + adresl_bak btfsc STATUS, C ; test du bit C (Carry) goto som0 goto som1 som0 incf octet2_tx , f ; (octet2_tx) = (octet2_tx) + 0x01 btfsc STATUS, Z ; test du bit Z (Zero) incf octet1_tx , f ; (octet1_tx) = (octet1_tx) + 0x01 som1 movf adresh_bak , W ; W = (adresh_bak) addwf octet2_tx , f ; (octet2_tx) = (octet2_tx) + adresh_bak btfsc STATUS, C ; test du bit C (Carry) incf octet1_tx , f ; (octet1_tx) = (octet1_tx) + 0x01 bcf PIR1 , ADIF ; on efface le drapeau de l'interruption du module ADC ; on teste si le compteur = 0x00 (= 256 ème mesure) movf nb_mesures , f ; (nb_mesures) = (nb_mesures) btfss STATUS , Z ; test du bit Z goto restauration ; Z = 0 c'est-à-dire (nb_mesures) != 0x00 ; 256 ème mesure bank1 bsf PIE1 , TXIE ; autorisation de l'interruption d'émission de l'USART bcf PIE1 , TMR1IE ; interdiction de l'interruption du TIMER1 (16 bits) bank0 goto restauration ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Traitement de l'interruption d'émission de l'USART ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx emission ; 3 octets à transmettre incf nb_octet_transmis , f ; on incrémente (nb_octet_transmis) movlw D'1' subwf nb_octet_transmis , W btfss STATUS , Z goto emm2 ; émission du 1er octet movf octet1_tx , W ;bank0 movwf TXREG ; transmission ; N.B. le flag TXIF est remis à 0 par une écriture dans le registre TXREG goto int1 ; pour transmettre le plus rapidement possible le 2ème octet emm2 movlw D'2' subwf nb_octet_transmis , W btfss STATUS , Z goto emm3 ; émission du 2ème octet movf octet2_tx , W ;bank0 movwf TXREG ; transmission ; N.B. le flag TXIF est remis à 0 par une écriture dans le registre TXREG goto int1 ; pour transmettre le plus rapidement possible le 3ème octet emm3 ; émission du 3ème octet movf octet3_tx , W ;bank0 movwf TXREG ; transmission ; N.B. le flag TXIF est remis à 0 par une écriture dans le registre TXREG bank1 bcf PIE1 , TXIE ; interdiction de l'interruption d'émission de l'USART bank0 clrf nb_octet_transmis goto restauration ;xxxxxxxxxxx restauration swapf STATUS_TEMP,W ; restauration des registres STATUS puis W movwf STATUS swapf W_TEMP,f swapf W_TEMP,W retfie ;xxxxxxxxxxxxxxx ; Initialisation ;xxxxxxxxxxxxxxx initialisation bank0 clrf PORTA ; mise à 0 des sorties du port A clrf PORTB ; mise à 0 des sorties du port B bank1 movlw B'11011000' movwf OPTION_REG ; bit 7 (/RBPU) = 1 : valeur par défaut (option non utilisée) ; bit 6 (INTEDG) = 1 : valeur par défaut (option non utilisée) ; bit 5 (T0CS) = 0 : l'horloge interne est l'horloge du timer0 ; bit 4 (T0SE) = 1 : valeur par défaut (option non utilisée) ; bit 3 (PSA) = 1 ; bit 2 (PS2) = 0 ; bit 1 (PS1) = 0 ; bit 0 (PS0) = 0 ; Prescaler du Timer0 = 1:1 ; Watchdog sans prescaler (1:1) ; le timer0 déborde toutes les 256*0,2 µs = 51,2 µs movlw B'11111111' movwf TRISA ; bit 0 du port A (RA0) = 1 : configuration en entrée (canal 0 du module ADC) ; bit 1 du port A (RA1) = 1 : configuration en entrée (canal 1 du module ADC) ; bit 2 du port A (RA2) = 1 : configuration en entrée (canal 2 du module ADC) ; bit 3 du port A (RA3) = 1 : configuration en entrée (canal 3 du module ADC) ; bit 4 du port A (RA4) = 1 : configuration en entrée (canal 4 du module ADC) ; bit 5 du port A (RA5) = X : configuration en entrée, par exemple ; bit 6 du port A (RA6) = X : configuration en entrée, par exemple ; bit 7 du port A (RA7) = X : configuration en entrée, par exemple movlw B'11111111' movwf TRISB ; bit 0 du port B (RB0) = X : configuration en entrée, par exemple ; bit 1 du port B (RB1) = X : configuration en entrée, par exemple ; bit 2 du port B (RB2) = 1 : configuration en entrée (RX : USART) ; bit 3 du port B (RB3) = X : configuration en entrée, par exemple ; bit 4 du port B (RB4) = X : configuration en entrée, par exemple ; bit 5 du port B (RB5) = 1 : configuration en entrée (TX : USART) ; bit 6 du port B (RB6) = 1 : configuration en entrée (canal 5 du module ADC) ; bit 7 du port B (RB7) = 1 : configuration en entrée (canal 6 du module ADC) movlw B'01111111' movwf ANSEL ; bit 7 du registre ANSEL = 0 : non implémenté ; bit 6 du registre ANSEL = 1 : configuration de la broche RB7/AN6 comme entrée analogique (canal 6) ; bit 5 du registre ANSEL = 1 : configuration de la broche RB6/AN5 comme entrée analogique (canal 5) ; bit 4 du registre ANSEL = 1 : configuration de la broche RA4/AN4 comme entrée analogique (canal 4) ; bit 3 du registre ANSEL = 1 : configuration de la broche RA3/AN3/VREF+ comme entrée analogique (canal 3) ; bit 2 du registre ANSEL = 1 : configuration de la broche RA2/AN2/VREF- comme entrée analogique (canal 2) ; bit 1 du registre ANSEL = 1 : configuration de la broche RA1/AN1 comme entrée analogique (canal 1) ; bit 0 du registre ANSEL = 1 : configuration de la broche RA0/AN0 comme entrée analogique (canal 0) ; Configuration du module ADC ; tension de référence haute : VDD (5 V) ; tension de référence basse : VSS (0 V) bcf ADCON1 , VCFG0 ; VCFG0 = 0 bcf ADCON1 , VCFG1 ; VCFG1 = 0 ; Choix du format du résultat de la conversion bsf ADCON1 , ADFM ; ADRESH = (0 0 0 0 0 0 b9 b8) ; ADRESL = (b7 b6 b5 b4 b3 b2 b1 b0) ; Choix de la fréquence d'horloge du convertisseur ADC ; F AD = F OSC / 32 = 625 kHz ; T AD = 1,6 µs bcf ADCON1 , ADCS2 ; ADCS2 = 0 bank0 bsf ADCON0 , ADCS1 ; ADCS1 = 1 bcf ADCON0 , ADCS0 ; ADCS0 = 0 bank1 ; configuration de la liaison RS232 movlw D'129' movwf SPBRG ; (SPBRG) = D'129' movlw B'00100100' movwf TXSTA ; bit 7 (CSRC) = 0 (non utilisé : 0 par exemple) ; bit 6 (TX9) = 0 : 8 bits de transmission ; bit 5 (TXEN) = 1 : autorise la réception ; bit 4 (SYNC) = 0 : mode asynchrone ; bit 3 = 0 (non implémenté) ; bit 2 (BRGH) = 1 : mode asynchrone haute vitesse ; bit 1 (TRMT) = 0 (en lecture seule) ; bit 0 (TX9D) = 0 (non utilisé : 0 par exemple) bank0 movlw B'10010000' movwf RCSTA ; bit 7 (SPEN) = 1 : utilisation du port série ; bit 6 (RX9) = 0 : 8 bits de réception ; bit 5 (SREN) = 0 (non utilisé : 0 par exemple) ; bit 4 (CREN) = 1 : autorise la réception ; bit 3 (ADDEN) = 0 (non utilisé : 0 par exemple) ; bit 2 (FERR) = 0 (en lecture seule) ; bit 1 (OERR) = 0 (en lecture seule) ; bit 0 (RX9D) = 0 (non utilisé : 0 par exemple) clrf PORTA ; mise à 0 des sorties du port A clrf PORTB ; mise à 0 des sorties du port B clrf nb_octet_transmis clrf nb_mesures bcf PIR1 , ADIF ; on efface le drapeau de l'interruption du module ADC bank1 bsf PIE1 , RCIE ; autorisation de l'interruption de réception de l'USART bcf PIE1 , TXIE ; interdiction de l'interruption d'émission de l'USART bsf PIE1 , ADIE ; autorisation de l'interruption du module ADC bsf INTCON , PEIE ; autorisation des interruptions des périphériques bsf INTCON, GIE ; autorisation globale des interruptions bank0 ; Mise en service du convertisseur ADC bsf ADCON0 , ADON ; ADON = 1 ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; Configuration du TIMER1 (16 bits) en mode timer ; Utilisation de l'interruption ; Débordement (0xFFFF -> 0x0000) ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx bcf T1CON , T1CKPS1 bcf T1CON , T1CKPS0 ; prescaler 1:1 bcf T1CON , TMR1CS ; Timer1 Clock Source = Internal clock (FOSC/4) bsf T1CON , TMR1ON ; Enables TIMER1 goto debut_programme ;xxxxxxxxxxxxxxxxxxxxx ; Programme principal ;xxxxxxxxxxxxxxxxxxxxx debut_programme goto debut_programme ; on attend une interruption END