;************************************************************************** ; SC001_multichip.ASM ; ; PROGRAM: Solar Garden Light Logger based upon Simple Serial Project ; ; ; NOTE: Chips oscillator calibration is stored in this source and the HEX file. ; Adjust to suit your chip. ; ; DESCRIPTION: ; I brought a Garden Light logger, and found its performance disappointing. ; ; I wanted to know how long the battery was being charged, and how long the LED is on at BRIGHT, DIM and EXHUSTED. ; ; Also, how long is the battery above a threshold voltage when the SOLAR CELL is not charging? ; ; This project uses a PIC 16F676 to measure the three voltages of interest on the garden light. ; ; Instead of storing each voltage sample, it processes the voltages using logic and increments counters. ; ; The counters are MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH ; ; MMcntTimeH, Incremented every tick ; MMcntSolarCellH, Incremented every tick when the solar Cell is charging battery ; MMcntBrightH, Incremented every tick when the LED is bright ; MMcntDimH, Incremented every tick when the LED is DIM ; MMcntVbattH Incremented every tick when the battery is not being charged and is above a threshold voltage. ; ; The ticks are every 4 seconds. ; ; The onlytime when the counters are not being activily incremented is just before dawn at about 03:00 ; ; It uses TMR1 to provides a realtime clock and ticks at 15 seconds. Once a day it saves the counts and resets them. ; ; It uses the 128 byte EEPROM to store calibration parameters and the days counts for about 9 day's worth of samples. ; ; It is based on a simple serial project that receives serial commands from a tty program. ; ; This allows simple access to the logger while it is running, using a tty terminal program. ; ; ; ; Serial Commands:- ; ; ; w,p,r,g,f,a ; ; Logger instructions ; ; On reset, Counts are reset, and after 4 seconds the chip will auto sample at rate set in eeprom[14] ; ; m; Display Vsolar,Vbatt,VtopLED,count,SolarCont,brightCount,DimmCount,Vbatt&NoChrgeCnt ; M; ResetCounts ; s; Start ticks ; S; Stop ticks ; d; dump Conts stored in EEPROM ; ; gaa; get EEPROM values ; paadd; put EEPROM values ; ; raa; read FILE or RAM values ; waadd; write FILE or RAM values ; ; The voltages are measured relative to Vref. Vref is connected to the top of a BLUE LED, which provides 3.25 volts ; This is only turned on to make the measurements, one every 4 seconds. ; ; tnn; toggle pin that turns on the BLUE LED that acts as a reference, ; 1nn; sets pin that turns on the BLUE LED that acts as a reference, turns off LED ; 0nn; resets pin that turns on the BLUE LED that acts as a reference, turns on LED ; ; ; NOTE: when repeat sampling the output is: ,count,SolarCont,brightCount,DimmCountVsolar,Vbatt,VtopLED,* ; ; AN1 is VREF, so the A to D can be made more sensitive and more stable when measuring V6,V5,V4. ; AN6 V6 = Vsolar, ; AN5 V5 = Vbattery - AN1 is VREF, so the A to D can be made more sensitive when measuring V4. ; AN4 V4 = VtopOfLED ; ; the EEPROM can be used to store config data, use pAADD; and gAA; ; the ee[n] values need to be < 0 ; ; g00; Get V6-V5+ee[g00] - If >0 then inc Solar Count ; g01; Get V5-v4-ee[g01] - If >0 then inc Dim Count ; g02; Get V5-v4-ee[g01]-ee[g02] - If >0 then inc Bright Count ; g03; Get V6-0xFF*ee[g03]-ee[g04] - If >0 then inc Vbattery ; g04; Get V6-0xFF*ee[g03]-ee[g04] - If >0 then inc Vbattery ; ; I started with left justified values, but ended up with right justified 16 bit subtracts. ; ; Measured Voltages: ; Vdd = 3.82 ; Vbatt = 0.94 ; Vref = 3.25 - using a BLUE LED ; ; Measured values of Solar Cell batter voltage for Dim ; 0 volts ; Off ; 1.74volts ; Vbattery - dim ; 2.2volts ; Vbattery - Bright ; ; ; Uses TMR1 and MMloopCount: ; ; TMR1 overflows Fosc/4, 1e6/2^16m = 1/15.2587890625 ; ; My Serial LCD display needs an inter Character delay to process the last character. ; You can configure an inter character deleay here. ; ; g05; Get delay between characters in bits to allow a serial LCD to be used. ; ; Here we use the EEPROM to store the counters. ; g07; Pointer to Samples ; g08 to g7F; Samples - there are 103 bytes, there are 5 counts so 10 sets can be stored. ; ; ; Special Instructions. ; tDD; Toggle for DD ms ; 1DD; Set 1 for DD ms wait for DD and then set to 1 ; 0DD; Set 0 for DD ms wait for DD and reset ; ; aDD; read AtoD converter and output in hex, DD is ADCON0 ; ; File Registers ; wAADD; write DD to register AA ; rAA; read AA and output to serial port ; ; File reg 25,26,27 stores the time to the next save of the EEPROM counts. ; R25; hours to next store ; R26; minutes to next store ; R27; seconds to next store ; ; This is needed as you want to save the counts when they are not being incremented, ; which is just before dawn. ; ; If you reset the PIC at 18:00, the chip will save at about 03:00 ; ; EEPROM ; pAADD; write DD to EEPROM register AA ; gAA; read EEPROM register AA and output to serial port ; ; PRIPHERALS ; ; SERIAL PORT CONTROL: ; ; PORT RA0 is Serial input ; PORT RA0 is serial output ; ; usb gmus-03 USB Serial Adapter ; ; TX D9 Pin 3 -[4k7]----+-----PA0 ; RX D9 Pin 2 ----------/ ; ; GND D9 Pin 5 ---------------- 0V ; ; 29/09/2008 discovered that using PA0 affects AtoD Reading. ; ; TX D9 Pin 3 -[4k7]----+-----PC5 ; RX D9 Pin 2 ----------/ ; ; GND D9 Pin 5 ---------------- 0V ; ; ; Crystal: 4MHz - Uses Internal RC oscillator ; ; I/O used:- ; ; ; Port B is used for the LCD ; ; OPERATION: ; The TMR1 ticks overflow and trigger the AtoD process periodically. ; The three volatages are measured, and then compared using logic. ; The appropriate counters are incremented. ; ; Every sample the current counts are output on the serial port. ; ; It is possible to use the serail port to update the EEPROM and start and stop the sampling. ; ; ; MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH ; ; Samples from logger - Vref is relative to Vdd, others are relative to Vref ;CNT ,SolC,Bright,Dim,Vbatt,,/,INTCON,T1,,t,HHMM,SS ,,,Vsc,Vba,Vled,Vref ; ;MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH,/t,hhmmss,Vsolar,Vbattery,VtopOfLED,Vref,//s,Vsolar-Vbatt,Vbatt-Vled ;007B,007B,0000,0000,0000,/t,08380D,0360,02B0,02B2,0345,//s,00B0,l,FFFE,,* ;007C,007C,0000,0000,0000,/t,08380C,0360,02B3,02B0,0345,//s,00AD,l,0003,,* ; ; ; MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH ; Every day the counts are stored and backed up, in the order: ; MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH ; ; Use the d; command to dump the EEPROM counts. ;d;* ;19,* ;19,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;23,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;2D,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;37,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;41,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;4B,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;55,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;5F,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;69,,FFFF,FFFF,FFFF,FFFF,FFFF,* ;73,,FFFF,,** ; ; ; Future Enhancements: ; ; ; AUTHOR: Douglas Rice ; Copyright 2006 ; ;************************************************************************** ;-------------------------------------------------------------------------- ; Sec 0. #Defines tofor different chips ;-------------------------------------------------------------------------- ; uncomment only one of these ; #define pic16F676 1 ;#define pic12F675 1 LIST w=1, R=DEC ;-------------------------------------------------------------------------- ; Sec 0.1 #Defines for 16F676 ;-------------------------------------------------------------------------- ifdef pic16F676 #define wantAtoD LIST P=16F676, R=DEC INCLUDE "p16F676.inc" __idlocs 0x0676 ;__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_CLKOUT _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & 0x31FF __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & 0x31FF cblock 0x20 endc ; *********** I/O EQUATES ************** PA0 EQU 0 ; Serial Out and Serial In - moved. This affects AtoD result. PA1 EQU 1 ; Output PA2 EQU 2 ; Output PA7 EQU 7 ; Output PC5 EQU 5 ; Serial Out and Serial In ;PORT_RS232 EQU PORTA ;TRIS_RS232 EQU TRISA ;RS232tx EQU PA0 ; Serial Out ;RS232rx EQU PA0 ; Serial In needs to be equal to BUTTON_RS232 PORT_RS232 EQU PORTC TRIS_RS232 EQU TRISC RS232tx EQU PC5 ; Serial Out RS232rx EQU PC5 ; Serial In needs to be equal to BUTTON_RS232 OUTPUTPIN EQU 3 ; endif ;-------------------------------------------------------------------------- ; Sec 0.2 #Defines for 16F876 ;-------------------------------------------------------------------------- ifdef pic16F876 #define buildPWM 1 LIST P=16F876, R=DEC INCLUDE "p16F876.inc" __idlocs 0x0876 __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_ON & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF cblock 0x20 endc ; *********** I/O EQUATES ************** PORT_RS232 EQU PORTA TRIS_RS232 EQU TRISA RS232tx EQU 0 ; Serial Out RS232rx EQU 0 ; Serial In needs to be equal to BUTTON_RS232 endif ;-------------------------------------------------------------------------- ; Sec 0.3 #Defines for 12F675 ;-------------------------------------------------------------------------- ifdef pic12F675 #define wantAtoD LIST P=12F675, R=DEC INCLUDE "p12F675.inc" __idlocs 0x0675 __config _PWRTE_ON & _WDT_OFF & _BODEN_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF cblock 0x20 endc ; *********** I/O EQUATES ************** PORT_RS232 EQU GPIO TRIS_RS232 EQU TRISIO RS232tx EQU 5 ; Serial Out RS232rx EQU 5 ; Serial In needs to be equal to BUTTON_RS232 OUTPUTPIN EQU 3 PORTA EQU GPIO PORTB EQU GPIO TRISA EQU TRISIO TRISB EQU TRISIO endif ;-------------------------------------------------------------------------- ; Sec 1. Equates and Constants ;-------------------------------------------------------------------------- ; The General Purpose Registers start at the end of the ; Special Purpose Registers. ; IPMentState values ; in normal running or in time setting modes ; ; DoTimeSlice bits ; these bits are set to schedule a timer chain event DTsS4event EQU 0 ; RUN_BUFF EQU 0 ; ; IPtrigMenu DTSFast EQU 0 ;-------------------------------------------------------------------------- ; Sec 1.1 Button and LED ;-------------------------------------------------------------------------- BUTTON_RS232 EQU RS232rx ; EDG - Bottom Buttom BUTTON_DOWN EQU 3 ; EDG - STore Counts Button. ;-------------------------------------------------------------------------- ; Sec 1.2 EEPROM LOCATIONS ;-------------------------------------------------------------------------- ; g00; Get V6-V5-ee[g00] - If >0 then inc Solar Count ; g01; Get V5-v4-ee[g01] - If >0 then inc Dim Count ; g02; Get V5-v4-ee[g01]-ee[g02] - If >0 then inc Bright Count ; g03; Get V6- ee[g03],ee[g04]- If >0 then inc Vbattery ; ; g00,g01,g02,are too insensitive, and the values have to be -2,-2,-1 ; g03 = 0x78 EEsolarOffset EQU 0x00 EEdimOffset EQU 0x01 EEbrightOffset EQU 0x02 EEbatteryOffsetH EQU 0x03 EEbatteryOffsetL EQU 0x04 EEinterCharDelay EQU 0x05 EEAtoDappatureDelay EQU 0x06 ; EQU 0x06 ; EQU 0x07 EEinterCharDelay EQU 0x05 EEFILESTART EQU 0x08 EEFILEPTR EQU EEFILESTART-1 ;-------------------------------------------------------------------------- ; Sec 2.0 Variables ;-------------------------------------------------------------------------- ; Variables start 0x0C ; ; DoTimeSlice Bits, to schedule, set bit cblock ; ; AD AtoD routine Variables. ; ADrl ADansel BTdelay BTdelayCnt BTdelayCnt1ms CLhh CLmm CLss DoTimeSlice IPnew IPlast IPbuttonEvent IPnewFast IPlastFast IPbuttonEventUp IPtrigMenu ; ; MM Solar Cell Measurement Code. ; MMtmph MMtmp ; Using Vref as Max MMV6h MMV6l MMV5h MMV5l MMV4h MMV4l ; Using Vdd as Max MMV1h MMV1l ; count, time, solarCell, bright, dim , MMcntTimeH MMcntTimeL MMcntSolarCellH MMcntSolarCellL MMcntBrightH MMcntBrightL MMcntDimH MMcntDimL MMcntVbattH MMcntVbattL ; ;MMloopCount EEptrEEPROM ; pointer to EEPROM EEptrMEM ; pointer to Memory - count, time, solarCell, bright, dim EEloopCount EEloopCount2 ; variables used by Serial input and output routines RStxTemp RStxTemp2 RSloopCnt RSdelayCnt RSin RSout RSinterCharDelay RSafterCRCharDelay ; Serial input buffer RSipBuffCnt ; input buffer counter ; start of buffer RScmd RSAa ; RSaA ; RSDd ; RSdD ; RSterminator ; end of buffer ; temporary variables RSaddr RSdata ; ENDC ;-------------------------------------------------------------------------- ; Sec 3. MACROS ;-------------------------------------------------------------------------- TEST_STRADDLE MACRO START if high( $ ) != high( START ) Error "Table straddles Page Boundary " + Start endif endm ;-------------------------------------------------------------------------- ; Sec 4. Program Code ;-------------------------------------------------------------------------- ORG 0 GOTO Start ORG 4 RETFIE GOTO Intrtn ;-------------------------------------------------------------------------- ; Sec 4.1 Main Program Init Code ;-------------------------------------------------------------------------- Start ;MOVLW 0x6C ; load the Calib movlw 0x98 ;CALL OscCalValue banksel OSCCAL MOVWF OSCCAL ; Debug jumps: ; CALL MMtsSample1false ; CALL MMtsSampleProcess BANKSEL TRISA MOVLW 1 << 4 | 1 << 5 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0 MOVWF TRISA ;BANKSEL TRISC MOVLW 1 << 4 | 1 << 5 | 1 << 2 | 1 << 1 | 1 << 0 MOVWF TRISC ; There is currently a conflict as serial is on RA0 banksel ANSEL MOVLW 1 << ANS5 | 1 << ANS4 | 0 << ANS2 | 1 << ANS1 | 0 << ANS0 movwf ANSEL ; Turn off the comparator. MOVLW 1 << CM2 | 1 << CM1 | 1 << CM0 banksel CMCON MOVWF CMCON CALL MMts MOVLW 1 << ANS5 | 1 << ANS4 | 1 << ANS1 movwf ADansel CALL ADconvert CALL INinit CALL INsayHello ; set up for manual start, get repeat time in g14 ; reset logger and delay first time for 8 seconds ; to allow user to type S; on reset. CALL MMinit ; init CALL MMinitTime CALL EEfileDump GOTO MainLoop ;-------------------------------------------------------------------------- ; Sec 4.2 Main Program ;-------------------------------------------------------------------------- MainLoop BANKSEL DoTimeSlice CALL IPtimesliceFast ; test for rising edge BTFSC IPbuttonEventUp,BUTTON_RS232 ; RS232 input start CALL IPrs232 BTFSC PIR1,TMR1IF CALL MMts MOVF DoTimeSlice,w Bz MainLoop BTFSC DoTimeSlice,RUN_BUFF CALL DLrunBuff GOTO MainLoop ;-------------------------------------------------------------------------- ; Sec 5. Subroutines, procedures and functions ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; Sec 5.1 Button Poll Routine ;-------------------------------------------------------------------------- IPtimeslice ; --_____ button press ; ----___ ; __----- /IPnew ; ----___ IPlast ; __--___ ; ; ; ; This reads all Port A inputs and looks for Press MOVFW IPnew MOVWF IPlast MOVFW PORTA MOVWF IPnew ; IP last contains new setting, IPlast contains previous ; look for falling edges COMF IPnew,W ANDWF IPlast,W ; now force IPbuttonEvent bits to high for new pressed button ; the service routine should reset the bit to clear the event. IORWF IPbuttonEvent,F RETURN IPtimesliceFast ; Look for rising edges MOVFW IPnewFast MOVWF IPlastFast MOVFW PORT_RS232 MOVWF IPnewFast COMF IPlastFast,W ANDWF IPnewFast,W IORWF IPbuttonEventUp,F RETURN ;-------------------------------------------------------------------------- ; Sec 5.2 ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; Sec 5.2 .1 run process on request ;-------------------------------------------------------------------------- DLrunBuff BANKSEL DoTimeSlice BCF DoTimeSlice,RUN_BUFF MOVFW RSin GOTO RSbuffInput ;return ;-------------------------------------------------------------------------- ; Sec 5.3 Button Input functions ;-------------------------------------------------------------------------- IPdownPressed BCF IPbuttonEvent,BUTTON_DOWN GOTO EEfileCounts IPrs232 BCF IPbuttonEventUp,BUTTON_RS232 GOTO RSrs232in ;-------------------------------------------------------------------------- ; Sec 5.4 Clock Chain Routine ;-------------------------------------------------------------------------- CLtimeslice ; BTFSS INTCON,T0IF RETURN ; TMR0 timeout BCF INTCON,T0IF BSF DoTimeSlice,DTsS4event CALL IPtimeslice RETURN ;-------------------------------------------------------------------------- ; Sec 5.5 Serial Input Routine ;-------------------------------------------------------------------------- RSjumpTable ; Its not a CLICK or HOLD MOVLW high ( $ ) MOVWF PCLATH ; Assume that the tabel is in the bottom 256 byte ; restrict to 32 states ;ANDLW 0x03 MOVFW RSloopCnt ADDWF PCL,f ; set choice State Table - limited to 8 states RETLW 'w' GOTO RSbuffInput2start RETLW 'p' GOTO RSbuffInput3start RETLW 'r' GOTO RSbuffInput4start RETLW 'g' GOTO RSbuffInput5start ; RETLW 'f' ; GOTO RSbuffInput6start RETLW 't' GOTO RSbuffInput7start RETLW '1' GOTO RSbuffInput8start RETLW '0' GOTO RSbuffInput9start RETLW 'a' GOTO RSbuffInput10start RETLW 'M' GOTO RSbuffInput11start RETLW 'm' GOTO RSbuffInput12start RETLW 's' GOTO RSbuffInput13start RETLW 'S' GOTO RSbuffInput14start RETLW 'd' GOTO RSbuffInput15start RETLW 0 TEST_STRADDLE RSjumpTable ;************************************************** RSrs232in ; Test is in main loop or uncomment code below to ; spin for a start bit ; CLRWDT ; BTFSS PORT_RS232,RS232rx ; GOTO RSrs232in ; CALL RSdelayBit ; delay through Stop Bit CALL RSdelayHalfBit ; delay halfway into first bit movlw 8 movwf RSloopCnt RSrs232inL0 CALL RSdelayBit ; delay halfway into first bit MOVFW PORT_RS232 ANDLW 1<< RS232rx ; mask off bit ADDLW -1<< RS232rx ; use ripple carry to move into C RRF RSin,F ; CALL RSdelayBit DECFSZ RSloopCnt,f goto RSrs232inL0 ; do not test for Stop bit COMF RSin,f BSF DoTimeSlice,RUN_BUFF RETURN ;-------------------------------------------------------------------------- ; Sec 5.6 Serial Output Routines ;-------------------------------------------------------------------------- RSwrtWasHex ; ; Write W reg as HEX to RS232 ; MOVWF RStxTemp2 SWAPF RStxTemp2,W CALL RSwrtHexNibble MOVFW RStxTemp2 GOTO RSwrtHexNibble RSwrtHexNibble ; currently only displays 0..9, A..F ANDLW 0x0F ADDLW 0x06 ; is it A..F, if so trigger a digit overflow SKPNDC ADDLW 7; subtract 10, then add 'A'-'0' ADDLW 0x30-6 ; Subtract extra 6 added to cause DC MOVWF RSout GOTO RStxChar RS232sendCR MOVLW 0x0D GOTO RS232sendWByte RS232sendLF MOVLW 0x0A GOTO RS232sendWByte RS232sendSpace MOVLW ' ' GOTO RS232sendWByte RS232sendComma MOVLW ',' GOTO RS232sendWByte RS232sendStar MOVLW '*' GOTO RS232sendWByte RS232sendWByte RStxChar ; ; Output Start Bit ; Start bit is low, data bits are inverted ; movwf RStxTemp comf RStxTemp,f BCF PORT_RS232,RS232tx ; Make RS232 pin an ouput while transmitting character BANKSEL TRIS_RS232 BCF TRIS_RS232,RS232tx BANKSEL PORT_RS232 ; 1200 baud output ; move the char into RStxtemp, it is destroyed. ;Start Bit BSF PORT_RS232,RS232tx call RSdelayBit movlw 8 movwf RSloopCnt RStxCharLp1 ; After start bit, which is 1, then test each bit ; I need to set PA:0 to same as LSB RStxTemp ; this compares PA:0 with RStxTemp so see if it needs toggling ; The xorwf PORT_RS232,f causes the bit to be toggled if required. RRF RStxTemp,f movfw STATUS andlw 1 << C ; mask off bit addlw ( 1 << RS232tx) -1 ; shift bit by using a ripple carry xorwf PORT_RS232,W ; Doeas output need toggling ? andlw 1 << RS232tx ; Mask off output pin xorwf PORT_RS232,f ; Toggle output pin if needed call RSdelayBit ; delay bit decfsz RSloopCnt,f goto RStxCharLp1 BCF PORT_RS232,RS232tx call RSdelayBit ; apply stop bit ; apply an inter character delay of 4 bits ; call RSdelayBit ; get inter character delay from the EEPROM ; you have to read from RAM, and not EEPROM as pXXXX; does not work as EEwrt needs delay before EEread MOVFW RSinterCharDelay RStxCharInterDelay movwf RSloopCnt RStxCharLp2 call RSdelayBit decfsz RSloopCnt,f goto RStxCharLp2 ; Make RS232 pin an input so that main loop can test for start bit BANKSEL TRIS_RS232 BSF TRIS_RS232,RS232tx BANKSEL PORT_RS232 RETURN ; timing functions to delay serial routines for a bit or half bit. RSdelayHalfBit MOVLW 0x1D ; shorten delay as edge detector takes about 22 us for 4800 baud GOTO RSdelayBit0 RSdelayBit NOP MOVLW 0x40 ; for 4800 baud RSdelayBit0 MOVWF RSdelayCnt RSdelayBit1 DECFSZ RSdelayCnt,f ; 1 GOTO RSdelayBit1 ; 2 clk CLRWDT RETURN ;-------------------------------------------------------------------------- ; Sec 5.7 Serial Output Format Routines ;-------------------------------------------------------------------------- RSasciiToNibble MOVWF RSin ; if 0..1 then 0x30 to 0x39 ; if A..F then 0x41 to 0x46 ; if a..f then 0x61 to 0x66 ; test if bit 4 set and assume a letter or number BTFSS RSin,4 ADDLW 0x09 ; letter so add 9 ANDLW 0x0F ; mask of nibble return ;-------------------------------------------------------------------------- ; Sec 5.8 Serial Input Buffer Routine ;-------------------------------------------------------------------------- ; take serial input CAADD and put into buffer ; if char id ; the do command ; if char is CR reset buffer pointer ; if buff end then reset buff pointer RSipbuffStart EQU RScmd RSipbuffEnd EQU RSterminator RSbuffInput MOVWF RSin ; look for line feed and reset buff cnt ADDLW -0x0D BNZ RSbuffInput1 RSbuffInput1start MOVLW RSipbuffStart MOVWF RSipBuffCnt RETURN RSbuffInput1 ; end of line command - do command ADDLW -';'+0x0D BNZ RSbuffInput2 GOTO RSbuffInputProcess RSbuffInput2 ; Store the current time into the next register. MOVFW RSipBuffCnt MOVWF FSR MOVFW RSin MOVWF INDF INCFSZ RSipBuffCnt,f MOVFW RSipBuffCnt ADDLW -(RSipbuffEnd+1) ; Check if the end of memory SKPZ GOTO RSbuffInputEnd1 MOVLW RSipbuffStart MOVWF RSipBuffCnt ; reset cursor CALL RS232sendCR RETURN RSbuffInputProcess MOVLW RSipbuffStart MOVWF RSipBuffCnt MOVFW RSAa ; if 0..1 then 0x30 to 0x39 ; if A..F then 0x41 to 0x46 ; if a..f then 0x61 to 0x66 ; test if bit 4 set and assume a letter or number BTFSS RSAa,4 ADDLW 0x09 ; letter so add 9 ANDLW 0x0F ; mask of nibble MOVWF RSin SWAPF RSin,F MOVFW RSaA BTFSS RSaA,4 ADDLW 0x09 ; letter so add 9 ANDLW 0x0F ; mask of nibble ADDWF RSin,w MOVWF RSaddr MOVFW RSDd BTFSS RSDd,4 ADDLW 0x09 ; letter so add 9 ANDLW 0x0F ; mask of nibble MOVWF RSin SWAPF RSin,F MOVFW RSdD BTFSS RSdD,4 ADDLW 0x09 ; letter so add 9 ANDLW 0x0F ; mask of nibble ADDWF RSin,w MOVWF RSdata ; CALL RStxChar ; got to end of buffer so process. does not allow for backspace MOVFW RScmd CALL RSfindAndRunCommand ; ; Write to file register ; MOVLW -'w' ; ADDWF RScmd,w ; test to see if command is s, if so save into register. ; bnz RSbuffInput3 RSbuffInput2start ; Write to file register MOVFW RSaddr MOVWF FSR MOVFW RSdata MOVWF INDF GOTO RSbuffInputEndOK RSbuffInput3start ; put octet in EEPROM BANKSEL RSaddr MOVFW RSaddr CALL EEsetAddr BANKSEL RSdata MOVFW RSdata CALL EEwrt GOTO RSbuffInputEndOK RSbuffInput4start ; read from file register MOVFW RSaddr MOVWF FSR MOVFW INDF MOVWF RSin RSbuffInput4display MOVLW '=' CALL RStxChar SWAPF RSin,w CALL RSwrtHexNibble MOVFW RSin CALL RSwrtHexNibble GOTO RSbuffInputEnd RSbuffInput5start ; get from EEPROM register MOVFW RSaddr CALL EEread MOVWF RSin GOTO RSbuffInput4display RSbuffInput7start ; Toggle A0 for AA ms CALL BTtoggle GOTO RSbuffInputEndOK RSbuffInput8start ; Set A0 CALL BTdelaySet GOTO RSbuffInputEndOK RSbuffInput9start ; Reset A0 CALL BTdelayReset GOTO RSbuffInputEndOK RSbuffInput10start CALL ADconvert GOTO RSbuffInputEnd RSbuffInput11start CALL MMinit GOTO RSbuffInputEndOK RSbuffInput12start MOVLW EEinterCharDelay ;0x15 CALL EEread MOVWF RSinterCharDelay CALL MMtsSample MOVLW ',' CALL RStxChar CALL MMdisplay GOTO RSbuffInputEndOK RSbuffInput13start CALL MMstartTicks GOTO RSbuffInputEndOK RSbuffInput14start ; STOP measure Solar Cells CALL MMstopTicks GOTO RSbuffInputEndOK ;RSbuffInput15 ; ; dump EEPROM ; MOVLW -'d' ; ADDWF RScmd,w ; bnz RSbuffInput16 RSbuffInput15start ; dump EEPROM CALL EEfileDump GOTO RSbuffInputEndOK RSbuffInput16 RSbuffInputEndNOK MOVLW '?' CALL RStxChar GOTO RSbuffInputEnd RSbuffInputEndOK MOVLW '*' CALL RStxChar RSbuffInputEnd CALL RS232sendCR CALL RS232sendLF RSbuffInputEnd1 return ;-------------------------------------------------------------------------- ; Sec 5.9 Lookup command letter by doing a linear search ;-------------------------------------------------------------------------- RSfindAndRunCommand ; look up command MOVWF RSin CLRF RSloopCnt RSfindCmd1 CALL RSjumpTable ; Increment pointer onto the command. INCF RSloopCnt,f ; test if command char has ben found in the list. XORWF RSin,w BZ RSfindCmdFound XORWF RSin,w BZ RSfindCmdEnd ; point onto next command INCF RSloopCnt,f GOTO RSfindCmd1 RSfindCmdFound GOTO RSjumpTable RSfindCmdEnd GOTO RSbuffInputEndNOK ;-------------------------------------------------------------------------- ; Sec 5.10 Initilization code - ;-------------------------------------------------------------------------- INinit ; Enable Interupts MOVLW H'00' ; BANKSEL INTCON is available in both banks. MOVWF INTCON CLRF PORT_RS232 ;Initialize PORT_RS232 by setting ;output data latches ifdef wantAtoD ; get the Oscillator calibration ;MOVLW 0x6C ; load the Calib ; BSF STATUS,RP0 ; CALL OscCalValue ; MOVWF OSCCAL BANKSEL CMCON MOVLW 0X07 ;Turn comparators off and MOVWF CMCON ;enable pins for I/O ; BANKSEL ANSEL ; CLRF ANSEL endif ifdef pic16F628 BANKSEL CMCON MOVLW 0X07 ;Turn comparators off and MOVWF CMCON ;enable pins for I/O endif ifdef pic16F876 ;make AtoD inputs digital BANKSEL ADCON1 MOVLW 0X07 ;Turn comparators off and MOVWF ADCON1 ;enable pins for I/O endif ifndef pic16F676 banksel TRISB MOVLW 0XF0 MOVWF TRISB endif banksel TRIS_RS232 BSF TRIS_RS232, RS232tx ; Make PORT_RS232 3:0 INPUTS. BCF TRIS_RS232, OUTPUTPIN banksel RSipbuffStart ; reset input buffer MOVLW RSipbuffStart MOVWF RSipBuffCnt ; Change Prescaler CLRWDT ; Configure Tmr 0 BSF STATUS,RP0 ; Set up prescaller for 8192 / 16 = 512 ticks perseconds. MOVLW 0x0 + 2 ; For Tmr0 0=/2, 1=/4, 2=/8,3=/16 MOVWF OPTION_REG BCF STATUS,RP0 ifdef buildPWM ; Configure Tmr 1 MOVLW 0x0 | 1<|---+------- Vbattery ; | | ; | +-[==]-- VLEDresitor ; | ; +---------------- 0 Volts ; ; V4 SolarCell ; V5 Vbattery ; V6 VLEDresistor ; ; if V5 > V2+Vdiode then charging ; if (V2-V3) = Vres ; ; if Vres > k1 then Bright ; if Vres < k2 then Off ; Else Dim ; MMinit CLRF MMcntTimeH CLRF MMcntTimeL CLRF MMcntSolarCellH CLRF MMcntSolarCellL CLRF MMcntBrightH CLRF MMcntBrightL CLRF MMcntDimH CLRF MMcntDimL CLRF MMcntVbattH CLRF MMcntVbattL return MMinitTime ; ; time in binary to time when samples are stored in EEPROM ; ; If you want to logger to sample at 03:00 and it is 18:00 ; you want the time to be ; 24:00 ; + 03:00 ; - 18:00 ; ===== ; 09:00 9 hours time ; ; banksel CLhh ; MOVLW .24 ; MOVWF CLhh ; MOVLW .60 ; MOVWF CLmm ; MOVLW .15 ; MOVWF CLss banksel CLhh MOVLW .09+1 ; MOVLW .00+1 MOVWF CLhh MOVLW .00+1 MOVWF CLmm MOVLW .00+1 MOVWF CLss ; CLss is in seconds / seconds between TMR1 timeout return MMstartTicks ;Clear and init TMR1, this will be used as a time base. banksel T1CON CLRF T1CON CLRF TMR1H CLRF TMR1L ; ; Start TMR1 to use the external oscillator. ; This should be a 32K768 Hz crystal, so the overflow is every 2 seconds. ; MOVLW 1 << T1OSCEN | 1 << T1CKPS0 | 1 << NOT_T1SYNC | 1 << TMR1CS | 1 << TMR1ON MOVWF T1CON return MMstopTicks ;Clear and init TMR1, this will be used as a time base. banksel T1CON MOVLW 0 << T1OSCEN | 1 << T1CKPS0 | 1 << NOT_T1SYNC | 1 << TMR1CS | 0 << TMR1ON MOVWF T1CON return MMts BANKSEL PIR1 BCF PIR1,TMR1IF BCF PORTC,3 ; tick every 4 seconds ; and reset chain for 24 hours timeout ; DECFSZ CLss,F GOTO MMts1 MOVLW .15 MOVWF CLss DECFSZ CLmm,F GOTO MMts1 MOVLW .60 MOVWF CLmm DECFSZ CLhh,F GOTO MMts1 MOVLW .24 MOVWF CLhh ; buffer counts once a day. CALL EEfileCounts CALL MMinit MMts1 MOVLW EEinterCharDelay ;0x15 CALL EEread MOVWF RSinterCharDelay CALL RS232sendLF CALL RS232sendCR CALL MMdisplay ; ouput the counts first, then the voltages ; so that the 24Char display shows the counts CALL MMtsSample MOVLW ',' CALL RStxChar MOVLW '*' CALL RStxChar BSF PORTC,3 RETURN ; run into MMtsSample MMtsSample ; tick once a second CALL MMincCntTime ; Measure VsolarCell MOVLW 6 movwf RSaddr CALL ADconvert banksel ADRESH movfw ADRESH movwf MMV6h banksel ADRESL movfw ADRESL movwf MMV6l MOVLW MMV6h CALL MMdisplayIndirect ; Measure Vbattery MOVLW 5 movwf RSaddr CALL ADconvert banksel ADRESH movfw ADRESH movwf MMV5h banksel ADRESL movfw ADRESL movwf MMV5l MOVLW MMV5h CALL MMdisplayIndirect ; Measure VtopOfLED MOVLW 4 movwf RSaddr CALL ADconvert banksel ADRESH movfw ADRESH movwf MMV4h banksel ADRESL movfw ADRESL movwf MMV4l MOVLW MMV4h CALL MMdisplayIndirect ; Measure Vref but relative to Vdd MOVLW 1 movwf RSaddr CALL ADconvertVdd banksel ADRESH movfw ADRESH movwf MMV1h banksel ADRESL movfw ADRESL movwf MMV1l MOVLW MMV1h CALL MMdisplayIndirect movlw '/' call RStxChar movlw ',' MMtsSampleProcess ; Subtract MMV6h - MMV5H+eeprom[10] ; The difference ; if MMV6h < MMV5H then Vbat > Vsolar so do not carry on with calc. ; 00 00 - ; 00 01 ;======== ; ff MOVFW MMV5l SUBWF MMV6l,w ; w = F-W or MM6L-MMV5 -> W MOVWF MMtmp MOVFW MMV5h ; Apply Borrow SKPC ADDLW 0x01 ; suntract the difference of the low bytes ; Note MMV5 - MMV6 to get negative value SUBWF MMV6h,w ; w = F-W or MM6L-MMV5 -> W MOVWF MMtmph ;; MMV6 = MMV5 ;; MMV6 > MMV5 ; Output difference between Solar Call and Vbattery ; This is the compliment movlw '/' call RStxChar movlw 's' call RStxChar movlw ',' call RStxChar MOVFW MMtmph CALL RSwrtWasHex MOVFW MMtmp CALL RSwrtWasHex movlw ',' call RStxChar ; V6,V5,V4 use Vref, the voltage across a blue LED ; Also measure the voltage of the BLUE LED relative to Vref. ; ; V6 = 0E0 - Solar cell in darkness ; V5 = A70 - Vbattery when LED is on bright ; V4 = 8EC - Vtop of LED when LED is bright ; ; Vref = D7C - Vdd ~ 3.82 Vref=3.25 volts ; this right shift reduces the sensitivity ; ; ; w = w-f ; ; MMtmp contains Vsolar-Vbat ; MMtmp = MMtmp - ( 0x0000 + EE[00] ) MOVLW EEsolarOffset ;0x00 CALL EEread ; SUBLW 0 ; Negate W ADDWF MMtmp,f MOVLW 0xFF ; Assume -ve ; Apply CARRY SKPNC ADDLW 0x01 ADDWF MMtmph,f ; if V6-V5-EEprom[10] < 0 then increment MMincCntSolarCell BTFSC MMtmph,7 ; test MSB to see if negative GOTO MMtsSample1false MMtsSample1true CALL MMincCntSolarCell GOTO MMtsSample1 MMtsSample1false ; So Solar Cell is not charging, ; Is battery above eeprom[13]and eeprom[14] ; MMtmp = MM5V - EEPROM[13,14] MOVLW EEbatteryOffsetL ;0x14 CALL EEread SUBWF MMV5l,w ; w=w-f MOVWF MMtmp MOVLW EEbatteryOffsetH ; 0x13 CALL EEread ; Apply Borrow SKPC ADDLW 0x01 SUBWF MMV5h,w MOVWF MMtmph BTFSS MMtmph, 7 CALL MMincCntVbatt GOTO MMtsSample1 MMtsSample1 ; Subtrac VtopOfLED from Vbatt ; if Negative, then LED on ; Subtract MMV5h - MMv4H+eeprom[11] ; The subtraction really needs the low voltages ;MOVFW MMv4h ;SUBWF MMV5h,w ; If Vbat < Vtop of Led MOVFW MMV4l SUBWF MMV5l,w ; w = F-W or MM6L-MMV5 -> W MOVWF MMtmp MOVFW MMV4h ; Apply Borrow SKPC ADDLW 0x01 ; suntract the difference of the low bytes ; Note MMV5 - MMV6 to get negative value SUBWF MMV5h,w ; w = F-W or MM6L-MMV5 -> W MOVWF MMtmph ; NOTE: MMV4L - MMV5 to get negative value MOVFW MMV4l SUBWF MMV5l,w MOVWF MMtmp movlw 'l' call RStxChar movlw ',' call RStxChar MOVFW MMtmph CALL RSwrtWasHex MOVFW MMtmp CALL RSwrtWasHex movlw ',' call RStxChar ; ; MMtmp contains Voltage across 20R ; ; Is LED DIM, BRIGHT or OFF ; get constants from EEPROM ; if (V5-V4)-EEprom[11] < 0 then OFF MOVLW EEdimOffset ; 0x11 CALL EEread SUBLW 0 ; W = 0 - W ADDWF MMtmp,f ; ADD Carry MOVLW 0xFF ; promote -ve EE[01] to 0xFFXX SKPNC ADDLW 1 ADDWF MMtmph,f BTFSC MMtmph,7 ; Not +ve so dim constant not reached RETURN ; If Still +ve, then the LED is Bright or DIM ; Subtract a bit more off ; Subtract some to see if it is bright or dim. MOVLW EEbrightOffset ; 0x12 CALL EEread SUBLW 0 ; W = 0 - W ADDWF MMtmp,f ; ADD Carry MOVLW 0xFF ; promote -ve EE[02] to 0xFFXX SKPNC ADDLW 1 ADDWF MMtmph,f BTFSC MMtmph,7 GOTO MMincCntDim GOTO MMincCntBright MMincCntTime incfsz MMcntTimeL return incf MMcntTimeH,f return MMincCntSolarCell incfsz MMcntSolarCellL return incf MMcntSolarCellH,f return MMincCntBright incfsz MMcntBrightL return incf MMcntBrightH,f return MMincCntDim incfsz MMcntDimL return incf MMcntDimH,f return MMincCntVbatt incfsz MMcntVbattL return incf MMcntVbattH,f return MMdisplay MOVLW MMcntTimeH CALL MMdisplayIndirect MOVLW MMcntSolarCellH CALL MMdisplayIndirect MOVLW MMcntBrightH CALL MMdisplayIndirect MOVLW MMcntDimH CALL MMdisplayIndirect MOVLW MMcntVbattH CALL MMdisplayIndirect ; ; Display - ; movlw '/' call RStxChar movlw 't' call RStxChar movlw ',' call RStxChar banksel CLhh MOVLW CLhh CALL MMdisplayIndirectThreeByte return MMdisplayIndirectThreeByte ; display file pointed to by W as 4 HEX nibbles. ; ; MOVLW MMcntTimeH ; ; CALL MMdisplayIndirect ; move address of file into FSR and then use INDF to get values. MOVWF FSR SWAPF INDF,w CALL RSwrtHexNibble MOVFW INDF CALL RSwrtHexNibble ; now increment point onto next byte INCF FSR,W MMdisplayIndirect ; display file pointed to by W as 4 HEX nibbles. ; ; MOVLW MMcntTimeH ; ; CALL MMdisplayIndirect ; move address of file into FSR and then use INDF to get values. MOVWF FSR SWAPF INDF,w CALL RSwrtHexNibble MOVFW INDF CALL RSwrtHexNibble ; now increment point onto next byte INCF FSR,W MMdisplayIndirectOneByte MOVWF FSR SWAPF INDF,w CALL RSwrtHexNibble MOVFW INDF CALL RSwrtHexNibble movlw ',' call RStxChar RETURN ;-------------------------------------------------------------------------- ; Sec 5.15 EE Routines to copy the counts into the EEPROM ;-------------------------------------------------------------------------- ; ; ;MMcntTimeH ;MMcntTimeL ;MMcntSolarCellH ;MMcntSolarCellL ;MMcntBrightH ;MMcntBrightL ;MMcntDimH ;MMcntDimL ;MMcntVbattH ;MMcntVbattL ; ; Copy the bytes into the EEPROM. ; Use the value at 0x17 as a pointer ; If the file pointer gets too big just return ; ; EEfileCounts ; MOVLW EEFILEPTR CALL EEread MOVWF EEptrEEPROM ; Add some overflow protection ADDLW -(0x7f-(MMcntVbattL-MMcntTimeH+1)) SKPNC RETURN MOVLW MMcntVbattL-MMcntTimeH+1 MOVWF EEloopCount MOVLW MMcntTimeH MOVWF FSR EEfileCounts1 MOVFW EEptrEEPROM CALL EEsetAddr MOVFW INDF CALL EEwrt BANKSEL EEptrEEPROM INCF EEptrEEPROM,f INCF FSR,f DECFSZ EEloopCount GOTO EEfileCounts1 ; now update the EEPROM pointer. ; There is no overflow test. MOVLW EEFILEPTR CALL EEsetAddr MOVFW EEptrEEPROM CALL EEwrt RETURN ;EEptrEEPROM ; pointer to EEPROM ;EEptrMEM ; pointer to Memory - count, time, solarCell, bright, dim ;************************************************* ; Upload the DDATA from the logger EEfileDump CALL RS232sendCR CALL RS232sendLF CALL RS232sendStar CALL RS232sendCR CALL RS232sendLF MOVLW EEFILEPTR CALL EEread CALL RSwrtWasHex CALL RS232sendComma MOVLW EEFILESTART MOVWF EEptrEEPROM BA0 CALL BA4_addrToRS232 MOVLW (MMcntVbattL-MMcntTimeH)/2+1 MOVWF EEloopCount BA2 MOVFW EEptrEEPROM CALL EEread CALL RSwrtWasHex INCF EEptrEEPROM,f MOVFW EEptrEEPROM CALL EEread CALL RSwrtWasHex CALL RS232sendComma INCF EEptrEEPROM,f MOVFW EEptrEEPROM ; Add some overflow protection ADDLW -(0x7f-(MMcntVbattL-MMcntTimeH+1)) SKPNC GOTO BA3 DECFSZ EEloopCount,f GOTO BA2 GOTO BA0 BA3 CALL RS232sendComma CALL RS232sendStar CALL RS232sendCR CALL RS232sendLF RETURN BA4_addrToRS232 CALL RS232sendStar CALL RS232sendCR CALL RS232sendLF SWAPF EEptrEEPROM,W CALL RSwrtHexNibble MOVFW EEptrEEPROM CALL RSwrtHexNibble CALL RS232sendComma CALL RS232sendComma RETURN ;-------------------------------------------------------------------------- ; Sec 6.0 Interrupt Routines ;-------------------------------------------------------------------------- Intrtn RETFIE ;-------------------------------------------------------------------------- ; Program End ;-------------------------------------------------------------------------- ifdef pic12F675 org 0x3FD RETLW 0x6C RETLW 0x6C OscCalValue RETLW 0x6C endif ifdef pic16F676 ; Read from the chip being used. ; 34A8 org 0x3FD RETLW 0x6C RETLW 0x6C OscCalValue ; RETLW 0x80 ; first chip ; RETLW 0xA8 ; second chip RETLW 0x98 ; first chip endif LastProgWord ;-------------------------------------------------------------------------- ; Sec 7.0 EEPROM data ;-------------------------------------------------------------------------- EEsolarOffset EQU 0x00 EEdimOffset EQU 0x01 EEbrightOffset EQU 0x02 EEbatteryOffsetH EQU 0x03 EEbatteryOffsetL EQU 0x04 EEinterCharDelay EQU 0x05 EEAtoDappatureDelay EQU 0x06 ORG 0x2100 ; solar,off,bright/dim,Timer 61=~41 seconds ticks 1e6/2^16m = 1/15.2587890625 DE 0x33 ; EEsolarOffset ; delta Vsolar-Vbattery DE 0x14 ; EEdimOffset ; delta Vbattery-VtopOfLED - thresehold of DIM DE 0x10 ; EEbrightOffset ; Subtract this to see if BRIGHT DE 0x02 ; EEbatteryOffsetH ; VbattH DE 0x50 ; EEbatteryOffsetL ; VbattL DE 0x08 ; EEinterCharDelay ; inter sample delay 0x3d = 4 seconds DE 0x0A ; EEAtoDappatureDelay ; Appature delay - time from setting up switches to start of sample and hold. ORG 0x2107 DE EEFILEPTR+1 ; INIT pointer to EEPROM file. cblock LastVar endc END