Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] MikroC Delay Using Interupt

Status
Not open for further replies.

sonar_abhi

Member level 1
Joined
Mar 15, 2016
Messages
36
Helped
2
Reputation
4
Reaction score
2
Trophy points
8
Activity points
380
Hello Guys,

Hello Guys,

I am trying to implement a delay using timer0 interrupt. I'll just post an abstraction of the code in mikroc


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void inittimer()
{
  //Timer initialization for a 32ms interrupt
}
 
void interrupt()
{
  //interrupt code;
  delayvariable++;
}
 
void main()
{
 TRISB = 0;          //PORTB is output
 TRISC.F0 = 1;   //PORTC Pin 0 is input and connected to a switch
 if (PORTC.F0 ==0) //check is the button is pressed
 {
   if (delayvariable==3)   //~100ms second delay to check buttton debounce
   {
     if (PORTC.F0==0) //check if the button is still pressed
      {
        PORTB = ~PORTB; //toggle PORTB
        delayvariable = 0;  //reset the delay variable
      }
   }
}
}



The above code does not work as I expected. Can somebody please point out the mistake I am making or suggest a better way for achieving a 100 ms delay using interrupt?
 
Last edited by a moderator:

Hard to give some insight without you specify precisely what do you mean by "not working as expected".
 

Hard to give some insight without you specify precisely what do you mean by "not working as expected".

My Bad...This is the complete code. Ideally, the PORTB should toggle if the button is pressed. But the problem lies in the button debounce part. The PORTB is toggled only if the button is pressed for more than 8 seconds. Also if the button is kept pressed, the PORTB keeps on toggling continuously every 32mS. I was expecting the button to be read and if after 32mS if the button is still pressed, the PORTB is toggled. Normally, delay is used to check the button debounce but I do not want to use the delay or the BUTTON library of mikroc. I want to do it via interrrupt

Code:
#define SW1 PORTC.RC0

char latdelay;

void InitTimer0(){
  OPTION_REG     = 0x87;
  TMR0           = 6;
  INTCON         = 0xA0;
}

void Interrupt(){
  if (TMR0IF_bit){
   TMR[syntax=c][/syntax]0IF_bit   = 0;
   TMR0         = 6;
   latdelay++;
  }
}

void main(){
 InitTimer0();
 TRISC.RC0 = 1;
 TRISB     = 0;
 PORTB     = 0x00;
 
 while (1){ 
  if (SW1 == 0){
   if (latdelay == 3)
    {
     if (SW1 == 0){
     PORTB = ~PORTB;
     latdelay=0;
     }
    }
   }
 }
}
 

Hi,

The 8s comes because when SW is not pressed then latdelay is not reset to 0, it runs 4, 5, 6....253, 254, 255, 0, 1, 2, 3. Then it
This is 256 x 32ms = 8,2s.
Therefore I recommend to use ">=" instead of "=".

I'm no C specialist. But here my ideas:
(Please see my code as pseudo code)
--> FOR TOGGELING THE PORT IN MAIN
* I think latdelay should be declared "volatile"
* use a new volatile variable, "SWdebounced"
* use a new volatile variable, "toggleFlag"

Within the ISR:
* SWdebounced = SW (this is updated every 32ms only, bouncing usually is less than 10ms --> simple debounce method. No need for hardware debounce)
* latdelay ++
* if latdelay >=3 then {
* latdelay = 0
* toggleFlag = 1 }

In main:
* if (SWdebounced AND toggleFlag) then {
* toggle port
* toggleFlag = 0}

But this needs to ensure that the main loop at least runs once per 64ms.
This is usually no problem, but in some cases in main loop you wait for sth, or you do heavy data communication...
********
Therefore consider to do the complete toggeling in the ISR.
(This still is very fast ISR)

In main:
do nothing

In ISR:
* latdelay ++
* if (latdelay >= 3) and SW then {
* toggle port
* latdelay =0}

