problem with reading the button input?

Status
Not open for further replies.

hemnath

Advanced Member level 3
Joined
Jun 24, 2012
Messages
702
Helped
61
Reputation
120
Reaction score
57
Trophy points
1,308
Location
Chennai
Visit site
Activity points
6,589
I'm using pic 18F2520 and ccs c compiler. Button is connected to PIN C0. My program goes upto 1500 lines and does some other things.

I'm continuously reading adc value and displaying in lcd. And, when button is pressed, it shows the display value(which is in float) in different units which i have programmed. Everything is working ok, but the problem is, when button is pressed, display unit changes and sometimes it doesn't changes. Due to polling the button pin, and the program is big, will it be a reason to miss the button press??

So i have decided to write a small isr routine using timer1. For every 100ms, timer_flag sets. And, when timer_flag is set and im checking the button is pressed or not. still the problem remains the same. I know that still i'm polling the button pin.

small routine program i have included in my program
HTML:
#INT_timer1
void isr()
{
if(TMR1IF == 1)
{
timer_flag = 0;
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xFE;             // Values calculated for 100 millisecond delay with 4MHz crystal
TMR1L = 0x79;
}
}

In main function
HTML:
while(1)
{
if(timer_flag==0)
{

if(input(Button)==0)
{
i = i + 0.1;
lcd_cmd(0x80);
printf(lcd_data,"%6.3f",i);
}
timer_flag = 1;
}
}

Is there any other method to accurately detect the button press. I know that can be done with external hardware interrupts. But i have connected pin C0 to button. Pin C0 dont have interrupt feasibility. Even i couldn't change the pin. So please help with this!!!
 

you have used the timer interrupt to simply set a flag. And the you are checking this flag in your main loop. It is no different from directly reading the button in main loop.

you should try reading the button INSIDE the timer interrupt itself. And also maybe have faster timer interrupt - maybe 10mS even. Then in the isr if you see button is pressed, you can set a flag - "button_pressed = TRUE". and clear it when it is processed in your main loop.

you can also use this idea to provide software debounce. i think it will work better then
 
One thing i dont understand and confused. in my isr routine below, interrupt occurs for every 10ms and checks the status of the pin. If i press the button, it goes to change_uom function. is it right? what i have to do in main loop? my change_uom function has more data's like conversion. So i think it takes more time to process. if i press the button continuously, will it react to the changes of the button?

I have changed the isr like this.

HTML:
#INT_timer1
void isr()
{
if(TMR1IF == 1)
{
if(input(button)==0)   // if button pressed
{
 change_uom (0);    // function to change the units in the display 
}
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xD8;             // 10ms 
TMR1L = 0xEF;
}
}
 

Hi hemmath, with that Timer1 interrupt you're doing an interrupted poll (only can detect the button during interrupt). Really, I think the only safe solution would be to use a pin with interrupt capacity. Another possibility if you can, would be if you're using a clock speed of 4MHz for example, increase it to 20Mhz and do the normal code polling to see the results. Just out of curiosity, why are you using these instructions to configure the Timer1?

Code:
if(TMR1IF == 1)
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xD8;             // 10ms 
TMR1L = 0xEF;

Why don't use the CCS own instructions to configure it?

Best Regards!
 
Last edited:

hi bmb_10, I couldn't change the pin because i have designed the pcb and ordered more pcb. All interrupt pins in uC are used for some other purpose.
Even i can't change the crystal frequency, because my device is battery operated. So current becomes major problem if i increase the crystal frequency.

CCS uses a command and i couldn't understand whats happening behind that. Because of curiosity, and look into detail whats happening inside the timer register, i have used the registers. It would be very grateful for me if someone can help me..
 

I have changed the isr like this.

instead try doing it the way i wrote --->

in the isr if you see button is pressed, you can set a flag - "button_pressed = TRUE". and clear it when it is processed in your main loop.
you can also use this idea to provide software debounce. i think it will work better then

i think you have much to learn also about software debounce, and how to set, check, use and reset flags. you can google and find lot of details. writing code without this knowledge will make many problems and funny results
 

hi kripacharya, like this??
HTML:
#INT_timer1
void isr()
{
if(TMR1IF == 1)
{
if(input(Button)==0)
{
timer_flag = 0;
}
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xD8;             // 10ms 
TMR1L = 0xEF;
}
}
main loop
HTML:
while(1)
{
if(timer_flag==0)
{
i = i + 0.1;
lcd_cmd(0x80);
printf(lcd_data,"%6.3f",i);
timer_flag = 1;
}
}

But still the problem persist. can you post some sample code, so that i can learn from it. Please help!!!
 

If there are delays in your code then there will be delay in recognizing your button presses. Use some PORTB pins for the button. You can use interrupt for button presses so that whenever button is pressed there will be an interrupt and the code for the button presses is serviced.
 

