; 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_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC servo0 equ 0 Same equ 1 MSB equ 7 ; -- 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 counter :1 subcounter :1 ENDC rtcc equ tmr0 DR equ 0 DX equ 1 servo0 equ 0 servo1 equ 1 ; 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' ;*** Macros pour lire les AD *** wait_ad MACRO local loop loop: btfsc adcon0,go goto loop ENDM admesure MACRO bsf status,rp0 movf adresl,w bcf status,rp0 ENDM BANK1 macro bsf status,rp0 endm BANK0 macro bcf status,rp0 endm ; ***** 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: btfss intcon,t0if goto busint ; ***** Interuption de timer ***** btfss flags,ms2 ; test du flag seconde moitié goto suite2ms clr: ;on efface toutes les lignes bcf portc,servo0 bcf portc,servo1 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 bcf intcon,gie ;interruption non protégée movf rcreg,w movwf XmtReg incf XmtReg,f call txhard movf rcreg,w call analyse goto finbusint ;----- dans tous les cas -------- finbusint: movf statussave,w movwf status movf wsave,w bcf intcon,intf retfie ; ***** La sous-routine de reset ***** reset: clrf intcon ; entrées analogiques bsf status,RP0 movlw b'00000010' movwf adcon1 bcf status,RP0 movlw b'01000001' movwf adcon0 ; 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' ; A0-A5 = AN1-6 tris porta movlw b'11111101' ; B7-B2 = input / B1 = TX / B0 = RX tris portb movlw b'10000000' ; C7 = RX C6 = TXmit C5-C2 = output / C1 = servo1 / C0 servo0 tris portc clrf portc movlw optionval option BANK1 movlw b'00100100' movwf txsta movlw .25 movwf spbrg bsf pie1,rcie ;interruption du port série BANK0 movlw b'10010000' movwf rcsta clrf buffer_in bsf flags,portvide bcf flags,f_sec_octet ; movlw b'11110000' ; (G|PEIE|T|I|Rb|T|I|Rb) movlw b'11100000' ; (G|PEIE|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 .0 movwf indf incf fsr,f incf eeadr,f I++ ENDW return ;------------------------------ ; interprétation de la commande ; 1er octet de controle: type ! voie ! D5-D0 ; type=1 => IO ; voie=1 => in ; voie=0 => out ; type=0 => servo ; voie=1 => servo1 ; voie=0 => servo0 analyse: movwf RcvReg movwf command movwf XmtReg ; on prépare l'écho de la commande ; type de trame btfss RcvReg,7 goto setServo ;-- Gestion des IO setIO ; btfss RcvReg,6 ; goto IOout ; return ;- IOout movf RcvReg,w movwf command rlf command,f rlf command,w movlw b'11111100' andwf command,f ; ---- MODE PROTEGE ON ---- bcf intcon,gie movf portc,w ; il faut bouger toutes les pattes du portc sans toucher aux servos andlw b'00000011' ; on efface les IO iorwf command,w ; on les met à jour avec la nouvelle valeur movwf portc bsf intcon,gie ; ---- MODE PROTEGE OFF ---- return ;-- Gestion des servos setServo ; n° de servo ; movwf eeadr ; on prépare l'écriture en eeprom movlw tabval movwf fsr ; on met à jour le pointeur de tableau btfsc command,6 ; on incrémente si c'est le servo 1 incf fsr,f rlf command,f rlf command,w ; 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<=1 waitnext ;exécute la macro bcf flags,ms2 movlw I addlw tabval movwf fsr ; ---- MODE PROTEGE ON ---- bcf intcon,gie movf indf,w btfss status,z bsf portc,I ; on lance le servo si sa position n'est pas nulle 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 ; Envoi d'un octet de synchro movlw '?' movwf XmtReg call txhard call waittx ; ENVOI DES DONNEES LOGIQUES ; envoi des entrées comparées envoi nop swapf portb,w ; DEBUG ; movlw '0' andlw b'11110000' ; les entrées numériques sont sur B0-B3 iorlw b'00000111' ; les entrées comparées sont la voie 7 movwf XmtReg call txhard ; tx version hard call waittx movf portb,w ; DEBUG ; movlw '0' andlw b'11110000' ; les entrées comparées sont sur B4-B7 ; xorlw b'11000000' ; petite inversion de cablage des comparateurs iorlw b'00000000' ; les entrées comparées sont la voie 0 movwf XmtReg call txhard ; tx version hard call waittx ; ENVOI DES DONNEES ANALOGIQUES I=0 WHILE I<=3 movlw b'11000111' andwf adcon0,f movlw (I*8) iorwf adcon0,f ; on choisit la voie I nop bsf adcon0,go wait_ad admesure ; DEBUG ; movlw '0' andlw b'11111000' ; les entrées numériques sont sur B0-B3 iorlw I ; les entrées comparées sont la voie I movwf XmtReg call txhard ; tx version hard call waittx I++ ENDW call wait20ms goto main ; *** envoi série txhard movf XmtReg,w movwf txreg return waittx call wait1ms return ;*** routine d'attente wait20ms load .20,counter loop20 call wait1ms decfsz counter,f goto loop20 return wait1ms clrf subcounter loop1 nop decfsz subcounter,f goto loop1 return END