;Quartz 4 MHz : cycle … 1 æs LIST p=16F84 __CONFIG _CP_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC ERRORLEVEL -305, -306, -302 #include P16F84.INC #define SDA PORTB,0 #define SCL PORTB,1 #define DATA PORTB,2 #define L_ROUGE PORTA,1 #define L_VERTE PORTA,0 #define PB1 PORTA,2 #define PB2 PORTA,3 VITESSE_AQUISITION EQU 30h CBLOCK 0Ch TEMP1 TEMP2 DONNEE ADRESSE_I2C TEMPER COUNT_PER_C COUNT_REMAIN TMP_TEMPO CPT_TIMER TEMPO_ROUGE W_SAVE DIV_RESTE_H DIV_RESTE_L DIV_DENOMINATEUR_H DIV_DENOMINATEUR_L DIV_NUMERATEUR_H DIV_NUMERATEUR_L DIV_TEMP_H DIV_TEMP_L DIV_LOOP_CPT MULTIPLICANDE MULTIPLICATEUR MUL_RESULTAT_H MUL_RESULTAT_L MUL_COUNT FLAGS TEMPERATURE_ENTIER TEMPERATURE_DECIMALE ACCA_H ACCA_L ACCB_H ACCB_L ENDC ORG 0 goto MAIN ORG 4 goto INT ;***************************************************************************** ; IN_BYTE : Lit un octet transf‚r‚ sur l'I2C, retour dans DONNEE ;***************************************************************************** IN_BYTE movlw 08h movwf TEMP1 ;compteur : 1 octet IN_SCL_Bas btfss SCL ;on attend que SCL passe … 1 goto IN_SCL_Bas bcf STATUS,C rlf DONNEE bcf DONNEE,0 btfsc SDA ;SCL … 1 : je lis la donn‚e bsf DONNEE,0 IN_SCL_Haut btfsc SCL ;on attend que SCL retombe … 0 goto IN_SCL_Haut decfsz TEMP1 goto IN_SCL_Bas return ;***************************************************************************** ; OUT_BYTE : envoie W sur l'I2C ;***************************************************************************** OUT_BYTE movwf TEMP2 movlw 08h movwf TEMP1 ;compteur : 1 octet OUT_bit_suivant bsf STATUS,RP0 ; bsf SDA ;SDA = 1 bcf STATUS,RP0 ; rlf TEMP2 btfsc STATUS,C goto OUT_SCL_Bas bcf SDA ; bsf STATUS,RP0 ; bcf SDA ;SDA = 0 bcf STATUS,RP0 ; OUT_SCL_Bas btfss SCL ;on attend que SCL passe … 1 goto OUT_SCL_Bas OUT_SCL_Haut ;donn‚e valide sur l'I2C btfsc SCL ;on attend que SCL passe … 0 goto OUT_SCL_Haut decfsz TEMP1 goto OUT_bit_suivant bsf STATUS,RP0 ; bsf SDA ;SDA = 1 bcf STATUS,RP0 ; return ;***************************************************************************** ; ACK : envoie un acknowledgement ;***************************************************************************** ACK bcf SDA ;acknowledgement : SDA = 0 bsf STATUS,RP0 bcf SDA ;SDA : sortie bcf STATUS,RP0 ACK_SCL_Bas btfss SCL ;on attend le front montant de SCL goto ACK_SCL_Bas ACK_SCL_Haut btfsc SCL goto ACK_SCL_Haut bsf STATUS,RP0 bsf SDA ;SDA : entree bcf STATUS,RP0 return ;***************************************************************************** ; NO_ACK : n'aquitte pas ;***************************************************************************** NO_ACK btfss SCL ;laisse passer un cycle d'horloge goto NO_ACK NO_ACK_SCL_Haut btfsc SCL goto NO_ACK_SCL_Haut retlw 0FFh ;***************************************************************************** ; LIS_ACK : lis l'acknowledgement du recepteur ; retour dans W --> FF : ack - 00 : no ack ;***************************************************************************** LIS_ACK btfss SCL ;attend le front montant de SCL goto LIS_ACK clrw btfss SDA ;SDA haut : pas d'ack movlw 0FFh LIS_ACK_SCL_Haut btfsc SCL goto LIS_ACK_SCL_Haut andlw 0FFh btfss STATUS,Z retlw 0FFh retlw 00h ;***************************************************************************** ; WAIT_STOP : attend un STOP ;***************************************************************************** WAIT_STOP btfss SCL goto WAIT_STOP attend_stop btfss SDA goto attend_stop retlw 00h ;***************************************************************************** ; I2C : routine de dialogue I2C, … appeler apres reception du START ;***************************************************************************** I2C call IN_BYTE ;lecture adresse bcf STATUS,C rrf DONNEE,W subwf ADRESSE_I2C,W btfss STATUS,Z ;pour moi goto NO_ACK ;pas pour moi call ACK btfss DONNEE,0 ;bit R/W goto ecriture movf TEMPERATURE_ENTIER,W call OUT_BYTE call LIS_ACK andlw 0FFh btfsc STATUS,Z goto WAIT_STOP ;no ack --> on attend le stop suite_Xfer movf TEMPERATURE_DECIMALE,W ;ack -----> on continue le transfert call OUT_BYTE call LIS_ACK andlw 0FFh btfsc STATUS,Z goto WAIT_STOP ;no ack --> on attend le stop goto suite_Xfer ;ack -----> on a plus rien … envoyer, on envoie toujours la mˆme chose ecriture call IN_BYTE call ACK goto WAIT_STOP ;***************************************************************************** ; TEMPO : 1 dans W : 5æs ;***************************************************************************** TEMPO movwf TMP_TEMPO tempo nop nop decfsz TMP_TEMPO goto tempo return ;***************************************************************************** ; LIS_DS : lis le DS1820, retour dans DONNEE ;***************************************************************************** LIS_DS movlw 08h movwf TEMP1 ;compteur : 1 octet lis_DS bcf DATA bsf STATUS,RP0 bcf DATA ;DATA = 0 en sortie bcf STATUS,RP0 movlw d'2' ;10 æs call TEMPO bsf STATUS,RP0 bsf DATA ;haute imp. bcf STATUS,RP0 nop nop clrw btfsc DATA movlw 80h addlw 0FFh ;carry = 1 si data = 1.... rrf DONNEE movlw d'12' ;60 æs call TEMPO decfsz TEMP1 goto lis_DS return ;***************************************************************************** ; ECRIS_DS : envoie W au DS1820 ;***************************************************************************** ECRIS_DS movwf TEMP2 movlw 08h movwf TEMP1 ;compteur : 1 octet ecris_DS bcf DATA bsf STATUS,RP0 bcf DATA ;DATA = 0 en sortie bcf STATUS,RP0 movlw d'2' ;attente 10 æs call TEMPO rrf TEMP2 btfsc STATUS,C bsf DATA movlw d'14' ;70 æs call TEMPO bsf STATUS,RP0 bsf DATA ;haute imp. bcf STATUS,RP0 nop decfsz TEMP1 goto ecris_DS return ;***************************************************************************** ; RESET_DS : W = FF : erreur, sinon 0 ;***************************************************************************** RESET_DS bsf STATUS,RP0 bcf DATA bcf STATUS,RP0 bcf DATA ;reset pulse ( > 480 æs ) movlw d'120' call TEMPO bsf STATUS,RP0 bsf DATA ;receive mode bcf STATUS,RP0 movlw d'14' ;70 æs call TEMPO btfsc DATA retlw 0FFh ;bit … 1 : pas de reponse movlw d'60' ;300 æs call TEMPO retlw 00h ;***************************************************************************** ; DS1820 : W = FF : erreur, sinon 0 ;***************************************************************************** DS1820 call RESET_DS andlw 0FFh btfss STATUS,Z retlw 0FFh ;retour de reset <> 0 : erreur movlw 0CCh ;skip ROM call ECRIS_DS movlw 0BEh ;read scratchpad call ECRIS_DS call LIS_DS ;LSB temperature movf DONNEE,W movwf TEMPER call LIS_DS ;MSB temperature call LIS_DS ;2 call LIS_DS ;3 call LIS_DS ;4 call LIS_DS ;5 call LIS_DS ;Count remain movf DONNEE,W movwf COUNT_REMAIN call LIS_DS ;Count per øC movf DONNEE,W movwf COUNT_PER_C call RESET_DS movlw 0CCh ;skip ROM call ECRIS_DS movlw 44h ;d‚but conversion temp. call ECRIS_DS retlw 00h ;***************************************************************************** ; LIS_ADRESSE : lecture de l'adresse du composant sur les switches ;***************************************************************************** LIS_ADRESSE btfss PORTB,4 movlw 43h btfss PORTB,5 movlw 42h btfss PORTB,6 movlw 41h btfss PORTB,7 movlw 40h movwf ADRESSE_I2C return ;***************************************************************************** ; INTERRUPTION ;***************************************************************************** INT movwf W_SAVE btfsc INTCON,RBIF goto RB_change btfsc INTCON,T0IF goto timer btfsc INTCON,INTF goto RB0_int goto fin_interruption RB_change call LIS_ADRESSE bcf INTCON,RBIF goto fin_interruption timer bcf L_VERTE decfsz CPT_TIMER goto fin_timer movlw VITESSE_AQUISITION movwf CPT_TIMER btfsc FLAGS,0 ;le calcul est fini ? goto fin_timer ;non call DS1820 bsf L_VERTE bsf FLAGS,0 ;signaler qu'il faut faire le calcul fin_timer btfss L_ROUGE goto fin_timer_bis decfsz TEMPO_ROUGE goto fin_timer_bis bcf L_ROUGE fin_timer_bis bcf INTCON,T0IF goto fin_interruption RB0_int btfss SCL goto fin_RB0 SCL_Haut btfsc SCL ;attend que SCL redescende goto SCL_Haut call I2C andlw 0FFh btfss STATUS,Z ;l'I2C etait pour moi ? goto fin_RB0 ;non bsf L_ROUGE movlw 0Ah movwf TEMPO_ROUGE fin_RB0 bcf INTCON,INTF fin_interruption movf W_SAVE,W bsf INTCON,GIE retfie ;***************************************************************************** ; DIV1616 ; division 16/16 DIV_NUMERATEUR/DIV_DENOMINATEUR -> DIV_NUMERATEUR ; reste dans DIV_RESTE ;***************************************************************************** DIV1616 movlw d'16' movwf DIV_LOOP_CPT movf DIV_NUMERATEUR_H, W movwf DIV_TEMP_H movf DIV_NUMERATEUR_L, W movwf DIV_TEMP_L clrf DIV_NUMERATEUR_H clrf DIV_NUMERATEUR_L clrf DIV_RESTE_H clrf DIV_RESTE_L DIV_Loop bcf STATUS, C rlf DIV_TEMP_L, F rlf DIV_TEMP_H, F rlf DIV_RESTE_L, F rlf DIV_RESTE_H, F movf DIV_DENOMINATEUR_H, W subwf DIV_RESTE_H, W btfss STATUS, Z goto DIV_Nochk movf DIV_DENOMINATEUR_L, W subwf DIV_RESTE_L, W DIV_Nochk btfss STATUS, C goto DIV_Nogo movf DIV_DENOMINATEUR_L, W subwf DIV_RESTE_L, F btfss STATUS, C decf DIV_RESTE_H, F movf DIV_DENOMINATEUR_H, W subwf DIV_RESTE_H, F bsf STATUS, C DIV_Nogo rlf DIV_NUMERATEUR_L, F rlf DIV_NUMERATEUR_H, F decfsz DIV_LOOP_CPT, F goto DIV_Loop return ;***************************************************************************** ; MUL8X8 ; multiplication 8x8 MULTIPLICANDE X MULTIPLICATEUR --> MUL_RESULTAT (16 bits) ;***************************************************************************** MUL8X8 clrf MUL_RESULTAT_H clrf MUL_RESULTAT_L movlw 08h movwf MUL_COUNT movf MULTIPLICANDE,W bcf STATUS,C MUL_Loop rrf MULTIPLICATEUR btfsc STATUS,C addwf MUL_RESULTAT_H rrf MUL_RESULTAT_H rrf MUL_RESULTAT_L decfsz MUL_COUNT goto MUL_Loop return ;***************************************************************************** ; ADD16 ; addition : ACCA + ACCB --> ACCB ;***************************************************************************** ADD16 movf ACCA_L,W addwf ACCB_L btfsc STATUS,C incf ACCB_H movf ACCA_H,W addwf ACCB_H return ;***************************************************************************** ; PROGRAMME PRINCIPAL ;***************************************************************************** MAIN clrwdt bsf STATUS,RP0 movlw b'00010111' ;pull ups port B, + timer 0 movwf OPTION_REG movlw 0FFh movwf TRISB ;port B en entr‚e movlw b'11111100' movwf TRISA bcf STATUS,RP0 movlw b'00111000' movwf INTCON ;interruption RB change + Timer0 + RB0 movlw VITESSE_AQUISITION movwf CPT_TIMER bcf L_VERTE bcf L_ROUGE call LIS_ADRESSE bsf INTCON,GIE debut clrwdt btfss FLAGS,0 ;doit on calculer ? goto debut ;non bcf TEMPER,0 ;on masque le poids faible bcf STATUS,C rlf TEMPER ;TEMPER = TEMPER * 2 decf TEMPER ;TEMPER = TEMPER - 1 movf COUNT_REMAIN,W subwf COUNT_PER_C,W ;W = COUNT_PER_C - COUNT_REMAIN movwf MULTIPLICANDE movlw d'100' movwf MULTIPLICATEUR ;MUL_RESULTAT = W * 100 call MUL8X8 movf MUL_RESULTAT_H,W movwf DIV_NUMERATEUR_H movf MUL_RESULTAT_L,W ;DIV_NUMERATEUR = MUL_RESULTAT movwf DIV_NUMERATEUR_L movf COUNT_PER_C,W movwf DIV_DENOMINATEUR_L clrf MUL_RESULTAT_H ;DIV_DENOMINATEUR = COUNT_PER_C call DIV1616 ;division movf TEMPER,W movwf MULTIPLICANDE movlw d'25' movwf MULTIPLICATEUR call MUL8X8 ;MUL_RESULTAT = TEMPER * 25 movf MUL_RESULTAT_H,W movwf ACCA_H movf MUL_RESULTAT_L,W ;ACCA = MUL_RESULTAT movwf ACCA_L movf DIV_NUMERATEUR_H,W movwf ACCB_H movf DIV_NUMERATEUR_L,W ;ACCB = DIV_NUMERATEUR movwf ACCB_L call ADD16 movf ACCB_H,W movwf DIV_NUMERATEUR_H movf ACCB_L,W movwf DIV_NUMERATEUR_L clrf DIV_DENOMINATEUR_H movlw d'100' movwf DIV_DENOMINATEUR_L call DIV1616 ;DIV_NUMERATEUR = ACCB / 100 movf DIV_NUMERATEUR_L,W movwf TEMPERATURE_ENTIER movf DIV_RESTE_L,W movwf TEMPERATURE_DECIMALE bcf FLAGS,0 goto debut END