;-------------------------------------------------------------------------------------------------------------------------------------- ; ; MOTORCYCLE DATA LOGGER - ASSEMBLY SOURCE CODE FOR THE MICROCHIP PIC 16F877 ; ; ; Author : Andries C. Tip ; andries.tip@planet.nl ; ; Start of programming : May 2002 ; Last Revision Date : December 29, 2006 ; ; Program code written with MPLAB IDE v7.00 from Microchip ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; Define firmware version, this number can be read by computer ; #define fwv0 a'1' ; version number #define fwv1 a'7' ; build number, most significant #define fwv2 a'9' ; build number, least significant ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; History: ; ; logger179.asm Bugfix: in the interrupt routine the movwf status_temp came after clrf status !! ; logger178.asm Bugfix: bank23 and bank32 macro's were faulty (rp1 instead of rp0) but were not used in the program ; logger177.asm First Public Release in datalogger ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; Font: Bitstream Vera Sans Mono (size 8 for screen display, size 6 for printing) ; ; Tabsize: 8 characters ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; Functional description of this firmware: ; ; This firmware is used in a datalogger that will record relevant data from sensors of a motorcycle and ; consists of a Microchip PIC 16F877, IIC EEPROM chips, IIC clock chip etc. After recording, the data can be ; read by using a computer with RS232 communication. The computer is also used for configuring the datalogger ; with settings such as logging rate, wheel diameter, input channels and so forth. ; ; The logging rate (measurements/second) can be given seperately for each channel. ; ; The rotary switch is used to start and stop the data logging. Multiple records can be taken before data readout ; by the computer is needed. Each record will have its own time and date recorded. The mark button can be ; pressed at any time during the logging and can be used to indicate periods in the computer graphs. ; ; Note: For reasons of clarity the external eeprom pages (64 bytes each) are called blocks instead of pages to avoid confusion ; with the memory pages which are used within the Microchip PIC chip. ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; Pinout: ; ; Port A0 = Analog input 0 Lambda sensor [0..1 V] ; Port A1 = Analog input 1 Voltage [0..5 V] ; Port A2 = Analog input 2 K-Type Thermocouple [0..1024? Celcius ?] ; Port A3 = Analog input 3 Air Temperature (NTC) ; Port A4 = Digital input Clock input 32768 Hz from Clock/Timer chip, used as interrupt ; Port A5 = Analog input 4 Water Temperature (NTC) ; ; Port B0 = Digital input Run ; Port B1 = Digital input _Mark_ ; Port B2 = Digital input Brake ; Port B3 = Digital input Laptime ; Port B4 = Digital input _TC disconnected_ ; Port B5 = Digital input BoardsupplyOn ; Port B6 = Digital output Status DuoLed Red ; Port B7 = Digital output Status DuoLed Green ; ; Port C0 = Digital output Computer CTS ; Port C1 = Digital input Speed [0..255 km/hr] ; Port C2 = Digital input RPM [0..16383 RPM] ; Port C3 = Digital in/output IIC SDA, clock chip, serial eeproms ; Port C4 = Digital output IIC SCL, clock chip, serial eeproms ; Port C5 = Digital input Computer RTS ; Port C6 = Digital output Computer RX (configure as input so the usart can use this pin !) ; Port C7 = Digital input Computer TX ; ; Port D0 = Digital output Led0, leds are rpm indicator/shift light ; Port D1 = Digital output Led1 ; Port D2 = Digital output Led2 ; Port D3 = Digital output Led3 ; Port D4 = Digital output Led4 ; Port D5 = Digital output Led5 ; Port D6 = Digital output Led6 ; Port D7 = Digital output Led7 ; ; Port E0 = Analog input 5 Throttle [0..100 %] ; Port E1 = Analog input 6 Longitudinal acceleration from G-sensor chip ; Port E2 = Analog input 7 Lateral acceleration from G-sensor chip ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; Format of data file as composed by computer from datalogger settings and record data ;-------------------------------------------------------------------------------------------------------------------------------------- ;Datalogger data file ; ;[Information] ;Serial number=2743 ;Start of logging=12/12/04 15:33:57 ;Original filename=D:\Datalogger\Data\Track_0018.dat ;Record size=2093104 << record size in bits ; ;[Errors] ;Log event overflow=1 ;Thermocouple disconnected=0 ;Memory full=1 ; ;[Settings] ;Wheel circumference=1967 ;Wheel radius=313.1 ;RPM maximum=5000 ; ;[Channels] ;RPM=32 ;Speed=32 ;Throttle=32 ;Thermocouple=32 ;Lambda=32 ;Voltage=32 ;Airtemp=32 ;Watertemp=32 ;LongAccel=32 ;LatAccel=32 ;Mark=32 ;Brake=32 ; ;[Data] ;0 PC 0 PC 0 L..... << raw data ; ; End of file. << just to inform user ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; PIC 14-bit core instruction set ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; Mnemonic Description Function Status affected Instr.Cycles ; ; ADDLW k Add literal to W k + W > W C, DC, Z 1 ; ADDWF f,d Add W and f W + f >d C, DC, Z 1 ; SUBLW k Subtract W from literal k - W > W C, DC, Z 1 ; SUBWF f,d Subtract W from f f - W > d C, DC, Z 1 ; BCF f, b Bit clear f 0 > f ( b ) 1 ; BSF f, b Bit set f 1 > f ( b ) 1 ; BTFSC f, b Bit test, skip if clear skip if f ( b ) = 0 1(2)* ; BTFSS f, b Bit test, skip if set skip if f ( b ) = 1 1(2)* ; CLRF f Clear f 0 >f Z 1 ; CLRW Clear W 0 >W Z 1 ; INCF f,d Increment f f + 1 > d Z 1 ; INCFSZ f,d Increment f, skip if zero f + 1 > d, skip if 0 1(2)* ; DECF f,d Decrement f f - 1 > d Z 1 ; DECFSZ f,d Decrement f, skip if zero f - 1 > d, skip if 0 1(2)* ; GOTO k Goto address (k is nine bits) k > PC (9 bits) 1 ; CALL k Call subroutine PC + 1 > TOS, k >PC 2 ; RETURN Return from subroutine TOS > PC 2 ; RETLW k Return with literal in W k > W, TOS > PC 2 ; RETFIE Return from interrupt TOS > PC, 1 > GIE 2 ; MOVLW k Move literal to W k > W 1 ; MOVF f,d Move f f > d Z 1 ; MOVWF f Move W to f W > f 1 ; SWAPF f,d Swap halves f f ( 0:3 ) > f ( 4:7) > d 1 ; RLF f,d Rotate left through carry C < 76543210 < C 1 ; RRF f,d Rotate right through carry C > 76543210 > C 1 ; COMF f,d Complement f .NOT. F > d Z 1 ; ANDLW k AND literal and W k .AND. W > W Z 1 ; ANDWF f,d AND W and f W .AND. F >d Z 1 ; IORLW k Inclusive OR literal and W k .OR. W > W Z 1 ; IORWF f,d Inclusive OR W and f W .OR. F >d Z 1 ; XORLW k Exclusive OR literal and W k .XOR. W > W Z 1 ; XORWF f,d Exclusive OR W and f W .XOR. F >d Z 1 ; NOP No operation 1 ; OPTION Load OPTION register W > OPTION Register 1 ; CLRWDT T Clear watchdog timer 0 > WDT (and prescaler) _TO , _PD 1 ; SLEEP Go into standby Mode 0 > WDT, stop oscillator _TO , _PD 1 ; TRIS f Tristate port f (only A,B,C!) W > I/O control register f 1 ; ; ; * = If the program counter (PC) is modified, or a conditional test is true, the instruction requires two cycles. The second ; cycle is executed as a NOP ; ; ; Field description: ; ; f register file address (0x00 to 0x7F) ; w working register (accumulator) ; b bit address within an 8-bit file register ; k literal field, constant data or label ; d destination select, d = 0 means store result in w, d = 1 means store result in file register f (default is d = 1) ; PC program counter ; TO time-out bit ; PD power-down bit ; ; ; Subtraction: Carry = 1 result is positive or zero ; Carry = 0 result is negative (borrow) ; Addition: Carry = 1 result is > 255 (overflow) ; Carry = 0 result is <=255 ; ;-------------------------------------------------------------------------------------------------------------------------------------- ; Configuration ;-------------------------------------------------------------------------------------------------------------------------------------- list p=16f877 ; directive to define processor radix dec ; all numbers are decimal unless stated otherwise errorlevel -219 ; suppress 'Invalid RAM location specified' warnings (editor warns unneededly about these ; addresses because of unused registers at the same locations in bank1 errorlevel -302 ; suppress 'not in register bank' warnings errorlevel -305 ; suppress 'default destination' warnings errorlevel -306 ; suppress 'crossing page boundary' warnings ;-------------------------------------------------------------------------------------------------------------------------------------- ; Version ;-------------------------------------------------------------------------------------------------------------------------------------- __IDLOCS h'0000' ; store the firmware version number in the pic identification memory locations ;-------------------------------------------------------------------------------------------------------------------------------------- ; Name registers ;-------------------------------------------------------------------------------------------------------------------------------------- w EQU H'0000' ; used in instructions like decsfz f EQU H'0001' ; to indicate destination ;----- Register Files-------------------------------------------------- ; BANK 0 : indf EQU H'0000' ; indirect file register tmr0 EQU H'0001' ; timer 0 module register pcl EQU H'0002' ; program counter (low byte) status EQU H'0003' ; status register fsr EQU H'0004' ; indirect data memory address pointer porta EQU H'0005' ; port A portb EQU H'0006' ; port B portc EQU H'0007' ; port C portd EQU H'0008' ; port D porte EQU H'0009' ; port E pclath EQU H'000A' ; write buffer for program counter (upper 5 bits) intcon EQU H'000B' ; interrupt control register pir1 EQU H'000C' ; peripheral interrupt flags pir2 EQU H'000D' ; CCP 2/SSP bus collision/eeprom write operation interrupt flags tmr1l EQU H'000E' ; timer 1 register low byte tmr1h EQU H'000F' ; timer 1 register high byte t1con EQU H'0010' ; timer 1 control register tmr2 EQU H'0011' ; timer 2 t2con EQU H'0012' ; timer 2 control register sspbuf EQU H'0013' ; SSP receive/xmit register sspcon EQU H'0014' ; SSP control register 1 ccpr1l EQU H'0015' ; CCP 1 low byte ccpr1h EQU H'0016' ; CCP 1 high byte ccp1con EQU H'0017' ; CCP 1 control register rcsta EQU H'0018' ; UART receive status and control register txreg EQU H'0019' ; UART xmit data register rcreg EQU H'001A' ; UART receive register ccpr2l EQU H'001B' ; CCP 2 low byte ccpr2h EQU H'001C' ; CCP 2 high byte ccp2con EQU H'001D' ; CCP 2 control register adresh EQU H'001E' ; A/D result register high byte adcon0 EQU H'001F' ; A/D operation control register ; BANK 1 : optionreg EQU H'0081' ; option register trisa EQU H'0085' ; Port A data direction control register trisb EQU H'0086' ; Port B data direction control register trisc EQU H'0087' ; Port C data direction control register trisd EQU H'0088' ; Port D data direction control register trise EQU H'0089' ; Port E data direction control register pie1 EQU H'008C' ; peripheral interrupt enable pie2 EQU H'008D' ; CCP 2/SSP bus collision/eeprom write operation interrupt enable pcon EQU H'008E' ; power control register sspcon2 EQU H'0091' ; SSP control register 2 pr2 EQU H'0092' ; timer 2 period register sspadd EQU H'0093' ; SSP (I2C mode) address register sspstat EQU H'0094' ; SSP status register txsta EQU H'0098' ; UART xmit status and control register spbrg EQU H'0099' ; UART baud rate generator speed control value adresl EQU H'009E' ; A/D result register low byte adcon1 EQU H'009F' ; A/D pin control register ; BANK 2 : eedata EQU H'010C' ; eeprom data register low byte eeadr EQU H'010D' ; eeprom address register low byte eedath EQU H'010E' ; eeprom data register high byte eeadrh EQU H'010F' ; eeprom address register high byte ; BANK 3 : eecon1 EQU H'018C' ; eeprom control register 1 eecon2 EQU H'018D' ; eeprom control register 2 ;----- STATUS Bits ---------------------------------------------------- irp EQU 7 rp1 EQU 6 rp0 EQU 5 not_to EQU 4 not_pd EQU 3 z EQU 2 dc EQU 1 c EQU 0 ;----- INTCON Bits ---------------------------------------------------- gie EQU 7 peie EQU 6 t0ie EQU 5 inte EQU 4 rbie EQU 3 t0if EQU 2 intf EQU 1 rbif EQU 0 ;----- PIR1 Bits ------------------------------------------------------ pspif EQU 7 adif EQU 6 rcif EQU 5 txif EQU 4 sspif EQU 3 ccp1if EQU 2 tmr2if EQU 1 tmr1if EQU 0 ;----- PIR2 Bits ------------------------------------------------------ eeif EQU 4 bclif EQU 3 ccp2if EQU 0 ;----- T1CON Bits ----------------------------------------------------- t1ckps1 EQU 5 t1ckps0 EQU 4 t1oscen EQU 3 t1sync EQU 2 tmr1cs EQU 1 tmr1on EQU 0 ;----- T2CON Bits ----------------------------------------------------- toutps3 EQU 6 toutps2 EQU 5 toutps1 EQU 4 toutps0 EQU 3 tmr2on EQU 2 t2ckps1 EQU 1 t2ckps0 EQU 0 ;----- SSPCON Bits ----------------------------------------------------- wcol EQU 7 sspov EQU 6 sspen EQU 5 ckp EQU 4 sspm3 EQU 3 sspm2 EQU 2 sspm1 EQU 1 sspm0 EQU 0 ;----- CCP1CON Bits ---------------------------------------------------- ccp1x EQU 5 ccp1y EQU 4 ccp1m3 EQU 3 ccp1m2 EQU 2 ccp1m1 EQU 1 ccp1m0 EQU 0 ;----- RCSTA Bits ---------------------------------------------------- spen EQU 7 rx9 EQU 6 sren EQU 5 cren EQU 4 adden EQU 3 ferr EQU 2 oerr EQU 1 rx9d EQU 0 ;----- CCP2CON Bits ---------------------------------------------------- ccp2x EQU 5 ccp2y EQU 4 ccp2m3 EQU 3 ccp2m2 EQU 2 ccp2m1 EQU 1 ccp2m0 EQU 0 ;----- ADCON0 Bits ---------------------------------------------------- adcs1 EQU 7 adcs0 EQU 6 chs2 EQU 5 chs1 EQU 4 chs0 EQU 3 go_notdone EQU 2 adon EQU 0 ;----- OPTION Register Bits ------------------------------------------ not_rbpu EQU 7 intedg EQU 6 t0cs EQU 5 t0se EQU 4 psa EQU 3 ps2 EQU 2 ps1 EQU 1 ps0 EQU 0 ;----- TRISE Bits ---------------------------------------------------- ibf EQU 7 obf EQU 6 ibov EQU 5 pspmode EQU 4 dirpe2 EQU 2 dirpe1 EQU 1 dirpe0 EQU 0 ;----- PIE1 Bits ------------------------------------------------------ pspie EQU 7 adie EQU 6 rcie EQU 5 txie EQU 4 sspie EQU 3 ccp1ie EQU 2 tmr2ie EQU 1 tmr1ie EQU 0 ;----- PIE2 Bits ------------------------------------------------------ eeie EQU 4 bclie EQU 3 ccp2ie EQU 0 ;----- PCON Bits ------------------------------------------------------ not_por EQU 1 not_bor EQU 0 ;----- SSPCON2 Bits ---------------------------------------------------- gcen EQU 7 ackstat EQU 6 ackdt EQU 5 acken EQU 4 rcen EQU 3 pen EQU 2 rsen EQU 1 sen EQU 0 ;----- SSPSTAT Bits --------------------------------------------------- smp EQU 7 cke EQU 6 d_nota EQU 5 p EQU 4 s EQU 3 r_notw EQU 2 ua EQU 1 bf EQU 0 ;----- TXSTA Bits ---------------------------------------------------- csrc EQU 7 tx9 EQU 6 txen EQU 5 sync EQU 4 brgh EQU 2 trmt EQU 1 tx9d EQU 0 ;----- ADCON1 Bits ---------------------------------------------------- adfm EQU 7 pcfg3 EQU 3 pcfg2 EQU 2 pcfg1 EQU 1 pcfg0 EQU 0 ;----- EECON1 Bits ---------------------------------------------------- eepgd EQU 7 wrerr EQU 3 wren EQU 2 wr EQU 1 rd EQU 0 ;-------------------------------------------------------------------------------------------------------------------------------------- ; RAM definition ;-------------------------------------------------------------------------------------------------------------------------------------- __MAXRAM H'1FF' __BADRAM H'8F'-H'90', H'95'-H'97', H'9A'-H'9D', H'105', H'107'-H'109', H'185', H'187'-H'189', H'18E'-H'18F' ;-------------------------------------------------------------------------------------------------------------------------------------- ; Configuration directive ;-------------------------------------------------------------------------------------------------------------------------------------- ; '__CONFIG' directive is used to embed configuration data within .asm file. _CP_ALL EQU H'0FCF' _CP_HALF EQU H'1FDF' _CP_UPPER_256 EQU H'2FEF' _CP_OFF EQU H'3FFF' _DEBUG_ON EQU H'37FF' _DEBUG_OFF EQU H'3FFF' _WRT_ENABLE_ON EQU H'3FFF' _WRT_ENABLE_OFF EQU H'3DFF' _CPD_ON EQU H'3EFF' _CPD_OFF EQU H'3FFF' _LVP_ON EQU H'3FFF' _LVP_OFF EQU H'3F7F' _BODEN_ON EQU H'3FFF' _BODEN_OFF EQU H'3FBF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC &_WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF ;-------------------------------------------------------------------------------------------------------------------------------------- ; Register bank macro's ;-------------------------------------------------------------------------------------------------------------------------------------- bank0 MACRO ; select register bank 0 bcf status,rp0 bcf status,rp1 ENDM bank1 MACRO ; select register bank 1 bsf status,rp0 bcf status,rp1 ENDM bank2 MACRO ; select register bank 2 bcf status,rp0 bsf status,rp1 ENDM bank3 MACRO ; select register bank 3 bsf status,rp0 bsf status,rp1 ENDM bank02 MACRO ; change from bank 0 to bank 2 bsf status,rp1 ENDM bank20 MACRO ; change from bank 2 to bank 0 bcf status,rp1 ENDM bank01 MACRO ; change from bank 0 to bank 1 bsf status,rp0 ENDM bank10 MACRO ; change from bank 1 to bank 0 bcf status,rp0 ENDM bank23 MACRO ; change from bank 2 to bank 3 bsf status,rp0 ENDM bank32 MACRO ; change from bank 3 to bank 2 bcf status,rp0 ENDM ;-------------------------------------------------------------------------------------------------------------------------------------- ; Program memory page macro's ;-------------------------------------------------------------------------------------------------------------------------------------- page0 MACRO ; select program memory page 0 (hex 0000 up to hex 07FF) bcf pclath,3 bcf pclath,4 ENDM page1 MACRO ; select program memory page 0 (hex 0800 up to hex 0FFF) bsf pclath,3 bcf pclath,4 ENDM page2 MACRO ; select program memory page 0 (hex 1000 up to hex 17FF) bcf pclath,3 bsf pclath,4 ENDM page3 MACRO ; select program memory page 0 (hex 17FF up to hex 1FFF) bsf pclath,3 bsf pclath,4 ENDM ;-------------------------------------------------------------------------------------------------------------------------------------- ; Constants definitions ;-------------------------------------------------------------------------------------------------------------------------------------- switch EQU 0 ; port B, rotary switch on datalogger (low=on/high=log) not_mark EQU 1 ; port B, marking switch at vehicle handlebar/steer (low=pressed) brake EQU 2 ; port B, switch connected to brake handle/pedal (high=pressed) laptime EQU 3 ; port B, extra laptime circuit to receive infrared beam from light along race track **** to do not_tcd EQU 4 ; port B, thermocouple disconnected (low=disconnected) boardsuppl EQU 5 ; port B, external power supply to datalogger (low=battery power only,high=exteral power on) led_red EQU 6 ; port B, red status led (see below) led_green EQU 7 ; port B, green status led (see below) ; status led: ; red = datalogger switched on ; green = logging ; yellow = logging, but memory almost full ; flashing red = one of the following errors: ; - logging stopped because memory is full ; - no channels enabled for logging ; - the table of contents (toc) is full, there is a maximum of 20 records rts_in EQU 5 ; Port C Pin 5 is input for uart flow control cts_out EQU 0 ; Port C Pin 0 is output for uart flow control @tocstart EQU d'56' ; start of table of contents in internal eeprom, runs up to and includes address 255 ;-------------------------------------------------------------------------------------------------------------------------------------- ; Variable definitions ;-------------------------------------------------------------------------------------------------------------------------------------- ; variables used at top of bank 0,1,2,3, available from any bank: (Hex 70-7F) w_temp EQU 0x70 ; variable used for context saving during interrupts status_temp EQU 0x71 ; variable used for context saving during interrupts pclath_temp EQU 0x72 ; variable used for context saving during interrupts fsr_temp EQU 0x73 ; variable used for context saving during interrupts numlow EQU 0x74 ; least significant or lower byte of 16 bit number (least significant byte of 24 bit number) nummiddle EQU 0x75 ; most significant or upper byte of 16 bit number (middle byte of 24 bit number) numhigh EQU 0x76 ; extended byte (most significant byte of 24 bit number) adtemp EQU 0x77 ; used in a/d conversion for channel selection and as delay counter adchannel EQU 0x78 ; channel number used in a/d conversion templow EQU 0x7A ; used in 8, 16 and 24 bit number read from buffer and transmission tempmiddle EQU 0x7B ; used in 16 and 24 bit number read from buffer and transmission temphigh EQU 0x7C ; used in 24 bit number transmission errors EQU 0x7D ; errors flags, bits will be when errors occur during logging (see below) flags1 EQU 0x7E ; status flag bits (see below) flags2 EQU 0x7F ; status flag bits (see below) ; bits of 'errors' register: logoflow EQU 0 ; previous log event was not finished when next event was started, logdata will be corrupted tcdiscon EQU 1 ; the thermocouple wire has been disconnected during logging, tc-logdata will be corrupted err_mf EQU 2 ; the external eeprom memory got full during logging ; bits of 'flags1' register: stx EQU 0 ; stx (start of text) byte received etx EQU 1 ; etx (end of text) byte received withdata EQU 2 ; command has data bytes command EQU 3 ; all bytes of command have been received, now ready for execution of command changese EQU 7 ; backdoor to change device serial number ; bits of 'flags2' register: lognow EQU 0 ; timer0 interrupt just occured which means data should be logged instantly tocfull EQU 1 ; table of contents in pic internal eeprom is full memfull EQU 2 ; external eeproms are all full rpmbusy EQU 3 ; do not disturb rpm calculation spdbusy EQU 4 ; do not disturb speed calculation shlight EQU 5 ; this flag is set when shift light should be on, used in timer interrupt to flash light norpm EQU 6 ; indicate we did not get a rpm pulse so calculate a dropping rpm rate nospeed EQU 7 ; indicate we did not get a speed pulse so calculate a dropping speed value ; variables used in bank 0 (Hex 20-6F) rx_byte EQU 0x20 ; byte received from UART rx_parity EQU 0x21 ; byte used in parity checking rx_checksum EQU 0x22 ; byte used in receive checksum calculation rx_pointer EQU 0x23 ; pointer for command input buffer rx_maxpos EQU 0x24 ; maximum location of received command bytes tx_byte EQU 0x25 ; byte ready to be sent tx_checksum EQU 0x26 ; used in transmission checksum calculation tx_parity EQU 0x27 ; used in parity calculation tx_numberl EQU 0x28 ; used in 8, 16 and 24 bit number transmission tx_numberm EQU 0x29 ; used in 16 and 24 bit number transmission tx_numberh EQU 0x2A ; used in 24 bit number transmission tx_counter EQU 0x2B ; used in 8 and 16 bit number transmission rx_buffer00 EQU 0x2D ; start of serial communications command receive buffer: rx_buffer01 EQU 0x2E ; register addresses 2D and 2E are used for two command bytes, rx_buffer02 EQU 0x2F ; addresses from 2F - 6F are used for a maximum of 64 data bytes rx_buffer03 EQU 0x30 ; rx_buffer04 EQU 0x31 ; rx_buffer05 EQU 0x32 ; rx_buffer06 EQU 0x33 ; rx_buffer07 EQU 0x34 ; rx_buffer08 EQU 0x35 ; rx_buffer09 EQU 0x36 ; rx_buffer10 EQU 0x37 ; rx_buffer11 EQU 0x38 ; rx_buffer12 EQU 0x39 ; rx_buffer13 EQU 0x3A ; rx_buffer14 EQU 0x3B ; rx_buffer15 EQU 0x3C ; rx_buffer16 EQU 0x3D ; rx_buffer17 EQU 0x3E ; rx_buffer18 EQU 0x3F ; rx_buffer65 EQU 0x6E ; rx_buffer66 EQU 0x6F ; plus one checksum byte (note: same locations as blockbuffer in bank1 !) ; variables used in bank 1 (Hex A0-EF) iicdata EQU 0xA0 ; data byte iicalow EQU 0xA1 ; address low byte (8 bits) iicahigh EQU 0xA2 ; address high byte (7 bits) iicchip EQU 0xA3 ; number of external eeprom chip (0..7) mem_alow EQU 0xA4 ; address select, low byte mem_ahigh EQU 0xA5 ; address select, high byte mem_chip EQU 0xA6 ; chip select for (block) write operations to external eeprom regpointer EQU 0xA7 ; register pointer in block buffer bitpointer EQU 0xA8 ; bit pointer in block buffer bitcounter EQU 0xA9 ; temporary counter used in shift operations for block buffer storage bitmask EQU 0xAA ; mask for one bit add operation in block buffer databyte0 EQU 0xAB ; used in copy and shift operations for storing data in the block buffer databyte1 EQU 0xAC ; used in copy and shift operations for storing data in the block buffer databyte2 EQU 0xAD ; used in copy and shift operations for storing data in the block buffer toc_pointer EQU 0xAE ; pointer for table of contents in internal eepromm blockbuff00 EQU 0xAF ; location of first byte in 64 byte block buffer for writes to external eeprom blockbuff63 EQU 0xEE ; location of last byte in block buffer (same locations as rx_buffer in bank0 !) toc_test EQU 0xEF ; testing for free location in table of contents in internal eeprom ; variables used in bank 2 (Hex 10-6F) iee_address EQU 0x10 ; pointer for write operations to pic internal eeprom timer1y EQU 0x11 ; extend range of timer1 with one byte to three bytes timer1z EQU 0x12 ; extend range of timer1 with one byte to four bytes new1cap0 EQU 0x13 ; captures byte 0 of timer 1 new1cap1 EQU 0x14 ; captures byte 1 of timer 1 new1cap2 EQU 0x15 ; captures byte 2 of timer 1 new1cap3 EQU 0x16 ; captures byte 3 of timer 1 old1cap0 EQU 0x17 ; holds previous value of captured byte 0 of timer 1 old1cap1 EQU 0x18 ; holds previous value of captured byte 1 of timer 1 old1cap2 EQU 0x19 ; holds previous value of captured byte 2 of timer 1 old1cap3 EQU 0x1A ; holds previous value of captured byte 3 of timer 1 new2cap0 EQU 0x1B ; captures byte 0 of timer 1 new2cap1 EQU 0x1C ; captures byte 1 of timer 1 new2cap2 EQU 0x1D ; captures byte 2 of timer 1 new2cap3 EQU 0x1E ; captures byte 3 of timer 1 old2cap0 EQU 0x1F ; holds previous value of captured byte 0 of timer 1 old2cap1 EQU 0x20 ; holds previous value of captured byte 1 of timer 1 old2cap2 EQU 0x21 ; holds previous value of captured byte 2 of timer 1 old2cap3 EQU 0x22 ; holds previous value of captured byte 3 of timer 1 divcounter EQU 0x23 ; used in division routine nrator0 EQU 0x24 ; used in division routine nrator1 EQU 0x25 ; used in division routine nrator2 EQU 0x26 ; used in division routine nrator3 EQU 0x27 ; used in division routine denom_r0 EQU 0x28 ; used in division routine of ccp1 (RPM) denom_r1 EQU 0x29 ; used in division routine denom_r2 EQU 0x2A ; used in division routine denom_r3 EQU 0x2B ; used in division routine denom_s0 EQU 0x2C ; used in division routine of ccp2 (Speed) denom_s1 EQU 0x2D ; used in division routine denom_s2 EQU 0x2E ; used in division routine denom_s3 EQU 0x2F ; used in division routine remain0 EQU 0x30 ; used in division routine remain1 EQU 0x31 ; used in division routine remain2 EQU 0x32 ; used in division routine remain3 EQU 0x33 ; used in division routine rpm_low EQU 0x34 ; engine rpm, result low byte of division rpm_high EQU 0x35 ; engine rpm, result high byte of division speed EQU 0x36 ; vehicle speed, result byte of division mult_a0 EQU 0x37 ; used in 16 bit multiplication routine mult_a1 EQU 0x38 ; used in 16 bit multiplication routine mult_b0 EQU 0x39 ; used in 16 bit multiplication routine mult_b1 EQU 0x3A ; used in 16 bit multiplication routine speed_const0 EQU 0x3B ; used in 16 bit multiplication routine speed_const1 EQU 0x3C ; used in 16 bit multiplication routine, 32 bit result speed_const2 EQU 0x3D ; used in 16 bit multiplication routine, 32 bit result speed_const3 EQU 0x3E ; used in 16 bit multiplication routine, 32 bit result multcounter EQU 0x3F ; used in 16 bit multiplication routine, 32 bit result rpmmax_low EQU 0x40 ; maximum rpm rate, low byte, copied from eeprom rpmmax_high EQU 0x41 ; maximum rpm rate, high byte, copied from eeprom rpmmax_0 EQU 0x42 ; maximum rpm rate time interval, least significant byte, used in comparison for shift light rpmmax_1 EQU 0x43 ; maximum rpm rate time interval, more significant byte 1, used in comparison for shift light rpmmax_2 EQU 0x44 ; maximum rpm rate time interval, more significant byte 2, used in comparison for shift light rpmmax_3 EQU 0x45 ; maximum rpm rate time interval, most significant byte, used in comparison for shift light ccp1interval0 EQU 0x46 ; temporary rpm interval storage ccp1interval1 EQU 0x47 ; temporary rpm interval storage ccp1interval2 EQU 0x48 ; temporary rpm interval storage ccp1interval3 EQU 0x49 ; temporary rpm interval storage ccp2interval0 EQU 0x4A ; temporary speed interval storage ccp2interval1 EQU 0x4B ; temporary speed interval storage ccp2interval2 EQU 0x4C ; temporary speed interval storage ccp2interval3 EQU 0x4D ; temporary speed interval storage intervalr0 EQU 0x4E ; present timer1 value intervalr1 EQU 0x4F ; present timer1 value intervalr2 EQU 0x50 ; present timer1 value intervalr3 EQU 0x51 ; present timer1 value intervals0 EQU 0x52 ; present timer1 value intervals1 EQU 0x53 ; present timer1 value intervals2 EQU 0x54 ; present timer1 value intervals3 EQU 0x55 ; present timer1 value lastintr0 EQU 0x56 ; interval between last two rpm pulses lastintr1 EQU 0x57 ; interval between last two rpm pulses lastintr2 EQU 0x58 ; interval between last two rpm pulses lastintr3 EQU 0x59 ; interval between last two rpm pulses lastints0 EQU 0x5A ; interval between last two speed pulses lastints1 EQU 0x5B ; interval between last two speed pulses lastints2 EQU 0x5C ; interval between last two speed pulses lastints3 EQU 0x5D ; interval between last two speed pulses pulses EQU 0x5E ; number of pulses per crankshaft revolution ; not used ; not used ; not used clockaddr EQU 0x66 ; holds address for static ram and control byte operations in IIC clock chip clockdata EQU 0x67 ; temporary storage for data for static ram operations seconds EQU 0x68 ; buffer for IIC clock chip settings minutes EQU 0x69 ; hours EQU 0x6A ; day EQU 0x6B ; date EQU 0x6C ; month EQU 0x6D ; year EQU 0x6E ; clockctrl EQU 0x6F ; settings byte in clock chip ; variables used in bank 3 (Hex 90-EF) tablepointer EQU 0x90 ; used in table lookups logcounter EQU 0x91 ; counter used during logger, increased every 1/32 of a second freq_rpm EQU 0x92 ; setting for log frequency of rpm channel freq_speed EQU 0x93 ; freq_lambda EQU 0x94 ; freq_voltage EQU 0x95 ; freq_tc EQU 0x96 ; freq_air EQU 0x97 ; freq_water EQU 0x98 ; freq_throttle EQU 0x99 ; freq_long EQU 0x9A ; freq_lat EQU 0x9B ; freq_mark EQU 0x9C ; freq_brake EQU 0x9D ; num_records EQU 0x9E ; counter for number of records current_rec EQU 0x9F ; select record for downloading rec_loopcntr EQU 0xA0 ; byte used in addition loop pointer_low EQU 0xA1 ; pointer to record data in external memory pointer_high EQU 0xA2 ; pointer_chip EQU 0xA3 ; endpoint_low EQU 0xA4 ; pointer to end of record data in external memory endpoint_high EQU 0xA5 ; endpoint_chip EQU 0xA6 ; recsizea0 EQU 0xA7 ; registers used in record size calculation recsizea1 EQU 0xA8 ; recsizea2 EQU 0xA9 ; recsizeb0 EQU 0xAA ; recsizeb1 EQU 0xAB ; recsizeb2 EQU 0xAC ; ;--------------------------------------------------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------------------------------------------------- ; Data EEPROM Contents (PIC16F877: 256 bytes) ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- org h'2100' ; start of eeprom data memory de d'175' ; 000 vehicle outer wheel circumference in millimeters (default 1967 mm), low byte de d'7' ; 001 vehicle outer wheel circumference in millimeters, high byte de d'255' ; 002 maximum rpm rate (default 10000 rpm) [0..16383], low byte de d'63' ; 003 maximum rpm rate high byte de d'2' ; 004 pulses per revolution de d'0' ; 005 de d'0' ; 006 de d'0' ; 007 de d'0' ; 008 de d'0' ; 009 de d'0' ; 010 de d'0' ; 011 de d'0' ; 012 de d'0' ; 013 de d'0' ; 014 de d'0' ; 015 error flags bits, any errors during logging are stored here de b'11111111' ; 016 rpm, channel logging frequency values de b'11111111' ; 017 speed logrates (see also 'logdata' routine): de b'11111111' ; 018 lambda de b'11111111' ; 019 voltage 00000000 32 Hz de b'11111111' ; 020 thermocouple 00000001 16 Hz de b'11111111' ; 021 air temperature 00000011 8 Hz de b'11111111' ; 022 water temperature 00000111 4 Hz de b'11111111' ; 023 throttle 00001111 2 Hz de b'11111111' ; 024 long acceleration 00011111 1 Hz or every second de b'11111111' ; 025 lat acceleration 00111111 1/2 Hz or every 2 seconds de b'11111111' ; 026 mark switch 01111111 1/4 Hz or every 4 seconds de b'11111111' ; 027 brake switch 11111111 never de d'0' ; 028 de d'0' ; 029 de d'0' ; 030 de d'0' ; 031 de d'0' ; 032 de d'0' ; 033 de d'0' ; 034 de d'0' ; 035 de d'0' ; 036 de d'0' ; 037 de d'0' ; 038 de d'0' ; 039 de d'0' ; 040 de d'0' ; 041 de d'0' ; 042 de d'0' ; 043 de d'0' ; 044 de d'0' ; 045 de d'0' ; 046 de d'0' ; 047 de d'0' ; 048 de d'0' ; 049 de d'0' ; 050 de d'0' ; 051 de d'0' ; 052 de d'0' ; 053 de b'1' ; 054 record incremental number de b'0' ; 055 record incremental number de d'0' ; 1, 056 start location of table of contents for data records de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; all bytes clear because nothing been recorded yet de d'0' ; 2 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 3 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 4 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 5 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 6 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 7 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 8 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 9 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 10 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 11 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 12 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 13 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 14 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 15 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 16 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 17 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 18 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 19 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; 20 de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; de d'0' ; ;###################################################################################################################################### ; Start of program code ;###################################################################################################################################### ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- org h'0000' ; tell the assembler to place following program code at the processor reset vector, ; which is the start of program memory page 0 ; this code executes when a reset occurs ; Note: The contents of the PCLATH register are unchanged after a RETURN or RETFIE instruction ; is executed ! The user must rewrite the contents of the PCLATH register for any subsequent ; subroutine calls or goto instructions (meaning: make sure page bits are set properly !) RESET bcf pclath,3 ; select program memory page 0 (hex 0000 up to hex 07FF) bcf pclath,4 ; select program memory page 0 (hex 0000 up to hex 07FF) clrf status ; ensure bank bits are clear goto INITIALIZE ; skip interrupt routine and subroutines and go to beginning of program ;-------------------------------------------------------------------------------------------------------------------------------------- org h'0004' ; tell the assembler to place following program code at interrupt vector location ; this code executes when an interrupt occurs INTERRUPT movwf w_temp ; save off current w register contents (will be stored in any bank !) swapf status,w ; swap status to be saved into w movwf status_temp ; save status register to status_temp register in bank 0 clrf status ; bank 0, regardless of current bank, clears irp,rp1,rp0 (for other than 16F877) movf fsr,w ; save fsr register movwf fsr_temp ; movf pclath,w ; only required if using pages 1,2 and/or 3 movwf pclath_temp ; save pclath clrf pclath ; select page zero, regardless of current page ; see what caused the interrupt and act upon it: ; page selection should not change in interrupt routines bsf flags2,norpm ; assume we will not get rpm or speed pulses bsf flags2,nospeed ; flag will be reset in ccp1 and ccp2 interrupt code bank0 ; test if the CCP1 module did a capture, if so, go calculate engine rpm pulse interval, but btfsc pir1,ccp1if ; only if we can use the present timer 1 values as we may get ccp and timer 1 irq's call INT_CCP1 ; at the same time ! else we wait until the timer 1 value has been increased, bank0 return bank0 ; test if the CCP2 module did a capture, if so, go calculate speed pulse interval, but btfsc pir2,ccp2if ; only if we can use the present timer 1 values as we may get ccp and timer 1 irq's call INT_CCP2 ; at the same time ! else we wait until the timer 1 value has been increased bank0 btfsc pir1,tmr1if ; test if timer 1 (which has 16 bits) has overflowed from 65535 to 0 call INT_TIMER1 ; if so, go increase the two extra counter bytes we use to extend the range, bank0 return bank0 ; btfsc pir1,rcif ; test if UART has received a byte from a connected computer through the RS232 call INT_RX ; if so, store valid bytes in buffer until command is complete, then set command flag call INT_SHIFT ; when calculated rpm rate is more than the given maximum turn on shift light, bank0 return ; done handling interrupts INT_RESTORE bank0 ; make sure we are in the right bank (for other than 16F877) movf pclath_temp,w ; restore the register contents to their values from before the interrupt movwf pclath ; restore pclath movf fsr_temp,w ; movwf fsr ; restore fsr swapf status_temp,w ; swap status_temp register into w (sets bank to original state) movwf status ; restore pre-isr status register contents swapf w_temp,f ; swapf w_temp,w ; restore pre-isr w register contents retfie ; return from interrupt, re-enable interrupts ;-------------------------------------------------------------------------------------------------------------------------------------- ; Handle Timer1 overflow interrupt ;-------------------------------------------------------------------------------------------------------------------------------------- INT_TIMER1 bank2 ; incf timer1y,f ; increase the lower of two bytes which are used to extend the range of timer 1 to a skpnz ; total of four bytes, did this byte roll over from 255 to 0 ? incf timer1z,f ; yes, also increase the upper of the two bytes btfsc flags2,norpm ; did we get a rpm pulse ? call INT_DROP_RPM ; no, calculate a dropping rpm rate, bank2 return btfsc flags2,nospeed ; did we get a speed pulse ? call INT_DROP_SPEED ; no, calculate a dropping speed value, bank2 return INT_TIMER1_SL movlw b'11111111' ; now see about the shift light, this is value for all leds on btfsc timer1y,0 ; we use this timer bit to flash the shift light as a stroboscope, is this bit high ? btfss flags2,shlight ; yes, so should we turn on the shift light ? clrw ; no, value for all leds off bank20 ; movwf portd ; yes, turn shift light on bcf pir1,tmr1if ; clear timer 1 receive interrupt flag bit return ; done, return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- ; Handle CCP1 capture interrupt ;-------------------------------------------------------------------------------------------------------------------------------------- INT_CCP1 ; since we can have both timer 1 overflow and ccp interrupt request at the same ; time it is important to update the timer 1 extension bytes at the right time, ; now see if we can use the present timer 1 values to calculate the engine RPM rate ; from CCP module 1 using the time (t) between two captures, otherwise we exit this ; routine and come back later when timer 1 has been incremented ; here we calculate the interval given by the rpm rate and use it to turn on or off the ; the so called 'shift light' to let the driver know it is time to shift gears, ; we do not want to calculate the actual RPM value on every interrupt since the division ; routine takes up too much processor time, the actual rpm calculation in done during logging ; or command execution ; engine RPM rate calculation: ; F [Hz] = 1 / t [s] ; RPM = 60 / t [s] ; RPM = 60 * timer1clockrate / interval [timer cycles] ; RPM = (60 * 3686400/4) Mhz / interval [instruction cycles] ; RPM = 55,296,000 / interval [instruction cycles] ; RPM = 55,296,000 / (capturevalue - previouscapturevalue) ; RPM = 55,296,000 / (new1cap - old1cap) ; quotient = numerator / denominator ; calculate interval (32 bits) and store result in denom: ; current = timer1z timer1y ccpr1h ccpr1l ; new = new1cap3 new1cap2 new1cap1 new1cap0 ; old = old1cap3 old1cap2 old1cap1 old1cap0 ; interval = denom_r3 denom_r2 denom_r1 denom_r0 ; see also CALC_RPM and COPY_RPM routines bcf flags2,norpm ; we did get a rpm pulse INT_CCP1_STORE bank02 ; yes, continue and handle CCP1 interrupt request movf new1cap0,w ; store previous captured values movwf old1cap0 ; movf new1cap1,w ; movwf old1cap1 ; movf new1cap2,w ; movwf old1cap2 ; movf new1cap3,w ; movwf old1cap3 ; INT_CCP1_CAPT bank20 ; get capture moment movf ccpr1l,w ; get first captured byte bank02 ; movwf new1cap0 ; movwf ccp1interval0 ; bank20 ; movf ccpr1h,w ; get second captured byte bank02 ; movwf new1cap1 ; movwf ccp1interval1 ; movf timer1y,w ; get third timer byte movwf new1cap2 ; movwf ccp1interval2 ; movf timer1z,w ; get newly capture values, first get the fourth timer byte movwf new1cap3 ; movwf ccp1interval3 ; INT_CCP1_CHECK bank20 btfss pir1,tmr1if ; do we also have a timer 1 overflow interrupt request ? goto INT_CCP1_SUB ; no, so it is ok to handle the CCP1 interrupt request movlw d'128' ; yes, now see if we can use the current timer 1 value (use halfway value) subwf ccpr1h,w ; any capture from (long) before the timer 1 overflow must use old timer values skpnc ; was the capture from before the timer 1 overflow ? goto INT_CCP1_SUB ; yes, bank02 ; incf ccp1interval2,f ; no, increase timer 1 bytes 3 and 4 incf new1cap2,f ; skpnz ; incf ccp1interval3,f ; movf ccp1interval3,w ; movwf new1cap3 ; INT_CCP1_SUB bank02 ; movf old1cap0,w ; subtraction, calculate the actual interval subwf ccp1interval0,f ; store interval byte 0 movf old1cap1,w ; skpc ; incfsz old1cap1,w ; subwf ccp1interval1,f ; movf old1cap2,w ; skpc ; incfsz old1cap2,w ; subwf ccp1interval2,f ; movf old1cap3,w ; skpc ; incfsz old1cap3,w ; subwf ccp1interval3,f ; INT_CCP1_LAST movf ccp1interval0,w ; copy time interval between last two pulses movwf lastintr0 ; movf ccp1interval1,w ; movwf lastintr1 ; movf ccp1interval2,w ; movwf lastintr2 ; movf ccp1interval3,w ; movwf lastintr3 ; INT_CCP1_DONE bank20 ; bcf pir1,ccp1if ; clear capture 1 interrupt flag return ; we're done here, return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- ; Handle CCP2 capture interrupt ;-------------------------------------------------------------------------------------------------------------------------------------- INT_CCP2 ; since we can have both timer 1 overflow and ccp interrupt request at the same ; time it is important to update the timer 1 extension bytes at the right time, ; now see if we can use the present timer 1 values to calculate the vehicle speed ; from CCP module 2 using the time (t) between two captures, otherwise we exit this ; routine and come back later when timer 1 has been incremented bcf flags2,nospeed ; we did get a speed pulse INT_CCP2_STORE bank02 ; yes, movf new2cap0,w ; store previous captured values movwf old2cap0 ; movf new2cap1,w ; movwf old2cap1 ; movf new2cap2,w ; movwf old2cap2 ; movf new2cap3,w ; movwf old2cap3 ; INT_CCP2_CAPT bank20 ; get capture moment movf ccpr2l,w ; get first captured byte bank02 ; movwf new2cap0 ; movwf ccp2interval0 ; bank20 ; movf ccpr2h,w ; get second captured byte bank02 ; movwf new2cap1 ; movwf ccp2interval1 ; movf timer1y,w ; get third timer byte movwf new2cap2 ; movwf ccp2interval2 ; movf timer1z,w ; get newly capture values, first get the fourth timer byte movwf new2cap3 ; movwf ccp2interval3 ; INT_CCP2_CHECK bank20 btfss pir1,tmr1if ; do we also have a timer 1 overflow interrupt request ? goto INT_CCP2_SUB ; no, so it is ok to handle the CCP2 interrupt request movlw d'128' ; yes, now see if we can use the current timer 1 value (use halfway value) subwf ccpr2h,w ; any capture from (long) before the timer 1 overflow must use old timer values skpnc ; was the capture from before the timer 1 overflow ? goto INT_CCP2_SUB ; yes, bank02 ; incf ccp2interval2,f ; no, increase timer 1 bytes 3 and 4 incf new2cap2,f ; skpnz ; incf ccp2interval3,f ; movf ccp2interval3,w ; movwf new2cap3 ; INT_CCP2_SUB bank02 ; movf old2cap0,w ; subtraction, the resulting interval is put in denominator subwf ccp2interval0,f ; store interval byte 0 for use in division routine movf old2cap1,w ; skpc ; is capture0 - hold0 < 0 ? incfsz old2cap1,w ; yes, 'borrow' from more significant byte subwf ccp2interval1,f ; no, borrow has been skipped, do subtraction and store for use in division movf old2cap2,w ; skpc ; incfsz old2cap2,w ; subwf ccp2interval2,f ; movf old2cap3,w ; skpc ; incfsz old2cap3,w ; subwf ccp2interval3,f ; INT_CCP2_LAST movf ccp2interval0,w ; copy time interval between last two pulses movwf lastints0 ; movf ccp2interval1,w ; movwf lastints1 ; movf ccp2interval2,w ; movwf lastints2 ; movf ccp2interval3,w ; movwf lastints3 ; INT_CCP2_DONE bank20 ; bcf pir2,ccp2if ; clear capture 2 interrupt flag return ; done, return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- INT_DROP_RPM ; Drop the speed value (calculate pulse interval) in case we do not get speed pulses anymore INT_DROP_R_NOW bank2 ; clrf intervalr0 ; get present timer1 value (now) clrf intervalr1 ; at the moment of overflow these values became zero movf timer1y,w ; get third timer byte movwf intervalr2 ; movf timer1z,w ; movwf intervalr3 ; store in rpm interval INT_DROP_R_SUB movf new1cap0,w ; calculate rpm value when we do not have any rpm pulses on the input subwf intervalr0,f ; subtraction, calculate the time interval between the last pulse and now movf new1cap1,w ; store the result in intervalr0-3 skpc ; incfsz new1cap1,w ; subwf intervalr1,f ; movf new1cap2,w ; skpc ; incfsz new1cap2,w ; subwf intervalr2,f ; movf new1cap3,w ; skpc ; incfsz new1cap3,w ; subwf intervalr3,f ; INT_DROP_R_TEST movf intervalr0,w ; is the time interval between the last pulse and now larger than the time between subwf lastintr0,w ; the last two pulses ? movf intervalr1,w ; skpc ; incfsz intervalr1,w ; subwf lastintr1,w ; movf intervalr2,w ; skpc ; incfsz intervalr2,w ; subwf lastintr2,w ; movf intervalr3,w ; skpc ; incfsz intervalr3,w ; subwf lastintr3,w ; skpnc ; return ; no, do nothing INT_DROP_R_YES movf intervalr0,w ; copy the new (longer) interval value so we drop the rpm rate movwf ccp1interval0 ; movf intervalr1,w ; movwf ccp1interval1 ; movf intervalr2,w ; movwf ccp1interval2 ; movf intervalr3,w ; movwf ccp1interval3 ; INT_DROP_R_OVR movlw d'255' ; timer1 and the extra bytes will overflow, this will affect the interval value indirectly subwf ccp1interval3,w ; since the new1cap values will stay the same, so we have to adjust the new1cap values skpz ; is the value of the interval about to overflow ? return ; no, done rlf new1cap3,f ; yes, get the most significant bit of new1cap skpc ; toggle it's value setc ; this will move the new1cap value in time skpnc ; so the interval value will be decreased but still very long to show zero rpm clrc ; rrf new1cap3,f ; return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ; See if we are getting input pulses of rpm and speed, otherwise calculate dropping rpm and speed values ;-------------------------------------------------------------------------------------------------------------------------------------- INT_DROP_SPEED ; calculate dropping rpm and speed values ; Drop the rpm rate (calculate new rpm pulse interval) in case we do not get rpm pulses anymore INT_DROP_S_NOW bank2 ; clrf intervals0 ; get present timer1 value (now) clrf intervals1 ; at the moment of overflow these values became zero movf timer1y,w ; get third timer byte movwf intervals2 ; movf timer1z,w ; movwf intervals3 ; store in speed interval INT_DROP_S_SUB movf new2cap0,w ; subtraction, calculate the time interval between the last pulse and now subwf intervals0,f ; store the result in intervals0-3 movf new2cap1,w ; skpc ; incfsz new2cap1,w ; subwf intervals1,f ; movf new2cap2,w ; skpc ; incfsz new2cap2,w ; subwf intervals2,f ; movf new2cap3,w ; skpc ; incfsz new2cap3,w ; subwf intervals3,f ; INT_DROP_S_TEST movf intervals0,w ; is the time interval between the last pulse and now larger than the time between subwf lastints0,w ; the last two pulses ? movf intervals1,w ; skpc ; incfsz intervals1,w ; subwf lastints1,w ; movf intervals2,w ; skpc ; incfsz intervals2,w ; subwf lastints2,w ; movf intervals3,w ; skpc ; incfsz intervals3,w ; subwf lastints3,w ; skpnc ; return ; no, do nothing INT_DROP_S_YES movf intervals0,w ; yes, copy the new (longer) interval value so we drop the speed value movwf ccp2interval0 ; movf intervals1,w ; movwf ccp2interval1 ; movf intervals2,w ; movwf ccp2interval2 ; movf intervals3,w ; movwf ccp2interval3 ; INT_DROP_S_OVR movlw d'255' ; timer1 and the extra bytes will overflow, this will affect the interval value indirectly subwf ccp2interval3,w ; since the new2cap values will stay the same, so we have to adjust the new2cap values skpz ; is the value of the interval about to overflow ? return ; no, done rlf new2cap3,f ; yes, get the most significant bit of new1cap skpc ; toggle it's value setc ; this will move the new2cap value in time skpnc ; so the interval value will be decreased but still very long to show zero speed value clrc ; rrf new2cap3,f ; return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- INT_SHIFT ; when the calculated rpm value is more than the given maximum turn on the shift light ; t [s] = 1 / F [Hz] ; t [s] = 60 / RPM ; interval [timer cycles] = 60 * timer1clockrate / RPM ; interval [instruction cycles] = (60 * 3686400/4) MHz / RPM ; interval [instruction cycles] = 55,296,000 / RPM ; (capturevalue - previouscapturevalue) = 55,296,000 / RPM ; (new1cap - old1cap) = 55,296,000 / RPM ; denominator1 (from ccp1 routine) = 55,296,000 / RPM ; so we want to compare the denominator1 value with the four interval bytes: ; interval : rpmmax_3 rpmmax_2 rpmmax_1 rpmmax_0 ; which we have calculated at initialization from the two maximum rpm bytes ; rpm max : rpmmax_high rpmmax_low bank2 ; movf ccp1interval0,w ; subtraction, when the measured rpm value is more than the set maximum we should turn on the subwf rpmmax_0,w ; so called 'shift light' to let the driver know it is time to shift gears movf ccp1interval1,w ; so turn on if: rpmmax - denominator (=interval) > 0 skpc ; is capture0 - hold0 < 0 ? incfsz ccp1interval1,w ; yes, 'borrow' from more significant byte subwf rpmmax_1,w ; no, borrow has been skipped, do subtraction movf ccp1interval2,w ; skpc ; incfsz ccp1interval2,w ; subwf rpmmax_2,w ; movf ccp1interval3,w ; skpc ; incfsz ccp1interval3,w ; subwf rpmmax_3,w ; bank20 ; skpc ; should we turn off the shift light ? INT_SHIFT_OFF bcf flags2,shlight ; yes, rpm rate is smaller than given maximum, turn shift light (flag) off, flag used in timer skpc ; again, should we turn off the shift light ? clrf portd ; yes, turn shift light off skpnc ; should we turn on the shift light ? INT_SHIFT_ON bsf flags2,shlight ; yes, with this high rpm rate, turn shift light flag on, used in timer interrupt to flash light return ; done, return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- ; Handle UART receive interrupt ;-------------------------------------------------------------------------------------------------------------------------------------- ; input bytes are stored in buffer for later use when the received command is going to be ; interpreted and executed ; check for command byte sequence, if all bytes of a command have been received set the flag ; bit that allows the command execute routine ; a valid command byte sequence is (in ascii): ; <STX> 1 byte indicator for start of command, value hex 02 ; <c1> 1 byte, first letter of command ; <c2> 1 byte, second letter of command ; <data bytes> 0-64 data bytes, all values accepted except ascii codes STX and ETX ; <ETX> 1 byte indicator for end of command, value hex 03 ; <checksum> 1 byte checksum, any hex value 00-FF (incl.hex 03 !), last byte of command ; the checksum byte value makes the sum of all bytes from <STX> up to and including <ETX> zero ; used bits for uart in flags register: ; bit 0 = high : STX received, started reception of rest of command ; bit 1 = high : ETX received, now wait for checksum ; bit 2 = high : command has data bytes ; bit 3 = high : all bytes received, now ready for execution of command INT_RX bank0 bsf portc,cts_out ; clear CTS to hold data stream from computer btfsc rcsta,oerr ; overrun error ? goto OVERFLOW_ERR ; yes, we cannot keep up with the input, go discard input btfsc rcsta,ferr ; no, framing error ? goto FRAMING_ERR ; yes, go discard input movlw b'00000001' ; no, select rx9d/parity bit (we use odd parity) andwf rcsta,w ; store only the parity bit in w register movwf rx_parity ; copy the value to rx_parity movf rcreg,w ; deque received byte movwf rx_byte ; store byte for later use CHECK_PARITY xorwf rx_parity,f ; use parity bit in calculation swapf rx_parity,w ; use w and rx_parity register for the calculation xorwf rx_parity,f ; calculate nibbles rrf rx_parity,w ; xorwf rx_parity,f ; at this point the parity values of the nibbles are in bit 2 and bit 0 btfss rx_parity,2 ; if parity one nibble is 1 then whole byte parity equals that of other nibble, skip ahead incf rx_parity,f ; otherwise, invert bit 0 btfsc rx_parity,0 ; parity error ? goto PARITY_ERR ; yes btfsc flags1,command ; no, did we already receive a command or are we busy executing one ? return ; yes, discard input,seems handshaking is ignored, but we cannot accept a new command right now VALID_BYTE movf rx_byte,w ; if we get here we have received valid input sublw h'02' ; ascii code for 'start of text' (STX) skpnz ; check if byte matches goto COMMAND_START ; match, go set flags to allow reception of rest of command STX? btfss flags1,stx ; no match, but did we already receive the STX byte ? goto NO_ERR ; no, do not use any received byte until STX has been received first ADD_TO_CS movf rx_byte,w ; yes, received byte is in rx_byte, what was it again ? addwf rx_checksum,f ; use all bytes including the checksum byte in the checksum calculation CHECKSUM? btfsc flags1,etx ; did we already receive all bytes of the command and is this the checksum byte ? goto CHECK_SUM ; yes, go test checksum ETX? sublw h'03' ; ascii code for 'end of text' (ETX) skpnz ; did we receive (ETX) and therefore all command and data bytes ? goto GOT_ETX ; yes, go set flag and exit OVERFLOW? movlw rx_buffer66 + 1 ; no, check if pointer has passed the maximum allowed address subwf rx_pointer,w ; see where the pointer is skpnz ; already there ? goto ABORT_COMMAND ; yes, too many data bytes: abort receiving this command STORE movf rx_pointer,w ; get the available address for storage of the newly received data byte movwf rx_maxpos ; store the pointer, keep the position of the last data byte movwf fsr ; use value to set the indirect file address bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) movf rx_byte,w ; what was the received byte again ? movwf indf ; store it in the command input buffer INC_POINTER incf rx_pointer,f ; go point to next position for any following byte goto NO_ERR ; done handling the received byte, return in bank0 COMMAND_START movlw h'02' ; the value of STX should be movwf rx_checksum ; the initial checksum value movlw rx_buffer00 ; first position in the input buffer for command bytes movwf rx_pointer ; use this value to reset pointer movwf rx_maxpos ; reset the pointer to the last received data byte bsf flags1,stx ; set flag 'STX has been received, wait for the rest of the command bytes' bcf flags1,withdata ; clear flag for data bytes goto NO_ERR ; done handling the received byte, return in bank0 CHECK_SUM movf rx_checksum,w ; the checksum is the sum of all bytes added together and should be zero skpz ; is checksum ok ? goto ABORT_COMMAND ; no, go abort the reception of the command CHECK_SIZE movlw rx_buffer01 ; yes, second position in buffer subwf rx_maxpos,w ; test if the last command byte has been placed at the second place or further, skpc ; so did we get at least two command bytes ? goto ABORT_COMMAND ; no, go abort the reception of the command skpz ; did we get more than three bytes ? bsf flags1,withdata ; yes, set flag 'this is a command with data' bsf flags1,command ; set flag to get command executed bcf flags1,stx ; now ok to reset stx flag for a next command bcf flags1,etx ; now ok to reset etx flag for a next command return ; bytes have been handled, return without setting CTS to keep data stream blocked, bank0 return GOT_ETX bsf flags1,etx ; we have received all command and data bytes, now wait for the checksum byte bcf portc,cts_out ; set CTS to allow computer to send data return ; done ABORT_COMMAND bcf flags1,stx ; abort receiving command, bcf flags1,etx ; clear any command bytes received up to now movlw h'15' ; negative acknowledgement (NAK) pagesel TX_BYTE ; make right page selection before call call TX_BYTE ; send 'command has NOT been accepted', return in bank0 pagesel NO_ERR ; make right page selection before call goto NO_ERR ; done handling the received byte, return in bank0 OVERFLOW_ERR movf rcreg,w ; deque byte (discard input byte) movf rcreg,w ; deque byte (discard input byte) bcf rcsta,cren ; clear overrun error bit bsf rcsta,cren ; re-enable receive bcf flags1,stx ; clear any command bytes received up to now bcf flags1,etx ; clear any command bytes received up to now bcf portc,cts_out ; set CTS to allow computer to send data return ; done FRAMING_ERR movf rcreg,w ; we did not deque received byte yet, do so now (discard input byte), update receive flags PARITY_ERR bcf flags1,stx ; clear any command bytes received up to now bcf flags1,etx ; clear any command bytes received up to now NO_ERR bcf portc,cts_out ; set CTS to allow computer to send data return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- ; Start of main program ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- INITIALIZE INIT_INT_OFF clrf intcon ; ensure there are no interrupt requests bank1 ; clrf pie1 ; disable all pheripheral interrupts clrf pie2 ; INIT_CHECKPIC ; ******* check pic integrity: checksum pic program memory, set/reset sram bits INIT_PORTA bank0 ; port A will have five analog inputs (note: port A is set as ANALOG i/o as default) clrf porta ; clear output data latches bank1 ; movlw b'00111111' ; movwf trisa ; make all six pins of port A inputs ; Port A0 = Input, Lambda sensor ; Port A1 = Input, Voltage In ; Port A2 = Input, Thermocouple ; Port A3 = Input, Air Temperature ; Port A4 = Input, clock input 32768 Hz from clock timer chip ; Port A5 = Input, Water Temperature INIT_PORTB bank0 ; port B clrf portb ; clear output data latches, make all outputs low bank1 ; movlw b'00111111' ; movwf trisb ; make port B input & outputs ; Port B0 = Input Run ; Port B1 = Input _Mark_ ; Port B2 = Input Brake ; Port B3 = Input Laptime ; Port B4 = Input _TC disconnected_ ; Port B5 = Input BoardsupplyOn ; Port B6 = Output Status Led Red ; Port B7 = Output Status Led Green INIT_PORTC bank0 ; inputs, communications port to computer (RS232) realtime clock and serial eeprom (IIC) clrf portc ; clear output data latches bank1 ; movlw b'11111110' ; movwf trisc ; set port C configuration ; Port C0 = Output computer CTS ; Port C1 = Input Speed ; Port C2 = Input RPM ; Port C3 = Input* SDA for MSSP IIC, configure as input ; Port C4 = Input* SCL for MSSP IIC, configure as input ; Port C5 = Input computer RTS ; Port C6 = Output* computer RX, configure as input ; Port C7 = Input computer TX INIT_PORTD bank0 ; port D will drive eight pairs of leds (rpm meter/shift light) clrf portd ; clear output data latches, all outputs low bank1 ; movlw b'00000000' ; movwf trisd ; make port D all outputs INIT_PORTE bank0 ; port E will have three analog inputs (note: port E is set as ANALOG i/o as default) clrf porte ; clear output data latches bank1 ; movlw b'00000111' ; make port E all inputs movwf trise ; ; Port E0 = Input Throttle ; Port E1 = Input XAccelleration ; Port E2 = Input YAccelleration INIT_TIMER0 clrwdt ; clear watchdog timer to prevent unintended device reset movlw b'10100001' ; we want 32 Hz interrupts using the 32768 Hz output from clock chip, divide by 4, bank1 ; assign prescaler to timer0, increment from external clock on low-to-high, movwf optionreg ; pull-ups on portb disabled, interrupt on falling edge of B0/int pin bcf intcon,t0ie ; disable interrupt from timer 0, it will be enabled only during logging INIT_TIMER1 bank0 ; use timer 1 as a timer/counter to count instruction cycles movlw b'00000001' ; use internal instruction cycle clock divided by 1, turn on timer movwf t1con ; configure timer 1 clrf tmr1l ; start timer at zero value clrf tmr1h ; start timer at zero value bank1 ; bsf pie1,tmr1ie ; enable interrupt from timer 1 INIT_TIMER2 bank0 ; movlw b'00000000' ; movwf t2con ; disable timer 2 INIT_CCP1 bank1 ; bsf trisc,2 ; make sure pin rc2/ccp1 is configured as input bsf pie1,ccp1ie ; enable interupts from CCP1 module bank0 ; movlw b'00000101' ; capture mode, on every rising edge of pin rc2/ccp1 movwf ccp1con ; INIT_CCP2 bank1 ; bsf trisc,1 ; make sure pin rc1/t1osi/ccp2 is configured as input bsf pie2,ccp2ie ; enable interrupt from CCP2 module bank0 ; movlw b'00000101' ; capture mode, on every rising edge of pin rc1/t1osi/ccp2 movwf ccp2con ; INIT_IIC bank1 ; configure the MSSP Module as IIC bus, PIC is bus master bcf pie1,sspie ; disable interrupt from ssp action bcf pie2,bclie ; disable interrupt from ssp bus collision movlw d'9' ; baud rate calculation: x = ((( Fosc / IICbaudrate)/4)-1) (~100 kHz @ 3.6864Mhz) movwf sspadd ; set IIC baud rate to 100 kHz bcf sspstat,cke ; select IIC input levels bsf sspstat,smp ; set slew rate for standard speed mode (100 kHz) bank0 ; movlw b'00101000' ; enable serial port, master mode movwf sspcon ; configure pagesel IIC_START ; make right program memory page selection call IIC_START ; send initialization sequence (see Microchip AN709): start, 9 ones, start, stop bank0 ; to properly reset eeprom devices on iic bus (when circuit has been reset during write) movlw b'11111111' ; send 8 times 1 movwf sspbuf ; send the slave address bank1 ; pagesel INIT_IIC_LOOP1 ; make right program memory page selection INIT_IIC_LOOP1 btfsc sspstat,r_notw ; is the transmission completed ? goto INIT_IIC_LOOP1 ; no, wait here until it is completed bsf sspcon2,ackdt ; select NOACK bsf sspcon2,acken ; send NOACK, 9th one bit INIT_IIC_LOOP2 btfsc sspcon2,acken ; send completed ? goto INIT_IIC_LOOP2 ; no, wait here until send has been completed pagesel IIC_START ; make right program memory page selection call IIC_START ; call IIC_STOP ; bank1 ; clrf iicchip ; select first eeprom chip INIT_AD bank1 ; movlw b'10000000' ; right justified, five pins of port A and three pins of port E will be analog inputs, movwf adcon1 ; note: more configuration is to be done in a/d subroutine bcf pie1,adie ; disable interrupt from a/d module INIT_UART bank1 ; configure UART for asynchronous communications movlw d'3' ; value for baudrate (23:9600, 11:19200, 3:57600, 1:115200 baud Fosc=3.6864 MHz) movwf spbrg ; set UART to this value movlw b'01000110' ; 9 bit, Tx off, async, high speed (transmit: 8 data bits, odd parity , 1 stop bit) movwf txsta ; load Tx status register bank0 ; movlw b'01010000' ; serial port disabled, 9 bit, Rx off (receive: 8 data bits, odd parity, 1 stop bit) movwf rcsta ; load Rx status register bsf rcsta,spen ; enable reception bank1 ; bsf txsta,txen ; enable transmission bsf pie1,rcie ; enable interrupt on receive bcf portc,cts_out ; set CTS to allow computer to send data INIT_CLOCK movlw d'7' ; location of clock control byte bank2 ; movwf clockaddr ; movlw b'10000011' ; clock control byte, set square wave at 32768 Hz but still disabled and it's output high call IIC_WR_CLKCHIP ; write byte to control bytes or static ram of clock chip, returns in bank1 INIT_EEPROM nop ; ****** see if datalogger internal eeprom has ever been intialized, otherwise set defaults INIT_VARIABLES clrf flags1 ; clear flag register1 clrf flags2 ; clear flag register2 bank2 ; clrf timer1y ; range extension for timer1 byte three clrf timer1z ; range extension for timer1 byte four clrf new1cap0 ; make sure the rpm and speed values start at zero when there are no input pulses clrf new1cap1 ; clrf new1cap2 ; clrf new1cap3 ; clrf new2cap0 ; clrf new2cap1 ; clrf new2cap2 ; clrf new2cap3 ; clrf lastintr0 ; clrf lastintr1 ; clrf lastintr2 ; clrf lastintr3 ; clrf lastints0 ; clrf lastints1 ; clrf lastints2 ; clrf lastints3 ; bank3 ; clrf current_rec ; no record selected for download pagesel COPY_RPMVALUES ; make right program memory page selection call COPY_RPMVALUES ; call all routines seperately because they have all returns call COPY_WHEELC ; to be able to use them individually, return with page setting... call COPY_LOGRATES ; pagesel COPY_ERRORFLAGS ; restore program memory page selection call COPY_ERRORFLAGS ; get values maximum rpm rate, wheel circumference, lograte values, error flag bits INIT_INT_ON bank0 clrf pir1 ; clear all pheripheral interrupt request flags clrf pir2 ; bsf intcon,peie ; enable peripheral interrupts bsf intcon,gie ; enable all interrupts INIT_READY bsf portb,led_red ; turn on red status led as indication power on and software initialized INIT_RUN ; empty line to avoid mplab error pagesel MAIN ; make right program memory page selection goto MAIN ; all initialization has been done, go run main code ;-------------------------------------------------------------------------------------------------------------------------------------- COPY_RPMVALUES ; reads the maximum rpm value from pic eeprom addresses, from this value the interval is ; calculated that will be used to turn on the shift light when the measured rpm rate is ; larger than the given maximum ; calculation below is for one pulse per revolution ; a correction is done for two pulses per revolution ; engine RPM rate calculation, see also INT_CCP1 ; F [Hz] = 1 / t [s] ; RPM = 60 / t [s] ; RPM = 60 * timer1clockrate / interval [timer cycles] ; RPM = (60 * 3686400/4) Mhz / interval [instruction cycles] ; RPM = 55,296,000 / interval [instruction cycles] ; RPM = 55,296,000 / (capturevalue - previouscapturevalue) ; RPM = 55,296,000 / (new1cap - old1cap) ; quotient = numerator / denominator ; see also CALC_RPM and COPY_RPM routines ; calculate interval (input values are 32 bits, the result is 32 bits): ; t [s] = 1 / F [Hz] ; t [s] = 60 / RPMMAX ; interval [timer cycles] = 60 * timer1clockrate / RPMMAX ; interval [instruction cycles] = (60 * 3686400/4) MHz / RPMMAX ; interval [instruction cycles] = 55,296,000 / RPMMAX ; interval [instruction cycles] = 55,296,000 / RPMMAX ; interval [instruction cycles] = 55,296,000 / RPMMAX ; interval [instruction cycles] = 55,296,000 / RPMMAX ; rpmmax_3&2&1&0 = 55,296,000 / rpmmax_high&low ; quotient = numerator / denominator ; numerator : nrator3 nrator2 nrator1 nrator0 ; denominator: denom_r3 denom_r2 denom_r1 denomr_0 ; quotient : rpmmax_3 rpmmax_2 rpmmax_1 rpmmax_0 ; remainder : remain3 remain2 remain1 remain0 ; the remainder R is not used ; interval : rpmmax_3 rpmmax_2 rpmmax_1 rpmmax_0 ; rpm max : rpmmax_high rpmmax_low COPY_PULSES movlw d'4' ; pic eeprom address of low byte of rpm maximum pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf pulses ; store value COPY_RPM_READ movlw d'2' ; pic eeprom address of low byte of rpm maximum call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf rpmmax_low ; store value, low byte movlw d'3' ; eeprom address of high byte of rpm maximum call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf rpmmax_high ; store value, high byte pagesel COPY_RPM_DIV ; make right program memory page selection COPY_CORRECTION btfsc pulses,0 ; do we have one pulse per revolution ? goto COPY_RPM_DIV ; yes, go use the value as it is clrc ; no, multiply the maxrpm value by two to correct for the number of pulses per revolution rlf rpmmax_low ; low byte rlf rpmmax_high ; high byte COPY_RPM_DIV bank2 ; movlw d'3' ; set numerator X = 55,296,000 = 3 : 75 : 192 : 0 movwf nrator3 ; movlw d'75' ; movwf nrator2 ; movlw d'192' ; movwf nrator1 ; movlw d'0' ; movwf nrator0 ; clrf denom_r3 ; get denominator clrf denom_r2 ; movf rpmmax_high,w ; movwf denom_r1 ; movf rpmmax_low,w ; movwf denom_r0 ; movlw d'32' ; there are 32 bits in this division movwf divcounter ; clrf remain0 ; clear remainder clrf remain1 ; clrf remain2 ; clrf remain3 ; COPY_RPM_LOOP clrc ; rlf nrator0,f ; shift next bit to remainder (msbit numerator to lsbit remainder) rlf nrator1,f ; rlf nrator2,f ; rlf nrator3,f ; rlf remain0,f ; rlf remain1,f ; rlf remain2,f ; rlf remain3,f ; COPY_RPM_TEST movf denom_r3,w ; subtract denominator from remainder, if no borrow then next bit of quotient is 1 subwf remain3,w ; if borrow next bit of the quotient is 0 skpz ; check, is the result of remain3 - denom3 exactly 0 ? goto COPY_RPM_NOTZ ; no, go check for negative result movf denom_r2,w ; yes, continue subwf remain2,w ; do test subtraction skpz ; check, is the result of remain2 - denom2 exactly 0 ? goto COPY_RPM_NOTZ ; no, go check for negative result movf denom_r1,w ; yes, continue subwf remain1,w ; do test subtraction skpz ; check, is the result of remain1 - denom1 exactly 0 ? goto COPY_RPM_NOTZ ; no, go check for negative result movf denom_r0,w ; yes, continue subwf remain0,w ; do test subtraction COPY_RPM_NOTZ skpc ; is the result of any remain - denom less than 0 thus negative ? goto COPY_RPM_NOGO ; yes, skip subtraction, this quotient bit will be zero COPY_RPM_SUB2 movf denom_r0,w ; no, start with real subtraction, the resulting interval is put in denominator subwf remain0,f ; movf denom_r1,w ; skpc ; is remain0 - denom0 < 0 ? incfsz denom_r1,w ; yes, 'borrow' from more significant byte subwf remain1,f ; no, borrow has been skipped, do subtraction movf denom_r2,w ; skpc ; is remain1 - denom1 < 0 ? incfsz denom_r2,w ; yes, 'borrow' from more significant byte subwf remain2,f ; no, borrow has been skipped, do subtraction movf denom_r3,w ; skpc ; is remain2 - denom2 < 0 ? incfsz denom_r3,w ; yes, 'borrow' from more significant byte subwf remain3,f ; no, borrow has been skipped, do subtraction setc ; this quotient bit is one COPY_RPM_NOGO rlf rpmmax_0,f ; shift bit into quotient result rlf rpmmax_1,f ; shift bit into quotient result rlf rpmmax_2,f ; shift bit into quotient result rlf rpmmax_3,f ; shift bit into quotient result decfsz divcounter,f ; goto COPY_RPM_LOOP ; go do next bit return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- COPY_WHEELC ; reads the wheel circumference in millimeters from pic eeprom, ; multiplies this value by 3318 and stores the result in speed_const0..3 ; please see INT_CCP2 code for details ; to be used in the calculate speed/ccp2 interrupt routine ; calculate product (input values are 16 bits, the result is 32 bits): ; number1 : - - mult_a1 mult_a0 ; number2 : - - mult_b1 mult_b0 ; result P : speed_const3 speed_const2 speed_const1 speed_const0 ; for minimum execution time number1 should be the smaller number of the two MULT16X16 bank0 ; multiply the two 16-bit numbers 3318 and circumference and store the 32 bit result movlw d'0' ; eeprom address of low byte of wheel diameter pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf mult_a0 ; store first number in multiplication, low byte bank0 ; movlw d'1' ; eeprom address of high byte of wheel diameter call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf mult_a1 ; store first number in multiplication, high byte movlw d'246' ; 3318 movwf mult_b0 ; store second number in multiplication, low byte movlw d'12' ; movwf mult_b1 ; store second number in multiplication, high byte clrf speed_const3 ; clear all four bytes of the 32 bit result clrf speed_const2 ; clrf speed_const1 ; clrf speed_const0 ; bsf speed_const1,7 ; set the 16th bit so we can use the speed_const registers as bit counter clrc ; start off with clear carry MULTLOOP rrf mult_a1,f ; rrf mult_a0,f ; pagesel MULTSHIFT ; make right program memory page selection skpc ; was the least significant bit a one ? goto MULTSHIFT ; no, bypass addition movf mult_b0,w ; yes, do addition addwf speed_const2,f ; add first of two bytes movf mult_b1,w ; skpnc ; check for overflow after add and incfsz mult_b1,w ; increment high byte if necessary addwf speed_const3,f ; add second of the two bytes MULTSHIFT rrf speed_const3,f ; shift to next position rrf speed_const2,f ; rrf speed_const1,f ; rrf speed_const0,f ; skpc ; are we done with the multiplication ? goto MULTLOOP ; no, next return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- COPY_LOGRATES ; copy the values from pic eeprom addresses to registers movlw d'16' ; internal eeprom address pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 bank3 ; movwf freq_rpm ; store value movlw d'17' ; call IEE_READ ; bank3 ; movwf freq_speed ; movlw d'18' ; call IEE_READ ; bank3 ; movwf freq_lambda ; movlw d'19' ; call IEE_READ ; bank3 ; movwf freq_voltage ; movlw d'20' ; call IEE_READ ; bank3 ; movwf freq_tc ; movlw d'21' ; call IEE_READ ; bank3 ; movwf freq_air ; movlw d'22' ; call IEE_READ ; bank3 ; movwf freq_water ; movlw d'23' ; call IEE_READ ; bank3 ; movwf freq_throttle ; movlw d'24' ; call IEE_READ ; bank3 ; movwf freq_long ; movlw d'25' ; call IEE_READ ; bank3 ; movwf freq_lat ; movlw d'26' ; call IEE_READ ; bank3 ; movwf freq_mark ; movlw d'27' ; call IEE_READ ; bank3 ; movwf freq_brake ; return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- COPY_ERRORFLAGS ; copy the value of the error flags register from pic eeprom addresses to the register movlw d'15' ; internal eeprom address pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read pic eeprom, address in w, data returned in w, returns in bank2 movwf errors ; store value return ; done ;--------------------------------------------------------------------------------------------------------------------------- FLASHREAD ; read from a location in the flash program memory ; address should be in eeadrh(bank2) and eeadr(bank2) ; data is returned in eedath(bank2) and eedata(bank2) bank3 ; bsf eecon1,eepgd ; point to flash program memory bsf eecon1,rd ; start read operation nop ; processor has to wait while data is being read nop ; wait return ; return in bank3 ;--------------------------------------------------------------------------------------------------------------------------- FLASHWRITE ; write to a location in the flash program memory ; address should be in eeadrh(bank2) and eeadr(bank2) ; data should be in eedath(bank2) and eedata(bank2) ; data will be verified, carry set means error, carry cleared means write was ok ; uses templow and tempmiddle registers during verification setc ; set error flag, presuming error bank2 ; movf eedata,w ; make a copy of the dataword value to use after the write movwf templow ; to check if the write was ok movf eedath,w ; movwf tempmiddle ; bank3 ; bsf eecon1,eepgd ; point to flash program memory bsf eecon1,wren ; enable writes movlw h'55' ; sequence needed to unlock pic write safety lock, movwf eecon2 ; used to prevent adverse writes movlw h'AA' ; movwf eecon2 ; bsf eecon1,wr ; start write operation nop ; two nops allow pic to setup for write and then nop ; the processor will stop execution for the duration of the entire write cycle bcf eecon1,wren ; disable writes call FLASHREAD ; read the value of the flash program memory location into eedata and eedath bank2 ; movf eedata,w ; copy the low byte value to w subwf templow,w ; compare it with the stored value to see if there was a write error skpz ; was there a write error in the low byte ? return ; yes, return with error flag (carry) set, return in bank2 movf eedath,w ; no, now check high byte subwf tempmiddle,w ; compare it with the stored value to see if there was a write error skpz ; was there a write error in the high byte ? return ; yes, return with error flag (carry) set, return in bank2 clrc ; reset error flag return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- org h'0800' ; start of program memory page 1 ; Note: The contents of the PCLATH register are unchanged after a RETURN or RETFIE instruction ; is executed ! The user must rewrite the contents of the PCLATH register for any subsequent ; subroutine calls or GOTO instructions ;-------------------------------------------------------------------------------------------------------------------------------------- MAIN ; main program code MAIN_ONLOOP ; program continously loops to here while rotary switch is set to 'on', pagesel EXEC_COMMAND ; prepare the right memory page in case we do call btfsc flags1,command ; commands are received via interrupt routine, has a complete command been put in the buffer ? call EXEC_COMMAND ; yes, handle it bank0 ; no, see if the position of the rotary switch has changed from 'on' to 'log' pagesel MAIN_ONLOOP ; make right program memory page selection btfss portb,switch ; is the position of the rotary switch currently 'log' ? goto MAIN_ONLOOP ; no, go back and see if a command has arrived we should handle btfsc flags1,stx ; yes, are we receiving a command at the moment ? goto MAIN_ONLOOP ; yes, finish reception first to minimize communication errors MAIN_LOGTEST bank0 ; we get here if the rotary switch is set to log bsf portc,cts_out ; clear CTS to hold data stream from computer, we need all processor time for bcf rcsta,cren ; the logging, so stop reception and ignore any incoming commands bcf portb,led_red ; turn off the red led bsf portb,led_green ; turn on the green led bank3 ; we want to make sure there are channels enabled for logging movf freq_rpm,w ; so check all channels for their setting andwf freq_speed,w ; andwf freq_lambda,w ; andwf freq_voltage,w ; andwf freq_tc,w ; andwf freq_air,w ; andwf freq_water,w ; andwf freq_throttle,w ; andwf freq_long,w ; andwf freq_lat,w ; andwf freq_mark,w ; andwf freq_brake,w ; andlw b'10000000' ; bit seven will be set if no channels are enabled skpz ; are there any channels enabled for logging ? goto MAIN_FLASHLED ; no, all channels are turned off, go flash status led MAIN_LOGSTART ; **** read errors flag register from eeprom call MEM_OPEN ; yes, initialize memory, get location for new data, store startdate and -time, bank1 return bcf flags2,lognow ; before starting actual logging clear this flag, it will be set during every timer0 interrupt bank0 ; clrf tmr0 ; clear timer0 register bcf intcon,t0if ; clear the timer 0 overflow flag movlw d'7' ; location of control byte in clock chip bank2 ; turn square wave of real time clock chip on movwf clockaddr ; select this location movlw b'10010011' ; clock control byte, set square wave at 32768 Hz, enabled call IIC_WR_CLKCHIP ; write control byte to clock chip, bank1 return movlw d'255' ; we want to start logging and get a value stored for bank3 ; all channels so use 255 as value since the register value movwf logcounter ; will be increased to zero (log all channels) the first time MAIN_LOGLOOP movlw d'7' ; show to the user how much room for storing the data there is left bank1 ; up to ca. 90% (seven out of eight chips) memory filled only green led is on, subwf mem_chip,w ; above 90% full the red led is also turned on: red and green together (extra bright) bank0 ; see how many of the eeprom chips we have used so far skpnc ; have we started filling the last eeprom chip ? bsf portb,led_red ; yes, turn on the red led as well btfsc flags2,memfull ; is all memory completely full ? goto MAIN_LOGSTOP ; yes, exit logloop to do cleanup and then flash red led to notify user btfsc intcon,t0if ; no, did we get a timer0 overflow interrupt so should we log data ? call LOGDATA ; yes, actual measurement for the different input channels and the data storage is done here bank0 ; no, btfsc portb,switch ; has the position of the rotary switch been changed back to 'on' ? goto MAIN_LOGLOOP ; no, keep doing the logging stuff MAIN_LOGSTOP bank2 ; yes, go turn off square wave of real time clock chip to save battery power movlw d'7' ; location of control byte in clock chip movwf clockaddr ; point to this location movlw b'10000011' ; set control value to square wave at 32768 Hz but disabled, output high call IIC_WR_CLKCHIP ; write control byte to clock chip, bank1 return call MEM_CLOSE ; write last data block to eeprom, write end position to toc, return in unknown bank bank0 ; we use this logstop routine in two cases, normal stop and memory full, which one was it ? btfss portb,switch ; has the position of the rotary switch been changed back to 'on' ? goto MAIN_CLEANUP ; yes, skip memory full MAIN_MEMFULL bsf errors,err_mf ; set error flag MAIN_FLASHLED bank0 ; we will flash red status led at about 2 Hz to notify user that the memory is full bcf portb,led_green ; turn off the green status led MAIN_FLASHLOOP bank2 btfsc timer1y,2 ; use timer1y bit for flash rate bsf portb,led_red ; turn on red status led btfss timer1y,2 ; bcf portb,led_red ; turn off red status led bank0 ; btfsc portb,switch ; has the position of the rotary switch been changed back to 'on' ? goto MAIN_FLASHLOOP ; no, keep waiting until the user to switches from 'log' back to 'on' status MAIN_CLEANUP movlw d'15' ; eeprom address for error flags register bank2 ; movwf iee_address ; set internal eeprom address pointer movf errors,w ; get the value of the error flags register call IEE_WRITE ; write data to eeprom, address in iee_address, data in w bank0 ; bsf rcsta,cren ; re-enable reception for incoming commands bcf portc,cts_out ; set CTS to re-enable data stream from computer bcf portb,led_green ; turn off the green status led bsf portb,led_red ; turn on the red status led goto MAIN_ONLOOP ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ; Handle logging flag (set during Timer0 interrupt) log data to external eeprom ;-------------------------------------------------------------------------------------------------------------------------------------- LOGDATA ; timer0 is used as the timebase for the logging event ; when logging is active this routine is called 32 times every second ; acquire input data and move it to the external eeprom ; check which channels need to be logged ; lograte table: ; 00000000 32 Hz ; 00000001 16 Hz ; 00000011 8 Hz ; 00000111 4 Hz ; 00001111 2 Hz ; 00011111 1 Hz or every second ; 00111111 1/2 Hz or every 2 seconds ; 01111111 1/4 Hz or every 4 seconds ; 1xxxxxxx never LOG_CLEARFLAG bcf intcon,t0if ; clear the flag that brought us here (timer 0 overflow) bank3 ; incf logcounter,f ; counter is increased every time, so the very first time it will be 0 bsf logcounter,7 ; this bit is used to skip channels so we want it always set LOG_RPM movf freq_rpm,w ; andwf logcounter,w ; compare counter to the bits of the lograte setting (see above) skpz ; is the result zero and should we take action ? goto LOG_SPEED ; no, see if we should log the next channel call CALC_RPM ; yes, calculate the RPM value from the time interval between the input pulses, return in bank2 movf rpm_low,w ; get low byte value (two bytes altogether for 0..16383 RPM) movwf numlow ; movf rpm_high,w ; get high byte value movwf nummiddle ; call MEM_ADD14 ; write fourteen bits to the external eeprom LOG_SPEED bank3 ; movf freq_speed,w ; andwf logcounter,w ; skpz ; goto LOG_LAMBDA ; call CALC_SPEED ; calculate speed value from time interval between input pulses, return in bank2 movf speed,w ; get value, maximum speed is limited to 255 km/hr (see ccp2 interrupt) movwf numlow ; copy value call MEM_ADD8 ; LOG_LAMBDA bank3 ; movf freq_lambda,w ; andwf logcounter,w ; skpz ; goto LOG_VOLTAGE ; movlw d'0' ; lambda is analog channel 0 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_VOLTAGE bank3 ; movf freq_voltage,w ; andwf logcounter,w ; skpz ; goto LOG_TC ; movlw d'1' ; 0..5 V voltage input is analog channel 1 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_TC bank3 ; movf freq_tc,w ; andwf logcounter,w ; skpz ; goto LOG_AIRTEMP ; movlw d'2' ; thermocouple is analog channel 2 bank0 ; btfss portb,not_tcd ; is the thermocouple disconnected ? bsf errors,tcdiscon ; yes, set error flag call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_AIRTEMP bank3 ; movf freq_air,w ; andwf logcounter,w ; skpz ; goto LOG_WATERTEMP ; movlw d'3' ; air temperature is analog channel 3 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_WATERTEMP bank3 ; movf freq_water,w ; andwf logcounter,w ; skpz ; goto LOG_THROTTLE ; movlw d'4' ; water temperature is analog channel 4 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_THROTTLE bank3 ; movf freq_throttle,w ; andwf logcounter,w ; skpz ; goto LOG_LONG ; movlw d'5' ; throttle is analog channel 5 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_LONG bank3 ; movf freq_long,w ; andwf logcounter,w ; skpz ; goto LOG_LAT ; movlw d'6' ; longitudinal acceleration is analog channel 6 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_LAT bank3 ; movf freq_lat,w ; andwf logcounter,w ; skpz ; goto LOG_MARK ; movlw d'7' ; lateral accelation is analog channel 7 call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 call MEM_ADD10 ; LOG_MARK bank3 ; movf freq_mark,w ; andwf logcounter,w ; skpz ; goto LOG_BRAKE ; clrw ; start with clearing w register bank0 ; btfss portb,not_mark ; test if mark input is high, use inverse value for not_mark signal movlw b'00000001' ; change if the value should be 1 call MEM_ADD1 ; LOG_BRAKE bank3 ; movf freq_brake,w ; andwf logcounter,w ; skpz ; goto LOG_CHK_OVERFL ; clrw ; start with clearing w register bank0 ; btfsc portb,brake ; test if brake input is high movlw b'00000001' ; change if the value should be 1 call MEM_ADD1 ; LOG_CHK_OVERFL btfsc intcon,t0if ; check for log event overflow, we just handled a log event, did we get a new request ? bsf errors,logoflow ; yes, set flag LOG_DONE return ; no, done ;-------------------------------------------------------------------------------------------------------------------------------------- ; Calculate the RPM rate ;-------------------------------------------------------------------------------------------------------------------------------------- CALC_RPM ; calculate RPM (input values are 32 bits, the result is 16 bits): ; numerator : nrator3 nrator2 nrator1 nrator0 ; denominator: denom_r3 denom_r2 denom_r1 denom_r0 ; quotient : - - rpm_high rpm_low ; remainder : remain3 remain2 remain1 remain0 ; only the lower 16 bits of the 32 bit quotient are used as rpm result ; the remainder R is not used ; after that even more bits are thrown away, a maximum rpm rate of 16383 rpm is ; more than sufficient and only needs 14 bits ; see also INT_CCP1 routine CALC_RPM_COPY bcf intcon,gie ; disable interrupts during copy bank2 ; movf ccp1interval3,w ; copy rpm interval for later use in division routine movwf denom_r3 ; movf ccp1interval2,w ; movwf denom_r2 ; movf ccp1interval1,w ; movwf denom_r1 ; movf ccp1interval0,w ; movwf denom_r0 ; these values are used to calculate the rpm rate bsf intcon,gie ; re-enable interrupts CALC_RPM_DIV movlw d'3' ; set numerator X = 55,296,000 = 3 : 75 : 192 : 0 movwf nrator3 ; movlw d'75' ; movwf nrator2 ; movlw d'192' ; movwf nrator1 ; movlw d'0' ; movwf nrator0 ; movlw d'32' ; there are 32 bits in this division movwf divcounter ; clrf rpm_low ; clear rpm result so we can check for 2 byte overflow (rpm > 65535) clrf rpm_high ; clrf remain0 ; clear remainder clrf remain1 ; clrf remain2 ; clrf remain3 ; CALC_RPM_LOOP clrc ; rlf nrator0,f ; shift next bit to remainder (msbit numerator to lsbit remainder) rlf nrator1,f ; rlf nrator2,f ; rlf nrator3,f ; rlf remain0,f ; rlf remain1,f ; rlf remain2,f ; rlf remain3,f ; CALC_RPM_TEST movf denom_r3,w ; subtract denominator from remainder, if no borrow then next bit of quotient is 1 subwf remain3,w ; if borrow next bit of the quotient is 0 skpz ; check, is the result of remain3 - denom3 exactly 0 ? goto CALC_RPM_NOTZ ; no, go check for negative result movf denom_r2,w ; yes, continue subwf remain2,w ; do test subtraction skpz ; check, is the result of remain2 - denom2 exactly 0 ? goto CALC_RPM_NOTZ ; no, go check for negative result movf denom_r1,w ; yes, continue subwf remain1,w ; do test subtraction skpz ; check, is the result of remain1 - denom1 exactly 0 ? goto CALC_RPM_NOTZ ; no, go check for negative result movf denom_r0,w ; yes, continue subwf remain0,w ; do test subtraction CALC_RPM_NOTZ skpc ; is the result of any remain - denom less than 0 thus negative ? goto CALC_RPM_NOGO ; yes, skip subtraction, this quotient bit will be zero CALC_RPM_SUB2 movf denom_r0,w ; no, start with real subtraction subwf remain0,f ; movf denom_r1,w ; skpc ; is remain0 - denom0 < 0 ? incfsz denom_r1,w ; yes, 'borrow' from more significant byte subwf remain1,f ; no, borrow has been skipped, do subtraction movf denom_r2,w ; skpc ; is remain1 - denom1 < 0 ? incfsz denom_r2,w ; yes, 'borrow' from more significant byte subwf remain2,f ; no, borrow has been skipped, do subtraction movf denom_r3,w ; skpc ; is remain2 - denom2 < 0 ? incfsz denom_r3,w ; yes, 'borrow' from more significant byte subwf remain3,f ; no, borrow has been skipped, do subtraction setc ; this quotient bit is one CALC_RPM_NOGO rlf rpm_low,f ; shift bit into quotient result, store lower 16 bits of quotient as result rlf rpm_high,f ; throw away the upper 16 bits skpnc ; do we have a rpm rate of more than 65535 rpm ? goto CALC_RPM_OFLOW ; yes, the result will not fit in the 16 bits of rpm_low and rpm_high, exit decfsz divcounter,f ; goto CALC_RPM_LOOP ; go do next bit CALC_RPM_2PULS btfsc pulses,0 ; do we have only one puls per revolution of the crankshaft ? goto CALC_RPM_14BIT ; yes, we do not need to adjust the value rrf rpm_high,f ; no, so we have two pulses per revolution, we have to divide the value by two rrf rpm_low,f ; no need to clear carry, it was already 'cleared' by previous instructions CALC_RPM_14BIT movlw b'11000000' ; test value to see if we use the upper 2 bits of the 16 bit rpm value andwf rpm_high,w ; do the test skpz ; is the rpm value more than 16383 (the maximum value that will fit in 14 bits) ? goto CALC_RPM_OFLOW ; yes, go set to maximum value (16383) return ; no, we're done here, return in bank2 CALC_RPM_OFLOW movlw d'255' ; we have an overflow, set to 14 bit maximum (16383) instead movwf rpm_low ; movlw d'63' ; movwf rpm_high ; return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- ; Calculate the Speed value ;-------------------------------------------------------------------------------------------------------------------------------------- CALC_SPEED ; since we can have both timer 1 overflow and ccp interrupt request at the same ; time it is important to update the timer 1 extension bytes at the right time, ; now see if we can use the present timer 1 values to calculate the vehicle speed ; from CCP module 2 using the time (t) between two captures, otherwise we exit this ; routine and come back later when timer 1 has been incremented ; we assume there is one puls per revolution of the wheel ; t [s] = time between pulses = 1 / rotation frequency of wheel = 1 / F [Hz] ; c [mm] = circumference wheel = distance per revolution of the wheel ; SPEED [mm/s] = F * c ; SPEED [km/hr] = (F * c * 3600) / 1000000 ; SPEED [km/hr] = ((1 / t) * c * 3600) / 1000000 ; SPEED [km/hr] = (c * 3600) / (t * 1000000) ; SPEED [km/hr] = (c * 3600) / ((1 / (timer1clockrate / interval)) * 1000000) ; SPEED [km/hr] = (c * 3600) / ((1 / (3686400 Hz / interval)) * 1000000) ; SPEED [km/hr] = (921600 * c * 3600) / (interval * 1000000) ; SPEED [km/hr] = (3318 * c) / interval ; SPEED [km/hr] = (3318 * c) / (capturevalue - previouscapturevalue) ; the value 3318 * c has been calculated during intialization at processor reset ; and is stored in speed_const0..3 (value 3318 is actually 3317.76) ; calculate interval (32 bits): ; current = timer1z timer1y ccpr1h ccpr1l ; new = new2cap3 new2cap2 new2cap1 new2cap0 ; old = old2cap3 old2cap2 old2cap1 old2cap0 ; interval = denom_s3 denom_s2 denom_s1 denom2_0 ; calculate speed (input values are 32 bits, the result is 16 bits): ; quotient Q = numerator X / denominator Y (and remainder R) ; numerator : nrator3 nrator2 nrator1 nrator0 ; denominator: denom_s3 denom_s2 denom_s1 denom2_0 ; result Q : - - - speed ; remainder : remain3 remain2 remain1 remain0 ; only the lower 8 bits of the 32 bit quotient are used as speed result, ; the other bits are thrown away since a top speed of 255 km/hr is more than ; sufficient and can be stored as just one byte ; final speed value (0..255 km/hr) is stored in speed register in bank2 CALC_SPEED_COPY bcf intcon,gie ; disable interrupts during copy bank2 ; movf ccp2interval3,w ; copy speed interval for use in division routine movwf denom_s3 ; movf ccp2interval2,w ; movwf denom_s2 ; movf ccp2interval1,w ; movwf denom_s1 ; movf ccp2interval0,w ; movwf denom_s0 ; use these values to calculate vehicle speed bsf intcon,gie ; re-enable interrupts CALC_SPEED_DIV movf speed_const3,w ; set numerator X = 3318 * circumference movwf nrator3 ; movf speed_const2,w ; movwf nrator2 ; movf speed_const1,w ; movwf nrator1 ; movf speed_const0,w ; movwf nrator0 ; movlw d'32' ; there are 32 bits in this division movwf divcounter ; clrf speed ; clear speed result so we can check for 1 byte overflow (speed > 255) clrf remain0 ; clear remainder clrf remain1 ; clrf remain2 ; clrf remain3 ; CALC_SPEED_LOOP clrc ; rlf nrator0,f ; shift next bit to remainder (msbit numerator to lsbit remainder) rlf nrator1,f ; rlf nrator2,f ; rlf nrator3,f ; rlf remain0,f ; rlf remain1,f ; rlf remain2,f ; rlf remain3,f ; CALC_SPEED_TEST movf denom_s3,w ; subtract denominator from remainder, if no borrow then next bit of quotient is 1 subwf remain3,w ; if borrow next bit of the quotient is 0 skpz ; check, is the result of remain3 - denom3 exactly 0 ? goto CALC_SPEED_NOTZ ; no, go check for negative result movf denom_s2,w ; yes, continue subwf remain2,w ; do test subtraction skpz ; check, is the result of remain2 - denom2 exactly 0 ? goto CALC_SPEED_NOTZ ; no, go check for negative result movf denom_s1,w ; yes, continue subwf remain1,w ; do test subtraction skpz ; check, is the result of remain1 - denom1 exactly 0 ? goto CALC_SPEED_NOTZ ; no, go check for negative result movf denom_s0,w ; yes, continue subwf remain0,w ; do test subtraction CALC_SPEED_NOTZ skpc ; is the result of any remain - denom less than 0 thus negative ? goto CALC_SPEED_NOGO ; yes, skip subtraction, this quotient bit will be zero CALC_SPEED_RSUB movf denom_s0,w ; no, start with real subtraction subwf remain0,f ; movf denom_s1,w ; skpc ; is remain0 - denom0 < 0 ? incfsz denom_s1,w ; yes, 'borrow' from more significant byte subwf remain1,f ; no, borrow has been skipped, do subtraction movf denom_s2,w ; skpc ; is remain1 - denom1 < 0 ? incfsz denom_s2,w ; yes, 'borrow' from more significant byte subwf remain2,f ; no, borrow has been skipped, do subtraction movf denom_s3,w ; skpc ; is remain2 - denom2 < 0 ? incfsz denom_s3,w ; yes, 'borrow' from more significant byte subwf remain3,f ; no, borrow has been skipped, do subtraction setc ; this quotient bit is one CALC_SPEED_NOGO rlf speed,f ; shift bit into quotient result, store lower 8 bits of quotient as result skpnc ; do we have a speed of more than 255 km/hr ? goto CALC_SPEED_OFLW ; yes, the result will not fit in the 8 bits of speed register, exit decfsz divcounter,f ; goto CALC_SPEED_LOOP ; go do next bit return ; we're done here, return in bank2 CALC_SPEED_OFLW movlw d'255' ; we have an overflow, set to 8 bit maximum (255) instead movwf speed ; return ; done, return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- ; analog input subroutine ;-------------------------------------------------------------------------------------------------------------------------------------- GET_ANALOG ; get 10 bit value of one analog input ; 3 bit channel number should be in w register (0..7) ; w register content is destroyed ; value is returned in numlow and nummiddle movwf adtemp ; use adtemp register in channel selection calculation swapf adtemp,f ; move channel selection bits to the right position rrf adtemp,w ; move channel selection bits to the right position, no need to clear carry: andlw b'00111000' ; mask out all but the three bits that hold channel number iorlw b'01000000' ; Fosc/8 gives 2.2 us bit conversion time@Fosc=3.6864 MHz), channel 0, a/d module off bank0 ; movwf adcon0 ; apply settings bsf adcon0,adon ; activate a/d module movlw d'7' ; wait the required acquisition time (approx. 20 microseconds), which is movwf adtemp ; about 19 instruction cycles @ 3.6864 Mhz (1085 ns per instruction) ADLOOP1 decfsz adtemp,f ; count down from to zero, this instruction is one cycle goto ADLOOP1 ; this instruction is two cycles, wait until we are done (7*3*1.085=22.8 us) bsf adcon0,go_notdone ; now start conversion ADLOOP2 btfsc adcon0,go_notdone ; is conversion done ? goto ADLOOP2 ; no, wait here until conversion is completed bcf adcon0,0 ; shut-off a/d module for minimal power consumption movf adresh,w ; store results, note that this will also give us the neccesary delay of 2 Tad movwf nummiddle ; between two a/d sampling actions (1.085 us per instruction @ 3.6864 Mhz ) bank1 ; movf adresl,w ; movwf numlow ; return ; return in bank1 ;-------------------------------------------------------------------------------------------------------------------------------------- ; PIC internal EEPROM read and write routines ;-------------------------------------------------------------------------------------------------------------------------------------- IEE_READ ; reads one byte from PIC EEPROM ; address should be in w ; data byte is returned in w ; returns in bank 2 bank2 ; movwf eeadr ; register address (0-255 decimal for PIC16F877) bank3 ; bcf eecon1,eepgd ; select eeprom data memory for read/write access instead of program memory bsf eecon1,rd ; set bit to read bank2 ; movf eedata,w ; return ; ;-------------------------------------------------------------------------------------------------------------------------------------- IEE_WRITE ; writes one byte to PIC EEPROM ; address should be in iee_address (bank2), data should be in w ; w content is destroyed ; returns in bank 0 bank3 ; btfsc eecon1,wr ; is there currently a write cycle busy ? goto $-1 ; wait here for previous write to finish bank2 ; movwf eedata ; set data movf iee_address,w ; get address movwf eeadr ; select address bank3 ; bcf eecon1,eepgd ; select eeprom data memory for read/write access instead of program memory bsf eecon1,wren ; write enable bcf intcon,gie ; disable all interrupts btfsc intcon,gie ; check if disabled goto $-2 ; else try again movlw h'55' ; required sequence movwf eecon2 ; movlw h'AA' ; movwf eecon2 ; bsf eecon1,wr ; start write bsf intcon,gie ; re-enable interrupts bcf eecon1,wren ; disable writes (does not affect current write cycle) bank0 ; btfss pir2,eeif ; goto $-1 ; wait here for the write to complete bcf pir2,eeif ; clear eeprom write interrupt flag return ; return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- ; IIC subroutines ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_IDLE bank1 ; use this subroutine for interrupt driven IIC communication btfsc sspstat,r_notw ; is the IIC bus free (test if a transmission is in progress) ? goto $-1 ; no, wait until it is free movf sspcon2,w ; yes, get a copy of sspcon2 to test status bits andlw b'00011111' ; apply mask to mask out non-status bits skpz ; test for zero state, if zero bus is idle, bus busy ? goto $-3 ; yes, test again until bus is free return ; no, bus is free, exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_START bank1 ; bsf sspcon2,sen ; generate start condition btfsc sspcon2,sen ; is the start completed ? goto $-1 ; no, wait until it is completed return ; yes, exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_RESTART bank1 ; bsf sspcon2,rsen ; generate restart condition btfsc sspcon2,rsen ; is the restart completed ? goto $-1 ; no, wait until it is completed return ; yes, exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_STOP bank1 ; bsf sspcon2,pen ; generate stop condition btfsc sspcon2,pen ; is the stop completed ? goto $-1 ; no, wait until it is completed return ; yes, exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_EADDRESS bank1 ; send the control byte, high and low address bytes to eeprom rlf iicchip,w ; get chip select number in right position, no need to clear carry prior to byte rotation andlw b'00001110' ; avoid possible errors and make sure we only use the three bit number iorlw b'10100000' ; control code for eeprom chips, chip number 0, bit 0 clear for write operation bank0 ; movwf sspbuf ; send the slave address bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? return ; no, exit and deal with error movf iicahigh,w ; yes, get upper byte of address (**** to do: current eeproms are only 32kB>15 bit number!) bank0 ; movwf sspbuf ; send address upper byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? return ; no, exit and deal with error movf iicalow,w ; yes, get lower address byte bank0 ; movwf sspbuf ; send lower address byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed return ; yes, exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_WRBYTE ; write one byte to external IIC eeprom ; address in iicchip, iicalow and iicahigh ; data in iicdata call IIC_START ; call IIC_EADDRESS ; send the address and check for any ACK errors btfsc sspcon2,ackstat ; did we get any ACK error while sending the address ? goto IIC_STOP ; yes, error, send stop then exit movf iicdata,w ; no, get data byte bank0 ; movwf sspbuf ; send data byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed IIC_POLL1 call IIC_STOP ; start write cycle, then poll eeprom for completion cycle, wait for ACK from eeprom call IIC_START ; (on completion of the write cycle the eeprom sends an ACK) bank1 ; send the control byte to eeprom: rlf iicchip,w ; get chip select number, no need to clear carry prior to byte rotation andlw b'00001110' ; avoid possible errors and make sure we only use the three bit number iorlw b'10100000' ; control code for eeprom chips, chip number 0, bit 0 clear for write operation bank0 ; movwf sspbuf ; send slave address bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_POLL1 ; no, go poll again goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_RDBYTE ; read one byte from external IIC eeprom ; address in iicchip, iicalow and iicahigh ; data is returned in iicdata call IIC_START ; call IIC_EADDRESS ; send the address and check for any ACK errors btfsc sspcon2,ackstat ; did we get any ACK error while sending the address ? goto IIC_STOP ; yes, send stop then exit call IIC_RESTART ; no, send restart bank1 ; send the control byte to eeprom: rlf iicchip,w ; get chip select number, no need to clear carry prior to byte rotation andlw b'00001110' ; avoid possible errors and make sure we only use the three bit number iorlw b'10100001' ; control code for eeprom chips, chip number 0, bit 0 set for read operation bank0 ; movwf sspbuf ; send slave address bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, send stop then exit bsf sspcon2,rcen ; receive data byte from eeprom btfsc sspcon2,rcen ; have we received the byte ? goto $-1 ; no, wait here until byte receive is completed bank0 ; movf sspbuf,w ; get received data byte bank1 ; movwf iicdata ; store the data byte bsf sspcon2,ackdt ; select NOACK bsf sspcon2,acken ; send NOACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_WRBLOCK ; writes one block (64 bytes) to the external IIC eeprom memory ; first address in iicchip, iicalow and iicahigh, when address value is not ; the start of a block, the address counter will roll over ; w register content is destroyed ; data is in block buffer in bank1, from address AF hex up to and including EE hex call IIC_START ; send start condition call IIC_EADDRESS ; send the address and check for any ACK errors bank1 ; btfsc sspcon2,ackstat ; did we get any ACK error while sending the address ? goto IIC_STOP ; yes, error, send stop then exit bcf status,irp ; no, make sure upper bit in bank address is zero (select bank 0 and 1) movlw blockbuff00 ; start position of data in buffer movwf fsr ; point to this address IIC_WRITELOOP movf indf,w ; read data byte from buffer bank0 ; movwf sspbuf ; send data byte to eeprom bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, send stop then exit incf fsr,f ; increase pointer to point to next value movf fsr,w ; use pointer value sublw blockbuff63 ; was this the last byte ? skpnc ; let's see goto IIC_WRITELOOP ; no, do loop again and send next data byte IIC_POLL2 call IIC_STOP ; yes, start block write, poll eeprom for completion cycle, wait for ACK from eeprom call IIC_START ; (on completion of the write cycle the eeprom sends an ACK) bank1 ; send the control byte to eeprom: rlf iicchip,w ; get chip select number in right position, no need to clear carry prior to byte rotation andlw b'00001110' ; avoid possible errors and make sure we only use the three bit number iorlw b'10100000' ; control code for eeprom chips, chip number 0, bit 0 clear for write operation bank0 ; movwf sspbuf ; send slave address bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_POLL2 ; no, go poll again goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_RDBLOCK ; reads one block (64 bytes) from the external IIC eeprom memory ; first address in iicchip, iicalow and iicahigh ; w register content is destroyed ; data is returned in buffer in bank1, from address 2F hex up to and including 6E hex ; return in bank1 movlw blockbuff00 ; no, start position of data in buffer movwf fsr ; point to this address bcf status,irp ; make sure upper bit in address is zero (select bank 0 and 1) call IIC_START ; read one byte from external IIC eeprom into iicdata, address in iicchip, iicalow and iicahigh call IIC_EADDRESS ; send the address and check for any ACK errors btfsc sspcon2,ackstat ; did we get any ACK error while sending the address ? goto IIC_STOP ; yes, send stop then exit call IIC_RESTART ; no, send restart bank1 ; send the control byte to eeprom: rlf iicchip,w ; get chip select number, no need to clear carry prior to byte rotation andlw b'00001110' ; avoid possible errors and make sure we only use the three bit number iorlw b'10100001' ; control code for eeprom chips, chip number 0, bit 0 set for read operation bank0 ; movwf sspbuf ; send slave address bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, send stop then exit IIC_READLOOP bsf sspcon2,rcen ; receive data byte from eeprom btfsc sspcon2,rcen ; have we received the byte ? goto $-1 ; no, wait here until byte receive is completed bank0 ; movf sspbuf,w ; get received data byte bank1 ; the buffer is in bank 1 movwf indf ; store the data byte at the right position in the buffer incf fsr,f ; increase pointer to point to next value movf fsr,w ; use pointer value sublw blockbuff63 ; was this the last byte ? skpc ; let's see goto IIC_READDONE ; yes, send termination NOACK then exit bcf sspcon2,ackdt ; select ACK bsf sspcon2,acken ; send ACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed goto IIC_READLOOP ; do loop again and read next data byte IIC_READDONE bsf sspcon2,ackdt ; select NOACK bsf sspcon2,acken ; send NOACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_RDCLOCK ; read the eight time related bytes from the external IIC clock chip DS1307 ; into the buffer in bank2, from address 68 hex up to and including 6F hex ; w register content is destroyed call IIC_START ; movlw b'11010000' ; clock control code/slave address, bit 0 is cleared as indication for write bank0 ; movwf sspbuf ; send the control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit bank0 ; clrw ; address byte is zero indicating start of clock memory movwf sspbuf ; send address byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit call IIC_STOP ; yes, continue call IIC_START ; send start bank0 ; movlw b'11010001' ; clock control code/slave address, bit 1 is set as indication for read movwf sspbuf ; send control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, send stop then exit movlw h'68' ; no, start position of data in buffer movwf fsr ; point to this address bsf status,irp ; make sure upper bit in address is one (select bank 2 and 3) IIC_CRDLOOP bank1 ; bsf sspcon2,rcen ; receive data byte from clock chip btfsc sspcon2,rcen ; have we received the byte ? goto $-1 ; no, wait here until byte receive is completed bank0 ; movf sspbuf,w ; get received data byte movwf indf ; store the data byte at the right position in the buffer incf fsr,f ; increase pointer to point to next value movf fsr,w ; use pointer value sublw h'6F' ; was this the last byte ? skpc ; let's see goto IIC_CRDDONE ; yes, send termination NOACK then exit bank1 ; bcf sspcon2,ackdt ; select ACK bsf sspcon2,acken ; send ACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed goto IIC_CRDLOOP ; do loop again and read next data byte IIC_CRDDONE bank1 ; bsf sspcon2,ackdt ; select NOACK bsf sspcon2,acken ; send NOACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_WRCLOCK ; write eight time related bytes to the external IIC clock chip DS1307 ; uses the data from buffer in bank2, from 68 hex up to and including 6F hex call IIC_START ; movlw b'11010000' ; clock chip control code, bit 0 is cleared as indication for write bank0 ; movwf sspbuf ; send the control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit bank0 ; yes, clrw ; address byte is zero indicating start of clock memory movwf sspbuf ; send address byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit movlw h'68' ; yes, start position of data in buffer movwf fsr ; point to this address bsf status,irp ; make sure upper bit in address is one (select bank 2 and 3) IIC_CWRLOOP bank0 ; movf indf,w ; read data byte from buffer movwf sspbuf ; send data byte to clock bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, send stop then exit incf fsr,f ; increase pointer to point to next value movf fsr,w ; use pointer value sublw h'6F' ; was this the last byte ? skpnc ; let's see goto IIC_CWRLOOP ; no, do loop again and send next data byte goto IIC_STOP ; yes, send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_RD_CLKCHIP ; read a byte from the control bytes or static ram of the clock chip DS1307 ; address in w register (0..63 addresses include the time settings and wrap around !) ; returns with value in w register bank2 ; movwf clockaddr ; store the address byte for later use call IIC_START ; movlw b'11010000' ; clock control code/slave address, bit 0 is cleared as indication for write bank0 ; movwf sspbuf ; send the control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit bank2 ; movf clockaddr,w ; get the address byte bank0 ; movwf sspbuf ; send address byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit call IIC_STOP ; yes, continue call IIC_START ; send start bank0 ; movlw b'11010001' ; clock control code/slave address, bit 1 is set as indication for read movwf sspbuf ; send control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it is completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, send stop then exit IIC_RSTLOOP bank1 ; bsf sspcon2,rcen ; receive data byte from clock chip btfsc sspcon2,rcen ; have we received the byte ? goto $-1 ; no, wait here until byte receive is completed bank0 ; movf sspbuf,w ; get received data byte bank2 ; movwf clockdata ; store data byte for later use bank1 ; bsf sspcon2,ackdt ; select NOACK bsf sspcon2,acken ; send termination NOACK btfsc sspcon2,acken ; is the transmission completed ? goto $-1 ; no, wait here until it is completed call IIC_STOP ; yes, send stop bank2 ; movf clockdata,w ; retrieve data value return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- IIC_WR_CLKCHIP ; write one byte to the control bytes or static ram of the clock chip DS1307 ; address in clockaddr register (0..63 addresses include the time settings and wrap around !) ; data in w register ; w register content is destroyed bank2 ; movwf clockdata ; store data byte for later use call IIC_START ; movlw b'11010000' ; clock chip control code, bit 0 is cleared as indication for write bank0 ; movwf sspbuf ; send the control byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed btfsc sspcon2,ackstat ; yes, has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit bank2 ; yes, movf clockaddr,w ; get address byte bank0 ; movwf sspbuf ; send address byte bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed btfsc sspcon2,ackstat ; has ACK been received ? goto IIC_STOP ; no, deal with error: send stop then exit bank2 ; yes, movf clockdata,w ; get data byte bank0 ; movwf sspbuf ; send data byte to clock bank1 ; btfsc sspstat,r_notw ; is the transmission completed ? goto $-1 ; no, wait here until it has completed goto IIC_STOP ; send stop then exit ;-------------------------------------------------------------------------------------------------------------------------------------- MEMORY ; EEPROMS - measured data is stored in the EXTERNAL eeprom, the location of this data in the ; external eeprom and starttime information are stored in the INTERNAL eeprom, meaning that ; the internal eeprom serves as a table of contents (TOC) ; TOC - the table of contents runs from '@tocstart' up to and including address 255, ; at the start of the logging the start time and date is stored in the toc, when closing the ; record file (after switching back from the 'log' to the 'on' mode) then the address of the ; last used bit in the external memory is stored in the toc (in iicalow, iicahigh and ; iicchip/bitp, so each record in the toc uses 10 bytes: ; 9 high byte upper nibble = bitpointer, lower nibble = iicchip ; 8 middle byte iicahigh ; 7 low byte iicalow ; 6 year start time ; 5 month ,, ; 4 date ,, ; 3 day ,, ; 2 hours ,, ; 1 minutes ,, ; 0 seconds ,, ; BLOCK SIZE - during logging all measured data values are written to the external eeprom and ; the actual writes happen in eeprom block write size (64 bytes, the eeprom datasheet calls ; them pages, but to avoid confusion with pic memory pages we will call them blocks) ; to maximize eeprom lifetime and data throughput, the data is first buffered in pic registers ; and will only written to the external eeprom when the 64 byte size has been reached or when ; the command MEM_CLOSE is executed ; the 64 byte block buffer is in bank 1 from 2F to 6E hex, 6F hex is used as overflow ; there are 512 blocks per eeprom chip (9 bit number), in total there are 4096 blocks ; the following registers hold the first available free block in the external eeprom: ; mem_alow here value is multiple of 64 to always point to start of a block ; mem_ahigh maximum value is 127 since each memory chip is only 32 kbytes in size ; mem_chip value from zero to seven, we have eight eeprom chips ; START POSITION - records always start at the beginning of a new eeprom block (64 bytes) ; and are NOT stored directly after the bits of the first record to make the download routine ; to the computer easier and to prolong the external eeprom lifetime ; the start position for any new record is calculated by the MEM_OPEN command ; note: the start address of the first record is always zero ; WRITES - the following commands are used to store the recorded data in the external ; eeprom chips, there are eight chips of 32k bytes each (total 2^21=2097152 bits) ; MEM_ADD1 digital channels: mark & brake ; MEM_ADD8 speed ; MEM_ADD10 analog channels ; MEM_ADD14 rpm ; writes are not verified by a read ! ; after each add command the value of the memfull bit in the flags register ; indicates if there is any room in the memory left, this memfull flag is set at the page ; before the last page so the close command can still write the very last block to the memory ; COMPRESSION - data is stored in compressed form, meaning that a 9 bit value will be stored ; as exactly nine bits in the external eeprom, directly after any previously stored bits ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_CLEAR movlw @tocstart ; clear all toc bytes, both the address and the starttime bytes bank2 ; location of first byte in table of contents movwf iee_address ; address for internal eeprom writes should be here MEM_CLEAR_LOOP clrw ; data for internal eeprom writes should be in w register call IEE_WRITE ; write data to eeprom, address in iee_address, data in w, bank0 return bank2 ; iee_address is in bank2 incfsz iee_address,f ; point to next byte and skip when all are done goto MEM_CLEAR_LOOP ; go clear next byte movlw d'15' ; eeprom address for error flags register bank2 ; movwf iee_address ; set internal eeprom address pointer clrf errors ; clear error flags register clrw ; clear all error flags in eeprom as well, call IEE_WRITE ; write data to eeprom, address in iee_address, data in w, bank0 return bank3 ; clrf num_records ; there are no records available anymore clrf current_rec ; there is no record selected for download anymore bcf flags2,memfull ; clear flag indicating the table of contents is now empty return ; return in bank3 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_OPEN ; when both the external memory and the table of contents are not full then: ; ; 1. get the new values for: ; mem_alow ; mem_ahigh ; mem_chip ; bitpointer ; regpointer ; toc_pointer ; memfull flag (set when memory is full, registers above will contain junk) ; ; 2. initialize (clear): blockbuff00 ; ; 3. write the current time as starttime (seven bytes) into toc movlw d'255' ; position of last byte in table of contents, we start at the top and work our way down bank1 ; empty locations will contain three zero values, first try three most upper bytes movwf toc_pointer ; point to the top location MEM_OPEN_SEARCH movf toc_pointer,w ; get copy of tocpointer value, needed in loop call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; pointer registers and eeprom block write buffer are all in bank 1 movwf mem_chip ; store value for later use, but remember this value includes bitpointer in upper nibble decf toc_pointer,f ; point to lower location in toc movf toc_pointer,w ; copy the value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; pointer registers and eeprom block write buffer are all in bank 1 movwf mem_ahigh ; store value for later use decf toc_pointer,f ; point to lower location in toc movf toc_pointer,w ; copy the value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; pointer registers and eeprom block write buffer are all in bank 1 movwf mem_alow ; store value for later use, check all three values of this record to see if they are all zero iorwf mem_ahigh,w ; since this indicates that this record location is not in use yet, iorwf mem_chip,w ; so it can be used in the next logging event skpz ; are all three values zero, meaning this location is not used ? goto MEM_OPEN_INUSE ; no, use this location to get address, then point to next location which we know is empty MEM_OPEN_EMTEST movlw d'7' ; yes, go see if the toc is completely empty or if there is already another record subwf toc_pointer,f ; point to start of time and date bytes for this record movlw @tocstart ; if toc is empty then we now point to the start of the toc subwf toc_pointer,w ; see if this is the first record in the toc skpnz ; will this be the first record in the toc ? goto MEM_OPEN_1STREC ; yes, go set address of first record to zero to point to bottom of external eeprom memory MEM_OPEN_DONEXT decf toc_pointer,f ; no, there are lower locations we should test goto MEM_OPEN_SEARCH ; do loop and try next MEM_OPEN_INUSE movlw d'255' - d'2' ; when toc is full this is where the pointer will be subwf toc_pointer,w ; test the value of tocpointer, it the pointer at the last record position skpnz ; is the current pointer value valid ? goto MEM_OPEN_TOCFUL ; no, stop looking, the toc is full MEM_OPEN_POINT movlw d'3' ; point to first time and date byte of next record we know is free to use addwf toc_pointer,f ; since we have started at the top of the toc MEM_OPEN_CALC movlw b'11000000' ; use the end address of a previous record to calculate the start of the next record andwf mem_alow,f ; find the start of the last used block by stripping the lower six bits from the low byte movlw d'64' ; this value is the size of one block addwf mem_alow,f ; add one block to point to the next block, which is not used yet skpnc ; did we get an overflow of the lower byte ? incf mem_ahigh,f ; yes, also increase high byte btfsc mem_ahigh,7 ; no, did we get an overflow of the lower seven bits of the high byte (we use 32k eeproms) ? incf mem_chip,f ; yes, also increase the chip select byte btfsc mem_ahigh,7 ; no, again, did we get an overflow of the lower seven bits of high byte (we use 32k eeproms) ? bcf mem_ahigh,7 ; yes, then reset this bit movlw b'00001111' ; no, the pointer to the last used bit was stored in upper nibble of the chip select byte andwf mem_chip,f ; we only want the chip select value so strip this nibble btfsc mem_chip,3 ; see if are we pointing to a non-existing eeprom chip (there are eight eeprom chips) goto MEM_OPEN_MEMFUL ; yes, we cannot use this non-existing location MEM_OPEN_TEST movlw d'7' ; no, chip number seven is the last chip subwf mem_chip,w ; see if we are using the last chip skpz ; are we pointing to the last chip ? goto MEM_OPEN_WRTIME ; no, the address is ok movlw d'127' ; yes, this is the number for last four pages subwf mem_ahigh,w ; see if we are already there skpnz ; are we using one of the last four pages ? goto MEM_OPEN_MEMFUL ; yes, we do not want to use this location goto MEM_OPEN_WRTIME ; no, the address is ok MEM_OPEN_1STREC clrf mem_alow ; yes, since there are no records yet we will start at address zero clrf mem_ahigh ; clear all address pointer bytes clrf mem_chip ; and start at the bottom of chip zero MEM_OPEN_WRTIME call IIC_RDCLOCK ; read the time and date bytes to buffer in bank2 (from 68..6E hex), bank1 return bsf status,irp ; make sure upper bit in bank address is one (select bank 2 and 3) movlw h'68' ; the time and date bytes were put here movwf fsr ; point to this address MEM_OPEN_WRLOOP bank1 ; switch to bank1 because of loop movf toc_pointer,w ; get a copy of the tocpointer value bank2 ; register is in bank2 movwf iee_address ; the address byte for internal eeprom write operations movf indf,w ; get the data value for this address call IEE_WRITE ; do the actual write operation, return in bank0 bank1 ; incf toc_pointer,f ; point to next position in toc, after all time writes value will be at first address position incf fsr,f ; point to the next time and date byte movlw h'6F' ; position past the last time and date byte subwf fsr,w ; check if all byte have been written skpz ; have we written all bytes ? goto MEM_OPEN_WRLOOP ; no, repeat until all bytes have been written to the toc MEM_OPEN_INIT clrf blockbuff00 ; yes, clear first byte of blockbuffer as we use logical or operation to add new bits to buffer clrf bitpointer ; clear pointer for any new write operations, point to first bit movlw blockbuff00 ; location of first byte in block buffer movwf regpointer ; use value to set register pointer to start of blockbuffer bcf flags2,memfull ; clear flag indicating the external eeproms are not full return ; return in bank1 MEM_OPEN_TOCFUL bsf flags2,tocfull ; set flag indicating the table of contents is full MEM_OPEN_MEMFUL bsf flags2,memfull ; set flag indicating the memory is full return ; return in bank1 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_WRITEBLOCK ; write of block buffer to external eeprom, update buffer pointers and memory address pointer ; block buffer should contain the data ; set the memfull flag when the page before the last page is reached, this is done to notify ; to the logging loop that recording should be stopped immediately to allow for a proper ; record file ending (the last page will only be used partially) ; the following registers should hold the address in the external eeprom: ; mem_alow this value is always a multiple of 64 to point to the start of a block ; mem_ahigh maximum value is 127 since each memory chip is only 32 kbytes in size ; mem_chip value from zero to seven, we have eight eeprom chips movlw blockbuff00 ; location of first byte in block buffer movwf regpointer ; reset the register pointer for following write events btfsc mem_chip,3 ; test chip number validity, is there still room in any of the eight external eeproms ? return ; no, return without writing data or updating pointers, the memfull flag has been set already movf mem_alow,w ; get address of the next available free block in the memory, select address low byte movwf iicalow ; copy value to iic write routine movf mem_ahigh,w ; select address high byte movwf iicahigh ; copy value to iic write routine movf mem_chip,w ; select chip movwf iicchip ; copy value to iic write routine call IIC_WRBLOCK ; yes, do the actual write operation and copy the block into the external eeprom movlw d'64' ; now update all adresses for following write operations, this is size of one block bank1 ; we will add one block to the address addwf mem_alow,f ; try to point to next block in same chip, low byte of pointer skpc ; should we also update high byte of pointer ? return ; no, we're done incf mem_ahigh,f ; yes, increase high byte of pointer btfsc mem_ahigh,7 ; is there any room left in this chip ? goto MEM_WRBL_NEXT ; no, go reset high address byte, we know low byte has wrapped around and is zero MEM_WRBL_TEST movlw d'7' ; go see if we have to set memfull flag, chip number seven is the last chip subwf mem_chip,w ; see if we are using the last chip skpz ; are we pointing to the last chip ? return ; no, we're done movlw d'127' ; yes, this is the number for last four pages subwf mem_ahigh,w ; see if we are already there skpnz ; are we using one of the last four pages ? bsf flags2,memfull ; yes, the external eeproms are almost full, set flag to allow for the very last block write return ; no, we're done, bank1 return MEM_WRBL_NEXT clrf mem_ahigh ; no, reset high address byte, we know low byte has wrapped around and is zero incf mem_chip,f ; point to next chip return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_ADD1 ; write one bit to the external eeprom ; actual writes are done when the 64 byte block buffer in pic is full ; this is done to optimize eeprom lifetime ; input = bit zero of w register (actually ior of all bits) bank1 ; block buffer pointer registers and eeprom block write buffer are all in bank 1 bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) iorlw d'00000000' ; see what value the bit is skpnz ; is input bit value a zero ? goto MEM_ADD1_ZERO ; yes, skip bit set code MEM_ADD1_ONE movf regpointer,w ; no, get the value of the pointer to the register where we will put the bit movwf fsr ; use indirect addressing movf bitpointer,w ; convert 3 bit number of bitpointer to eight bit mask, for example 010>00000100 andlw b'00000011' ; first strip upper six bits and continue with only two bits movwf bitmask ; store the result incf bitmask,w ; increase by one btfsc bitmask,1 ; is the first bit in mask a one ? iorwf bitmask,f ; yes, adjust result incf bitmask,f ; no, increase by one btfsc bitpointer,2 ; was bitpointer value larger than three, should we have got a bit in upper nibble ? swapf bitmask,f ; yes, simply swap nibbles movf bitmask,w ; no, result is eight bit mask iorwf indf,f ; use OR operation to set the bit MEM_ADD1_ZERO nop ; zero bit, we have to do nothing since the new bytes are always cleared MEM_ADD1_INC incf bitpointer,f ; be ready for next push so increase pointer to point to next bit btfss bitpointer,3 ; has the bitcounter reached value 8 (bit 3 is now set) ? return ; no, done clrf bitpointer ; yes, so we move on to the next byte, let the bitpointer point to the first bit again incf regpointer,f ; increase the register pointer by one movlw blockbuff63 + 1 ; one position past buffer, overflow value subwf regpointer,w ; see if the register pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer to external eeprom and reset register pointer, bank1 return movf regpointer,w ; no, get a copy of the register pointer movwf fsr ; use this copy to set indirect file pointer to point to this location clrf indf ; clear every new byte return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_ADD8 ; write eight bits (one byte) to the external eeprom ; actual writes are done when the 64 byte block buffer in pic is full ; this is done to optimize eeprom lifetime ; the byte should be in numlow register ; numlow and nummiddle content is not changed ; databyte0 and databyte1 contents are destroyed MEM_ADD8_SELECT bank1 ; block buffer pointer registers and eeprom block write buffer are all in bank 1 bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) movf numlow,w ; copy value movwf databyte0 ; movf regpointer,w ; get the register location where we will put the data bits movwf fsr ; use indirect addressing clrf databyte1 ; use databyte1 as shift register or to clear new locations movf bitpointer,w ; get the position of the first free bit in this register skpnz ; is bit number zero the first free bit ? goto MEM_ADD8_POS0 ; yes, so we can copy the byte directly and don't have to shift any of the bits MEM_ADD8_POS1_7 movwf bitcounter ; no, we need to shift the bits left, copy value of bitpointer to the loopcounter clrc ; we only need to clear carry once since databyte1 has been cleared MEM_ADD8_LOOP rlf databyte0,f ; shift the bits rlf databyte1,f ; shift the bits decfsz bitcounter,f ; are all the bits in the right position ? goto MEM_ADD8_LOOP ; no, go do another shift MEM_ADD8_POS0 movf databyte0,w ; yes, add the lower bits to the currently selected register of the block buffer iorwf indf,f ; we use the or operation to add the new bits incf regpointer,f ; set pointer to the next byte in the buffer movlw blockbuff63 + 1 ; pointing past buffer, overflow value subwf regpointer,w ; see if the pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer contents to external eeprom and reset register pointer movf regpointer,w ; no, get the (updated) register location where we will put the data bits movwf fsr ; use indirect addressing movf databyte1,w ; get the upper bits or clear byte movwf indf ; store value return ; done, we don't have to update bitpointer since we added exactly eight bits ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_ADD10 ; write ten bits to the external eeprom ; actual writes are done when the 64 byte block buffer in pic is full ; this is done to optimize eeprom lifetime ; the bits should be in numlow and nummiddle register ; numlow and nummiddle content stays unchanged ; databyte0, databyte1 and databyte2 content is destroyed MEM_ADD10_SEL bank1 ; block buffer pointer registers and eeprom block write buffer are all in bank 1 bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) movf numlow,w ; copy value movwf databyte0 ; movf nummiddle,w ; copy value movwf databyte1 ; movlw b'00000011' ; make sure we use a 10 bit number andwf databyte1,f ; strip any excess bits clrf databyte2 ; use databyte2 as shift register or to clear new locations movf regpointer,w ; get the register location where we will put the data bits movwf fsr ; use indirect addressing movf bitpointer,w ; get the position of the first free bit in this register skpnz ; is bit number zero the first free bit ? goto MEM_ADD10_POS0 ; yes, so we can copy the bytes directly and don't have to shift any of the bits MEM_ADD10_POS17 movwf bitcounter ; no, we need to shift the bits left, copy value of bitpointer to the loopcounter clrc ; we only need to clear carry once since databyte1 and databyte2 have been cleared MEM_ADD10_LOOP rlf databyte0,f ; shift the bits rlf databyte1,f ; shift the bits rlf databyte2,f ; shift the bits decfsz bitcounter,f ; are all the bits in the right position ? goto MEM_ADD10_LOOP ; no, go do another shift MEM_ADD10_POS0 movf databyte0,w ; yes, add the lower bits to the currently selected register of the block buffer iorwf indf,f ; we use the or operation to add the new bits incf regpointer,f ; set pointer to the next byte in the buffer movlw blockbuff63 + 1 ; pointing past buffer, overflow value subwf regpointer,w ; see if the pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer contents to external eeprom and reset register pointer movf regpointer,w ; no, get the (updated) register location where we will put the data bits movwf fsr ; use indirect addressing movf databyte1,w ; no, get (part of) the upper bits movwf indf ; store these bits incf bitpointer,f ; update the position of the bitcounter incf bitpointer,f ; new bitpointer value = (bitpointer + 10) MOD 8 = bitpointer + 2 btfss bitpointer,3 ; was the start position of the bitcounter bit 6 or bit 7 ? return ; no, still some room left after storing 10 bit value in two registers, done MEM_ADD10_THREE bcf bitpointer,3 ; yes, no room left or using three registers, update register pointer, clear overflow bit incf regpointer,f ; set pointer to the next byte in the buffer movlw blockbuff63 + 1 ; pointing past buffer, overflow value subwf regpointer,w ; see if the pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer contents to external eeprom and reset register pointer movf regpointer,w ; get the (updated) register location where we will put the data bits movwf fsr ; use indirect addressing movf databyte2,w ; no, get the uppermost bit movwf indf ; store this bit return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_ADD14 ; write fourteen bits to the external eeprom ; actual writes are done when the 64 byte block buffer in pic is full ; this is done to optimize eeprom lifetime ; the bits should be in numlow and nummiddle register ; numlow and nummiddle content stays unchanged ; databyte0, databyte1 and databyte2 content is destroyed MEM_ADD14_SEL bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) movf numlow,w ; copy value bank1 ; block buffer pointer registers and eeprom block write buffer are all in bank 1 movwf databyte0 ; movf nummiddle,w ; copy value andlw b'00111111' ; make sure we use a 14 bit number movwf databyte1 ; store result movf regpointer,w ; get the register location where we will put the data bits movwf fsr ; use indirect addressing bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) clrf databyte2 ; use databyte2 as shift register or to clear new locations movf bitpointer,w ; get the position of the first free bit in this register skpnz ; is bit number zero the first free bit ? goto MEM_ADD14_POS0 ; yes, so we can copy the bytes directly and don't have to shift any of the bits MEM_ADD14_POS17 movwf bitcounter ; no, we need to shift the bits left, copy value of bitpointer to the loopcounter clrc ; we only need to clear carry once since we know value of databyte1 and databyte2 MEM_ADD14_LOOP rlf databyte0,f ; shift the bits rlf databyte1,f ; shift the bits rlf databyte2,f ; shift the bits decfsz bitcounter,f ; are all the bits in the right position ? goto MEM_ADD14_LOOP ; no, go do another shift MEM_ADD14_POS0 movf databyte0,w ; yes, add the lower bits to the currently selected register of the block buffer iorwf indf,f ; we use the or operation to add the new bits incf regpointer,f ; set pointer to the next byte in the buffer movlw blockbuff63 + 1 ; pointing past buffer, overflow value subwf regpointer,w ; see if the pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer contents to external eeprom and reset register pointer movf regpointer,w ; no, get the (updated) register location where we will put the data bits movwf fsr ; use indirect addressing movf databyte1,w ; no, get (part of) the upper bits movwf indf ; store these bits movlw d'6' ; update the position of the bitcounter addwf bitpointer,f ; new bitpointer value = (bitpointer + 14) MOD 8 = bitpointer + 6 btfss bitpointer,3 ; was the start position of the bitcounter bit 2 or greater ? return ; no, still some room left after storing 14 bit value in two registers, done MEM_ADD14_THREE bcf bitpointer,3 ; yes, no room left or using three registers, update register pointer, clear overflow bit incf regpointer,f ; set pointer to the next byte in the buffer movlw blockbuff63 + 1 ; pointing past buffer, overflow value subwf regpointer,w ; see if the pointer has arrived at this overflow register skpnc ; is the 64 byte block buffer full ? call MEM_WRITEBLOCK ; yes, write block buffer contents to external eeprom and reset register pointer movf regpointer,w ; get the (updated) register location where we will put the data bits movwf fsr ; use indirect addressing movf databyte2,w ; no, get the uppermost bits movwf indf ; store these bits return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_CLOSE ; write any bytes that are still in the blockbuffer to the external eeprom, unused bytes are ; cleared first, update the table of contents with the address of the last used bit ; this routine may also be called when we didn't store anything yet, when the memory is full ; or when the table of contents is already full and we are just aborting the logging ; note: during the add commands we use a pointer that points to the next free bit, ; but we store the position of last used bit in the toc MEM_CL_CHECK1 nop ; **** check if we have added anything to store at all MEM_CL_CHECK2 btfsc flags2,tocfull ; is the table of contents full and should we ignore the call to this subroutine ? return ; yes, return without updating the table of contents MEM_CL_CHECKOK movlw blockbuff00 ; no, start of block buffer location bank1 ; pointer registers and eeprom block write buffer are all in bank 1 subwf regpointer,w ; see if we are still at the first byte of the block buffer skpz ; did we write anything into the buffer yet ? goto MEM_CL_CLRBUFF ; yes, go clear rest of bytes in buffer movf bitpointer,w ; no, also get value of bitpointer skpnz ; are we sure the buffer is completely empty ? goto MEM_CL_DECPOINT ; yes, we don't have to write this block to the external eeprom MEM_CL_CHECKP movlw blockbuff63 ; no, position of last byte in buffer subwf regpointer,w ; see if we are pointing to the last byte in the buffer skpnz ; are we pointing to the last byte ? goto MEM_CL_ADDR ; yes, there are no bytes to be cleared, skip clear routine MEM_CL_CLRBUFF incf regpointer,w ; no, start at register pointer location plus one with clearing bytes movwf fsr ; use indirect addressing bcf status,irp ; make sure upper bit in address is zero (select register bank 0 and 1) MEM_CL_CLRLOOP clrf indf ; clear byte of buffer, we want to clear all the rest of the buffer movlw blockbuff63 ; position of last byte in buffer incf fsr,f ; point to next byte in buffer for when we do loop subwf fsr,w ; see if the pointer has arrived at last position skpz ; have we done the all of the 64 byte block buffer ? goto MEM_CL_CLRLOOP ; no, do loop to clear next byte MEM_CL_ADDR movf mem_alow,w ; yes, write contents of block buffer to external eeprom, use address of next free block movwf iicalow ; copy value to iic write routine movf mem_ahigh,w ; select address high byte movwf iicahigh ; copy value to iic write routine movf mem_chip,w ; select chip movwf iicchip ; copy value to iic write routine call IIC_WRBLOCK ; do the actual write operation and copy the block into the external eeprom, bank1 return MEM_CL_DECPOINT decf bitpointer,f ; don't point to next free bit anymore but to the last used bit, decrement pointer one bit movlw blockbuff00 ; offset between zero and start address of blockbuffer in bank1 subwf regpointer,w ; get lower six bits of the lower address byte (end position can be anywhere in a block) iorwf mem_alow,f ; merge with upper two bits of low address byte (which always holds start of a block) comf bitpointer,w ; since decf does not change the carry we use the complement to see if the result is negative skpnz ; is the complement zero, meaning the result of the decrement was a negative value ? decf mem_alow,f ; yes, decrease the lower address byte by one because we have to borrow movlw b'00000111' ; no, when the result from the decrement of the bitpointer is negative then andwf bitpointer,f ; set the bitpointer to its maximum value instead comf mem_alow,w ; since decf does not change the carry we use the complement to see if the result is negative skpnz ; was the result of the decrement of the low byte negative ? decf mem_ahigh,f ; yes, decrease the higher address byte by one because we have to borrow comf mem_ahigh,w ; since decf does not change the carry we use the complement to see if the result is negative skpnz ; is the complement zero, meaning the result of the decrement was a negative value ? decf mem_chip,f ; yes, borrow from the chip select byte movlw b'01111111' ; no, when the result from the decrement of the high address byte is negative then andwf mem_ahigh,f ; set the high address byte to its maximum value instead (we use 15 bit/32kB eeproms) MEM_CL_WRITETOC movf toc_pointer,w ; get the location in the toc where we should store the address of the last used bit bank2 ; so we can determine where data from one record stops and a new record begins movwf iee_address ; copy value for use in to pic eeprom write routine bank1 ; pointer registers and eeprom block write buffer are all in bank 1 movf mem_alow,w ; get the low byte of the address pointer call IEE_WRITE ; write one byte to pic eeprom, address in iee_address(bank2), data in w register, bank0 return bank2 ; incf iee_address,f ; point to next byte in toc bank1 ; movf mem_ahigh,w ; get the high byte of the address pointer call IEE_WRITE ; write one byte to pic eeprom, address in iee_address(bank2), data in w register, bank0 return bank2 ; incf iee_address,f ; point to next byte in toc bank1 ; swapf bitpointer,f ; move bitpointer bits to high nibble movf mem_chip,w ; since the bitpointer and the chip select value are stored in the same byte iorwf bitpointer,w ; combine values of bitpointer and chip select call IEE_WRITE ; write one byte to pic eeprom, address in iee_address(bank2), data in w register, bank0 return return ; done, return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_USAGE nop ; **** get the used space of the external eeprom memory in percent into w register nop ; **** read end of last record position, do division to get percentage movlw d'100' ; **** dummy value return ; **** return in bank? ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_GETNUMRECS ; determine the number of records currently present in the table of contents ; value is stored in num_records in bank3 ; registers used: toc_pointer, toc_test, num_records ; returns in bank1 or in bank3 movlw d'255' ; start with number of records is -1 bank3 ; movwf num_records ; movlw @tocstart + d'7' ; start address of address bytes of first record in table of contents in internal eeprom bank1 ; movwf toc_pointer ; point to this location MEM_GETNRLOOP bank3 ; incf num_records,f ; increment number of records by one movlw @tocstart ; to test for pointer overflow after loop increment see if value of pointer bank1 ; subwf toc_pointer,w ; has not wrapped around since the table of contents ends at address 255 skpc ; is the current pointer value valid ? return ; no, the pointer has wrapped around, exit with number of 20 records, return in bank3 movf toc_pointer,w ; yes, get value of pointer call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; movwf toc_test ; store value to test if all three bytes are zero incf toc_pointer,f ; pointer to the next location in the toc movf toc_pointer,w ; use copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; iorwf toc_test,f ; also test this byte for zero value incf toc_pointer,f ; pointer to the next location in the toc movf toc_pointer,w ; use copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank1 ; iorwf toc_test,f ; also test this byte for zero value movlw d'8' ; records in toc each take ten bytes, we already increased pointer by two addwf toc_pointer,f ; point to next record in toc in case we do loop movf toc_test,w ; now we have to test again if all three bytes are zero skpz ; is the value of all three byte zero ? goto MEM_GETNRLOOP ; no, this location is already taken, go see if next location is free return ; yes, return in bank1 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_SELECTREC ; reset the block download pointers pointer_low/high/chip and endpoint_low/high/chip for the ; given record number, update current_rec ; record number should be in w register ; the pointer values are rounded to block size since we can only download complete blocks bank3 ; this routine is called only with a valid record selection, no need to check record number movwf current_rec ; the new record number selection is in w register movlw @tocstart +d'7' ; start off with pointing to the first address byte of the first record in the toc bank1 ; we will have to look up the right address movwf toc_pointer ; so we will use this value in the pointer calculation which follows bank3 ; this routine is called only with a valid record selection, no need to check record number decf current_rec,w ; copy selected record number minus one to a loopcounter, value is now 0..19 movwf rec_loopcntr ; we may use this counter in the following loop skpnz ; is the value zero meaning record number one is currently selected ? goto MEM_SELECTR_ZER ; yes, this is a special case, the starting address is not in the toc since it is always zero MEM_SELECTR_INC bank3 ; first time we get here is with records 2..20, loopcounter value 1..19 decf rec_loopcntr,f ; count every record skpnz ; should we increase the pointer to the next record ? goto MEM_SELECTR_STA ; no, get values movlw d'10' ; yes, we repeat until the pointer has the right value bank1 ; each record uses ten bytes in the table of contents addwf toc_pointer,f ; point to the next record goto MEM_SELECTR_INC ; repeat until the pointer has the right value MEM_SELECTR_STA bank1 ; no, read the values from the toc into the pointer registers movf toc_pointer,w ; use the value of the tocpointer call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf pointer_low ; bank1 ; incf toc_pointer,f ; also for the next byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf pointer_high ; bank1 ; incf toc_pointer,f ; and for this byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf pointer_chip ; this value also includes bitpointer MEM_SELECTR_CAL movlw b'11000000' ; strip the lower six bits from pointer_low value andwf pointer_low,f ; since we want to start at beginning of the next block movlw d'64' ; this value is the size of one block addwf pointer_low,f ; add one block to current block pointer skpnc ; did we get an overflow of the lower byte ? incf pointer_high,f ; yes, also increase high byte of pointer btfsc pointer_high,7 ; no, did we get an overflow of the lower seven bits of the high byte (we use 32k eeproms) ? incf pointer_chip,f ; yes, also increase the chip select byte btfsc pointer_high,7 ; no, again, did we get an overflow of the lower seven bits of high byte (we use 32k eeproms) ? bcf pointer_high,7 ; yes, then reset this bit movlw b'00001111' ; no, the pointer to the last used bit was stored in upper nibble of the chip select byte andwf pointer_chip,f ; we only want chip select so strip bitpointer from value movlw d'8' ; point to end address positions bank1 ; we already increased the pointer by two positions addwf toc_pointer,f ; now add the other eight movf toc_pointer,w ; copy value MEM_SELECTR_END call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf endpoint_low ; movlw b'11000000' ; strip the lower six bits from pointer_low value andwf endpoint_low,f ; since we want to start at beginning of the block bank1 ; incf toc_pointer,f ; also for the next byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf endpoint_high ; bank1 ; incf toc_pointer,f ; and for this byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf endpoint_chip ; this value also includes bitpointer movlw b'00001111' ; last free bit pointer is stored in upper nibble andwf endpoint_chip,f ; we only want chip select so strip bitpointer from value return ; return in bank3 MEM_SELECTR_ZER clrf pointer_low ; we get here in bank3 clrf pointer_high ; set block pointer to zero for record number one clrf pointer_chip ; since this record always starts at the bottom of the memory bank1 ; movf toc_pointer,w ; get pointer of address bytes of first record goto MEM_SELECTR_END ; tocpointer was already set to right address for end of record number one ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_GETTIMEDATE ; read the record start time and date of currently selected record from the toc and store ; these in the time and date buffer in bank2 ; return in bank2 bsf status,irp ; make sure upper bit in address is one (select bank 2 and 3) movlw h'68' ; get the time and date bytes in the buffer in bank2 movwf fsr ; since we have to decode them first, set pointer which we will use later movlw @tocstart -d'10' ; point to the time bytes of first record in the toc, bank1 ; minus ten bytes since following addition loop runs at least once movwf toc_pointer ; use this value in the pointer calculation which follows bank3 ; movf current_rec,w ; get the currently selected record number and use this number to calculate the offset movwf rec_loopcntr ; in the table of contents, increment value with one for proper loop end MEM_GTDFINDLOOP movlw d'10' ; each record uses ten bytes in the table of contents bank1 ; addwf toc_pointer,f ; point to the next record bank3 ; decfsz rec_loopcntr,f ; should we repeat the addition ? goto MEM_GTDFINDLOOP ; yes, repeat until the pointer has the right value MEM_GTDCOPYLOOP bank1 ; no, now go copy the bytes from internal eeprom to buffer movf toc_pointer,w ; use the value of the tocpointer call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 movwf indf ; store the data value for this address bank1 ; incf toc_pointer,f ; point to next position in table of contents incf fsr,f ; point to the next time and date byte movlw h'6F' ; position past the last time and date byte subwf fsr,w ; check if all byte have been written skpz ; have we copied all bytes ? goto MEM_GTDCOPYLOOP ; no, repeat until all bytes have been copied to the buffer return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_GETRECSIZE ; store size (in bits) of currently selected record into registers numlow, nummiddle, numhigh ; this routine is called only with a valid record selection, no need to check record number movlw @tocstart +d'7' ; start off with pointing to the first address byte of the first record in the toc bank1 ; we will have to look up the right address for the selected record movwf toc_pointer ; use this value in the pointer calculation which follows bank3 ; this routine is called only with a valid record selection, no need to check record number decf current_rec,w ; copy selected record number minus one to a loopcounter, value is now 0..19 movwf rec_loopcntr ; we may use this counter in the following loop skpnz ; is the value zero meaning record number one is currently selected ? goto MEM_RECSIZE_ZER ; yes, this is a special case, the starting address is not in the toc since it is always zero MEM_RECSIZE_INC bank3 ; first time we get here is with records 2..20, loopcounter value 1..19 decf rec_loopcntr,f ; loopcounter skpnz ; should we repeat the addition ? goto MEM_RECSIZE_STA ; no, we are at the right position, go use this location as start address of record movlw d'10' ; yes, we repeat until the pointer has the right value bank1 ; each record uses ten bytes in the table of contents addwf toc_pointer,f ; point to the next record goto MEM_RECSIZE_INC ; do loop until we get right address MEM_RECSIZE_STA bank1 ; no, read the values from the toc into the pointer registers movf toc_pointer,w ; use the value of the tocpointer call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizea0 ; a0/a1/a2 is the smaller number (record n), b0/b1/b2 will be the larger number (record n+1) bank1 ; so result is record size = b - a [bits] incf toc_pointer,f ; also for the next byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizea1 ; bank1 ; incf toc_pointer,f ; and for this byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizea2 ; this value is combined chipselect (least significant nibble) and bitpointer (upper nibble) movlw d'8' ; move pointer to end address position bytes bank1 ; we already increased the pointer by two positions addwf toc_pointer,f ; now add the other eight MEM_RECSIZE_CAL bank3 ; we have to adjust the start address movlw b'11000000' ; use the end address of a previous record to calculate the start of the next record andwf recsizea0,f ; find the start of the last used block by stripping the lower six bits from the low byte movlw d'64' ; this value is the size of one block addwf recsizea0,f ; add one block to point to the next block, which is not used yet skpnc ; did we get an overflow of the lower byte ? incf recsizea1,f ; yes, also increase high byte btfsc recsizea1,7 ; no, did we get an overflow of the lower seven bits of the high byte (we use 32k eeproms) ? incf recsizea2,f ; yes, also increase the chip select byte btfsc recsizea1,7 ; no, again, did we get an overflow of the lower seven bits of high byte (we use 32k eeproms) ? bcf recsizea1,7 ; yes, then reset this bit movlw b'00001111' ; no, the pointer to the last used bit was stored in upper nibble of the chip select byte andwf recsizea2,f ; we only want the chip select value so strip this nibble MEM_RECSIZE_END bank1 ; select bank since we may come from bank3 (record number is zero code below) movf toc_pointer,w ; get pointer of address bytes of first record call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizeb0 ; bank1 ; incf toc_pointer,f ; also for the next byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizeb1 ; bank1 ; incf toc_pointer,f ; and for this byte movf toc_pointer,w ; get copy of value call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 bank3 ; movwf recsizeb2 ; this value also includes bitpointer MEM_RECSIZE_HI rlf recsizeb2,w ; the b recordsize registers hold larger address movwf numhigh ; calculate address from bitp/chipselect, high address byte and low address byte rlf numhigh,f ; store address in numlow, nummiddle and numhigh rlf recsizeb0,w ; movwf numlow ; rlf recsizeb1,w ; movwf nummiddle ; rlf numhigh,f ; rlf numlow,f ; rlf nummiddle,f ; rlf recsizeb2,f ; rlf numhigh,f ; rlf numlow,f ; alow43210 bitp210 rlf nummiddle,f ; ahigh43210 alow765 rlf recsizeb2,w ; andlw b'00011111' ; movwf numhigh ; 0 0 0 chip210 ahigh65 MEM_RECSIZE_LO rlf recsizea2,w ; the a recordsize registers hold smaller address movwf recsizeb2 ; calculate address from bitp/chipselect, high address byte and low address byte rlf recsizeb2,f ; store address in recsizeb2, recsizeb1, recsizeb0 rlf recsizea0,w ; movwf recsizeb0 ; rlf recsizea1,w ; movwf recsizeb1 ; rlf recsizeb2,f ; rlf recsizeb0,f ; rlf recsizeb1,f ; rlf recsizea2,f ; rlf recsizeb2,f ; rlf recsizeb0,f ; rlf recsizeb1,f ; rlf recsizea2,w ; andlw b'00011111' ; movwf recsizeb2 ; MEM_RECSIZE_SUB movf recsizeb0,w ; now do subtraction to get record size subwf numlow,f ; store result in numlow, nummiddle and numhigh movf recsizeb1,w ; skpc ; incfsz recsizeb1,w ; subwf nummiddle,f ; movf recsizeb2,w ; skpc ; incfsz recsizeb2,w ; subwf numhigh,f ; MEM_RECSIZE_ADD movlw d'1' ; because of the way we store the start and end position of a record in the table of contents addwf numlow,f ; we have to add one extra bit to the size of the record skpnc ; a record of one bit will not be found in the toc since the start and end addresses are of incf nummiddle,f ; the same value, therefore the minimum size of a record is two bits skpnz ; incf numhigh,f ; return ; return in bank3 MEM_RECSIZE_ZER clrf recsizea0 ; set block pointer to zero for record number one clrf recsizea1 ; since this record always starts at the bottom of the memory clrf recsizea2 ; goto MEM_RECSIZE_END ; tocpointer is already at right address ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_RDBLOCK ; copy data block from external eeprom to the block buffer in bank1 ; carry set when all blocks done ; return in bank1 or bank3 MEM_RDBL_CHECK2 bank3 ; movf pointer_low,w ; check for end of record, have we sent all blocks? subwf endpoint_low,w ; subtract, first low bytes movf pointer_high,w ; high byte skpc ; did we have to borrow ? incfsz pointer_high,w ; yes, adjust value subwf endpoint_high,w ; no, subtract high bytes movf pointer_chip,w ; chip select bytes skpc ; did we have to borrow ? incfsz pointer_chip,w ; yes, adjust value subwf endpoint_chip,w ; no, subtract chip select bytes skpnc ; do we have a valid address ? goto MEM_RDBL_COPY ; yes, go copy the block from external eeprom to buffer in bank1 setc ; no, set carry as indication that we have already read all blocks of this record return ; carry has been set, return in bank3 MEM_RDBL_COPY bank3 ; get block pointer movf pointer_low,w ; address low byte bank1 ; movwf iicalow ; copy value bank3 ; movf pointer_high,w ; select address high byte bank1 ; movwf iicahigh ; copy value bank3 ; movf pointer_chip,w ; select chip bank1 ; movwf iicchip ; copy value call IIC_RDBLOCK ; read 64 bytes from external eeprom, address in iicchip, iicalow and iicahigh, bank1 return clrc ; clear carry return ; return in bank1 ;-------------------------------------------------------------------------------------------------------------------------------------- MEM_INC_RDBLOCK ; auto increment blockpointer, then copy data block from external eeprom to the block ; buffer in bank1 ; carry set when all blocks done ; return in bank1 or bank3 MEM_RDBL_CHECK1 bank3 ; movf pointer_low,w ; check for end of record, have we sent all blocks? subwf endpoint_low,w ; subtract, first low bytes movf pointer_high,w ; high byte skpc ; did we have to borrow ? incfsz pointer_high,w ; yes, adjust value subwf endpoint_high,w ; no, subtract high bytes movf pointer_chip,w ; chip select bytes skpc ; did we have to borrow ? incfsz pointer_chip,w ; yes, adjust value subwf endpoint_chip,w ; no, subtract chip select bytes skpnc ; do we have a valid address ? goto MEM_RDBL_INCADD ; yes, go copy the block from external eeprom to buffer in bank1 setc ; no, set carry as indication that we have already read all blocks of this record return ; carry has been set, return in bank3 MEM_RDBL_INCADD movlw d'64' ; no, this is the size of one memory block in external eeprom bank3 ; addwf pointer_low,f ; increment memory block pointer, first low byte skpc ; do we need to update high byte as well ? goto MEM_RDBLOCK ; no, go check address again, then copy block incf pointer_high,f ; yes, do so btfsc pointer_high,7 ; the current eeprom chips are 32kB (15 bits address), did we get an overflow ? incf pointer_chip,f ; yes, also increase chip select byte bcf pointer_high,7 ; no, we don't use bit 7 since we have 32kB eeproms, clear bit goto MEM_RDBLOCK ; go check address again, then copy block ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- org h'1000' ; start of program memory page 2 ;-------------------------------------------------------------------------------------------------------------------------------------- ; RS232 subroutines for transmitting and receiving bytes and numbers (ascii strings) ;-------------------------------------------------------------------------------------------------------------------------------------- ; a command byte sequence is (in ascii): ; <STX> 1 byte indicator for start of command, value hex 02 ; <c1> 1 byte, first letter of command ; <c2> 1 byte, second letter of command ; <data bytes> 0-64 data bytes, all values accepted except ascii codes STX and ETX ; <checksum> 1 byte checksum (see below), any hex value 00-FF ; <ETX> 1 byte indicator for end of command, value hex 03 ; checksum value makes sum of all bytes from <STX> up to and including <ETX> zero TX_BINVALUE addlw h'30' ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') TX_BYTE ; transmit content of w register through RS232 (odd parity) ; checksum calculation is included ; w register content is destroyed ; returns in bank0 bank0 ; select bank, then calculate what the value of the parity bit is going to be: movwf tx_byte ; w holds the byte to be transmitted, store w for use after the parity calculation addwf tx_checksum,f ; use byte in checksum calculation movwf tx_parity ; swapf tx_parity,w ; use w and tx_parity registers for the calculation xorwf tx_parity,f ; calculate nibbles rrf tx_parity,w ; xorwf tx_parity,f ; at this point the parity values of the nibbles are in bit 2 and bit 0 btfss tx_parity,2 ; if parity one nibble is 1 then the byte parity is that of other nibble, skip ahead incf tx_parity,f ; otherwise, invert bit 0 bank1 ; bcf txsta,tx9d ; first assume we should reset the parity bit that will be send bank0 ; btfss tx_parity,0 ; was it the right decision to reset the bit ? goto TX_LOOP ; yes, go send the byte bank1 ; bsf txsta,tx9d ; no, first set the parity bit and then send the byte bank0 ; TX_LOOP btfss pir1,txif ; yes, ready to send ? (bit set means transmit buffer is empty) goto TX_LOOP ; no, keep trying TX_POLL_RTS btfsc portc,rts_in ; is the PC input buffer empty, so are we allowed to send data ? (RTS serves as a CTS here) goto TX_POLL_RTS ; no, keep trying ; **** to do: we would like to have some timeout testing here.... movf tx_byte,w ; yes, move character to w movwf txreg ; transmit byte ;nop ; there is a delay of one instruction cycle after writing to txreg, before txif gets cleared return ; line above, nop, is just information for of possible future changes, return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_COMMANDSTART ; send ACK, STX and command mnemonics movlw h'06' ; Acknowledgement (ACK) call TX_BYTE ; send 'command has been accepted', return in bank0 clrf tx_checksum ; start off with clear checksum value movlw h'02' ; STX call TX_BYTE ; return in bank0 movf rx_buffer00,w ; location of first letter of mnemonic in RS232 buffer call TX_BYTE ; movf rx_buffer01,w ; location of second letter of mnemonic in RS232 buffer call TX_BYTE ; return ; ;-------------------------------------------------------------------------------------------------------------------------------------- TX_COMMANDEND ; send checksum and ETX, clear command status byte bank0 ; movlw h'03' ; ETX call TX_BYTE ; transmit, return in bank0 movf tx_checksum,w ; get checksum value sublw d'0' ; calculate right value (all command bytes added should result in zero value) call TX_BYTE ; transmit, return in bank0 bcf flags1,command ; now command has been handled we can clear the execute flag bcf portc,cts_out ; set CTS to re-enable data stream from computer bsf portb,led_red ; turn on red status led bcf portb,led_green ; turn off green status led return ; return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_NUMBER ; this routine transmits the 8 bit number (0-255) in the w register via RS232 as ; (up to three) ascii characters without preceding zeros (23 will be sent as '23' ; and not as '023'), transmit checksum is calculated ; w register content is destroyed ; returns in bank0 ; 255 byte value ; ; 100 100 ; 10 10 ; 1 1 bank0 movwf tx_numberl ; store the value of the number for use in the calculation movlw b'10000000' ; use the upper bit of the counter as a flag for preceding zeros, movwf tx_counter ; 1 means skip characters movlw d'100' ; how many hundreds ? call TX_DIGIT ; send digit movlw b'10000000' ; select flag bit andwf tx_counter,f ; clear counter but keep preceding zeros flag bit movlw d'10' ; how many tens ? call TX_DIGIT ; send digit clrf tx_counter ; the last character always has to be sent so clear counter and flag bit too movlw d'1' ; how many ones ? goto TX_DIGIT ; goto instead of call because we are done here TX_NLOOP bcf tx_counter,7 ; this character is non-zero, so begin sending characters incf tx_counter,f ; increment counter TX_DIGIT subwf tx_numberl,f ; subtract skpnc ; is the result negative ? goto TX_NLOOP ; no, repeat addwf tx_numberl,f ; undo negative result, we need the right value for the rest of the calculation btfsc tx_counter,7 ; can we still skip the preceding zero characters ? return ; yes, skip those characters movlw a'0' ; in ascii numbers start at 30 hex addwf tx_counter,w ; so add the counter to get the right ascii code call TX_BYTE ; send the ascii character stored in register w, return in bank0 return ; return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_LNUMBER ; this routine transmits the 16 bit number (0-65535) in the registers numlow and ; nummiddle via RS232 as (up to five) ascii characters without preceding zeros ; transmit checksum is calculated ; w register content is destroyed ; returns in bank0 ; 65,535 high_byte low_byte ; ; 10,000 39 16 ; 1,000 3 232 ; 100 0 100 ; 10 0 10 ; 1 0 1 movf numlow,w ; get lower byte of number bank0 ; movwf tx_numberl ; store it for use during calculation movf nummiddle,w ; get upper byte of number movwf tx_numberh ; store it for use during calculation movlw b'10000000' ; use the upper bit of the counter as a flag for preceding zeros, movwf tx_counter ; 1 means skip characters movlw d'16' ; first count number of 10,000's, lower byte of binary number 10,000 movwf templow ; movlw d'39' ; upper byte of binary number 10,000 movwf temphigh ; call TX_LDIGIT ; movlw d'232' ; count number of 1,000's, lower byte of binary number 1,000 movwf templow ; movlw d'3' ; upper byte of binary number 1,000 movwf temphigh ; call TX_LDIGIT ; movlw d'100' ; count number of 100's, lower byte of binary number 100 movwf templow ; clrf temphigh ; high byte is zero call TX_LDIGIT ; movlw d'10' ; count number of 10's, lower byte of binary number 10 movwf templow ; clrf temphigh ; high byte is zero call TX_LDIGIT ; movlw d'1' ; count number of 1's, lower byte of binary number 1 movwf templow ; clrf temphigh ; high byte is zero clrf tx_counter ; the last character always has to be sent so clear counter and flag bit too goto TX_LDIGIT ; goto instead of call because we are done here TX_LDIGIT movlw b'10000000' ; select flag bit andwf tx_counter,f ; clear counter but keep flag bit for preceding zeros TX_LTEST movf templow,w ; check if subtraction will give positive or zero result subwf tx_numberl,w ; compare lower byte movf temphigh,w ; skpc ; incfsz temphigh,w ; subwf tx_numberh,w ; high byte skpc ; is the result >= zero ? goto TX_LSEND ; no, result is negative, go send character TX_LSUBTR bcf tx_counter,7 ; yes, clear flag bit since we skipped possible zero character, now start sending characters incf tx_counter,f ; increment counter movf templow,w ; subtract subwf tx_numberl,f ; low byte movf temphigh,w ; skpc ; incfsz temphigh,w ; high byte subwf tx_numberh,f ; goto TX_LTEST ; next TX_LSEND btfsc tx_counter,7 ; can we still skip the preceding zero characters ? return ; yes, skip those characters movlw a'0' ; in ascii numbers start at 30 hex addwf tx_counter,w ; so add the counter to get the right ascii code call TX_BYTE ; send the ascii character stored in register w,return in bank0 return ; return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_WNUMBER ; this routine transmits the 24 bit number (0-16777215)('wide' number) in the registers ; numlow(lsB), nummiddle (middle byte) and numhigh (msB) (word extended) via RS232 as ; (up to eight) ascii characters without preceding zeros, a transmit checksum is calculated ; w register content is destroyed ; returns in bank0 ; ; 16,777,215 upper_byte middle_byte lower_byte ; 10,000,000 152 150 128 ; 1,000,000 15 66 64 ; 100,000 1 134 160 ; 10,000 0 39 16 ; 1,000 0 3 232 ; 100 0 0 100 ; 10 0 0 10 ; 1 0 0 1 bank0 ; movf numlow,w ; get lower byte of number movwf tx_numberl ; store it for use during calculation movf nummiddle,w ; get middle byte of number movwf tx_numberm ; store it for use during calculation movf numhigh,w ; get upper byte of number movwf tx_numberh ; store it for use during calculation movlw b'10000000' ; use the upper bit of the counter as a flag for preceding zeros, movwf tx_counter ; 1 means skip characters movlw d'128' ; first count number of 10,000,000's, lower byte movwf templow ; movlw d'150' ; middle byte movwf tempmiddle ; movlw d'152' ; upper byte movwf temphigh ; call TX_WDIGIT ; movlw d'64' ; count number of 1,000,000's, lower byte movwf templow ; movlw d'66' ; middle byte movwf tempmiddle ; movlw d'15' ; upper byte movwf temphigh ; call TX_WDIGIT ; movlw d'160' ; count number of 100,000's, lower byte movwf templow ; movlw d'134' ; middle byte movwf tempmiddle ; movlw d'1' ; upper byte movwf temphigh ; call TX_WDIGIT ; movlw d'16' ; count number of 10,000's, lower byte movwf templow ; movlw d'39' ; middle byte movwf tempmiddle ; clrf temphigh ; upper byte is zero call TX_WDIGIT ; movlw d'232' ; number of 1,000's movwf templow ; movlw d'3' ; middle byte movwf tempmiddle ; clrf temphigh ; upper byte is zero call TX_WDIGIT ; movlw d'100' ; number of 100's movwf templow ; clrf tempmiddle ; middle byte is zero clrf temphigh ; upper byte is zero call TX_WDIGIT ; movlw d'10' ; count number of 10's movwf templow ; clrf tempmiddle ; middle byte is zero clrf temphigh ; upper byte is zero call TX_WDIGIT ; movlw b'00000001' ; count number of 1's movwf templow ; clrf tempmiddle ; middle byte is zero clrf temphigh ; high byte is zero clrf tx_counter ; the last character always has to be sent so clear counter and flag bit too goto TX_WDIGIT ; goto instead of call because we are done here TX_WDIGIT movlw b'10000000' ; select flag bit andwf tx_counter,f ; clear counter but keep flag bit for preceding zeros TX_WTEST movf templow,w ; check if subtraction will give positive or zero result subwf tx_numberl,w ; compare lower byte movf tempmiddle,w ; skpc ; incfsz tempmiddle,w ; subwf tx_numberm,w ; middle byte movf temphigh,w ; skpc ; incfsz temphigh,w ; high byte subwf tx_numberh,w ; skpc ; is the result >= zero ? goto TX_WSEND ; no, result is negative, go send character TX_WSUBTR bcf tx_counter,7 ; yes, clear flag bit since we skipped possible zero character, now start sending characters incf tx_counter,f ; increment counter movf templow,w ; subtract subwf tx_numberl,f ; low byte movf tempmiddle,w ; skpc ; incfsz tempmiddle,w ; subwf tx_numberm,f ; middle byte movf temphigh,w ; skpc ; incfsz temphigh,w ; high byte subwf tx_numberh,f ; goto TX_WTEST ; next TX_WSEND btfsc tx_counter,7 ; can we still skip the preceding zero characters ? return ; yes, skip those characters movlw a'0' ; in ascii numbers start at 30 hex addwf tx_counter,w ; so add the counter to get the right ascii code call TX_BYTE ; send the ascii character stored in register w,return in bank0 return ; return in bank0 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_TIMEANDDATE ; this routine transmits the time and date values from the buffer in bank2 as a string ; use Windows format: 'DD/MM/YY HH:MM:SS' ; transmit checksum is calculated ; w register content is destroyed ; returns in bank2 bank2 ; swapf date,w ; get date/ 10 date andlw b'00000011' ; strip date call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf date,w ; get date/ 10 date andlw b'00001111' ; strip 10 date call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') movlw a'/' ; call TX_BYTE ; bank2 ; swapf month,w ; get months/ 10 month andlw b'00000001' ; strip months call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf month,w ; get months/ 10 month andlw b'00001111' ; strip 10 month call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') movlw a'/' ; call TX_BYTE ; bank2 ; swapf year,w ; get year/ 10 year andlw b'00001111' ; strip year call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf year,w ; get year/ 10 year andlw b'00001111' ; strip 10 year call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') movlw a' ' ; call TX_BYTE ; bank2 ; swapf hours,w ; get hours/ 10 hours andlw b'00000011' ; strip hours call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf hours,w ; get 10 hours/ hours andlw b'00001111' ; strip 10 hours call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') movlw a':' ; call TX_BYTE ; bank2 ; swapf minutes,w ; get minutes/ 10 minutes andlw b'00000111' ; strip minutes call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf minutes,w ; get 10 minutes/ minutes andlw b'00001111' ; strip 10 minutes call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') movlw a':' ; call TX_BYTE ; bank2 ; swapf seconds,w ; get seconds/ 10 seconds / oscillator enable andlw b'00000111' ; strip seconds / oscillator enable call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') bank2 ; movf seconds,w ; get seconds/ 10 seconds / oscillator enable andlw b'00001111' ; strip 10 seconds / oscillator enable call TX_BINVALUE ; transmit the binary value (0..9) in w register as an ascii character ('0'..'9') return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- TX_FREQVALSTR ; w register should hold the frequency settings value ; this routine transmits the corresponding value from the table below as an ascii string ; 00000000 32 ; 00000001 16 ; 00000011 8 ; 00000111 4 ; 00001111 2 ; 00011111 1 ; 00111111 0.5 ; 01111111 0.25 ; 11111111 0 TX_FREQ_32 bank0 ; movwf tx_numberl ; movlw b'00000000' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_16 ; movlw a'3' ; call TX_BYTE ; transmit byte , return in bank0 movlw a'2' ; call TX_BYTE ; transmit byte , return in bank0 return ; return in bank0 TX_FREQ_16 movlw b'00000001' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_8 ; movlw a'1' ; call TX_BYTE ; movlw a'6' ; call TX_BYTE ; return ; TX_FREQ_8 movlw b'00000011' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_4 ; movlw a'8' ; call TX_BYTE ; return ; TX_FREQ_4 movlw b'00000111' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_2 ; movlw a'4' ; call TX_BYTE ; return ; TX_FREQ_2 movlw b'00001111' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_1 ; movlw a'2' ; call TX_BYTE ; return ; TX_FREQ_1 movlw b'00011111' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_0.5 ; movlw a'1' ; call TX_BYTE ; return ; TX_FREQ_0.5 movlw b'00111111' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_0.25 ; movlw a'0' ; call TX_BYTE ; movlw a'.' ; call TX_BYTE ; movlw a'5' ; call TX_BYTE ; return ; TX_FREQ_0.25 movlw b'01111111' ; subwf tx_numberl,w ; skpz ; goto TX_FREQ_0 ; movlw a'0' ; call TX_BYTE ; movlw a'.' ; call TX_BYTE ; movlw a'2' ; call TX_BYTE ; movlw a'5' ; call TX_BYTE ; return ; TX_FREQ_0 movlw b'11111111' ; subwf tx_numberl,w ; skpz ; return ; movlw a'0' ; call TX_BYTE ; return ; ;-------------------------------------------------------------------------------------------------------------------------------------- GET_NUMBER ; reads the ascii characters of the RS232 input buffer and converts this data to an ; eight bit number (0-255), preceding zeros are accepted ; returns in bank 0 with: ; w holds number - carry is cleared - read OK ; w holds junk - carry is set - error: not a number bank0 ; clrf templow ; we will add the values of each character to this register, so start with zero movlw (rx_buffer00+2) ; start position of data in buffer (runs up to and includes maxpos) movwf fsr ; point to this address bcf status,irp ; make sure upper bit in address is zero (select bank 0 and 1) READVALUE movlw h'3A' ; subtract 3A hex from the buffer number subwf indf,w ; if the character is a number, the result should be negative skpnc ; is the result negative? HIGHERR return ; no, so it is not an ascii number, we cannot handle this data, exit with carry set, error addlw h'0A' ; yes, if the character is a number then the result of this addition should be positive skpc ; is the result positive ? LOWERR goto GN_ERROR ; no, we cannot handle this data ADDVALUE addwf templow,f ; yes, store the resulting value skpnc ; is the resulting number greater than 255 decimal ? return ; yes, so it won't fit in 1 byte, we cannot handle this data, exit with carry set, error POINTER incf fsr,f ; no, increase pointer to point to next value movf fsr,w ; use pointer value subwf rx_maxpos,w ; was this the last character ? skpc ; let's see goto READOK ; yes, end loop and go to exit with carry cleared as indication for no errors TESTSIZE movlw d'26' ; the value should be smaller than 26 because 25 times 10 will be 250 subwf templow,w ; and we know there is a next character, result should fit in one byte skpnc ; will the result times 10 be larger than 250 ? return ; yes, we cannot handle this data, exit with carry set, error TIMES10 clrc ; no, go multiply the current value by ten, start off with clear carry bit: rlf templow,f ; first times two, movf templow,w ; store in w, rlf templow,f ; and this makes times 4, rlf templow,f ; and this times 8, addwf templow,f ; plus 2 is 10 times goto READVALUE ; next, do loop again and add new numbers GN_ERROR setc ; indication for not a number, error return ; done READOK movf templow,w ; what is the resulting number value of the ascii characters ? return ; done, exit with carry cleared as indication for no errors ;-------------------------------------------------------------------------------------------------------------------------------------- GET_LNUMBER ; reads the ascii characters of the RS232 input buffer and converts this data to an ; a number from 0-65535, preceding zeros are accepted ; returns in bank 0 with: ; numlow & nummiddle hold number - carry is cleared - read OK ; numlow & nummiddle hold junk - carry is set - error: not a number bank0 ; clrf numlow ; we will add the values of each character to these registers, clrf nummiddle ; so start with zero movlw (rx_buffer00+2) ; start position of data in buffer (runs up to and includes maxpos) movwf fsr ; point to this address bcf status,irp ; make sure upper bit in address is zero (select bank 0 and 1) LREADVALUE movlw h'3A' ; subtract 3A hex from the buffer number subwf indf,w ; if the character is a number, the result should be negative skpnc ; is the result negative? LHIGHERR goto LGN_ERROR ; no, so it is not an ascii number we cannot handle this data addlw h'0A' ; yes, if the character is a number then the result of this addition should be positive skpc ; is the result positive ? LLOWERR goto LGN_ERROR ; no, we cannot handle this data LADDVALUE addwf numlow,f ; yes, store the resulting value skpc ; is the resulting number greater than 255 decimal ? goto LPOINTER ; no, go get next character incf nummiddle,f ; yes, add one count to upper byte of number (perform two byte add with carry) skpnz ; is the resulting number greater than 65535 decimal ? goto LGN_ERROR ; yes, so it won't fit in 2 bytes, we cannot handle this data LPOINTER incf fsr,f ; no, increase pointer to point to next value movf fsr,w ; use pointer value subwf rx_maxpos,w ; was this the last character ? skpc ; let's see return ; yes, end loop and exit with carry cleared as indication for no errors LTESTSIZE movlw d'231' ; the value of the upper byte should not be more than 25 because 25 times 10 will be 250 addwf nummiddle,w ; and we know there is a next character, the result should fit in two bytes skpnc ; is the value of the upper byte equal or more than 25 ? goto LTESTMORE ; yes, go see how much it is exactly and see how much is the lower byte LTIMES10 bcf status,c ; yes, go multiply the current value by ten, start off with clear carry bit: rlf numlow,f ; first times two, movf numlow,w ; movwf templow ; store value temporarily rlf nummiddle,f ; first times two, use carry bit from lower byte movf nummiddle,w ; movwf temphigh ; store value temporarily rlf numlow,f ; and this makes times 4, lower byte rlf nummiddle,f ; and this makes times 4, upper byte, use carry bit of lower byte rlf numlow,f ; and this makes times 8, lower byte rlf nummiddle,f ; and this makes times 8, upper byte, use carry bit of lower byte movf templow,w ; addwf numlow,f ; plus 2 is 10 times, lower byte skpnc ; incf nummiddle,f ; transport carry bit movf temphigh,w ; addwf nummiddle,f ; plus 2 is 10 times, upper byte goto LREADVALUE ; next, do loop again and add new numbers LTESTMORE skpz ; is the value exactly 25 ? return ; no, number won't fit in two bytes therefore we cannot handle this data, exit with carry set movlw d'154' ; yes, lower byte should be smaller than 154 because the total value should be less than 6553 subwf numlow,w ; skpc ; is the number represented by the two bytes smaller than 6554 ? goto LTIMES10 ; yes, continue and multiply by 10 and then fetch next character LGN_ERROR setc ; set error flag return ; no, number won't fit in two bytes therefore we cannot handle this data, exit with carry set ;-------------------------------------------------------------------------------------------------------------------------------------- GET_TIMEANDDATE ; convert the 17 byte Windows format input string 'DD/MM/YY HH:MM:SS' into eight bytes for ; clock, store the values in the time and date buffer in bank2 ; w register content destroyed ; returns in bank2 bank0 ; DATE movlw h'30' ; ascii to binary offset subwf rx_buffer03,w ; get Day and convert from ascii character to binary value bank2 ; movwf date ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer02,f ; get 10 Days and convert from ascii character to binary value swapf rx_buffer02,w ; place result in upper four bits bank2 ; iorwf date,f ; bank0 ; MONTH movlw h'30' ; ascii to binary offset subwf rx_buffer06,w ; get Months and convert from ascii character to binary value bank2 ; movwf month ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer05,f ; get 10 Months and convert from ascii character to binary value swapf rx_buffer05,w ; place result in upper four bits bank2 ; iorwf month,f ; bank0 ; YEAR movlw h'30' ; ascii to binary offset subwf rx_buffer09,w ; get Years and convert from ascii character to binary value bank2 ; movwf year ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer08,f ; get 10 Years and convert from ascii character to binary value swapf rx_buffer08,w ; place result in upper four bits bank2 ; iorwf year,f ; bank0 ; HOURS movlw h'30' ; ascii to binary offset subwf rx_buffer12,w ; get Hours and convert from ascii character to binary value bank2 ; movwf hours ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer11,f ; get 10 Hours and convert from ascii character to binary value swapf rx_buffer11,w ; place result in upper four bits bank2 ; iorwf hours,f ; bcf hours,6 ; select 24 hour clock bank0 ; MINUTES movlw h'30' ; ascii to binary offset subwf rx_buffer15,w ; get Minutes and convert from ascii character to binary value bank2 ; movwf minutes ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer14,f ; get 10 Minutes and convert from ascii character to binary value swapf rx_buffer14,w ; place result in upper four bits bank2 ; iorwf minutes,f ; bank0 ; SECONDS movlw h'30' ; ascii to binary offset subwf rx_buffer18,w ; get Seconds and convert from ascii character to binary value bank2 ; movwf seconds ; move value to clock buffer bank0 ; movlw h'30' ; subwf rx_buffer17,f ; get 10 Seconds and convert from ascii character to binary value swapf rx_buffer17,w ; place result in upper four bits bank2 ; iorwf seconds,f ; bcf seconds,7 ; set bit to enable clock oscillator, is CH (clock halt) bit in clock chip movlw d'1' ; day 1 movwf day ; just start DAY start at day 1, Sunday, although we don't know this for sure, doesn't matter movlw b'10000011' ; set square wave at 32768 Hz but disabled and it's output high movwf clockctrl ; CONTROL return ; return in bank2 ;-------------------------------------------------------------------------------------------------------------------------------------- GET_FREQVALNUM ; convert string data that goes with the logfrequency setting commands to the right lograte ; value according to the following table (example for 16 Hz: 16 > 00000001) ; carry cleared - value is ok ; carry set - error reading number ; 32 00000000 ; 16 00000001 ; 8 00000011 ; 4 00000111 ; 2 00001111 ; 1 00011111 ; 0.5 00111111 ; 0.25 01111111 ; 0 11111111 (actually 1xxxxxxx is used since only bit 7 is tested) F_32 bank0 ; movlw a'3' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_16 ; movlw a'2' ; subwf rx_buffer03,w ; test second data byte skpz ; goto F_ERROR ; movlw rx_buffer03 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00000000' ; clrc ; clear carry to indicate result is ok return F_16 movlw a'1' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_8 ; movlw rx_buffer03 ; subwf rx_maxpos,w ; test length first, we not only have the value 16 but also the value 1 skpz ; goto F_1 ; movlw a'6' ; subwf rx_buffer03,w ; test second data byte skpz ; goto F_ERROR ; movlw b'00000001' ; clrc ; clear carry to indicate result is ok return F_8 movlw a'8' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_4 ; movlw rx_buffer02 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00000011' ; clrc ; clear carry to indicate result is ok return F_4 movlw a'4' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_2 ; movlw rx_buffer02 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00000111' ; clrc ; clear carry to indicate result is ok return F_2 movlw a'2' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_1 ; movlw rx_buffer02 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00001111' ; clrc ; return ; clear carry to indicate result is ok F_1 movlw a'1' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_0 ; movlw rx_buffer02 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00011111' ; clrc ; clear carry to indicate result is ok return F_0 movlw a'0' ; test first data byte subwf rx_buffer02,w ; skpz ; goto F_ERROR ; movlw rx_buffer02 ; subwf rx_maxpos,w ; test length skpz ; goto F_0.5 ; movlw b'11111111' ; clrc ; clear carry to indicate result is ok return F_0.5 movlw a'.' ; test second data byte subwf rx_buffer03,w ; skpz ; goto F_ERROR ; movlw a'5' ; test third data byte subwf rx_buffer04,w ; skpz ; goto F_0.25 ; movlw rx_buffer04 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'00111111' ; clrc ; clear carry to indicate result is ok return F_0.25 movlw a'2' ; test third data byte subwf rx_buffer04,w ; skpz ; goto F_ERROR ; movlw a'5' ; test fourth data byte subwf rx_buffer05,w ; skpz ; goto F_ERROR ; movlw rx_buffer05 ; subwf rx_maxpos,w ; test length skpz ; goto F_ERROR ; movlw b'01111111' ; clrc ; clear carry to indicate result is ok return F_ERROR setc ; none of the values matched return ; return with carry set as indication result is not ok ;-------------------------------------------------------------------------------------------------------------------------------------- ; Commands: ;-------------------------------------------------------------------------------------------------------------------------------------- COMMANDS ; label to allow use of pagesel ;-------------------------------------------------------------------------------------------------------------------------------------- EXIT_ACK movlw h'06' ; acknowledgement (ACK) call TX_BYTE ; send 'command has been accepted', return in bank0 bcf flags1,command ; now command has been handled we can clear the execute flag, ready for next command bcf portc,cts_out ; set CTS to re-enable data stream from computer bsf portb,led_red ; turn on red status led bcf portb,led_green ; turn off green status led return ; done ;-------------------------------------------------------------------------------------------------------------------------------------- EXIT_NAK movlw h'15' ; unknown command, exit, send negative acknowledgement (NAK) call TX_BYTE ; send 'command has NOT been accepted', return in bank0 bcf flags1,command ; clear any command bytes received up to now get, ready for next command bcf portc,cts_out ; set CTS to re-enable data stream from computer bsf portb,led_red ; turn on red status led bcf portb,led_green ; turn off green status led return ; go back to main program loop see what else we can do ;-------------------------------------------------------------------------------------------------------------------------------------- AU ; read the string with the name of the author of this software uses a table read that works ; anywhere in the memory. A normal table read using just the 'addwf pcl' instruction will only ; work if the program code and table code are entirely in the first 8-bit page of program ; memory = the first 256 memory locations ! ; a write opens the backdoor for the serial number write (command SE) btfsc flags1,withdata ; is there any data ? goto AU_COMMAND ; yes, so we should use this data call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank3 ; clrf tablepointer ; start the reading of the table at the first position AU_LOOP movlw high AU_TABLE ; see where the assembler will put the table in PIC memory and get the high byte movwf pclath ; now move this into pclath movlw low AU_TABLE+1 ; load w with the memory address low byte of the first piece of data in the table addwf tablepointer,w ; calculate the offset address and see if it overflows skpnc ; did it overflow ? incf pclath,f ; yes, so increase pclath one count AU_GET_CHAR call AU_TABLE ; no, lookup value in table, returns ascii character in w register xorlw d'00' ; zero indicates end of table skpnz ; are we at the end of the table ? goto TX_COMMANDEND ; yes, exit: send checksum and ETX, clear command flag call TX_BYTE ; returns in bank0 bank3 ; incf tablepointer,f ; point to next position in table goto AU_LOOP ; AU_TABLE movwf pcl ; w contains low program counter byte and points to the next location plus counter retlw a'A' ; offset text in table is 'Andries C. Tip' retlw a'n' ; retlw a'd' ; Note: in a Microchip application note it states that it is neccesary to disable the retlw a'r' ; interrupts before executing the instruction movwf pcl because an interrupt during retlw a'i' ; this instruction may cause the program to jump to an unknown address. It turnes retlw a'e' ; out to be not true, so table reads do not have to disable any interrupts. retlw a's' ; retlw a' ' ; retlw a'C' ; retlw a'.' ; retlw a' ' ; retlw a'T' ; retlw a'i' ; retlw a'p' ; retlw d'00' ; end of message AU_COMMAND bsf flags1,changese ; backdoor to allow serial number to be changed goto EXIT_NAK ; exit and be ready for next command ;-------------------------------------------------------------------------------------------------------------------------------------- CA ; read/write value of static ram address (value 0..63) ; write: input is ascii string with 8 bit number btfsc flags1,withdata ; is there any data ? goto CA_COMMAND ; yes, so we should use this data CA_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank2 ; movf clockaddr,w ; call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte CA_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command andlw b'11000000' ; the maximum address for the clock chip static ram and control bytes is 63 skpz ; is the address value valid ? goto EXIT_NAK ; no, exit and be ready for next command call GET_NUMBER ; again, read the data input number that goes with the command into the w register bank2 ; movwf clockaddr ; goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- CD ; IIC clock chip serial control bytes and static ram read/ write btfsc flags1,withdata ; is there any data ? goto CD_COMMAND ; yes, so we should use this data CD_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel IIC_RD_CLKCHIP ; make right program memory page selection call IIC_RD_CLKCHIP ; get data byte from clock chip into w register pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte CD_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command pagesel IIC_WR_CLKCHIP ; make right program memory page selection call IIC_WR_CLKCHIP ; write byte to static ram pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- CL ; read/set clock time and data in the following format HH:MM:SS MM/DD/YY ; external clock chip is Dallas DS1307 (www.dalsemi.com) btfsc flags1,withdata ; is there any data ? goto CL_COMMAND ; yes, so we should use this data to write to the clock chip through IIC CL_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel IIC_RDCLOCK ; make right program memory page selection call IIC_RDCLOCK ; read the eight time related bytes from external clock chip into buffer (bank2, 68..6F hex) pagesel TX_TIMEANDDATE ; make right program memory page selection call TX_TIMEANDDATE ; send time and date values from the buffer in bank2 as a string, bank2 return goto TX_COMMANDEND ; send checksum and ETX, clear command flag CL_COMMAND call GET_TIMEANDDATE ; convert string serial input buffer, store in time and date buffer in bank2, bank2 return pagesel IIC_WRCLOCK ; make right program memory page selection call IIC_WRCLOCK ; write the eight time related bytes from buffer in bank2 (68..6F) to clock pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- EA ; set eeprom read/write address ; write: input string is 8 bit address btfsc flags1,withdata ; is there any data ? goto EA_COMMAND ; yes, so we should use this data to write to the eeprom location EA_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank2 ; movf iee_address,w ; get address of eeprom location bank0 ; call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte EA_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command bank2 ; movwf iee_address ; store the number for later use with command ED bank0 ; goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ED ; read/write eeprom memory location ; write: input is ascii string with 8 bit number btfsc flags1,withdata ; is there any data ? goto ED_COMMAND ; yes, so we should use this data to write to the eeprom location ED_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank2 ; movf iee_address,w ; get address of eeprom location bank0 ; pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ED_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command pagesel IEE_WRITE ; no, make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ER ; read/write error flags byte ; write: input is ascii string with 8 bit number btfsc flags1,withdata ; is there any data ? goto ER_COMMAND ; yes, so we should use this data to write to the eeprom location ER_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank3 ; movf errors,w ; get value of error flags register call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ER_COMMAND movlw d'15' ; eeprom address for error flags register bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command movwf errors ; write value to error flags register pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FA ; read/write air temperature logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FA_COMMAND ; yes, so we should use this data to write to the eeprom location FA_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_air,w ; get value of lograte for air temperature channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FA_COMMAND movlw d'21' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_air ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FB ; read/write brake switch logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FB_COMMAND ; yes, so we should use this data to write to the eeprom location FB_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_brake,w ; get value of lograte for brake switch channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FB_COMMAND movlw d'27' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_brake ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FE ; read/write lateral acceleration logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FE_COMMAND ; yes, so we should use this data to write to the eeprom location FE_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_lat,w ; get value of lograte for lateral acceleration channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FE_COMMAND movlw d'25' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_lat ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FH ; read/write thermocouple logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FH_COMMAND ; yes, so we should use this data to write to the eeprom location FH_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_tc,w ; get value of lograte for thermocouple channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FH_COMMAND movlw d'20' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_tc ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FL ; read/write lambda logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FL_COMMAND ; yes, so we should use this data to write to the eeprom location FL_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_lambda,w ; get value of lograte for lambda channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FL_COMMAND movlw d'18' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_lambda ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FM ; read/write mark switch logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FM_COMMAND ; yes, so we should use this data to write to the eeprom location FM_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_mark,w ; get value of lograte for mark switch channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FM_COMMAND movlw d'26' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_mark ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FO ; read/write longitudinal acceleration logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FO_COMMAND ; yes, so we should use this data to write to the eeprom location FO_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_long,w ; get value of lograte for longitudinal acceleration channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FO_COMMAND movlw d'24' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_long ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FR ; read/write rpm logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FR_COMMAND ; yes, so we should use this data to write to the eeprom location FR_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_rpm,w ; get value of lograte for rpm channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FR_COMMAND movlw d'16' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_rpm ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FS ; read/write speed logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FS_COMMAND ; yes, so we should use this data to write to the eeprom location FS_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_speed,w ; get value of lograte for speed channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FS_COMMAND movlw d'17' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_speed ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FT ; read/write throttle logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FT_COMMAND ; yes, so we should use this data to write to the eeprom location FT_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_throttle,w ; get value of lograte for throttle channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FT_COMMAND movlw d'23' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_throttle ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FV ; read/write voltage logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FV_COMMAND ; yes, so we should use this data to write to the eeprom location FV_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_voltage,w ; get value of lograte for voltage channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FV_COMMAND movlw d'19' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_voltage ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- FW ; read/write water temperature logging frequency from/to pic eeprom btfsc flags1,withdata ; is there any data ? goto FW_COMMAND ; yes, so we should use this data to write to the eeprom location FW_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; movf freq_water,w ; get value of lograte for water temperature channel call TX_FREQVALSTR ; transmit value as string, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command status byte FW_COMMAND movlw d'22' ; eeprom address for log frequency setting bank2 ; movwf iee_address ; set internal eeprom address pointer call GET_FREQVALNUM ; read the value that goes with the command, convert it and put it in w register skpnc ; were there any errors reading the value ? goto EXIT_NAK ; yes, exit bank3 ; no, movwf freq_water ; copy value pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ID ; read the identification string explaining the application of this PIC chip ; uses a table read that works anywhere in the memory. ; A normal table read using just the 'addwf pcl' instruction will only work if the ; program code and table code are entirely in the first 8-bit page of program ; memory = the first 256 memory locations ! btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank3 ; clrf tablepointer ; start the reading of the table at the first position ID_LOOP movlw high ID_TABLE ; see where the assembler will put the table in PIC memory and get the high byte movwf pclath ; now move this into pclath movlw low ID_TABLE+1 ; load w with the memory address low byte of the first piece of data in the table addwf tablepointer,w ; calculate the offset address and see if it overflows skpnc ; did it overflow ? incf pclath,f ; yes, so increase pclath one count ID_GET_CHAR call ID_TABLE ; no, lookup value in table, returns ascii character in w register xorlw d'00' ; zero indicates end of table skpnz ; are we at the end of the table ? goto TX_COMMANDEND ; yes, exit: send checksum and ETX, clear command status byte call TX_BYTE ; returns in bank0 bank3 ; incf tablepointer,f ; point to next position in table goto ID_LOOP ; ID_TABLE movwf pcl ; w contains low program counter byte and points to the next location plus counter retlw a'M' ; offset text in table is 'Motorcycle Datalogger' retlw a'o' ; retlw a't' ; Note: in a Microchip application note it states that it is neccesary to disable the retlw a'o' ; interrupts before executing the instruction movwf pcl because an interrupt during retlw a'r' ; this instruction may cause the program to jump to an unknown address. It turnes retlw a'c' ; out to be not true, so table reads do not have to disable any interrupts. retlw a'y' ; retlw a'c' ; retlw a'l' ; retlw a'e' ; retlw a' ' ; retlw a'D' ; retlw a'a' ; retlw a't' ; retlw a'a' ; retlw a'l' ; retlw a'o' ; retlw a'g' ; retlw a'g' ; retlw a'e' ; retlw a'r' ; retlw d'00' ; end of message ;-------------------------------------------------------------------------------------------------------------------------------------- KC ; read/write wheel circumference [mm] to/from pic eeprom ; value is used in speed calculation ; write: input is ascii string with 16 bit number btfsc flags1,withdata ; is there any data ? goto KC_COMMAND ; yes, so we should use this data KC_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics movlw d'0' ; eeprom address 0 bank2 ; movwf iee_address ; set address of pic eeprom location pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 movwf numlow ; movlw d'1' ; eeprom address 1 movwf iee_address ; set address of pic eeprom location call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 movwf nummiddle ; pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte KC_COMMAND call GET_LNUMBER ; read the data input number that goes with the command into the numlow and nummiddle register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command movlw d'0' ; bank2 ; movwf iee_address ; set address of pic eeprom location movf numlow,w ; pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w movlw d'1' ; bank2 ; movwf iee_address ; set address of pic eeprom location movf nummiddle,w ; call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel COPY_WHEELC ; make right program memory page selection call COPY_WHEELC ; *** do not update while logging/calculate constant from value pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- KP ; read/write pulses per revolution to/from pic eeprom ; value is used in rpm calculation ; write: input is ascii string with 8 bit number (only values 1 and 2 are allowed) btfsc flags1,withdata ; is there any data ? goto KP_COMMAND ; yes, so we should use this data KP_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics movlw d'4' ; eeprom address 4 bank2 ; movwf iee_address ; set address of pic eeprom location pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w register as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte KP_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command sublw d'1' ; no, the number should be one or two KP_TESTONE skpnz ; is the value one ? goto KP_VALUEOK ; yes, go store value call GET_NUMBER ; no, read the data input number that goes with the command into the w register sublw d'2' ; the number should be one or two KP_TESTTWO skpz ; is the value two ? goto EXIT_NAK ; no, exit and be ready for next command KP_VALUEOK movlw d'4' ; yes, eeprom address 4 bank2 ; movwf iee_address ; set address of pic eeprom location call GET_NUMBER ; read the data input number that goes with the command into the w register pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel COPY_RPMVALUES ; make right program memory page selection call COPY_RPMVALUES ; copy the value from eeprom to pic registers for use during the ccp interrupt pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- KR ; set or read the maximum RPM rate, above this RPM rate, the shift light will be ; turned on when the measured rpm value is more than this maximum, otherwise the shift ; light is off ; write: input is ascii string with a number of not more than 14 bits (0..16383) btfsc flags1,withdata ; is there any data ? goto KR_COMMAND ; yes, so we should use this data KR_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics movlw d'2' ; eeprom address for rpm maximum low byte pagesel IEE_READ ; make right program memory page selection call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 movwf numlow ; movlw d'3' ; eeprom address for rpm maximum high byte call IEE_READ ; read value from internal eeprom, address in w, data returned in w, return in bank2 movwf nummiddle ; pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte KR_COMMAND call GET_LNUMBER ; read the data input number that goes with the command into the numlow and nummiddle register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command movlw b'11000000' ; value for test andwf nummiddle,w ; test if the upper two bits of the received number are ones skpz ; is the received number larger than 16383 ? goto EXIT_NAK ; yes, so it will not fit in 14 bits, exit and be ready for next command movlw d'2' ; no, continue, this is the eeprom address for the rpm maximum low byte bank2 ; movwf iee_address ; select eeprom write address movf numlow,w ; pagesel IEE_WRITE ; make right program memory page selection call IEE_WRITE ; write data to eeprom, address in iee_address, data in w movlw d'3' ; eeprom address for the rpm maximum high byte bank2 ; movwf iee_address ; select eeprom write address movf nummiddle,w ; call IEE_WRITE ; write data to eeprom, address in iee_address, data in w pagesel COPY_RPMVALUES ; make right program memory page selection call COPY_RPMVALUES ; copy the value from eeprom to pic registers for use during the ccp interrupt pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- LS ; **** select start condition for logging (RPM, mark button...) ; input value is eight bit number btfsc flags1,withdata ; is there any data ? goto LS_COMMAND ; yes, so we should use this data LS_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'0' ; **** dummy value call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte LS_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command nop ; **** store the value in the proper place goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- LV ; **** select value for start condition for logging (when RPM, Speed...) ; input value is 16 bit, use 14 bits for RPM or 8 bits for speed btfsc flags1,withdata ; is there any data ? goto LV_COMMAND ; yes, so we should use this data LV_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'0' ; **** dummy value movwf numlow ; movwf nummiddle ; call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte LV_COMMAND call GET_LNUMBER ; read the data input number that goes with the command into numlow and nummiddle registers skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command ;nop ; **** store the value in the proper place goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- RC ; clear all record memory btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RC_COMMAND ; empty line to prevent illegal label error from MPLAB IDE pagesel MEM_CLEAR ; make right program memory page selection call MEM_CLEAR ; clear all bytes of the table of contents, return in bank3 pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- RD ; download record data in blocks of 64 bytes btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RD_REQUEST bank3 ; check if there are any records movf current_rec,w ; get currently selected record number, zero for no selection yet or when no records available skpnz ; are there any records and has there been a record selected yet ? goto EXIT_NAK ; no, exit pagesel MEM_RDBLOCK ; yes, make right program memory page selection call MEM_RDBLOCK ; copy data block to buffer in bank1, increase blocknumber, carry set when all blocks were done pagesel EXIT_NAK ; make right program memory page selection RD_RI_CODE skpnc ; have we sent all blocks ? (from here same code for RD and RI commands) goto EXIT_NAK ; yes, exit RD_TRANSMIT call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bcf status,irp ; make sure upper bit in address is zero (select bank 0 and 1) movlw blockbuff00 ; start position of data in buffer in bank1 movwf fsr ; point to this address RD_LOOP bank1 ; the buffer is in bank 1 movf indf,w ; read the data byte at the right position in the buffer call TX_BYTE ; transmit the value of the w register, return in bank0 incf fsr,f ; increase pointer to point to next value movf fsr,w ; get pointer value sublw blockbuff63 ; was this the last byte ? skpnc ; let's see goto RD_LOOP ; no, do loop again and read next data byte goto TX_COMMANDEND ; no, send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- RI ; increment block number, then download record data in blocks of 64 bytes btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RI_REQUEST bank3 ; check if there are any records movf current_rec,w ; get currently selected record number, zero for no selection yet or when no records available skpnz ; are there any records and has there been a record selected yet ? goto EXIT_NAK ; no, exit pagesel MEM_INC_RDBLOCK ; yes, make right program memory page selection call MEM_INC_RDBLOCK ; copy data block to buffer in bank1, increase blocknumber, carry set when all blocks were done pagesel RD_RI_CODE ; make right program memory page selection goto RD_RI_CODE ; from here same code as for RD command, save space ;-------------------------------------------------------------------------------------------------------------------------------------- RM ; return the percentage of memory that is used ; value 0..100% btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RM_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel MEM_USAGE ; make right program memory page selection call MEM_USAGE ; **** get the percentage of used space of external eeprom memory into w register, bank? return pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- RN ; number of records in datalogger memory ; value 0..20 btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RN_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel MEM_GETNUMRECS ; make right program memory page selection call MEM_GETNUMRECS ; get the number of records stored in memory, value stored in num_records, bank1/3 return bank3 ; movf num_records,w ; copy the number of records pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- RS ; select one record for downloading and reset the block download position to the start of ; this record ; valid value range is 1..number of available records (maximum 20) btfsc flags1,withdata ; is there any data ? goto RS_COMMAND ; yes, so we should use this data RS_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank3 ; movf current_rec,w ; get the number of the currently selected record call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte RS_COMMAND ; empty line to prevent illegal label error from MPLAB IDE pagesel MEM_GETNUMRECS ; make right program memory page selection call MEM_GETNUMRECS ; get the number of records stored in memory, value stored in num_records, bank1/3 return pagesel GET_NUMBER ; make right program memory page selection call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command iorlw d'0' ; see if number is zero without changing w register, the number should not be less than one skpnz ; is the number zero ? goto EXIT_NAK ; yes, exit bank3 ; no, continue subwf num_records,w ; see if the new value is valid skpc ; is the new value more than the available number of records ? goto EXIT_NAK ; yes, do not update value and exit, be ready for next command call GET_NUMBER ; no, again read the data input number that goes with the command into the w register pagesel MEM_SELECTREC ; make right program memory page selection call MEM_SELECTREC ; select record for downloading by value in w register and reset the block download pointer pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- RT ; read start time and date of the currently selected record ; in the following format HH:MM:SS MM/DD/YY btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RT_REQUEST bank3 ; no, check current record selection movf current_rec,w ; test for zero value skpnz ; are there any records and is there already a valid record selected ? goto EXIT_NAK ; no, exit call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel MEM_GETTIMEDATE ; make right program memory page selection call MEM_GETTIMEDATE ; store start time and date of currently selected record in the time and date buffer in bank2 pagesel TX_TIMEANDDATE ; make right program memory page selection call TX_TIMEANDDATE ; send time and date values from the buffer in bank2 as a string, bank2 return goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- RZ ; get record size (in bits !) of currently selected record btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit RZ_REQUEST bank3 ; no, check current record selection movf current_rec,w ; test for zero value skpnz ; are there any records and is there already a valid record selected ? goto EXIT_NAK ; no, exit call TX_COMMANDSTART ; yes, send ACK, STX and command mnemonics pagesel MEM_GETRECSIZE ; make right program memory page selection call MEM_GETRECSIZE ; store size (in bits) of currently selected record into registers numlow, nummiddle, numhigh pagesel TX_WNUMBER ; make right program memory page selection call TX_WNUMBER ; transmit the 24 bit number in numlow(lsB), nummiddle and numhigh(msB), bank0 return goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- SE ; get serial number of device from location in bootloader area ; the four topmost words in PIC flash memory are reserved for storing serial numbers etc. ; after the write backdoor is closed again btfsc flags1,withdata ; is there any data ? goto SE_COMMAND ; yes, so we should use this data SE_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics call SE_LOADADDRESS ; bank2 return pagesel FLASHREAD ; make right program memory page selection call FLASHREAD ; read flash program memory, address in eeadr/eeadrh, data in eedata/eedath, bank3 return bank2 ; movf eedata,w ; get data value into wordlow and wordmiddle movwf numlow ; movf eedath,w ; movwf nummiddle ; pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte SE_COMMAND call GET_LNUMBER ; read the data input number that goes with the command into the numlow and nummiddle register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command btfss flags1,changese ; check the backdoor flag that allows the serial number to be changed goto EXIT_NAK ; yes, exit and be ready for next command movlw b'00111111' ; words of pic program memory are 14 bits wide, strip upper two bits andwf nummiddle,f ; movf numlow,w ; copy data bank2 ; movwf eedata ; low movf nummiddle,w ; movwf eedath ; high bcf flags1,changese ; clear backdoor flag that allows serial number to be changed call SE_LOADADDRESS ; bank2 return pagesel FLASHWRITE ; make right program memory page selection call FLASHWRITE ; write flash memory,addr. in eeadr/eeadrh,data in eedata/eedath, carry set on error, bank2 ret. pagesel EXIT_ACK ; make right program memory page selection skpnc ; was the data written ok ? goto EXIT_NAK ; exit, there was a data write verification error goto EXIT_ACK ; done SE_LOADADDRESS bank2 ; movlw h'FF' ; get low byte value movwf eeadr ; low byte movlw h'1F' ; get low byte value movwf eeadrh ; high byte return ; return in bank2 ;------------------------------------------------------------------------------------------------------------------------------------- SV ; read firmware build version (for example: 1.66) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit SV_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics movlw fwv0 ; version bytes, defined at the very top of this program call TX_BYTE ; movlw a'.' ; call TX_BYTE ; movlw fwv1 ; call TX_BYTE ; movlw fwv2 ; call TX_BYTE ; goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- V0 ; get values of all inputs (read only), separated by a horizonal tab (456 22 1014 ...) ; actual command mnemonic is V$, but we cannot use the dollar character in labels ; transmit order: ; RPM,speed,lambda,voltage,thermocouple,air,water,throttle,longitudinal,lateral,digital btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit V0_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics V0_RPM ; prevent mplab ide errror pagesel CALC_RPM ; make right program memory page selection call CALC_RPM ; yes, calculate the RPM value from the time interval between the input pulses, return in bank2 movf rpm_low,w ; get low byte value movwf numlow ; movf rpm_high,w ; get high byte value movwf nummiddle ; pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters V0_TAB0 movlw d'9' ; seperator character is ascii horizontal tab character call TX_BYTE ; send separator character V0_SPEED ; prevent mplab ide errror pagesel CALC_SPEED ; make right program memory page selection call CALC_SPEED ; calculate speed value from time interval between input pulses, return in bank2 movf speed,w ; get value pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w register as ascii characters V0_TAB1 movlw d'9' ; seperator character is ascii horizontal tab character call TX_BYTE ; send separator character V0_ANALOG_CHAN clrf adchannel ; start at channel zero V0_LOOP movf adchannel,w ; select channel pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters V0_TAB2 movlw d'9' ; seperator character is ascii horizontal tab character call TX_BYTE ; send separator character incf adchannel,f ; select next channel movlw d'8' ; there's eight analog channels subwf adchannel,w ; see if we have done all skpz ; was this the last measurement ? goto V0_LOOP ; no, next V0_DIGITAL bank0 ; yes, movf portb,w ; get the status of portb call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; exit, send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VA ; get value of air temperature analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VA_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'3' ; analog input channel 3 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VD ; get the value of digital portb, which are the digital inputs (upper two bits are outputs) ; read: bit7=green led, red led, brdsuppl,tcdisc,laptime,brake,mark,_run_/log=bit0 ; write: only upper two bits (the leds) are written btfsc flags1,withdata ; is there any data ? goto VD_COMMAND ; yes, so we should use this data to write to the eeprom location VD_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank0 ; movf portb,w ; get the status of portb call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag VD_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command bank0 xorwf portb,w ; calculate the difference between new data and the actual status andlw b'11000000' ; mask, we only should only change bits 6 and 7 which are outputs xorwf portb,f ; flip bits if they are not the same and write the new value to portb goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- VE ; get value of lateral g-sensor analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VE_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'7' ; analog input channel 7 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VH ; get value of throttle (handlebar) analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VH_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'5' ; analog input channel 5 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VI ; set or read the eight leds of port D (shift light leds) btfsc flags1,withdata ; is there any data ? goto VI_COMMAND ; yes, so we should use this data VI_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics bank0 ; movf portd,w ; get the current leds status call TX_NUMBER ; transmits the value of w as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte VI_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command bank0 ; movwf portd ; set leds to new value goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- VL ; get value of lambda analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VL_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'0' ; analog input channel 0 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VO ; get value of longitudinal g-sensor analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VO_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'6' ; analog input channel 6 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VR ; returns value of engine rpm, calculated from pulses on CCP1 input btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VR_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel CALC_RPM ; make right program memory page selection call CALC_RPM ; calculate the RPM value from the time interval between the input pulses, return in bank2 movf rpm_low,w ; get low byte value bank0 ; movwf numlow ; bank2 ; movf rpm_high,w ; get high byte value bank0 ; movwf nummiddle ; pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- VS ; returns value of vehicle speed in km/hr, calculated from pulses on CCP2 input btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VS_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel CALC_SPEED ; make right program memory page selection call CALC_SPEED ; calculate speed value from time interval between input pulses, return in bank2 movf speed,w ; get value pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmits the value of w register as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte ;-------------------------------------------------------------------------------------------------------------------------------------- VT ; get value of thermocouple analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VT_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'2' ; analog input channel 2 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters, return in bank0 goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VV ; get value of voltage analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VV_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'1' ; analog input channel 1 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- VW ; get value of water temperature analog input (read only) btfsc flags1,withdata ; is there any data ? goto EXIT_NAK ; yes, exit VW_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics movlw d'4' ; analog input channel 4 pagesel GET_ANALOG ; make right program memory page selection call GET_ANALOG ; get value of analog input (selected by w register) into numlow and nummiddle, return in bank1 pagesel TX_LNUMBER ; make right program memory page selection call TX_LNUMBER ; transmit value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command flag ;-------------------------------------------------------------------------------------------------------------------------------------- XA ; set external eeprom address, input is ascii string with 16 bit number btfsc flags1,withdata ; is there any data ? goto XA_COMMAND ; yes, so we should use this data XA_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank1 ; movf iicalow,w ; copy iic address registers to rs232 number receive/transmit registers bank0 ; movwf numlow ; bank1 ; movf iicahigh,w ; bank0 ; movwf nummiddle ; call TX_LNUMBER ; transmits the value of numlow and nummiddle as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte XA_COMMAND call GET_LNUMBER ; read the data input number that goes with the command into the numlow and nummiddle register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command btfsc nummiddle,7 ; size of the eeproms is 32k x 8 (256kbit), therefore the address maximum is 32767 goto EXIT_NAK ; movf numlow,w ; store address in iic address registers bank1 ; movwf iicalow ; bank0 ; movf nummiddle,w ; bank1 ; movwf iicahigh ; goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- XC ; select external eeprom chip, input is ascii character with 8 bit number (0..7) btfsc flags1,withdata ; is there any data ? goto XC_COMMAND ; yes, so we should use this data XC_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics bank1 ; movf iicchip,w ; get number of selected chip call TX_NUMBER ; transmits the value w register as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte XC_COMMAND call GET_NUMBER ; read the data input number that goes with the command into w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command sublw d'7' ; maximum number of eeprom chips is eight, therefore the number should be from 0..7 skpc ; is the number larger than 7 ? goto EXIT_NAK ; yes, exit and be ready for next command sublw d'7' ; no, restore w register content to its previous value bank1 ; movwf iicchip ; store new chip select value goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- XD ; read/write data byte from external eeprom value ; write: input is ascii string with 8 bit number btfsc flags1,withdata ; is there any data ? goto XD_COMMAND ; yes, so we should use this data XD_REQUEST call TX_COMMANDSTART ; send ACK, STX and command mnemonics pagesel IIC_RDBYTE ; make right program memory page selection call IIC_RDBYTE ; read data byte from external eeprom, address is in iicchip, iicalow and iicahigh bank1 ; movf iicdata,w ; store data byte in w register bank0 ; pagesel TX_NUMBER ; make right program memory page selection call TX_NUMBER ; transmit the value of the w register as ascii characters goto TX_COMMANDEND ; send checksum and ETX, clear command status byte XD_COMMAND call GET_NUMBER ; read the data input number that goes with the command into the w register skpnc ; errors reading number ? goto EXIT_NAK ; yes, exit and be ready for next command bank1 ; movwf iicdata ; store data byte from w register pagesel IIC_WRBYTE ; make right program memory page selection call IIC_WRBYTE ; write byte in iicdata to external eeprom, address in iicchip, iicalow and iicahigh pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- XP ; read/write data 1 block of 64 bytes from external eeprom ; write 64 bytes of data from RS232 input buffer ; **** the receive routine prevents the character h'03' to be included in the data ! btfsc flags1,withdata ; is there any data ? goto XP_COMMAND ; yes, so we should use this data XP_REQUEST call TX_COMMANDSTART ; no, send ACK, STX and command mnemonics pagesel IIC_RDBLOCK ; make right program memory page selection call IIC_RDBLOCK ; read 64 data bytes from external eeprom, address in iicchip, iicalow and iicahigh bcf status,irp ; make sure upper bit in bank address is zero (select bank 0 and 1) movlw h'AF' ; start position of data in buffer in bank1 movwf fsr ; point to this address XP_LOOP1 movf indf,w ; read the data byte at the right position in the buffer pagesel TX_BYTE ; make right program memory page selection call TX_BYTE ; transmit the value of the w register incf fsr,f ; increase pointer to point to next value movf fsr,w ; use pointer value sublw h'EE' ; was this the last byte ? skpnc ; let's see goto XP_LOOP1 ; no, do loop again and read next data byte goto TX_COMMANDEND ; send checksum and ETX, clear command status byte XP_COMMAND bank0 ; check that we actually got 64 bytes movlw rx_buffer65 ; position of last data byte subwf rx_maxpos,w ; test length skpz ; did we get exactly 64 data bytes ? goto EXIT_NAK ; no, exit and be ready for next command movlw h'2F' ; yes, copy the 64 databytes from databuffer in bank0 to the block buffer in bank1 movwf fsr ; point to the start position of the data buffers in bank0 and bank1 (!) bcf status,irp ; make sure upper bit in bank address is zero (select bank 0 and 1) XP_LOOP2 movf indf,w ; read the data byte at the right position in the buffer bsf fsr,7 ; the block buffer is in bank1 (hex 80 to hex FF) movwf indf ; write the data byte incf fsr,f ; increase pointer to point to next value bcf fsr,7 ; the receive databuffer is in bank 0 (hex 00 to hex 7F) movf fsr,w ; use pointer value sublw h'6E' ; was this the last byte ? skpnc ; let's see goto XP_LOOP2 ; no, do loop again and read next data byte pagesel IIC_WRBLOCK ; make right program memory page selection call IIC_WRBLOCK ; yes, write 64 bytes to external eeprom, address in iicchip, iicalow and iicahigh pagesel EXIT_ACK ; make right program memory page selection goto EXIT_ACK ; done ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------------------------------------- org h'1800' ; start of program memory page 3 ;-------------------------------------------------------------------------------------------------------------------------------------- ; command interpreter: find and go execute selected command ;-------------------------------------------------------------------------------------------------------------------------------------- ; ; to do commands are marked with a '>' character ; non optimized commands are marked with '***' ; ; mnemonic read/ value range or description ; write example ; ; ; AU R(/W) Andries C. Tip returns software author, a write opens the backdoor to change serial number ; ; CL R/W 05/31/04 11:23:47 clock time and date in the following format MM/DD/YY HH:MM:SS ; CA R/W 0..63 clock static ram address byte (address wraps around) ; CD R/W 0..255 clock static ram data byte at address specified by CA ; ; EA R/W 0..255 address location for PIC internal eeprom ; ED R/W 0..255 data of the PIC internal eeprom at the address specified by EA ; ER R/W 0..255 error flag bits, bits will be set when errors occur during logging ; ; FA R/W 32 air temperature logging frequency ; FB R/W 16 brake switch logging frequency ; FE R/W 8 lateral acceleration logging frequency ; FH R/W 0 thermocouple logging frequency ; FL R/W 2 lambda logging frequency ; FM R/W 1 mark switch logging frequency ; FO R/W 0.5 longitudinal acceleration logging frequency ; FR R/W 0.25 rpm logging frequency ; FS R/W 0 speed logging frequency ; FT R/W 4 throttle logging frequency ; FV R/W 0 voltage logging frequency ; FW R/W 0 water temperature logging frequency ; ; ID R Motorcycle Datalogger returns device identification string ; ; >KA R/W 0..16383 engine stationary RPM adjust, left half of leds are on, 0=off ; >KB R/W 0..16383 engine high RPM adjust. right half of leds are on, 0=off ; KC R/W 1..65535 wheel circumference [millimeters] used in speed calculation ; >KN R/W 1..255 puls count setting: Number of notches/pulses per revolution of wheel ; >KP R/W 2 pulses per crankshaft revolution, used in rpm calculation ; KR R/W 0..16383 max RPM rate, leds will flash above this rate ; ; >LS R/W 0..255 select logging start condition (Rotary switch, Mark Button, Speed, RPM) ; >LV R/W 0..16363 select value for logging start condition (when RPM/Speed) ; ; >PA R/W 1..7/13 select the desired logging resolution of a channel ; ; RN R 0..20 number of records in datalogger memory ; RS R/W 0..19 select a record for downloading ; RT R 07/28/04 12:32:04 record start time and date in the following format MM/DD/YY HH:MM:SS ; RZ R 93645543 get record size (in bits !) and reset download position ; RD R 6%gr'@:sE.... download record data in blocks of one block (64 bytes) ; RI R 6%gr'@:sE.... increment block, then download record data in blocks of one block (64 bytes) ; RC W clear all record memory ; >RM R 0..100 memory usage/maximum memory address ?? ; ; >SD R 14/28/04 device programming date, stored in flash program memory of bootloader ; SE R(/W) 0..16383 device serial number in top of flash program memory, see AU command ; >ST R 0..255 datalogger status (busy, idle, full, error, etc.) ; SV R 1.55 returns firmware version ; ; V$ R 0..1023 values of all inputs separated by a tab (234 444 ...) ; VA R 0..1023 analog input channel 3: air temperature (NTC) ; VD R/W 0..255 status of digital portb ; VE R 0..1023 analog input channel 7: lateral G-sensor ; VH R 0..1023 analog input channel 5: throttle (0..5V) ; VI R/W 0..255 status of leds at portd functioning as shift light and rpm counter ; VL R 0..1023 analog input channel 0: lambda sensor ; VO R 0..1023 analog input channel 6: longitudinal G-sensor ; VR R 0..16383 RPM rate (ccp1 pulse input) ; VS R 0..255 Speed [km/hr] from ccp2 pulse input ; VT R 0..1023 analog input channel 2: K-type thermocouple ; VV R 0..1023 analog input channel 1: voltage in 0..5 V ; VW R 0..1023 analog input channel 4: water temperature (NTC) ; ; XA R/W 0..32767 external eeprom address ; XC R/W 0..7 select external eeprom chip ; XD R/W 0..255 data byte of the external eeprom at the position specified by XA and XC ; XP R/W ABC@%432_;!... block size read or write (64 bytes) external eeprom ; ;-------------------------------------------------------------------------------------------------------------------------------------- EXEC_COMMAND ; go look in buffer to find out which command was sent and has to be executed ; a command starts with two letters which may be followed by one or more data bytes ; remember CTS has already been cleared to hold data stream from computer ; CTS will be set again after command execution to re-enable data reception bank0 ; bcf portb,led_red ; turn off red status led bsf portb,led_green ; turn on green status led A? movlw a'A' ; subwf rx_buffer00,w ; skpnz ; goto A_ ; C? movlw a'C' ; does the command start with the letter 'C' ? subwf rx_buffer00,w ; compare to first command character (first byte in buffer) skpnz ; let's see goto C_ ; yes it does, go to all commands starting with the letter 'C' E? movlw a'E' ; subwf rx_buffer00,w ; skpnz ; goto E_ ; F? movlw a'F' ; subwf rx_buffer00,w ; skpnz ; goto F_ ; I? movlw a'I' ; subwf rx_buffer00,w ; skpnz ; goto I_ ; K? movlw a'K' ; subwf rx_buffer00,w ; skpnz ; goto K_ ; L? movlw a'L' ; subwf rx_buffer00,w ; skpnz ; goto L_ ; R? movlw a'R' ; subwf rx_buffer00,w ; skpnz ; goto R_ ; S? movlw a'S' ; subwf rx_buffer00,w ; skpnz ; goto S_ ; V? movlw a'V' ; subwf rx_buffer00,w ; skpnz ; goto V_ ; X? movlw a'X' ; subwf rx_buffer00,w ; skpnz ; goto X_ ; pagesel EXIT_NAK ; make right program memory page selection goto EXIT_NAK ; no command mnemonic matched, exit ;-------------------------------------------------------------------------------------------------------------------------------------- A_ ; empty line to prevent mplab editor error pagesel COMMANDS ; make right program memory page selection movlw a'U' ; subwf rx_buffer01,w ; skpnz ; goto AU ; goto EXIT_NAK ; exit_nak is on same page as commands so pagesel is valid C_ ; empty line to prevent mplab editor error pagesel COMMANDS ; movlw a'A' ; subwf rx_buffer01,w ; skpnz ; goto CA ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto CD ; movlw a'L' ; subwf rx_buffer01,w ; skpnz ; goto CL ; goto EXIT_NAK ; E_ ; pagesel COMMANDS ; movlw a'A' ; subwf rx_buffer01,w ; skpnz ; goto EA ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto ED ; movlw a'R' ; subwf rx_buffer01,w ; skpnz ; goto ER ; goto EXIT_NAK ; F_ ; pagesel COMMANDS ; movlw a'A' ; subwf rx_buffer01,w ; skpnz ; goto FA ; movlw a'B' ; subwf rx_buffer01,w ; skpnz ; goto FB ; movlw a'E' ; subwf rx_buffer01,w ; skpnz ; goto FE ; movlw a'H' ; subwf rx_buffer01,w ; skpnz ; goto FH ; movlw a'M' ; subwf rx_buffer01,w ; skpnz ; goto FM ; movlw a'L' ; subwf rx_buffer01,w ; skpnz ; goto FL ; movlw a'O' ; subwf rx_buffer01,w ; skpnz ; goto FO ; movlw a'R' ; subwf rx_buffer01,w ; skpnz ; goto FR ; movlw a'S' ; subwf rx_buffer01,w ; skpnz ; goto FS ; movlw a'T' ; subwf rx_buffer01,w ; skpnz ; goto FT ; movlw a'V' ; subwf rx_buffer01,w ; skpnz ; goto FV ; movlw a'W' ; subwf rx_buffer01,w ; skpnz ; goto FW ; goto EXIT_NAK ; I_ ; pagesel COMMANDS ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto ID ; goto EXIT_NAK ; K_ ; pagesel COMMANDS ; movlw a'C' ; subwf rx_buffer01,w ; skpnz ; goto KC ; movlw a'P' ; subwf rx_buffer01,w ; skpnz ; goto KP ; movlw a'R' ; subwf rx_buffer01,w ; skpnz ; goto KR ; goto EXIT_NAK ; L_ ; pagesel COMMANDS ; movlw a'S' ; subwf rx_buffer01,w ; skpnz ; goto LS ; movlw a'V' ; subwf rx_buffer01,w ; skpnz ; goto LV ; goto EXIT_NAK ; R_ ; pagesel COMMANDS ; movlw a'C' ; subwf rx_buffer01,w ; skpnz ; goto RC ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto RD ; movlw a'I' ; subwf rx_buffer01,w ; skpnz ; goto RI ; movlw a'M' ; subwf rx_buffer01,w ; skpnz ; goto RM ; movlw a'N' ; subwf rx_buffer01,w ; skpnz ; goto RN ; movlw a'S' ; subwf rx_buffer01,w ; skpnz ; goto RS ; movlw a'T' ; subwf rx_buffer01,w ; skpnz ; goto RT ; movlw a'Z' ; subwf rx_buffer01,w ; skpnz ; goto RZ ; goto EXIT_NAK ; S_ ; pagesel COMMANDS ; movlw a'E' ; subwf rx_buffer01,w ; skpnz ; goto SE ; movlw a'V' ; subwf rx_buffer01,w ; skpnz ; goto SV ; goto EXIT_NAK ; V_ ; pagesel COMMANDS ; movlw a'$' ; subwf rx_buffer01,w ; skpnz ; goto V0 ; movlw a'R' ; subwf rx_buffer01,w ; skpnz ; goto VR ; movlw a'S' ; subwf rx_buffer01,w ; skpnz ; goto VS ; movlw a'A' ; subwf rx_buffer01,w ; skpnz ; goto VA ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto VD ; movlw a'E' ; subwf rx_buffer01,w ; skpnz ; goto VE ; movlw a'H' ; subwf rx_buffer01,w ; skpnz ; goto VH ; movlw a'I' ; subwf rx_buffer01,w ; skpnz ; goto VI ; movlw a'L' ; subwf rx_buffer01,w ; skpnz ; goto VL ; movlw a'O' ; subwf rx_buffer01,w ; skpnz ; goto VO ; movlw a'T' ; subwf rx_buffer01,w ; skpnz ; goto VT ; movlw a'V' ; subwf rx_buffer01,w ; skpnz ; goto VV ; movlw a'W' ; subwf rx_buffer01,w ; skpnz ; goto VW ; goto EXIT_NAK ; X_ ; pagesel COMMANDS ; movlw a'A' ; subwf rx_buffer01,w ; skpnz ; goto XA ; movlw a'C' ; subwf rx_buffer01,w ; skpnz ; goto XC ; movlw a'D' ; subwf rx_buffer01,w ; skpnz ; goto XD ; movlw a'P' ; subwf rx_buffer01,w ; skpnz ; goto XP ; goto EXIT_NAK ; ;-------------------------------------------------------------------------------------------------------------------------------------- org h'1EA4' ; start of bootloader version 1.1 from file boot31.asm is at h'1EA5' !!! nop ; force assembler to notice the start of this page ; we switched off the assember error messages but we want to see if we cross boundaries ;-------------------------------------------------------------------------------------------------------------------------------------- end ; tell the assembler to stop
file: /Techref/member/AT-planet-T9/datalogger.htm, 425KB, , updated: 2011/2/23 22:13, local time: 2024/10/4 07:51,
owner: AT-planet-T9,
35.171.164.77:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.massmind.org/Techref/member/AT-planet-T9/datalogger.htm"> Datalogger</A> |
Did you find what you needed? |