on the other forum this was asked
http://support.melabs.com/forum/picb...unter#post8333I'd like to create a millisecond counter with a range from 5 milliseconds to 40 milliseconds. It does not have to be resolved to a single millisecond; e.g. need to know when it's hit each in a series of N+5 (5,10,15,20,25,30,35,40) milliseconds known. There'll be a photo interrupter reading an aperture in a disk and possibly be 8 LEDs each designating those 8 positions. Sort of like how an LED guitar tuner displays; 1st LED=5ms, 2nd=10ms, 3rd=15ms, etc.
Will I need a subroutine to avoid inaccuracy? Can I get by with PULSIN?
no complete code solution was asked for. seemed a waste so i will post my idea here as an example of a state machine solution rather than waste the effort
the asm code is a leftover of first implementing a full charlieplexer for the leds , until i realized there was never a need to show more than one at any one time
and cut it down to a charlie with no plexer
Code:;@ 12f1822#CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON __config _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_19 & _LVP_OFF #ENDCONFIG goto overasm asm pc_val ;led charlieplex lata data addwf PCL, F retlw 2 retlw 1 retlw 1 retlw 4 retlw 1 retlw 32 retlw 2 retlw 4 retlw 2 tc_val ;led charlieplex trisa data addwf PCL, F retlw 252 retlw 252 retlw 250 retlw 250 retlw 222 retlw 222 retlw 249 retlw 249 retlw 221 _LDS ;SHOW LED X=1 TO 9 BANKSEL LATA ;start with all LEDS off clrf LATA BANKSEL TRISA movlw 0xff IORWF TRISA,F BANKSEL 0 decf _ledx ,w L?CALL tc_val ;lookup tris value BANKSEL TRISA MOVWF TRISA BANKSEL _ledx decf _ledx,W L?CALL pc_val ;lookup port value BANKSEL LATA MOVWF LATA ;ignite the led BANKSEL 0 RETURN endasm overasm: DEFINE OSC 16 OSCCON = $78 ANSELA = 0 TRIGGER VAR PORTa.4 ;timer gate control pin timer var word ext ;the result in uS ledx var byte bank0 ;current led to ignite 1-9 tmp var word ;temporary store state VAR BYTE ;current state of machine 0, uninitialised 1, seeking pulse 2, pulse detected 3, good result 4, error old_state VAR BYTE ;previous state of machine @timer = TMR1L ;alias tmr1 to timer var clear 'post FOR ledx= 1 TO 9 CALL LDS ;SHOW LEDx pause 80 NEXT IOCAN.4 = 1 ;SET FALLING EDGE DETECTION INT ON TRIGGER PIN T1CON = $20 ;timer off T1GCON = $c0 ;timer gate control to count on high gate state = 1 ;all done lets go MAIN: if state != old_state then ;manage state change if state == 1 then 'reset timer pir1.0 = 0 TIMER = 0 T1CON.0 = 1 ledx= 9 ;led 9 on CALL LDS IOCAF=0 elseif state == 2 then ;evaluate result if pir1.0 then ;timer overflow ledx= 4 ;led overflow on state = 4 elseif timer < 4800 then ;too short ledx= 8 ;led UNDER on state = 4 elseif timer > 40200 then ;too long ledx= 1 ;led OVER on state = 4 else ;goldilocks TMP = TIMER / 5000 - 1 IF TIMER // 5000 > 2499 THEN TMP = TMP + 1 ;round up ledx= 8 - TMP ;led ledx on state = 3 endif CALL LDS ;SHOW LEDx TMP=1500 ;15 sec timeout to show result then reset endif old_state = state endif select case state ;manage current state case 1 ;SEEKING A PULSE CAPTURE EVENT IF IOCAF.4 || pir1.0 THEN ;FALLING EDGE ON TRIGGER PIN DETECTED or overflow T1CON.0 = 0 ;stop timer no retriggering LATA = 0 'led9 oFF show pulse captured state = 2 endif case 3 ;good result show it if tmp then ;15 sec timeout then reset TMP = TMP - 1 else state = 1 ;then reset endif case 4 ;error condition flash ledx if tmp then ;15 sec timeout countdown then reset if tmp//50==0 then LATA = 0 if tmp//50==25 then CALL LDS TMP = TMP - 1 else state = 1 ;then reset endif end select PAUSE 10 ;set loop to 10 mS GOTO MAIN




Bookmarks