;****************************************************************************** ; * ; Filename: elec.asm * ; Date: 25.11.06 * ; File Version: 1.0.0 * ; * ; Author: JP ROUBELAT * ; * ;****************************************************************************** ; NOTES: * ; * ; * ;****************************************************************************** ; CHANGE LOG: * ; * ; * ;****************************************************************************** list p=12F675 #include __CONFIG(_BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT) #define TMRCNT .120 ; 1 minute #define TMRMSB 0x0b ; Timer1 MSB for 0.5s #define TMRLSB 0xdd ; Timer1 LSB for 0.5s #define TMR_B0 .106+.3 ; 1200 uS #define TMR_B1 .181+.3 ; 600 uS #define TMR_BS .131+.3 ; 1000 uS #define ADD_A1 0x22 ; Address of the device A1 #define ADD_A2 0x24 ; Address of the device A2 #define ADD_A3 0x26 ; Address of the device A3 #define TYP_A 0x9 ; Type of the device (Intensity) #define TYP_V 0x8 ; Type of the device (Voltage) #define len d'11' ; data buffer length #define CALIB 3 ; port for Tx calibration #define TXD 5 ; port for Tx data #define DEBUG 1 #define TEST 1 ; flags of flagReg #define START 0 ; ask to start the frame #define SENDF 1 ; frame is sending #define STOPB 2 ; stop bit #define REPEAT 3 ; repeat frame #define SVFRAM 4 ; send voltage frame #define MVOLT 5 ; kind of measure voltage/intensity 1/0 #define ANZERO 6 ; analog measure is zero #define READY 7 ; ready to send measures ;****************************************************************************** ; VARIABLE DEFINITIONS * ;****************************************************************************** cblock 0x20 ;0x20-0x5c w_save ; variable used for context saving sts_save ; variable used for context saving fsr_save ; variable used for context saving sndPos ; byte to send sndMask ; bit to send preSend ; preamble delay msgType ; type of the message msgAddr ; address of the message msgChck ; checksum of the message cptmes ; counter of measures save_h ; save counter high 8 bits save_l ; save counter low 8 bits tmpreg ; temporary register storage tmpval ; temporary value storage rest_h ; rest of division h byte rest_l ; rest of division l byte val_h ; h byte value of 10 bits ADC val_l ; l byte value of 10 bits ADC bcd_h ; h byte of BCD result bcd_m ; m byte of BCD result bcd_l ; l byte of BCD result loopcount ; loop count for division cpt_h ; measure counter h 8 bits cpt_m ; measure counter m 8 bits cpt_l ; measure counter l 8 bits ; counters to send frames ready1 ; frame 1 must be sent ready2 ; frame 2 must be sent ready3 ; frame 3 must be sent readyV ; frame V must be sent ; channel 1 acq1_hh ; ch1 acquisition hh byte acq1_h ; ch1 acquisition h byte acq1_m ; ch1 acquisition m byte acq1_l ; ch1 acquisition l byte ; channel 2 acq2_hh ; ch1 acquisition hh byte acq2_h ; ch1 acquisition h byte acq2_m ; ch1 acquisition m byte acq2_l ; ch1 acquisition l byte ; channel 3 acq3_hh ; ch1 acquisition hh byte acq3_h ; ch1 acquisition h byte acq3_m ; ch1 acquisition m byte acq3_l ; ch1 acquisition l byte ; channel 4 - Voltage acq4_hh ; ch1 acquisition hh byte acq4_h ; ch1 acquisition h byte acq4_m ; ch1 acquisition m byte acq4_l ; ch1 acquisition l byte ; memorized voltage values cptv_h ; measure counter h 8 bits cptv_l ; measure counter l 8 bits bcdv_h ; h byte of BCD voltage bcdv_m ; m byte of BCD voltage bcdv_l ; l byte of BCD voltage buffer:len ; frame buffer flagReg ; flags register calPos ; input number calibration endc ;****************************************************************************** ; RESET VECTOR * ;****************************************************************************** org 0x0000 goto _start ;****************************************************************************** ; INTERRUPT VECTOR * ;****************************************************************************** org 0x0004 ; Save the state (see page 64 of PIC12F675 data) movwf w_save ; Save W register swapf STATUS,W ; Save STATUS (don't touch flags) bcf STATUS,RP0 ; Back to bank 0 movwf sts_save ; source of interrupt btfss PIR1,TMR1IF ; Timer1 interrupt ? goto _timer0_int ; Clear the timer interrupt, and reload counter bcf PIR1,TMR1IF ; Clear flag TMR1IF movlw TMRMSB ; Timer1 MSB movwf TMR1H movlw TMRLSB ; Timer1 LSB movwf TMR1L ; decrement ready1 flag movfw ready1 skpz decf ready1,f ; decrement ready2 flag movfw ready2 skpz decf ready2,f ; decrement ready3 flag movfw ready3 skpz decf ready3,f ; test for frame send btfss flagReg,START goto _timer0_int ; start a new double frame bcf flagReg,REPEAT ; validate first frame bsf flagReg,STOPB ; first is start bit bcf flagReg,START ; clear start flag bsf flagReg,SENDF ; sending frame _timer0_int btfss INTCON,T0IF ; Timer0 interrupt ? goto _exitInt ; This is a timer0 interrupt ; Clear the timer interrupt bcf INTCON,T0IF btfss flagReg,SENDF goto _exitInt movfw preSend ; pre-send delay ? bz _snd decf preSend,f goto _exitInt _snd ; save index movfw FSR movwf fsr_save ; save FSR btfss flagReg,STOPB goto _sndStop ; send start half bit (0=1200uS, 1=600uS) _sndStart bcf flagReg,STOPB ; next is stop bit movfw sndPos ; position of byte to send movwf FSR movfw sndMask ; bit to send andwf INDF,w movlw TMR_B1 ; send start bit=1 skpnz ; or movlw TMR_B0 ; send start bit=0 movwf TMR0 bsf GPIO,TXD goto _sndEnd ; send stop half bit _sndStop bsf flagReg,STOPB ; next is start bit movlw TMR_BS movwf TMR0 bcf GPIO,TXD ; send stop bit rrf sndMask,f ; shift right the mask bnc _sndEnd movlw 0x08 ; mask of 1st bit movwf sndMask incf sndPos,f movfw sndPos xorlw buffer+len bnz _sndEnd btfsc flagReg,REPEAT ; first frame ? goto _sndLast ; resent the frame (2nd time) bsf flagReg,STOPB ; next is start bit bsf flagReg,REPEAT ; 2nd frame movlw buffer ; beginning of buffer movwf sndPos movlw 0x08 ; mask of 1st bit movwf sndMask movlw .15 ; 30mS movwf preSend goto _sndEnd _sndLast bcf flagReg,SENDF ; end sending frame btfss flagReg,SVFRAM goto _sndVoltF goto _sndEnd _sndVoltF clrf readyV movlw .150 movwf preSend _sndEnd movfw fsr_save movwf FSR ; restore FSR ; All done, restore STATUS _exitInt swapf sts_save,w movwf STATUS swapf w_save,f swapf w_save,w retfie ;****************************************************************************** ; MAINLINE CODE * ;****************************************************************************** _start clrf GPIO ; Init GPIO movlw 0x07 ; Set GP<2:0> to movwf CMCON ; digital IO bsf STATUS,RP0 ; Bank 1 movlw 0x1f ; Set 2uS conversion frequency movwf ANSEL ; and set four analog inputs movlw 0x1f ; Set GP<4:0> as inputs movwf TRISIO ; and set GP<5> as output call 3FFh movwf OSCCAL ; calibrate oscillator movlw 0x82 ; timer0 and prescaler/8 on internal clock, movwf OPTION_REG ; and no pull-ups -> option register bcf STATUS,RP0 ; Bank 0 movlw 0x81 ; right justified movwf ADCON0 ; and ADC on ;==================================================================================== ; Arm timer 0 (prescaler/8) = 2.048 mS max ; clrf TMR0 bcf INTCON,T0IF ; Clear flag T0IF bsf INTCON,T0IE ; allow interrupts ;==================================================================================== ; Arm timer 1 ; for 0,5 second. Initialized to 0x0bdd ; clrf TMR1H clrf TMR1L bcf PIR1,TMR1IF ; Clear flag TMR1IF movlw TMRMSB ; Timer1 MSB movwf TMR1H movlw TMRLSB ; Timer1 LSB movwf TMR1L bsf INTCON,PEIE ; allow interrupts bsf INTCON,GIE ; allow interrupts bsf STATUS,RP0 ; Bank 1 bsf PIE1,TMR1IE bcf STATUS,RP0 ; Bank 0 movlw 0x31 ; Internal clock, prescaler/8 movwf T1CON movlw .1 movwf calPos ;==================================================================================== ; clean memory ; _restart clrf flagReg ; all flags false clrf preSend ; frames preamble delay movlw acq1_hh movwf FSR call _cleanx movlw acq2_hh movwf FSR call _cleanx movlw acq3_hh movwf FSR call _cleanx movlw acq4_hh movwf FSR call _cleanx call _cleanV ;==================================================================================== ; preload the 3 soft timers ; movlw TMRCNT-.80 movwf ready2 movlw TMRCNT-.40 movwf ready3 movlw TMRCNT movwf ready1 movwf readyV ;==================================================================================== ; Main loop ; _mainLoop ; select an0 (Intensity) bcf flagReg,MVOLT bcf ADCON0,CHS0 bcf ADCON0,CHS1 movlw acq1_hh movwf FSR call _getOnePeriod ; select an1 (Intensity) bcf flagReg,MVOLT bcf ADCON0,CHS0 bsf ADCON0,CHS1 movlw acq2_hh movwf FSR call _getOnePeriod ; select an2 (Intensity) bcf flagReg,MVOLT bsf ADCON0,CHS0 bcf ADCON0,CHS1 movlw acq3_hh movwf FSR call _getOnePeriod ; select an3 (Voltage) bsf flagReg,MVOLT bsf ADCON0,CHS0 bsf ADCON0,CHS1 movlw acq4_hh movwf FSR call _getOnePeriod _waitLoop0 movfw readyV bnz _waitLoop1 ; ask to send voltage frame incf readyV,f movfw bcdv_h movwf bcd_h movfw bcdv_m movwf bcd_m movfw bcdv_l movwf bcd_l movlw TYP_V movwf msgType bsf flagReg,SVFRAM ; the voltage frame call _sendFrame goto _mainLoop _waitLoop1 movfw ready1 bnz _waitLoop2 ; get voltage and save values call _div64 ; get number of voltage measures movlw acq4_hh movwf FSR call _div3216 call _hexToDec movfw bcd_h movwf bcdv_h movfw bcd_m movwf bcdv_m movfw bcd_l movwf bcdv_l call _cleanx call _cleanV bsf flagReg,READY ; ready ! ; get Int1 and send frame 1 movlw ADD_A1 movwf msgAddr movlw TYP_A movwf msgType movlw acq1_hh movwf FSR call _div3216 call _hexToDec call _cleanx bcf flagReg,SVFRAM ; not the voltage frame call _sendFrame _waitLoop1End movlw TMRCNT movwf ready1 goto _mainLoop _waitLoop2 movfw ready2 bnz _waitLoop3 btfss flagReg,READY ; ready ? goto _waitLoop2End ; get Int2 and send frame 2 movlw ADD_A2 movwf msgAddr movlw TYP_A movwf msgType movlw acq2_hh movwf FSR call _div3216 call _hexToDec call _cleanx bcf flagReg,SVFRAM ; not the voltage frame call _sendFrame _waitLoop2End movlw TMRCNT movwf ready2 goto _mainLoop _waitLoop3 movfw ready3 bnz _waitLoop4 btfss flagReg,READY ; ready ? goto _waitLoop3End ; get Int3 and send frame 3 movlw ADD_A3 movwf msgAddr movlw TYP_A movwf msgType movlw acq3_hh movwf FSR call _div3216 call _hexToDec call _cleanx bcf flagReg,SVFRAM ; not the voltage frame call _sendFrame _waitLoop3End movlw TMRCNT movwf ready3 _waitLoop4 btfsc GPIO,CALIB goto _mainLoop ;==================================================================================== ; Calibrate, send a frame each 5 seconds ; ; switch the kind of measure _cal_1 btfss calPos,0 goto _cal_2 bsf flagReg,MVOLT bcf ADCON0,CHS0 bcf ADCON0,CHS1 movlw ADD_A1 movwf msgAddr movlw TYP_A movwf msgType movlw acq1_hh movwf FSR goto _calStart _cal_2 btfss calPos,1 goto _cal_3 bsf flagReg,MVOLT bcf ADCON0,CHS0 bsf ADCON0,CHS1 movlw ADD_A2 movwf msgAddr movlw TYP_A movwf msgType movlw acq2_hh movwf FSR goto _calStart _cal_3 btfss calPos,2 goto _cal_4 bsf flagReg,MVOLT bsf ADCON0,CHS0 bcf ADCON0,CHS1 movlw ADD_A3 movwf msgAddr movlw TYP_A movwf msgType movlw acq3_hh movwf FSR goto _calStart _cal_4 btfss calPos,3 goto _calEnd bsf flagReg,MVOLT bsf ADCON0,CHS0 bsf ADCON0,CHS1 movlw ADD_A1 movwf msgAddr movlw TYP_V movwf msgType movlw acq4_hh movwf FSR goto _calStart _calibrate ; make a measure call _getOnePeriod movfw ready1 bnz _calibrate bsf flagReg,SVFRAM ; voltage frame call _div64 ; get number of voltage measures call _div3216 call _hexToDec call _cleanx call _cleanV call _sendFrame _calStart movlw .10 ; 5 seconds movwf ready1 btfss GPIO,CALIB goto _calibrate clrc btfsc calPos,3 setc rlf calPos,f _calEnd bcf flagReg,MVOLT goto _restart ;==================================================================================== ; Prepare buffer and ask to send the frame ; _sendFrame clrf msgChck movlw 0x0 ; 1st quartet header movwf buffer movlw 0xa ; 2nd quartet header movwf buffer+.1 addwf msgChck,f movfw msgType ; type of data movwf buffer+.2 addwf msgChck,f swapf msgAddr,w ; MSB address andlw 0xf movwf buffer+.3 addwf msgChck,f movfw msgAddr ; LSB address andlw 0xf movwf buffer+.4 addwf msgChck,f movfw bcd_h ; 1st digit andlw 0xf movwf buffer+.5 addwf msgChck,f swapf bcd_m,w ; 2nd digit andlw 0xf movwf buffer+.6 addwf msgChck,f movfw bcd_m ; 3rd digit andlw 0xf movwf buffer+.7 addwf msgChck,f swapf bcd_l,w ; 4th digit andlw 0xf movwf buffer+.8 addwf msgChck,f movfw bcd_l ; 5th digit andlw 0xf movwf buffer+.9 addwf msgChck,w ; last checksum in W andlw 0xf movwf buffer+.10 ; checksum ; Ask to send a frame movlw buffer ; beginning of buffer movwf sndPos movlw 0x08 ; mask of 1st bit movwf sndMask bsf flagReg,START ; ask to start the frame return ;==================================================================================== ; Read one Period ; _getOnePeriod ; if period is started, wait until end... _getAndWaitValEnd call _getAnValue bnz _getAndWaitValEnd ; wait end of low 1/2 period (all zero) clrf cptmes _getAndWaitValEnd0 call _getAnValue bnz _getAndWaitValEnd2 decfsz cptmes,f ; max 256 measures goto _getAndWaitValEnd0 ; value is not 0 1/2 period is beginning _getAndWaitValEnd1 call _getAnValue bz _getAndWaitValEnd3 _getAndWaitValEnd2 call _add1632 ; add the measure to the sum of the measures btfss flagReg,MVOLT goto _volt1 incf cpt_l,f ; increment the measures counter skpnz incf cpt_m,f skpnz incf cpt_h,f goto _getAndWaitValEnd1 _volt1 ; do not increment in intensity mode nop nop nop nop goto _getAndWaitValEnd1 ; be sure at least 20 contiguous measures are 0 _getAndWaitValEnd3 movlw .20 movwf loopcount _getAndWaitValEnd4 call _getAnValue bnz _getAndWaitValEnd2 decfsz loopcount goto _getAndWaitValEnd4 return ;==================================================================================== ; Get an analog value ; _getAnValue clrwdt ; watchdog ; start conversion bsf ADCON0,GO_DONE ; wait end of conversion _getAn0Wait btfsc ADCON0,GO_DONE goto _getAn0Wait bcf flagReg,ANZERO ; Value is 0 by default ; read LSB value bsf STATUS,RP0 ; Bank 1 movfw ADRESL bcf STATUS,RP0 ; Bank 0 movwf val_l skpz bsf flagReg,ANZERO ; Value is not 0 ; read MSB value movfw ADRESH movwf val_h skpz bsf flagReg,ANZERO ; Value is not 0 clrz btfss flagReg,ANZERO ; value is 0 ? setz return ;************************************************************************************ ; Mathematic routines ;************************************************************************************ ;==================================================================================== ; 16 bits addition, result in the 32 bits pointed by FSR ; _add1632 movfw FSR ; save FSR movwf tmpreg movlw .3 addwf FSR,f ; points to l ; movf val_l,w ; Get low byte addwf INDF,f ; Add to destination decf FSR,f ; points to m movf val_h,w ; move one of the high bytes into W btfsc STATUS,C ; if there is a carry from the low byte operation then... incfsz val_h,w ; increment the first high byte, skip next if zero since there is no need to add to 0 addwf INDF,f ; add the second high byte to W, store in W skpc ; if there is a carry from the medium byte operation then... goto _add1632End ; there is a carry, propagate to next byte decf FSR,f ; points to h incf INDF,f ; increment h byte skpz goto _add1632End ; result of the increment is zero, propagate to next byte decf FSR,f ; points to hh incf INDF,f ; increment hh byte _add1632End movfw tmpreg movwf FSR ; restore FSR return ;==================================================================================== ; _div64 copy and division of the counter by 64 ; _div64 movfw cpt_l movwf tmpval movfw cpt_m movwf cptv_l movfw cpt_h movwf cptv_h ; add 31 to round division movlw .31 addwf tmpval,f bnc _div64_1 incf cptv_l,f skpnz incf cptv_h,f _div64_1 rlf tmpval,f rlf cptv_l,f rlf cptv_h,f rlf tmpval,f rlf cptv_l,f rlf cptv_h,f return ;==================================================================================== ; 32 bits / 16 bits division (adapted from Zlatko Petkov) ; _div3216 movlw .3 addwf FSR,w ; restore FSR movwf tmpreg movwf FSR movfw cptv_h movwf save_h movfw cptv_l movwf save_l clrf rest_h clrf rest_l movlw .32 movwf loopcount _loopu3216 rlf INDF,w ;shift dividend left to move next bit to remainder decf FSR,f rlf INDF,f decf FSR,f rlf INDF,f decf FSR,f rlf INDF,f rlf rest_l,f ;shift carry (next dividend bit) into remainder rlf rest_h,f movfw tmpreg ; restore FSR movwf FSR rlf INDF,f ;finish shifting the dividend and save carry in aargb2.0, ;since remainder can be 17 bit long in some cases ;(e.g. 0x800000/0xffff). this bit will also serve ;as the next result bit. movf save_l,w ;substract divisor from 16-bit remainder subwf rest_l,f movf save_h,w btfss STATUS,C incfsz save_h,w subwf rest_h,f ;here we also need to take into account the 17th bit of remainder, which ;is in aargb2.0. if we don't have a borrow after subtracting from lower ;16 bits of remainder, then there is no borrow regardless of 17th bit ;value. but, if we have the borrow, then that will depend on 17th bit ;value. if it is 1, then no final borrow will occur. if it is 0, borrow ;will occur. these values match the borrow flag polarity. skpnc ;if no borrow after 16 bit subtraction bsf INDF,0 ;then there is no borrow in result. overwrite ;aargb2.0 with 1 to indicate no borrow. ;if borrow did occur, aargb2.0 already ;holds the final borrow value (0-borrow, 1-no borrow) btfsc INDF,0 ;if no borrow after 17-bit subtraction goto _uok46ll ;skip remainder restoration. addwf rest_h,f ;restore higher byte of remainder. (w ;contains the value subtracted from it ;previously) movf save_l,w ;restore lower byte of remainder addwf rest_l,f _uok46ll decfsz loopcount,f ;decrement counter goto _loopu3216 ;and repeat the loop if not zero. movlw .3 ; adjust FSR subwf FSR,f return ;==================================================================================== ; Binary to decimal conversion / 16 bits -> 5 digits ; _hexToDec movlw .3 addwf FSR,w ; save FSR movwf tmpreg movwf FSR bcf STATUS,0 ; clear the carry bit movlw .16 movwf loopcount clrf bcd_h clrf bcd_m clrf bcd_l _loop16 movfw tmpreg movwf FSR rlf INDF, F decf FSR,f rlf INDF, F rlf bcd_l, F rlf bcd_m, F rlf bcd_h, F decfsz loopcount, F goto _adjDEC movlw .2 ; adjust FSR subwf FSR,f return _adjDEC movlw bcd_l movwf FSR call _adjBCD movlw bcd_m movwf FSR call _adjBCD movlw bcd_h movwf FSR call _adjBCD goto _loop16 _adjBCD movlw 3 addwf 0,W movwf tmpval btfsc tmpval,3 ; test if result > 7 movwf 0 movlw 30 addwf 0,W movwf tmpval btfsc tmpval,7 ; test if result > 7 movwf 0 ; save as MSD return ;==================================================================================== ; Clean memory for acquisition ; _cleanx clrf INDF incf FSR,f clrf INDF incf FSR,f clrf INDF incf FSR,f clrf INDF movlw .3 subwf FSR,f ; restore FSR return ;==================================================================================== ; Clean voltage counter ; _cleanV clrf cpt_l clrf cpt_m clrf cpt_h return ;==================================================================================== ; End of program ; end