' ========================================================================= ' 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.3 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 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 ' 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 word ' 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. theDig VAR Tach_Array(1) 'Uses byte 1 of Tach_Array. dug VAR Tach_Array(2) 'Uses byte 2 of Tach_Array. ' Watch statements for debuging WATCH rpm watch RPM_LSB watch RPM_MSB watch rpmlast watch rpmlast_LSB watch rpmlast_MSB WATCH pWidth, 16, UDEC WATCH Segs, 8, UBIN WATCH Digs, 4, UBIN WATCH dug, 8, UDEC WATCH addr ' for Debug/Poll mode WATCH button WATCH pwidth0, 16, UDEC watch pwidth1, 16, UDEC ' ------------------------------------------------------------------------- ' Subroutine Declarations ' ------------------------------------------------------------------------- DELAY_MS SUB 1, 2 ' delay in milliseconds SHOW_DISPLAY SUB DIG FUNC 1, 2, 3 MEM_OUT SUB 3 ' write value to eeprom memory MEM_IN FUNC 1,2 ' read byte from eeprom memory ' ========================================================================= 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 DO ' Measure pulse low time 'PULSIN Sensor, 0, pWidth0 pWidth0 = 50_821 ' Measure pulse high time 'PULSIN Sensor, 1, pWidth1 pWidth1 = 50_822 ' 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 break ' 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 ' rpm now holds the correct value SHOW_DISPLAY '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=123 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 'BREAK ' allow WATCH window view LOOP END ' ------------------------------------------------------------------------- ' Subroutine Code ' ------------------------------------------------------------------------- '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: SHOW_DISPLAY 'takes no input (rpm is global) SUB SHOW_DISPLAY 'Reminder, i'm calling DIG and DELAY in here, so tmpW1-2 and tmpB1-2 are off limits! 'Don't get fancy and try to pass the loop number in using those "local" vars ' 'This number has to be a multiple of 4 since we need to loop 4 times to get all 4 digits FOR counter = 1 to 40 READ DigSel + theDig, Digs ' select digit column number (theDig) from Digs dug = DIG rpm, theDig ' get the digit in rpm we are about to lookup and draw READ Digit0 + dug, Segs ' move digit drawing DATA pattern to segs pins inc theDig ' Update the, theDig = theDig // 4 ' ,digit column pointer DELAY_MS 5 'how long to light each singular digit (POV) Segs = Blank 'clear the gnds or we will light up the next digit column before we are ready NEXT RETURN ENDSUB ' Use: result = DIG value, position ' -- "value" is byte or word ' -- "position" is byte, 0 to 4 FUNC DIG IF __PARAMCNT = 2 THEN tmpW1 = __PARAM1 tmpB1 = __PARAM2 ELSE tmpW1 = __WPARAM12 tmpB1 = __PARAM3 ENDIF tmpB2 = 0 IF tmpB1 < 4 THEN LOOKUP tmpB1, 1, 10, 100, 1000, tmpW2 tmpW1 = tmpW1 / tmpW2 tmpW1 = tmpW1 // 10 tmpB2 = tmpW1_LSB ENDIF RETURN tmpB2 ENDFUNC ' 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 ' -----[ Data ]----------------------------------------------------- ' %.GFEDCBA Digit0: DATA %00111111 Digit1: DATA %00000110 Digit2: DATA %01011011 Digit3: DATA %01001111 Digit4: DATA %01100110 Digit5: DATA %01101101 Digit6: DATA %01111101 Digit7: DATA %00000111 Digit8: DATA %01111111 Digit9: DATA %01100111 DigSel: DATA %1110 ' digit 0 active DATA %1101 ' digit 1 active DATA %1011 ' digit 2 active DATA %0111 ' digit 3 active