Teclado Matricial 4x4 a Display 7 segmentos con STM32F407G-DISC1

Hola, buen día.

He estado haciendo un proyecto el cual consiste en mostrar, por medio de las teclas presionadas en el teclado matricial de 4x4, un número de 8 dígitos usando 2 displays de 7 segmentos con 4 dígitos cada uno, pero me surge un problema.
El ejercicio consiste en que al presionar una tecla "X" se debe mostrar en el display y si presiono otra tecla "Y" se recorre al lado izquierdo formando un número "XY".
Ejemplo:
Presiono el "3" y se muestra el "3", después presiono el "4" y se muestra el "34", enseguida presiono el "5" y se muestra el "345" y así se va sumando y recorriendo cada tecla que vaya presionando.

Mi problema radica en que al presionar una tecla, digamos "1", me salen tres o cuatro veces el mismo número en el display.
Pienso que son los rebotes e intenté arreglarlo con retardos pero me sigue sucediendo lo mismo.

Quisiera saber si me podrían ayudar, de antemano gracias.
Anexo código
C:
/////////////////////////////////////////////////////////////////////////////////////


#include "main.h"

#include "stm32f4xx.h"


void SystemClock_Config(void);

static void MX_GPIO_Init(void);


#define GPIOE_CLOCK (1<<4);


void DisplayNumber(int count);

void SetDisplay(int dig1, int dig2, int dig3, int dig4, int dig5, int dig6, int dig7, int dig8);

void DecodeKeyboard1(void);

void DecodeKeyboard2(void);

void DecodeKeyboard3(void);

void DecodeKeyboard4(void);


int numeros[10]={0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9};

int count;

uint32_t Key;

uint32_t KeyboardNumber;

int D1=0x70;        //Y7

int D2=0x60;

int D3=0x50;

int D4=0x40;

int D5=0x30;

int D6=0x20;

int D7=0x10;

int D8=0x00;         //Y0


int main(void)

{


       RCC->AHB1ENR |=GPIOE_CLOCK;

    GPIOE->MODER |=0x5555;


  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();


  while (1)

  {

      DisplayNumber(KeyboardNumber);

  }


}


void DisplayNumber(int count)

{

    int dig1, dig2, dig3, dig4, dig5, dig6, dig7, dig8;

    dig1=count%10;                        //Decenas de Millón

    dig2=(count%100)/10;                //Unidades de Millar

    dig3=(count%1000)/100;                //Centenas de Millar

    dig4=(count%10000)/1000;            //Decenas de Millar

    dig5=(count%100000)/10000;            //Unidades de Millar

    dig6=(count%1000000)/100000;        //Centenas

    dig7=(count%10000000)/1000000;        //Decenas

    dig8=(count%100000000)/10000000;    //Unidades

    SetDisplay(dig8, dig7, dig6, dig5, dig4, dig3, dig2, dig1);

  }


void SetDisplay(int dig1, int dig2, int dig3, int dig4, int dig5, int dig6, int dig7, int dig8)

{

    GPIOE->ODR=numeros[dig1]+D1;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig2]+D2;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig3]+D3;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig4]+D4;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig5]+D5;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig6]+D6;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig7]+D7;

    HAL_Delay(1);


    GPIOE->ODR=numeros[dig8]+D8;

    HAL_Delay(1);

}


void DecodeKeyboard1(void)

{

            GPIOD->ODR = 0x10;

            if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))

              {

                  Key=1;

              }


            GPIOD->ODR = 0x20;

            if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))

              {

                  Key=2;

              }


            GPIOD->ODR = 0x40;

            if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))

              {

                  Key=3;

              }


            GPIOD->ODR = 0x80;

            if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))

              {

                  Key=0;

              }

            GPIOD->ODR = 0xF0;

            KeyboardNumber=((KeyboardNumber%10000000)*10+Key);

}


void DecodeKeyboard2(void)

{

        GPIOD->ODR = 0x10;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))

          {

              Key=4;

          }


        GPIOD->ODR = 0x20;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))

          {

              Key=5;

          }


        GPIOD->ODR = 0x40;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))

          {

              Key=6;

          }


        GPIOD->ODR = 0x80;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))

          {

              Key=0;

          }

        GPIOD->ODR = 0xF0;

        KeyboardNumber=((KeyboardNumber%10000000)*10+Key);

}


void DecodeKeyboard3(void)

