' ========================================================================= ' File....... milltach.SXB ' Purpose.... Display optical RPM reading to 4 element matrix'd 7led display ' Author..... David Mcanulty ' E-mail..... dave000@hellspark.com ' Started.... NOV 2007 ' Updated.... DEC 11 2007 bells and whistles edition ' ========================================================================= ' -----[ Program Description ]--------------------------------------------- ' This program is designed to read via rb.0 (schmitt triggered) pulses from ' An IR reciever that are being reflected off a spinning spindle of a micro ' milling machine. ' ' Eventually i want to add a EEPROM to store diffrent rpm rates. I'd also ' Like to experemint with running this via a battery and "sleep" the SX '------{ Device Settings ]------------------------------------------------- DEVICE SX28,TURBO,BANKS8,OSCHS3,SYNC,OPTIONX FREQ 50_000_000 ID "MILLTACH" ' -----[ I/O Definitions ]------------------------------------------------- Sensor PIN RB.0 INPUT SCHMITT ' INTR_RISE button PIN RB.1 INPUT '7 segment display vars Segs PIN RC OUTPUT ' Segments on RC.0 - RC.7 Digs PIN RA OUTPUT ' Digit control pins (gnd) SDA PIN RB.1 INPUT PULLUP SCL PIN RB.2 INPUT PULLUP ' -----[ Constants ]------------------------------------------------------- Blank CON %00000000 ' all segments off Ltr_O CON %00111111 ' pattern for "O" Ltr_F CON %01110001 ' pattern for "F" SlaveID CON $A0 ' for G16069 24C00 128 BIT Serial EEPROM Ack CON 0 Nak CON 1 Button_Down CON 0 Button_Up CON 1 ' -----[ Variables ]------------------------------------------------------- ' have room for 2 more words ' Display vars display VAR Byte(3) ' multiplexed segments digPntr VAR Byte ' digit pointer digLimit VAR Byte ' 0-3 ' tach vars rpm VAR WORD rpmlast VAR WORD dividendMSW VAR WORD dividendLSW VAR WORD 'eeprom vars addr VAR Word ' address in eeprom addrLo VAR addr_LSB addrHi VAR addr_MSB counter VAR Byte 'wanna be local variables tmpW1 VAR Word tmpW2 VAR Word tmpB1 VAR Byte tmpB2 VAR Byte pWidth VAR tmpW1 ' Variable "pWidth0" will use the same memory space as variable "tmpW1". pWidth0 VAR tmpW1 ' Variable "pWidth0" will use the same memory space as variable "tmpW1". pWidth1 VAR tmpW2 ' Variable "pWidth1" will use the same memory space as variable "tmpW2". Tach_Array VAR BYTE(16) 'Create a 16-byte array to hold tach variables. overflow VAR Tach_Array(0).0 'Uses byte 0, bit 0 of Tach_Array. doneBit VAR Tach_Array(0).1 'Uses byte 0, bit 1 of Tach_Array. ReadSensor VAR counter ' Watch statements for debuging WATCH rpm watch RPM_LSB watch RPM_MSB watch rpmlast watch rpmlast_LSB watch rpmlast_MSB WATCH pWidth WATCH Segs, 8, UBIN WATCH Digs, 4, UBIN WATCH addr ' for Debug/Poll mode WATCH button WATCH counter ' JUMP SUB DECLARTIONS SO INTERRUPTS STAY ON PAGE0 INTERRUPT ISR_Start: GOTO Int_Start ' ------------------------------------------------------------------------- ' Subroutine Declarations ' ------------------------------------------------------------------------- DELAY_MS SUB 1, 2 ' delay in milliseconds MEM_OUT SUB 3 ' write value to eeprom memory MEM_IN FUNC 1,2 ' read byte from eeprom memory PUSH_NEW_DISPLAY_VARS SUB ' ------------------------------------------------------------------------- ' THE INTERRUPT ' ------------------------------------------------------------------------- Int_Start: IF ReadSensor = 250 THEN ReadSensor = 0 rpmlast = rpm ' Measure pulse low time PULSIN Sensor, 0, pWidth0 ' Measure pulse high time PULSIN Sensor, 1, pWidth1 ' Find total pulse time (high + low) pWidth = pWidth0 + pWidth1 ' Set dividend to 6,000,000 ($5B8D80) this many 10u/seconds in a minute dividendMSW = $005B dividendLSW = $8D80 ' Perform 32 bit division (rpm = dividend / pWidth) rpm = 1 overflow = 0 DO doneBit = rpm.15 rpm = rpm << 1 IF overflow = 1 THEN rpm.0 = 1 dividendMSW = dividendMSW - pWidth ELSE IF dividendMSW >= pWidth THEN rpm.0 = 1 dividendMSW = dividendMSW - pWidth ENDIF ENDIF overflow = dividendMSW.15 dividendMSW = dividendMSW << 1 dividendMSW.0 = dividendLSW.15 dividendLSW = dividendLSW << 1 LOOP UNTIL doneBit = 1 rpm = rpm << 1 rpm.0 = overflow IF dividendMSW >= pWidth THEN rpm.0 = 1 ENDIF ENDIF Update_Display: INC digPntr ' point to next digit IF digPntr = digLimit THEN ' update digit digPntr = 0 ' wrap if needed ENDIF Segs = Blank ' blank display (remove all grounds) READ DigCtrl + digPntr, Digs ' select display element (select Digit # to ground) Segs = display(digPntr) ' output new digit segs (select + to activate) ISR_Exit: RETURNINT ' ========================================================================= PROGRAM Start ' ========================================================================= ' ------------------------------------------------------------------------- ' Program Code ' ------------------------------------------------------------------------- Start: ST_B = %00000001 ' make RB.1 schmitt triggered 'PLP_B = %00000001 ' pullup (1=up) unused pins Digs = %1110 ' rightmost digit ground on segs = %10000000 ' light up decimal point to show resets/etc DELAY_MS 1000 ' pause to show init/resets/brownouts/etc rpm = 0 OPTION = $88 DO ReadSensor=0 'This causes the interrupt to sample the tach into Rpm if rpm <> rpmlast THEN PUSH_NEW_DISPLAY_VARS ENDIF 'DELAY_MS 240 BREAK LOOP END 'read last rpm ' addr=0 ' rpmlast_LSB = MEM_IN addr ' get from eeprom ' addr=1 ' rpmlast_MSB = MEM_IN addr ' get from eeprom ' DELAY_MS 500 'delay for poll mode (debug) ' 'write current rpm ' if button = button_down THEN ' RPM=1234 ' addr=0 ' MEM_OUT addr, rpm_LSB ' send to eeprom ' DELAY_MS 12 ' per datasheet "4 ms maximum byte write cycle time" ' addr=1 ' MEM_OUT addr, rpm_MSB ' DELAY_MS 12 ' per datasheet "4 ms maximum byte write cycle time" ' endif ' ------------------------------------------------------------------------- ' Subroutine Code ' ------------------------------------------------------------------------- SUB PUSH_NEW_DISPLAY_VARS IF rpm = 0 THEN PUT display(0), Ltr_F, Ltr_F, Ltr_O ' if 0, show "OFF" digLimit = 3 ELSE digLimit = 1 ' at least one digit IF rpm > 9 THEN ' into 10s? INC digLimit ' -- yes, show another digit ENDIF IF rpm > 99 THEN ' into 100s? INC digLimit ' -- yes, show another digit ENDIF IF rpm > 999 THEN ' into 1000s? INC digLimit ' -- yes, show another digit ENDIF tmpW1 = rpm ' convert value to segments tmpW2 = tmpW1 / 100 tmpW1 = __REMAINDER READ SegMaps + tmpW2, display(2) tmpW2 = tmpW1 / 10 tmpW1 = __REMAINDER READ SegMaps + tmpW2, display(1) READ SegMaps + tmpW1, display(0) ENDIF ENDSUB 'Use: DELAY_MS msecs SUB DELAY_MS IF __PARAMCNT = 1 THEN tmpW1 = __PARAM1 ' save byte value ELSE tmpW1 = __WPARAM12 ' save word value ENDIF PAUSE tmpW1 RETURN ENDSUB ' Use: MEM_OUT address, value ' -- writes 'value' to 24LC16B location at 'address' SUB MEM_OUT tmpW1 = __WPARAM12 ' copy address tmpB1 = __PARAM3 ' copy value I2CSTART SDA tmpW1_MSB = tmpW1_MSB & $03 ' get block value tmpW1_MSB = tmpW1_MSB << 1 tmpW1_MSB = tmpW1_MSB | SlaveID ' create control byte tmpW1_MSB.0 = 0 ' set RW bit for write I2CSEND SDA, tmpW1_MSB ' send slave ID I2CSEND SDA, tmpW1_LSB ' send word address I2CSEND SDA, tmpB1 ' send data byte I2CSTOP SDA ' finish ENDSUB ' Use: value = MEM_IN address ' -- reads 'value' from 24LC16B location at 'address' FUNC MEM_IN tmpW1 = __WPARAM12 ' copy address I2CSTART SDA tmpW1_MSB = tmpW1_MSB & $03 ' get block value tmpW1_MSB = tmpW1_MSB << 1 tmpW1_MSB = tmpW1_MSB | SlaveID ' create control byte tmpW1_MSB.0 = 0 ' set RW bit for write I2CSEND SDA, tmpW1_MSB ' send slave ID I2CSEND SDA, tmpW1_LSB ' send word address I2CSTART SDA ' restart for read tmpW1_MSB.0 = 1 ' set RW bit for Read I2CSEND SDA, tmpW1_MSB ' resend slave ID I2CRECV SDA, tmpB1, Nak ' get one byte I2CSTOP SDA RETURN tmpB1 ENDFUNC ' ========================================================================= ' User Data ' ========================================================================= SegMaps: ' segments maps ' .gfedcba DATA %00111111 ' 0 DATA %00000110 ' 1 DATA %01011011 ' 2 DATA %01001111 ' 3 DATA %01100110 ' 4 DATA %01101101 ' 5 DATA %01111101 ' 6 DATA %00000111 ' 7 DATA %01111111 ' 8 DATA %01100111 ' 9 DATA %01110111 ' A DATA %01111100 ' b DATA %00111001 ' C DATA %01011110 ' d DATA %01111001 ' E DATA %01110001 ' F DigCtrl: DATA %11111110 ' column 0 on DATA %11111101 DATA %11111011 DATA %11110111