I've got a little more time to elaborate... On Thu, 27 Jan 2000, Scott Dattalo wrote: task switching: > movlw start_address_of_my_next_state1 > movwf task1_state > movf task2_state,w > movwf pcl > start_address_of_my_next_state1 > > > and similarly for the other task: > > movlw start_address_of_my_next_state2 > movwf task2_state > movf task1_state,w > movwf pcl > start_address_of_my_next_state2 > > > Only 5 cycles are needed to switch between tasks (as opposed to 9). Let's assume all of the code fits into one code page (i.e. it's less than 256 bytes). That way, the above code will be sufficient to switch between the co-routines. Now, if I understand your requirements, you want to simultaneously control two identical timers. Each timer will be doing the following: 1) count for a delay that ranges between 1 and 20 seconds 2) when the delay has expired, generate a pulse between 4 to 40 milliseconds In essence, each timer is itself composed of two more timers: a delay timer and a pulse generator timer. There are several ways to partition the tasks. I think the most straight forward approach is to break them down to pieces that are increment (or decrementing actually) one of the timers. To the code fairly consistent, I further suggest that the delay and pulse timers be made the same. So for one of the tasks you could do this: 1) initialize the task for delay mode of 20 seconds 2) start the task 3) decrement the delay timer - if the delay timer is not zero go to (3) 4) // Delay has expired Assert pulse 5) decrement pulse timer - if the pulse timer is not zero go to (5) 6) De-assert pulse 7) go to (3) Now, you also need to handle the other task. So in between each step you'd perform the task switch to the other timer. There's also another detail that needs to be handled; how do you program the delay times and pulse widths? For the delay timer and pulse timer I'd suggest 24-bit decrementing counters. Dmitry showed a clever method once for decrementing a 24-bit timer in 5 cycles - but I can't recall the algorithm right now (perhaps it was a 24bit increment?): tmr1_dec_delay: movlw -1 ; addwf timer1_l,f ;decrement low byte skpc ; addwf timer1_m,f ;dec. middle byte if there was a borrow skpc ; addwf timer1_h,f ;dec. high byte if there was a borrow ; If the carry is cleared, then the timer just decremented from ; 0x000000 to 0xffffff. nop movf tmr1_next_mode,w ;either assert pulse, or de-assert pulse skpnc movlw tmr1_dec_delay TASKSW tmr1_state, tmr2_state tmr1_delay_just_completed ASSERT_PULSE_TMR1 ;e.g. bsf port,bit movf pulse1_l,w movwf timer1_l movf pulse1_m,w movwf timer1_m movf pulse1_h,w movwf timer1_h movlw tmr1_pulse_just_completed movwf tmr1_next_mode movlw tmr1_dec_delay TASKSW tmr1_state, tmr2_state ; e.g. : ; movwf tmr1_state ; movf tmr2_state,w ; movwf pcl tmr1_pulse_just_completed ;; perhaps this is where the times for the next delay ;; and width are obtained? DEASSERT_PULSE_TMR1 ;e.g. bcf port,bit movf delay1_l,w movwf timer1_l movf delay1_m,w movwf timer1_m movf delay1_h,w movwf timer1_h movlw tmr1_delay_just_completed movwf tmr1_next_mode movlw tmr1_dec_delay TASKSW tmr1_state, tmr2_state The time spent in each sub-task is 10 cycles for the task and 4 cycles for the task switch. Each 24-bit counter will be decremented once every 28 cycles (14 for one task and 14 for the other). For a 20Mhz pic, the 28 cycles will correspond to a 'task resolution' of 5.6uS. The 24-bit wide counter gives you a time of about 93.9 seconds. This meets your goals. Now, I've neglected the code necessary to re-program the timer periods. Without more info, there's not much more to do (except to optimize - I see one way to reduce the task time by one cycle) Scott