{

        GPIOD->ODR = 0x10;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))

          {

              Key=7;

          }


        GPIOD->ODR = 0x20;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))

          {

              Key=8;

          }


        GPIOD->ODR = 0x40;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))

          {

              Key=9;

          }


        GPIOD->ODR = 0x80;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))

          {

              Key=0;

          }

        GPIOD->ODR = 0xF0;

        KeyboardNumber=((KeyboardNumber%10000000)*10+Key);

}


void DecodeKeyboard4(void)

{

        GPIOD->ODR = 0x10;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))

          {

              Key=0;

          }


        GPIOD->ODR = 0x20;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))

          {

              Key=0;

          }


        GPIOD->ODR = 0x40;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))

          {

              Key=0;

          }


        GPIOD->ODR = 0x80;

        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))

          {

              Key=0;

          }

        GPIOD->ODR = 0xF0;

        KeyboardNumber=((KeyboardNumber%10000000)*10+Key);

}


void EXTI0_IRQHandler(void)

{

    for(int i=0;i<100000;i++);

    DecodeKeyboard1();

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

}


void EXTI1_IRQHandler(void)

{

    for(int i=0;i<100000;i++);

    DecodeKeyboard2();

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);

}


void EXTI2_IRQHandler(void)

{

    for(int i=0;i<100000;i++);

    DecodeKeyboard3();

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);

}


void EXTI3_IRQHandler(void)

{

    for(int i=0;i<10000;i++);

    DecodeKeyboard4();

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);

}

1605732039239.png
 
Buenas,
el sistema que yo uso para evitar rebotes es el enclavamiento. Digamos que detectas el cero (pulsado). Entonces entras en un lazo que contiene un retardo, del que se sale con un uno (tecla liberada).
Creo que lo que te pasa es que lees varias veces la misma tecla, puede que debido a los rebotes.
También se puede probar con una red pasa bajos RC entre el pulsador y el microcontrolador.
1605735165196.png

1605735522335.png
 
Última edición:
Que tal, buenas noches.

Intenté hacer el filtro pasa bajas que me comentaron pero aún así en los displays me salían de de dos a tres números repetidos por lo que decidí intentar resolver el problema de manera distinta.

Lo que hice, dentro de los void donde decodifico el teclado "DecodeKeyboard", fue poner un condicional que me pregunte:
La tecla que se está leyendo es distinta a la tecla anterior?
Lo que hará esto es solo mandar a los displays las teclas que sean distintas a las ya presionadas, el único inconveniente será que no podremos presionar dos veces la misma tecla.


Anexo código corregido
C:
#include "main.h"
#include "stm32f4xx.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

#define GPIOE_CLOCK (1<<4);

void DisplayNumber(int count);
void SetDisplay(int dig1, int dig2, int dig3, int dig4, int dig5, int dig6, int dig7, int dig8);
void DecodeKeyboard1(void);
void DecodeKeyboard2(void);
void DecodeKeyboard3(void);
void DecodeKeyboard4(void);

int numeros[10]={0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9};
int count;
int Key;
int nKey;
uint32_t KeyboardNumber;
int D1=0x70;        //Y7
int D2=0x60;
int D3=0x50;
int D4=0x40;
int D5=0x30;
int D6=0x20;
int D7=0x10;
int D8=0x00;         //Y0

int main(void)
{

       RCC->AHB1ENR |=GPIOE_CLOCK;
    GPIOE->MODER |=0x5555;

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();

  while (1)
  {
      DisplayNumber(KeyboardNumber);
  }

}

void DisplayNumber(int count)
{
    int dig1, dig2, dig3, dig4, dig5, dig6, dig7, dig8;
    dig1=count%10;                        //Decenas de Millón
    dig2=(count%100)/10;                //Unidades de Millar
    dig3=(count%1000)/100;                //Centenas de Millar
    dig4=(count%10000)/1000;            //Decenas de Millar
    dig5=(count%100000)/10000;            //Unidades de Millar
    dig6=(count%1000000)/100000;        //Centenas
    dig7=(count%10000000)/1000000;        //Decenas
    dig8=(count%100000000)/10000000;    //Unidades
    SetDisplay(dig8, dig7, dig6, dig5, dig4, dig3, dig2, dig1);
  }

void SetDisplay(int dig1, int dig2, int dig3, int dig4, int dig5, int dig6, int dig7, int dig8)
{
    GPIOE->ODR=numeros[dig1]+D1;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig2]+D2;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig3]+D3;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig4]+D4;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig5]+D5;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig6]+D6;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig7]+D7;
    HAL_Delay(1);

    GPIOE->ODR=numeros[dig8]+D8;
    HAL_Delay(1);
}

