; NIQ800 : free clone of MIC800 ; clock : 4,096MHz ( T_inst=1us ) ; serial line : 9600bps ( T= 104 cycles ) ;-------------------- ;Trame de commande : ; 1er octet de controle: Res-EE-cs2-cs1-cs0-s2-s1-s0 ; 2eme octet de position: la position du servo de 0 à 255 ; Maximum 1,25ms entre les deux octets, sinon, le premier est oublié ;-------------------------------- errorlevel 0, -224, -205, -302 ;-------------------------------- ;----- PORTABILITE -------------- include "p16f876.inc" include "m_84.asm" __CONFIG _DEBUG_OFF & _WRT_ENABLE_ON & _CPD_OFF & _LVP_OFF & _BODEN_ON & _PWRTE_ON & _WDT_OFF & _XT_OSC servo0 equ 0 Same equ 1 MSB equ 7 ;***************** Communication Parameters ************************** ; X_MODE equ 1 ; If ( X_MODE==1) Then transmit LSB first ; if ( X_MODE==0) Then transmit MSB first ( CODEC like ) R_MODE equ 1 ; If ( R_MODE==1) Then receive LSB first ; if ( X_MODE==0) Then receive MSB first ( CODEC like ) X_Nbit equ 1 ; if (X_Nbit==1) # of data bits ( Transmission ) is 8 else 7 R_Nbit equ 1 ; if (R_Nbit==1) # of data bits ( Reception ) is 8 else 7 ; Sbit2 equ 0 ; if Sbit2 = 0 then 1 Stop Bit else 2 Stop Bits ; ;************************************************************************* ;X_flag equ PA0 ; Bit 5 of F3 ( PA0 ) ;R_flag equ PA1 ; Bit 6 of F3 ( PA1 ) ; BAUD_1 equ .68 ; 3+3X = CLKOUT/Baud BAUD_2 equ .67 ; 6+3X = CLKOUT/Baud BAUD_3 equ .34 ; 3+3X = 0.5*CLKOUT/Baud BAUD_4 equ .86 ; 3+3X = 1.25*CLKOUT/Baud BAUD_X equ .66 ; 11+3X = CLKOUT/Baud BAUD_Y equ .66 ; 9 +3X = CLKOUT/Baud ; -- Scratchpad du pic utilisé ( 1er adresse mémoire utilisable ) sp equ h'20' ;(PIC 16f876) debug equ 0 ; debugging ;-------------------------------- ; Variable definition CBLOCK sp buffer_in value:1 command:1 chipID:1 flags:1 countwdt:1 curentvalue:1 wsave:1 statussave tabval:8 RcvReg :1 ; Data received XmtReg :1 ; Data to be transmitted Count :1 ; Counter for #of Bits Transmitted DlyCnt :1 ENDC rtcc equ tmr0 ; bits de porta chID0 equ 0 chID1 equ 1 chID2 equ 2 ;servo0 equ 0 ; dans flags ms2 equ 0 ; continuer la deuxième ms portvide equ 1 f_sec_octet equ 2 ; -- bits de flags bus_wr equ 3 ; bits de l'octet commande : reset_b equ 7 eeprom_b equ 6 ;----------------------------- ;----------------------------- BUSROBOT.ASM ;----------------------------- ;----------------------------- ; -- option optionval equ b'01000010' edg_msk equ b'01000000' ; ***** Mise à jour de l'EEPROM ; *********************************************** org h'2100' de 1,.40,.75,.110,.145,.180,.215,.255 ; ***** Début du code ; *********************************************** ORG 0 ;vecteur de reset goto reset ORG 4 serviceint: btfsc intcon,intf goto busint ; ***** Interuption de timer ***** btfss flags,ms2 ; test du flag seconde moitié goto suite2ms clr: ;on efface toutes les lignes clrf portb bcf porta,servo0 bsf flags,portvide ; ça y est le port est bien vide bcf intcon,t0if ;flag timer retfie suite2ms: ; on lance la seconde moitié bsf flags,ms2 ; flag qui dit qu'on est entré dans la seconde moitié movwf wsave clrf rtcc movf curentvalue,w ; on remplit la rtcc subwf rtcc,f bcf intcon,t0if ;flag timer movf wsave,w retfie ; ***** Interuption de bus ***** busint: movwf wsave movf status,w movwf statussave ;*************************************************************** ; Receiver ; Rcvr IF R_Nbit movlw 8 ; 8 Data bits ELSE movlw 7 ; 7 data bits ENDIF ; movwf Count R_next bcf STATUS,C IF R_MODE rrf RcvReg,Same ; to set if MSB first or LSB first ELSE rlf RcvReg,Same ENDIF btfsc PORTA,DR ; IF R_MODE IF R_Nbit bsf RcvReg,MSB ; Conditional Assembly ELSE bsf RcvReg,MSB-1 ENDIF ELSE bsf RcvReg,LSB ENDIF ; call DelayY decfsz Count,Same goto R_next ;**************************************************** ;R_over movf RcvReg,0 ; Send back What is Just Received ; movwf XmtReg call work ;**************************************************** ; Transmitter ; Xmtr IF X_Nbit movlw 8 ELSE movlw 7 ENDIF movwf Count ; IF X_MODE ELSE IF X_Nbit ELSE rlf XmtReg,Same ENDIF ENDIF ; bcf PORTA,DX ; Send Start Bit call Delay1 X_next bcf STATUS,C ; IF X_MODE rrf XmtReg,Same ; Conditional Assembly ELSE ; to set if MSB first or LSB first rlf XmtReg,Same ENDIF ; btfsc STATUS,C bsf PORTA,DX btfss STATUS,C bcf PORTA,DX call DelayX decfsz Count,Same goto X_next bsf PORTA,DX ; Send Stop Bit call Delay1 ; IF Sbit2 bsf PORTA,DX call Delay1 ENDIF ; goto finbusint ; ; End of Transmission ; DelayY movlw BAUD_Y goto save DelayX movlw BAUD_X goto save Delay4 movlw BAUD_4 goto save Delay1 movlw BAUD_1 ; 104 uS for 9600 baud goto save Delay2 movlw BAUD_2 save movwf DlyCnt redo_1 decfsz DlyCnt,Same goto redo_1 retlw 0 ; ;---------------------------- ;-- old bus_int ;---------------------------- movf portc,w btfsc flags,f_sec_octet goto sec_octet movwf command bsf flags,f_sec_octet goto finbusint sec_octet movwf value call work bcf flags,f_sec_octet ;----- dans tous les cas -------- finbusint: movf statussave,w movwf status movf wsave,w bcf intcon,intf retfie ; ***** La sous-routine de reset ***** reset: ; pour les tris, seuls les lignes à 0 peuvent être basculées en entrée. Les broches à 1 doivent rester en entrée ( sauf la broche RW dans le cas d'une liaison non-duplex ) movlw b'11111111' tris porta movlw b'11111101' ; B7-B2 = input / B1 = TX / B0 = RX tris portb movlw b'00000000' ; C7-C2 = output / C1 = servo1 / C0 servo0 tris portc clrf portc movlw optionval option clrf buffer_in bsf flags,portvide bcf flags,f_sec_octet movlw b'10110000' ; (G|EE|T|I|Rb|T|I|Rb) movwf intcon call restore_defaults goto main ;---------------- restore_defaults: clrf eeadr movlw tabval movwf fsr I=0 WHILE I<=7 ; EEread ; lit l'eeprom à l'adresse eeadr et place le résultat dans eedata ; movf eedata,w movlw .128 movwf indf incf fsr,f incf eeadr,f I++ ENDW return ;------------------------------ ; interprétation de la commande ; 1er octet de controle: D5-D0 ! type ! voie ; type=1 => IO ; voie=1 => in ; voie=0 => out ; type=0 => servo ; voie=1 => servo1 ; voie=0 => servo0 work: movf RcvReg,w movwf XmtReg,f ; on prépare l'écho de la commande ; type de trame btfss RcvReg,1 goto setServo ;-- Gestion des IO setIO btfss RcvReg,1 goto IOout ;- IOin movf portb,w movwf XmtReg,f ;mise en forme de la trame : bsf XmtReg,0 ; IO bsf XmtReg,1 ; in return ;- IOout movf RcvReg,w andlw '11111100' movwf command movf portc,w ; il faut bouger toutes les pattes du portb sans toucher aux servos andlw '00000011' ; on efface les IO iorwf command ; on les met à jour avec la nouvelle valeur movwf portc return ;-- Gestion des servos setServo ; n° de servo movf command,w andlw b'11111100' movwf value,f andlw b'00000001' movwf eeadr ; on prépare l'écriture en eeprom addlw tabval movwf fsr ; on met à jour le pointeur de tableau movf value,w ; on copie la valeur dans le tableau movwf indf ; écriture en eeprom ? ; btfsc command,eeprom_b ; goto seteeprom ; ; return ;seteeprom: ; movwf eedata ; on met la valeur dans eedata ; EEwrite return ;---- on passe par une macro pour spécifier le label en local waitnext MACRO LOCAL again again: btfss flags,portvide ; si le portb est vide, alors il faut lancer le signal du servo suivant goto again ; sinon, on continue le poling ENDM ;--------------- main: I=0 WHILE I<=7 waitnext ;exécute la macro bcf flags,ms2 movlw I addlw tabval movwf fsr ; ---- MODE PROTEGE ON ---- bcf intcon,gie IF I==7 ;on allume la bonne ligne de sortie bsf porta,servo0 ELSE bsf portb,I+1 ENDIF bcf flags,portvide ; le port n'est plus vide ; on charge la rtcc pour attendre la première ms load .198,rtcc ; on met la valeur de la "seconde ms" dans curentvalue ; par cette technique, la position est échelonée de 0 à 255 ( avant : 1 correspondait au 1ms, donc on incrémente la valeur, comme ça 0 correspond au 1 qui correspond à 1ms ) incf indf,w movwf curentvalue bsf intcon,gie ; ---- MODE PROTEGE OFF ---- I++ ENDW goto main END