With this solution toggeling works even if the main loop is busy.
When SW = 1, then the counter runs 0, 1, 2, 3, 0, 1...
When SW = 0, then the counter runs 0, 1, 2, 3, 4, 5, ...
This means min toggleperiod is 100ms, but you will see immediate response when pressing SW after a longer time.

Klaus
 
Hi,

The 8s comes because when SW is not pressed then latdelay is not reset to 0, it runs 4, 5, 6....253, 254, 255, 0, 1, 2, 3. Then it
This is 256 x 32ms = 8,2s.
Therefore I recommend to use ">=" instead of "=".

I'm no C specialist. But here my ideas:
(Please see my code as pseudo code)
--> FOR TOGGELING THE PORT IN MAIN
* I think latdelay should be declared "volatile"
* use a new volatile variable, "SWdebounced"
* use a new volatile variable, "toggleFlag"

Within the ISR:
* SWdebounced = SW (this is updated every 32ms only, bouncing usually is less than 10ms --> simple debounce method. No need for hardware debounce)
* latdelay ++
* if latdelay >=3 then {
* latdelay = 0
* toggleFlag = 1 }

In main:
* if (SWdebounced AND toggleFlag) then {
* toggle port
* toggleFlag = 0}

But this needs to ensure that the main loop at least runs once per 64ms.
This is usually no problem, but in some cases in main loop you wait for sth, or you do heavy data communication...
********
Therefore consider to do the complete toggeling in the ISR.
(This still is very fast ISR)

In main:
do nothing

In ISR:
* latdelay ++
* if (latdelay >= 3) and SW then {
* toggle port
* latdelay =0}

With this solution toggeling works even if the main loop is busy.
When SW = 1, then the counter runs 0, 1, 2, 3, 0, 1...
When SW = 0, then the counter runs 0, 1, 2, 3, 4, 5, ...
This means min toggleperiod is 100ms, but you will see immediate response when pressing SW after a longer time.

Klaus

Hi Klaus,

Thanks man. You sure cleared the 8.2 Second triggering reason. I did try the method that you suggested and have got the result I wanted. Thanks a ton.

Here is the updated code if anybody would need it. Now it does toggle the PORT without jumping around.

Code:
#define SW1 PORTC.RC0


char latdelay, portdelay;

void InitTimer0(){
  OPTION_REG     = 0x87;
  TMR0           = 6;
  INTCON         = 0xA0;
}

void Interrupt(){
  if (TMR0IF_bit){
   TMR0IF_bit   = 0;
   TMR0         = 6;
   latdelay++;
  if (latdelay>3){
    portdelay=1;
    latdelay=0;
   }
  }
}

void main(){
 InitTimer0();
 TRISC.RC0 = 1;
 TRISB     = 0;
 PORTB     = 0x00;
 
 while (1){ 
     if (SW1==0)
     {
      latdelay=0;
     if (SW1 == 0 && portdelay ==1){
     PORTB = ~PORTB;
     portdelay=0;
     }
   }
 }
}
 
  • Like
Reactions: Garyl

    Garyl

    Points: 2
    Helpful Answer Positive Rating
Hi,

Maybe you could optimize code and processing time:

Main...
Code:
while (1){ 
     if (portdelay == 1){
          If (SW1 == 0 {
               PORTB = ~PORTB;
               }
          portdelay=0;
       }
 }

Klaus
 

This is a good approach by the way. For example, you have a driver like that:
void * GetMeSomeDataFromInterface (void ** params, char paramsN, int TimeOut);
This driver creates a sturcture in RAM and returning back to you the pointer to that structure. But before it waits for some data by pooling interface activity flag. The only way how you can be sure that operation will not be stuck is to keep some timer in independend task which anyway will be executed whatever your main thread is doing - the interrupt. So, basicaly, you only need to descreese some shared variable and when driver detects that it is reached 0, it returns back for example pointer equal to 0, which means error. But this variable have to be 'volatile'!
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top