[SOLVED] Switch led on for x seconds using timer

Status
Not open for further replies.

tawny

Newbie
Joined
Jul 19, 2020
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
27
Hello everyone,

I'm doing a project that is almost finished, I just have one small problem. Days have gone by and I can't seem to solve it. I'm using uvision from keil to program and an AT89S51 (11,0592MHz crystal).
I have 2 leds, one green (P2_2), and one red (P2_3). I'm using a UART connection to ask the user for a code and read his answer, if the code is right the green led should turn on for 5 seconds and if it's wrong the red led should be on for 2 seconds. The problem is the leds do switch on when they should, but they never go off after that.

I'm using Timer 0 for this and I wrote the following code:

C:
unsigned int aux1=0;
unsigned int aux2=0;

void counter()
{
TMOD=0x01;         //Timer0 mode 1
TH0=0x4C;         //for 50ms
TL0=0X00;
TR0=1;             //start timer
}

// Configuration for the Interrupt of Timer0
void configInterrupt(){
EA=1;             //activate interrupts on 8051
ET0=1;            //activate interrupt of Timer0
}

void interruptTimer0Routine() interrupt 1{
TH0=0x4C;         //everytime there's overflow, we reload the value
TL0=0X00;
aux1++;
aux2++;
}




void main(){

counter();
configInterrupt();
P2_2=0;
P2_3=0;

   
while(1){

if(answerIsRight){
P2_2=1;            //turn on green led
if(aux1==100){     //overflow 100 times 50ms*100=5s
    P2_2=0;     //turn off green led
    aux1=0;
    }
    }  

else{
P2_3=1;            //turn on red led
if(aux2==40){     //overflow 40 times 50ms*40=2s
    P2_3=0;     //turn off red led
    aux2=0;
    }
    }
}
}
 
Last edited:

You do not declare your ISR variables as volatile, that should be done.



Also when you enter ISR I do not see any code to turn ISR off while you execute
ISR code. Not knowing the 8051 is that handled in HW when ISR called ? Or do
you have to handle that in SW ?

When sitting in while() loop can one ISR handling cause the other ISR to inc the
aux1, 2 test values beyond its respective test value such that the if == statement
never gets executed ? Eg. test for == should be >= ? Or do test in ISR and set a flag.


Regards, Dana.
--- Updated ---

There are several general approaches once can do.

One is start the timer when code state becomes available, set it for
use in one shot mode, do the timeout and then ISR. Some UP do not
have one shot mode, so just stop it when count is reached.

Another approach is timer runs continuously, when code state becomes
available read timers value. Then look for value that is the time delay you
are seeking. Of course you have to handle timer rollover occuring when
the delay still not yet met.

Have you seen this - https://www.keil.com/appnotes/docs/apnt_105.asp


Regards, Dana.
 
Last edited:
I'm kind of new to this, the only thing related to interrupts I did before was 3 blinking leds at different rates, and it worked with the aux1 and aux2 counting overflows . I've already tried inicializing the timer and activate the interrupt after I turn on the leds, but it didn't work either.

I did something like this:

C:
unsigned int aux1=0;
unsigned int aux2=0;

void counter()
{
TMOD=0x01;            //Timer0 mode 1
TH0=0x4C;            //for 50ms
TL0=0X00;
}

void interruptTimer0Routine() interrupt 1{
TH0=0x4C;            //everytime there's overflow, we reload the value
TL0=0X00;
aux1++;                //variable to count overflows       
aux2++;                //second variable to count overflows
}

void main(){

counter();
P2_2=0;
P2_3=0;


while(1){

if(answerIsRight){
P2_2=1;                //turn on green led
EA=1;                //enable 8051 interrupts
ET0=1;                //enable timer 0 interrupt
TR0=1;                //inicialize counter
if(aux1==100){        //overflow 100 times 50ms*100=5s
    P2_2=0;            //turn off green led
    TR0=0;            //stop counter
    aux1=0;            //clears the number of overflows
    }
    } 
    
if(answerIsWrong){
P2_3=1;                //turn on red led
EA=1;                //enable 8051 interrupts
ET0=1;                //enable timer 0 interrupt
TR0=1;                //inicialize counter
if(aux2==40){        //overflow 40 times 50ms*40=2s
    P2_3=0;            //turn off red led
    TR0=0;            //stop counter
    aux2=0;            //clears the number of overflows
    }
    }   
}
}
 

If you look ta Keil ap note you will see -

1) First thing done in ISR function is turn off interrupt, ET0, next execute
ISR code, then turn interrupt back on.

2) In main() use one instruction to enable ISR and do it right after main() and before
your while() loop. For both EA and ET0. The only time they will be turned off and back on
after this initialization is in ISR, just ET0. In ap note is an initialization routine that only needs to
be called once.

3) As I discussed before you need to declare variables in ISR as volatile. Look at this
discussion of static and volatile variables as applied to ISR.



4) Where is definition of variables answerIsWrong and answerIsRight ?



Some examples -




Note some of the examples do not declare ISR variables as volatile, that is
a mistake. Always declare ISR variables as volatile.

In you debugger can you see you are getting into ISR routine ?

Lastly your test for timer value, example "if(aux2==40){"
In your example code this is OK because you have no other ISR
activity. However if you did you would change this to
"if(aux2 >= 40){" because you could miss a timer value while
another ISR is executing. Or do the "==" test in the ISR and set
a flag, process the flag in main(). Whether or not this is a problem
also depends on priority assigned to ISRs.


Regards, Dana.
 
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…