View previous topic :: View next topic |
Author |
Message |
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Wed Aug 07, 2024 1:25 pm |
|
|
Yep yep, that's fine, I wasn't really addressing that part as it was already covered in previous discussion. I was just letting the OP know that the statement I highlighted earlier was not fully correct for that family they were using. |
|
|
reelthymes
Joined: 26 Jul 2024 Posts: 10
|
|
Posted: Thu Aug 08, 2024 6:56 am |
|
|
Ttelmah wrote: | You are right on this chip. On most chips they are not relocatable.
However using the interrupts, you will have problems with bounce.
Understand they a simple keyboard may well give a dozen or more
makes when a key is pushd. It depends massively. on the quality of
the contacts, and how the user pushes the key |
So is bounce not an issue when using an "input change notification" (CN) pin? As for debounce in general, can't that simply be handled in the software, i.e. you sample the input at some interval and consider the signal stable if it's consistent across intervals?
Would this software debounce method work for either pin type (external interrupt or CN input)? |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Thu Aug 08, 2024 11:25 am |
|
|
To debounce a switch input you would not use an external interrupt or a change interrupt at all. Just poll the pin input at a regular interval and look for a stable change of state.
An interrupt on a switch would only be useful if you need to wake from sleep on a switch press. |
|
|
reelthymes
Joined: 26 Jul 2024 Posts: 10
|
|
Posted: Thu Aug 08, 2024 12:58 pm |
|
|
gaugeguy wrote: | To debounce a switch input you would not use an external interrupt or a change interrupt at all. Just poll the pin input at a regular interval and look for a stable change of state.
An interrupt on a switch would only be useful if you need to wake from sleep on a switch press. |
Ok, thanks this is is helpful. So in this case, if I were to simply poll the pin input at regular intervals, doesn't this risk being unresponsive or slow because now it's part of my main program loop? i.e. the polling action may have to wait for many other actions to complete before being reached... whereas a change notification interrupt would be immediate?
I also thought that was the general point and application of interrupts. i.e. they exist to make your program respond immediately to some event (usually some external stimulus).
Or I suppose as Ttlemah previously stated, I could use a timer interrupt? |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Thu Aug 08, 2024 1:25 pm |
|
|
Not in a properly written program.
10ms is a long time from a microprocessors view.
200ms is a short time from a human response view. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Aug 08, 2024 1:43 pm |
|
|
reelthymes wrote: |
Or I suppose as Ttlemah previously stated, I could use a timer interrupt? |
That's also an option. I have a few programs where I have a spare interrupt running that takes a 16 bit variable, shifts it left one bit and OR's in the input of the pin in question. Then in my main code , I look to see if the pin is debounced high (variable = 0xFFFF), debounced low (variable = 0x0000, or in transition (an other value).
Something like (untested, just typed out freehand)
Code: |
#define PIN_LOW 0x0000
#define PIN_HIGH 0xFFFF
volatile unsigned int16 g_PIN_B6_debounce = PIN_LOW;
#INT_TIMER5
void debounce_timer(){
g_PIN_B6_debounce = (g_PIN_B6_debounce << 1) | input_state(PIN_B6);
}
void main(void){
static unsigned int16 last_PIN_B6 = PIN_LOW; // assuming initial state
// setup timer 5 to some reasonable debounce time
while(TRUE){
if(last_PIN_B6 == PIN_LOW && g_PIN_B6_debounce == PIN_HIGH){
last_PIN_B6 = PIN_HIGH;
//rising edge processing
}
if(last_PIN_B6 == PIN_HIGH && g_PIN_B6_debounce == PIN_LOW){
last_PIN_B6 = PIN_LOW;
//falling edge processing
}
// ignore other values of B6 until it debounces to a known value
}
}
|
|
|
|
reelthymes
Joined: 26 Jul 2024 Posts: 10
|
|
Posted: Thu Aug 08, 2024 1:58 pm |
|
|
jeremiah wrote: | reelthymes wrote: |
Or I suppose as Ttlemah previously stated, I could use a timer interrupt? |
That's also an option. I have a few programs where I have a spare interrupt running that takes a 16 bit variable, shifts it left one bit and OR's in the input of the pin in question. Then in my main code , I look to see if the pin is debounced high (variable = 0xFFFF), debounced low (variable = 0x0000, or in transition (an other value).
Something like (untested, just typed out freehand)
Code: |
#define PIN_LOW 0x0000
#define PIN_HIGH 0xFFFF
volatile unsigned int16 g_PIN_B6_debounce = PIN_LOW;
#INT_TIMER5
void debounce_timer(){
g_PIN_B6_debounce = (g_PIN_B6_debounce << 1) | input_state(PIN_B6);
}
void main(void){
static unsigned int16 last_PIN_B6 = PIN_LOW; // assuming initial state
// setup timer 5 to some reasonable debounce time
while(TRUE){
if(last_PIN_B6 == PIN_LOW && g_PIN_B6_debounce == PIN_HIGH){
last_PIN_B6 = PIN_HIGH;
//rising edge processing
}
if(last_PIN_B6 == PIN_HIGH && g_PIN_B6_debounce == PIN_LOW){
last_PIN_B6 = PIN_LOW;
//falling edge processing
}
// ignore other values of B6 until it debounces to a known value
}
}
|
|
That looks like a great solution, thanks for sharing. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Aug 08, 2024 2:03 pm |
|
|
reelthymes wrote: |
That looks like a great solution, thanks for sharing. |
No problem. If you find the interrupt takes too much time you can simplify the generated code at the cost of a less readable solution:
Code: |
#INT_TIMER5
void debounce_timer(){
#BIT B6_BIT = g_PIN_B6_debounce.0;
g_PIN_B6_debounce = g_PIN_B6_debounce << 1;
B6_BIT = input_state(PIN_B6);
}
|
That reduces the generated ASM quite a bit. That takes the generated code down to:
Code: |
.................... #BIT B6_BIT = g_PIN_B6_debounce.0;
....................
.................... g_PIN_B6_debounce = g_PIN_B6_debounce << 1;
020E: SL 800
.................... B6_BIT = input_state(PIN_B6);
0210: BCLR.B 800.0
0212: BTSC.B 2CA.6
0214: BSET.B 800.0
|
You can also change the 16 bit global to an 8 bit global (and the constants) if you think you only need 8 debounce attempts |
|
|
reelthymes
Joined: 26 Jul 2024 Posts: 10
|
|
Posted: Fri Aug 09, 2024 9:26 am |
|
|
Quote: |
Code: |
void main(void){
static unsigned int16 last_PIN_B6 = PIN_LOW; // assuming initial state
// setup timer 5 to some reasonable debounce time
}
|
|
regarding setting up the timer period, please see my below reasoning. Can you let me know if I'm in the ballpark or is this totally off-base?
I have the following line in the setup portion of my main() function: Code: | setup_timer_1(TMR_INTERNAL, 0x0148)); |
Here is the logic behind this:
1) The PIC24 has an 8 MHz internal clock. That means the period of each clock cycle is 0.125 us.
2) The 16 bit timer has max value of 0xFFFF (65,535), which means that 8*10^6 / 65535 = 122. This is the number of cycle count per bit of the timer.
3) Therefor, each bit of the timer represents (122 * 0.125 us) = about 15 us
4) so, for a (I think reasonable?) period of 5 ms for my interrupt, I should set the period value of ( 5ms / 15 us = 328). In other words, 328 (0x148).
5) so, the interrupt will fire every 5 ms, and we keep going until the g_PIN_doubounce variable is filled up with all 1s (0xFFFF). So this will occur at approx. 75 ms because (5 ms * 16 = 75 ms). i.e. if I understand your algorithm correctly, inside the interrupt we OR the pin HIGH input with that variable and keep shifting left until the whole thing is filled up. So that means 16 passes through the interrupt routine to ensure a stable signal.
Lastly, is there a reason you recommended timer 5 as opposed to one of the others? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Fri Aug 09, 2024 5:57 pm |
|
|
reelthymes wrote: |
regarding setting up the timer period, please see my below reasoning. Can you let me know if I'm in the ballpark or is this totally off-base?
I have the following line in the setup portion of my main() function: Code: | setup_timer_1(TMR_INTERNAL, 0x0148)); |
Here is the logic behind this:
1) The PIC24 has an 8 MHz internal clock. That means the period of each clock cycle is 0.125 us.
2) The 16 bit timer has max value of 0xFFFF (65,535), which means that 8*10^6 / 65535 = 122. This is the number of cycle count per bit of the timer.
3) Therefor, each bit of the timer represents (122 * 0.125 us) = about 15 us
4) so, for a (I think reasonable?) period of 5 ms for my interrupt, I should set the period value of ( 5ms / 15 us = 328). In other words, 328 (0x148).
5) so, the interrupt will fire every 5 ms, and we keep going until the g_PIN_doubounce variable is filled up with all 1s (0xFFFF). So this will occur at approx. 75 ms because (5 ms * 16 = 75 ms). i.e. if I understand your algorithm correctly, inside the interrupt we OR the pin HIGH input with that variable and keep shifting left until the whole thing is filled up. So that means 16 passes through the interrupt routine to ensure a stable signal.
Lastly, is there a reason you recommended timer 5 as opposed to one of the others? |
I wasn't intending to suggest timer 5 specifically. It was more just for example. On most (all???) PIC24FJ chips, timer 1 is the only timer with an asynchronous input, so we reserve that one for our external 32KHz crystal in order to wake our boards up from full sleep using a timer (other timers normally cannot do this). I just picked a timer at random for the example.
In terms of your timing, I would always recommend you toggle an I/O line using the timer interrupt and measure it on a scope to verify the timing and your clock settings. PIC24's divide the incoming clock by 2x so the 8 MHz would be 4 MHz (unless your clock is really 16 MHz, then it would be 8MHz). (SIDE NOTE: PIC18s and below divide the clock by 4x).
You are correct about my algorithm that it takes 16 passes (due to the unsigned int16 type). And my algorithm does wait until all 16 are 1's but also makes sure the last time it was full it was all 0's before (essentially a rising edge). That way the stuff in the IF only triggers once until the logic goes low 16 times and then high 16 times again (so a falling edge followed by a rising edge). Hopefully that makes sense. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Aug 09, 2024 6:59 pm |
|
|
One potential issue with software debounce is that you've got it working perfect with brand x, style 3 switches then.... have to buy brand k, style 1 switches, which of course have a totally different debounce 'action'.
You can lose a lot of time over this head scratcher....really, all switches are the same , right ????
I learned decades ago to spend a few pennies in hardware to get solid,clean signals. Usually 'hard' pullups, 1mfd filter caps, schmitt(sp) buffers. In automotive products ,used 5V regulators as +12 to +5 level converters. Boss said that adds cost but SAVED money as NO defective boards due to 'front end' damage. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Sat Aug 10, 2024 1:44 pm |
|
|
and (of course), switches that are fine when you build the unit, then
give bounce problems in the future, or when a different person uses the
key.... |
|
|
|