function to read buttons doesn't work as expected

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Hi guys

I think it may be a long short to get an answer without the hardware for this, but I am stuck and want to try my luck here. So I basically want to write a function to drive and read a digital IO (the IO need to switch between input and output). And I need to do that to a lot of IOs. So I wrote an function to do that so I don't need to copy and paste the code many many times.

The thing is it works if I duplicate the code manually, but it doesn't work with my function.

So here is the codes:
Code:
    typedef struct
    {
        // b type input 1 - 6
        uint8_t set1 : 1;
        uint8_t reset1 : 1;
        uint8_t set2 : 1;
        uint8_t reset2 : 1;
        uint8_t set3 : 1;
        uint8_t reset3 : 1;
        uint8_t set4 : 1;
        uint8_t reset4 : 1;
        uint8_t set5 : 1;
        uint8_t reset5 : 1;
        uint8_t set6 : 1;
        uint8_t reset6 : 1;
        // VoIP calling status
        uint8_t connecting : 1;
        uint8_t connected : 1;
        // intercom control
        uint8_t intercomEnable : 1;
    }INPUTS;
codes that works:
Code:
run_every_1ms()
{ 
        static uint8_t states = 0;
        static uint8_t db1 = 0;
        static uint8_t db2 = 0;
        states++;

        // driving and reading first IO
        if (states == 1)
        {
            /* start reading button state*/
            TRISCbits.TRISC5 = 1;         // input
            __delay_us(1);
            if (!PORTCbits.RC5)
            {
                if (db1 < INPUT_BTN_DEBOUNCE_DELAY)
                    db1++;
                else
                    inputs.set6 = 1;
            }
            else
            {
                if (db1 != 0)
                    db1--;
                else
                    inputs.set6 = 0;
            }

            /* drive buttons LEDs */
            TRISCbits.TRISC5 = 0;         // output
            LATCbits.LATC5 = 1;          // high, LED off
        }
        else if (states == STATE_NUM)
        {
            /* drive buttons LEDs */
            LATCbits.LATC5 = 0;          // low, LED on
        }

        // driving and reading 2nd IO
        if (states == 1)
        {
            /* start reading button state*/
            TRISCbits.TRISC4 = 1;         // input
            __delay_us(1);
            if (!PORTCbits.RC4)
            {
                if (db2 < INPUT_BTN_DEBOUNCE_DELAY)
                    db2++;
                else
                    inputs.reset6 = 1;
            }
            else
            {
                if (db2 != 0)
                    db2--;
                else
                    inputs.reset6 = 0;
            }

            /* drive buttons LEDs */
            TRISCbits.TRISC4 = 0;         // output
            LATCbits.LATC4 = 1;          // high, LED off
        }
        else if (states == STATE_NUM)
        {
            /* drive buttons LEDs */
            LATCbits.LATC4 = 0;          // low, LED on
        }
       
        // drive and read another io....
        // drive and read another io....
        // drive and read another io....

        if (states == STATE_NUM) states = 0;    // reset states
}
my function that doesn't work:
Code:
run_every_1ms()
{
        static uint8_t states = 0;
        static uint8_t db1 = 0;
        static uint8_t db2 = 0;
        states++;
        inputs.set6 = buttonScan(&SET6_TRIS, &SET6_PORT, &SET6_LAT, SET6_PIN, &db1, states);
        inputs.reset6 = buttonScan(&RESET6_TRIS, &RESET6_PORT, &RESET6_LAT, RESET6_PIN, &db2, states);
        // drive and read another io....
        // drive and read another io....
        if (states == STATE_NUM) states = 0;
}

