This example shows you how to create multiple non-blocking delays with only one timer, using :
- timer 1
- interrupts
- arrays of pointers to functions
- structures
It is made for a P18F452 but it could be used with others pics with just minor adjustments.
The binary code is less than 2K, so that you can use the unlicenced mikroC compiler to build the HEX file.
This example can be discussed in the forum.
/*
* this source code shows how to use pic timers, interrupts, and arrays of pointers to functions
* and how to make non-blocking multiples delays, using a single timer
*
* Bruno Gavand, march 2006
* www.micro-examples.com
*
* P18F452 @8Mhz, HS clock, EASYPIC2 / EASYPIC3
* pull-down on PORTB
* pull-up on keyboard
* enable PORTB, PORTC and PORTD LEDs
*
* pressing RB0 key will toggle PORTC after a 2s non-blocking delay
* pressing RB1 key will toggle PORTD after a 3s non-blocking delay
*
* used ROM : 1676 bytes
*/
/*
* number of delayed keys, up to 255
*/
#define NBKEYS 2
/*
* struct for one key
*/
typedef struct
{
unsigned char flag ; // active = 1, 0 otherwise
unsigned char ctr ; // counter of timer1 overflows
void (*stop)() ; // pointer to a function to call after delay
} KEY_STRUCT ;
KEY_STRUCT keys[NBKEYS] ; // struct array
/*
* functions that do something visible for the example
*/
void toggleC()
{
PORTC = ~PORTC ; // invert PORTC (toggle LEDs)
}
void toggleD()
{
PORTD = ~PORTD ; // invert PORTD (toggle LEDs)
}
/*
* start to count down d milliseconds for key i
*/
void keyStart(unsigned char i, unsigned long d)
{
KEY_STRUCT *k ;
k = &keys[i] ; // struct pointer
if(k->flag == 0) // if free ?
{
d <<= 18 ; // multiply by 4 * 2 ^ 16
d /= 1000 ; // divide by 1000 because
d /= (long)Clock_Khz() ; // clock frequency is known in Khz
k->ctr = d ; // assign counter
k->flag = 1 ; // set flag to start countdown in interrupt
}
}
/*
* interrupt vector
*/
void interrupt()
{
if(PIR1.TMR1IF) // timer1 overflow, Fosc/(4 * 2^16) times per second
{
unsigned char i ;
for(i = 0 ; i < NBKEYS ; i++) // for each keys
{
KEY_STRUCT *k ;
k = &keys[i] ; // get pointer to the key struct
if(k->flag) // if key countdown activated
{
if(k->ctr) // if countdown in progress
{
k->ctr-- ; // count down
}
else
{
k->flag = 0 ; // count down reached 0, disable
(k->stop)() ; // call user's function
}
}
}
PIR1.TMR1IF = 0 ; // reset timer1 interrupt flag
}
}
/*
* program starts here
*/
void main()
{
unsigned char i ;
ADCON1 |= 0x07; // PORTA as digital I/O
PORTA = PORTB = PORTC = PORTD = 0 ; // clear ports
TRISA = 0 ; // PORTA as output
TRISB = 0b00000011 ; // 2 LSB of PORTB as inputs, others as outputs
TRISC = 0 ; // PORTC as output
TRISD = 0 ; // PORTD as output
keys[0].stop = toggleC ; // assign user's function to first key
keys[1].stop = toggleD ; // assign user's function to second key
for(i = 0 ; i < NBKEYS ; i++) // for each keys
{
keys[i].flag = 0 ; // reset struct
keys[i].ctr = 0 ;
}
T1CON.T1CKPS1 = 0 ; // no prescaler
T1CON.T1CKPS0 = 0 ; // on timer1
T1CON.T1OSCEN = 0 ; // disable timer1 oscillator
T1CON.TMR1CS = 0 ; // timer1 is on Fosc
T1CON.TMR1ON = 1 ; // start timer1
INTCON.GIE = 1 ; // enable global interrupts
INTCON.PEIE = 1 ; // enable peripheral interrupts
PIE1.TMR1IE = 1 ; // enable timer1 overflow interrupts
for(;;) // forever
{
if(PORTB.F0) // if RB0 key pressed
{
keyStart(0, 2000) ; // start key #0 countdown for 2000 ms
}
else if(PORTB.F1) // if RB1 key pressed
{
keyStart(1, 3000) ; // start key #1 countdown for 3000 ms
}
}
}
|