please read my above posts. I know that it can be done with interrupts. But i can't change the pin. i have connected the button to uC pin C0 . Is there any other method?
 

yes better, but still many problem areas.

you have not put any code for debounce

after proper debounce you have to make code to also check button is released, and again pressed, before setting flag a 2nd time. otherwise you will get repeated flag set many many times each time button is pressed even once.

sorry, i do not have time now to post code. also i do not know pIC instruction set.
 

jayanth .. i think you didnt understand my question. my problem is not about debounce. read my 1st post Please.
Due to polling the button, and the program is pretty big (say about 1500 lines) , button press is not detected sometimes. for eg, say about im pressing the button with interval of 500ms, sometimes units has been changed in the display corresponding to button press and sometimes it doesn't changes. Thats the real problem. Read from the 1st post. Also, I am aware of debounce.

So i have wrote a small program, when i press the button, increments a counter in the display. It works perfectly and never misses a button press whatever the interval may be. So i have concluded that the program is big, will it cause the problem while polling the button press. Please help if someone knows alternate and perfect solution.
 

I couldn't change the pin because i have designed the pcb and ordered more pcb. All interrupt pins in uC are used for some other purpose.
Even i can't change the crystal frequency, because my device is battery operated.

If you are locked into using pin RC0 as the button input, another possible option is to implement an interrupt and ISR which utilizes the external timer1/3 clock feature of RC0.

Simply enable either Timer1 or Timer3 with an external timer clock input, load corresponding timer with the highest value before overflow and enable the corresponding Timer Overflow Interrupt.

The next button closure will trigger the corresponding Timer Overflow Interrupt and ISR to handle the button closure. You may possibly be able to handle the button debouncing with creative coding.


BigDog
 

hi bigdogguru,
your idea will help me to solve and come out from the problem. Please help me how to do? can u please explain with some good examples.
 


ok good. i thought you did not do debounce because it is not in your sample posted code. maybe you have done h/w debounce.

So next you can try simple queueing of the keypress. That is, the isr will increment the button_press whenever it detects a new button press only. Then in your main routine, you have to service button press the counted number of times. just make sure that counter decrement in main does not conflict with counter increment in isr.

this way even if main routine takes long, it will not miss button press. just some delay might happen. Of course you should keep the interrupts enabled as much as possible.

other method is to process complete buttonpress routine inside the isr itself. but if you have time critical process elsewhere, then you have to do this carefully.
 

Hi hemnath, I believe that bigdogguru has given you a very good idea. You can implement that as follows (is only a small example):

Code:
#include <18F2520.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=4000000)
#define button PIN_C0
#define LED PIN_B0

int1 var_1 = false;

#int_TIMER1
void  TIMER1_isr(void) 
{
   var_1 = true;
   set_timer1(65535);
}

void main()
{
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);
   set_timer1(65535);

   while(TRUE)
   {
      if(var_1)
      {
         output_toggle(LED);
         var_1 = false;
      }
   }
}

If you start the Timer1 with a value of 65535 and you give it a clock pulse (with PIN_C0), the Timer1 overflows and enters to the interrupt routine. There you can do directly what you need in the interrupt routine (if it is no too long), or activate a variable (as in the example) and use it in the code.

Attached are sample files and simulation in Proteus.

Best regards!
 

Attachments

  • button.zip
    14.5 KB · Views: 117
hi bmb_10, thanks for spending your time. implemented your interrupt in my program and it works better. But i don't say its perfect. There is some delay when displaying the different units whenever i press the button. may be polling will it cause the problem.

Can you please explain, when i look into your code, same timer1 has been used. Even in my post #7 i too have did the same. Interrupt occurs and set the flag. And in main loop, checking the flag is set and doing something inside and also resets the flag. But it works slightly better in your case. What could be the reason?
 

Hello hemnath, once the variable in the interrupt routine has been activated, you can be sure that the routine within the if() is executed. I think that the delay your program is presenting now, is due to the large number of lines that it have. If what the program have to do once you press the button is not very extensive, you can put that code directly within the interruption routine and it will be faster.

Best Regards!
 

I think that the delay your program is presenting now, is due to the large number of lines that it have.
thats what hemnath has already said
If what the program have to do once you press the button is not very extensive, you can put that code directly within the interruption routine and it will be faster.

supposedly what has to be done is to display on LCD. this process can take tens of milliseconds to complete. however OP may have only used this only for testing purpose, and actual processing is less, then of course this makes sense.
 

supposedly what has to be done is to display on LCD. this process can take tens of milliseconds to complete. however OP may have only used this only for testing purpose, and actual processing is less, then of course this makes sense.

Some LCD driver instructions takes a long time. For example lcd_putc() causes the compiler to display some warnings, then should not be used directly in the interrupt routine.

Best Regards!
 

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…