Code:
uint8_t buttonScan(volatile unsigned char *TRIS,
        volatile unsigned char *PORT,
        volatile unsigned char *LAT,
        uint8_t pinNum,
        uint8_t *db,
        uint8_t states)
{
    uint8_t result;
    if (states == 1)
    {
        /* start reading button state*/
        SET_BIT(*TRIS, pinNum);         // input
        _delay(10);
        if (!CHECK_BIT(*PORT, pinNum))
        {
            if ((*db) < INPUT_BTN_DEBOUNCE_DELAY)
                (*db)++;
            else
                result = 1;
        }
        else
        {
            if ((*db) != 0)
                (*db)--;
            else
                result = 0;
        }

        /* drive buttons LEDs */
        CLR_BIT(*TRIS, pinNum);         // output
        SET_BIT(*LAT, pinNum);          // high, LED off
    }
    else if (states == STATE_NUM)
    {
        /* drive buttons LEDs */
        CLR_BIT(*LAT, pinNum);          // low, LED on
    }
    return result;
}
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Can you elaborate on what that means? What is it not doing, or alternatively, what is it doing that is wrong?

John
So a pin is connected to a LED and a button, my code need to drive the led at ~10% duty cycle at ~100Hz. Both method of my code can drive a LED properly. But only the code I manually duplicated can read the button, but my function doesn't read the button properly.

To be exact, when a button is pressed, the return a my function is undetermined (sometime is true, sometime is false).

When no buttons are pressed, both code working correctly (which only drive LEDs on 10% duty cycle)
 

dannyf

Joined Sep 13, 2015
2,197
I recently posted a hardware independent readaptation of the Kuhn debouncer - I will post a link later.

It can be modified to suit your denouncing logic and dual use fairly easily.
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
I recently posted a hardware independent readaptation of the Kuhn debouncer - I will post a link later.

It can be modified to suit your denouncing logic and dual use fairly easily.
I don't think it's the debounce that cause the problem. If it is, both of my code should not work correctly, as they debounce the same way. However, I am interested in having a look of your hardware independent readaptation of the Kuhn debouncer.
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Addition info:
For some reason, in my function, pressing button reset6, will trigger button set6 to return true too. It looks like the datas is corrupted inside my function somewhere, but I don't know why and how.
Code:
        inputs.set6 = buttonScan(&SET6_TRIS, &SET6_PORT, &SET6_LAT, SET6_PIN, &db1, states);
        inputs.reset6 = buttonScan(&RESET6_TRIS, &RESET6_PORT, &RESET6_LAT, RESET6_PIN, &db2, states);
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
  1. CLR_BIT(*TRIS, pinNum); // output
  2. SET_BIT(*LAT, pinNum); // high, LED off
Are these macros?
yes, they are:

Code:
#define SET_BIT(p,n) ((p) |= (1 << (n)))
#define CLR_BIT(p,n) ((p) &= ~((1) << (n)))
#define CHECK_BIT(p,n) ((p) & (1 << (n)))
 

dannyf

Joined Sep 13, 2015
2,197
So here is the link: https://dannyelectronics.wordpress.com/2016/06/05/a-generic-software-debouncer/

In your application, it goes like this:

Code:
#include "keyint.h"  //include kuhn debouncer

//user handler for key1, active low
KEY_STATE key1read(void) {
  KEY_STATE tmp;
  IO_IN(KEY1_DDR, KEY1); //key1 as input
  if (IO_GET(KEY1_PORT, KEY1)==0) tmp = KEY_PRESSED; //if key1 low, returned pressed
  else tmp = KEY_NOTPRESSED;
  IO_OUT(KEY1_DDR, KEY1); //key1 return as output
  return tmp;
}

//key2 user handler, active high
KEY_STATE key2read(void) {
  KEY_STATE tmp;
  IO_IN(KEY2_DDR, KEY2); //key2 as input
  if (IO_GET(KEY2_PORT, KEY2)==0) tmp = KEY_NOTPRESSED; //low = key not pressed
  else tmp = KEY_PRESSED;
  IO_OUT(KEY2_DDR, KEY2); //key2 return as output
  return tmp;
}


int main(void) {

  KEY_TypeDef key1, key2, key3, ....; //define your keys here

  key_init(&key1, key1read); //install user handler for key1
  key_init(&key2, key2read); //install user handler for key2

  while (1) {
    key_read(&key1); //read key1
    key_read(&key2); //read key2

  if (key_get(&key1) == KEY_PRESSED) do_something();
  if (key_get(&key2) == KEY_PRESSED) do_somethingelse();
The number of keys it can access is only limited by the chip.

Hope it helps.
 
Top