void DecodeKeyboard1(void)
{
        GPIOD->ODR = 0x10;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))
         {
            Key=1;
         }

        GPIOD->ODR = 0x20;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))
        {
            Key=2;
        }

        GPIOD->ODR = 0x40;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))
         {
            Key=3;
         }

        GPIOD->ODR = 0x80;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_0))
         {
            Key=0;
         }
        if(Key!=nKey)
         {
              nKey=Key;
              KeyboardNumber=((KeyboardNumber%10000000)*10+Key);
         }
        GPIOD->ODR = 0xF0;
}

void DecodeKeyboard2(void)
{
        GPIOD->ODR = 0x10;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              Key=4;
          }

        GPIOD->ODR = 0x20;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              Key=5;
          }

        GPIOD->ODR = 0x40;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              Key=6;
          }

        GPIOD->ODR = 0x80;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              Key=0;
          }
        if(Key!=nKey)
          {
              nKey=Key;
                 KeyboardNumber=((KeyboardNumber%10000000)*10+Key);
          }
        GPIOD->ODR = 0xF0;
}

void DecodeKeyboard3(void)
{
        GPIOD->ODR = 0x10;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))
          {
              Key=7;
          }

        GPIOD->ODR = 0x20;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))
          {
              Key=8;
          }

        GPIOD->ODR = 0x40;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))
          {
              Key=9;
          }

        GPIOD->ODR = 0x80;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2))
          {
              Key=0;
          }
        if(Key!=nKey)
            {
                nKey=Key;
                KeyboardNumber=((KeyboardNumber%10000000)*10+Key);
            }
            GPIOD->ODR = 0xF0;
}

void DecodeKeyboard4(void)
{
        GPIOD->ODR = 0x10;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))
          {
              Key=0;
          }

        GPIOD->ODR = 0x20;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))
          {
              Key=0;
          }

        GPIOD->ODR = 0x40;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))
          {
              Key=0;
          }

        GPIOD->ODR = 0x80;
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_3))
          {
              Key=0;
          }
        if(Key!=nKey)
            {
                nKey=Key;
                KeyboardNumber=((KeyboardNumber%10000000)*10+Key);
            }
            GPIOD->ODR = 0xF0;
}

void EXTI0_IRQHandler(void)
{
    for(int i=0;i<100000;i++);
    DecodeKeyboard1();
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

void EXTI1_IRQHandler(void)
{
    for(int i=0;i<100000;i++);
    DecodeKeyboard2();
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}

void EXTI2_IRQHandler(void)
{
    for(int i=0;i<100000;i++);
    DecodeKeyboard3();
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
}

void EXTI3_IRQHandler(void)
{
    for(int i=0;i<10000;i++);
    DecodeKeyboard4();
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
}
 
C++:
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              Key=4;
          }

Prueba con:

C++:
        if(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1))
          {
              // Con 10ms debería bastar.
              // retardo();

              // Espero a que se suelte la tecla.
              while(HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_1));
              Key=4;
          }

Aun así el código se puede compactar muchísimo ya que tiene muchas cosas duplicadas.
 
Habia visto que manejan el teclado con interrupciones, donde en la misma hacen el calculo de cual tecla se presiono, y se guarda en una variable global, pero los vi en PIC con la interrupcion de cambio de estado de un puerto completo. No se si se podra con los STM...
 
No veo el porque de la limitación, eso era cosa de los viejos micros. Recuerdo los PIC que ni siquiera tenían interrupción y solo 2 lugares en el STACK. En esos días si que había que sacarse el sombrero ante los programadores...

Si bien hay ciertas estructuras la verdad es que cada código tiene su ADN y debe haber tantas formas de programar como personas en el mundo.

Yo pondría todos los pines de las columnas en alto (o en bajo si estan las pull-up habilitadas en las filas, que seria lo ideal para evitar valores falsos) e interrupción por cambio en pin. Al entrar en la interrupción se escanea columna por columna para saber cual fue el dígito. Si se detecta dos teclas presionadas se descarta o no, todo depende de la aplicación.
 
Si un filtro RC no resuelve es que el problema no son rebotes. Es el programa.
Puede que lea demasiado rápido. Entre una tecla y otra debes enclavar hasta que se libere el teclado y esperar ...
¿Usas interrupción seguida de exploración, o bien explotas en free running?
 
Arriba