Timer Interrupt on Due for Matrix Keyboard Scan

Hello,

I've been trying to get to work a program, in which I would like it to be a sketch I could use in several other problems related to matrix keyboard uses.

The thing is, I'm putting together a 8x4 keyboard and the initial ideia was to make the Due, the board I'm utilising, to multiplex the 8 outputs (columns) and whenever a signal low was detected on one of the rows (inputs) it would store and print a number on the serial monitor. I start the columns as high and each 10ms one of them go to low, the inputs are set up as pull-ups.

I was having some problems to set up the timer interrupt on the Due but it seems it's working. In order to see that, I printed the number one to eight on the serial monitor every time it scans a column.

As a result I'm getting on the serial monitor the number one to eight printed but several other caracthers too which should only be displayed if a connection was made between the a column and a row. It keeps displaying particularly the last row of caracthers along with the number one to eight even though I didn't connect anything to do so. I'm also not getting anything displayed on the serial monitor by doing connections betweens the outputs and inputs.

I would really appreciate to have one guide me through this, as well as give hints of I what I can do to get it done in a better way.

I'm going to attach the .ino skecth because it says the code is too long to post here.

teclado_varredura_8x4_Due.ino (14.3 KB)

Hello,

I've been trying to get to work a program, in which I would like it to be a sketch I could use in several other problems related to matrix keyboard uses.

The thing is, I'm putting together a 8x4 keyboard and the initial ideia was to make the Due, the board I'm utilising, to multiplex the 8 outputs (columns) and whenever a signal low was detected on one of the rows (inputs) it would store and print a number on the serial monitor. I start the columns as high and each 10ms one of them go to low, the inputs are set up as pull-ups.

I was having some problems to set up the timer interrupt on the Due but it seems it's working. In order to see that, I printed the number one to eight on the serial monitor every time it scans a column.

As a result I'm getting on the serial monitor the number one to eight printed but several other caracthers too which should only be displayed if a connection was made between the a column and a row. It keeps displaying particularly the last row of caracthers along with the number one to eight even though I didn't connect anything to do so. The columns one to seven if connected to the first three rows it display the right caracther on the serial monitor.

I would really appreciate to have one guide me through this, as well as give hints of I what I can do to get it done in a better way.

I'm going to attach the .ino skecth because it says the code is too long to post here.

teclado_varredura_8x4_Due.ino (14.3 KB)

I can't open the attachment because I'm on a phone here.

Help us help you by trimming the code down to the smallest possible example which compiles and shows the problem. Often that will reveal the problem to you.

I do not know the Due, but never call the print from a interrupt routine!
Basically interrupt routines has to be very short and this mostly precludes system calls.

I've merged your cross posts @phfm30.

Cross posting is against the rules of the forum. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend 15 minutes writing a detailed answer on this thread, without knowing that someone else already did the same in the other thread.

Repeated cross posting will result in a suspension from the forum.

In the future, please take some time to pick the forum section that best suits the topic of your question and then only post once to that forum section. This is basic forum etiquette, as explained in the sticky "How to use this forum - please read." post you will find at the top of every forum section. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

Hello, eveyone.

I've stumbled upon some errors on a program I'm developing for the scanning of a 8x4 Matrix Keyboard. The board I'm using is the Arduino Due.

I am using a Timer Interrupt in order to change the state of the columns defined as outputs each 10ms one of them go to 0 and as soon as one of the rows (input pull-ups) identify a low state one number is stored and showed on the serial monitor.

It's partially working but there's some minor bugs I would like to get rid of.

It keeps displaying on the serial monitor the last row of numbers even though I haven't connected anything to do so. (Numbers 25 to 32)

When I connect the columns to the row it displays the numbers correctly, but for some reason I can't understand why the last column does not display aything if connected to the rows.

Here is the first part of the program:

// =============================================================================================================
// --- Hardware ---
#define  col_1   2                    //coluna 1 do teclado
#define  col_2   3                    //coluna 2 do teclado
#define  col_3   4                    //coluna 3 do teclado
#define  col_4   5                    //coluna 4 do teclado
#define  col_5   6                    //coluna 5 do teclado
#define  col_6   7                    //coluna 6 do teclado
#define  col_7   8                    //coluna 7 do teclado
#define  col_8   9                    //coluna 8 do teclado
#define  row_A   10                   //linha A  do teclado
#define  row_B   11                   //linha B  do teclado
#define  row_C   12                   //linha C  do teclado
#define  row_D   13                   //linha D  do teclado

#include <hd44780.h>

// =============================================================================================================
// --- Functions ---
void readKeyboard();                  //Função para leitura do teclado
void store(char value);               //Função para armazenar o número digitado no teclado matricial
void numero();                        //Função para imprimir o número digitado na tela do LCD


// =============================================================================================================
// --- Global Variables ---
//char control = 0x01;                  
// char counter = 0x00;             
//int  number  = 0x00;                
volatile uint8_t control = 0x01;      //variável de controle de teclado
volatile uint8_t number  = 0x00;      //variável para armazenar o número pressionado no teclado
volatile uint8_t  counter = 0x00;     //variável auxiliar de contagem
volatile uint8_t flag = 0x00;

The interruption:

// =============================================================================================================
// --- Interruption ---
void TC7_Handler()
{
  //get the status to clear it and allow the interrupt to fire again
  TC_GetStatus(TC2, 1);
  counter++;

  if(counter == 0x05)
    {
     counter = 0x00;
     flag = 0x01;     
    }
}

// =============================================================================================================
// --- Initial Setup ---
void setup()
{
     Serial.begin(9600);
  
     for(char i=2;i< 9;i++) pinMode(i, OUTPUT);             //Saídas para varredura das colunas
     for(char j=9;j<13;j++) pinMode(j, INPUT_PULLUP);       //Entradas para as linhas
     
     
     digitalWrite(col_1, HIGH);                             //Inicializa coluna 1 em HIGH
     digitalWrite(col_2, HIGH);                             //Inicializa coluna 2 em HIGH
     digitalWrite(col_3, HIGH);                             //Inicializa colune 3 em HIGH
     digitalWrite(col_4, HIGH);                             //Inicializa coluna 4 em HIGH
     digitalWrite(col_5, HIGH);                             //Inicializa coluna 5 em HIGH
     digitalWrite(col_6, HIGH);                             //Inicializa colune 6 em HIGH
     digitalWrite(col_7, HIGH);                             //Inicializa coluna 7 em HIGH
     digitalWrite(col_8, HIGH);                             //Inicializa coluna 8 em HIGH
   
     pmc_set_writeprotect(false);     // disable write protection for pmc registers

  //************** TIMER INTERRUPT *****************************

  /* turn on the timer clock in the power management controller */ 
  pmc_enable_periph_clk(ID_TC7);   // enable peripheral clock TC7
  /* we want wavesel 01 with RC */
  TC_Configure(/* clock */TC2,/* channel */1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); 
  TC_SetRC(TC2, 1, 6562); //10ms
  TC_Start(TC2, 1);

  // enable timer interrupts on the timer
  TC2->TC_CHANNEL[1].TC_IER=TC_IER_CPCS;   // IER = interrupt enable register
  TC2->TC_CHANNEL[1].TC_IDR=~TC_IER_CPCS;  // IDR = interrupt disable register

  /* Enable the interrupt in the nested vector interrupt controller */
  /* TC4_IRQn where 4 is the timer number * timer channels (3) + the channel number (=(1*3)+1) for timer1 channel1 */
  NVIC_EnableIRQ(TC7_IRQn);

  //************** TIMER INTERRUPT *****************************
 
} //end setup

Void Loop:

// =============================================================================================================
// --- Infinite Loop ---
void loop()
{
 if (flag == 0x01){
  readKeyboard();
  }
  flag = 0x00;
} //end loop

I'm going to post the functions on the reply below.

If any of you guys could hint me with tips of what I can be doing wrong would be preety nice. Since I'm planning to expand the project and add a 20X4 LCD as well.

Thank you all in advance.

teclado_varredura_8x4_Due.ino (14.3 KB)

Functions:

// =============================================================================================================
// --- Desenvolvimento das Funções ---
void readKeyboard()                       //Função para leitura do teclado
{

   if(digitalRead(col_1) && control == 0x01)       //Coluna 1 em nível high? Control igual 1?
   {                                               //Sim...
         control = 0x02;                           //control igual a 2
         digitalWrite(col_1,  LOW);                //apenas coluna 1 em nível baixo
         digitalWrite(col_2, HIGH);
         digitalWrite(col_3, HIGH);
         digitalWrite(col_4, HIGH);
         digitalWrite(col_5, HIGH);
         digitalWrite(col_6, HIGH);
         digitalWrite(col_7, HIGH);
         digitalWrite(col_8, HIGH);
         //Serial.println("1");
      
      // -- Testa qual tecla foi pressionada e armazena o valor --
         if     (!digitalRead(row_A))  store(1);
         else if(!digitalRead(row_B))  store(9);
         else if(!digitalRead(row_C))  store(17);
         else if(!digitalRead(row_D))  store(25);
      
   } //end if col_1
   
   else if(digitalRead(col_2) && control == 0x02)   //Coluna 2 em nível high? Control igual 2?
   {                                                //Sim...
         control = 0x03;                            //control igual a 3
         digitalWrite(col_1, HIGH);
         digitalWrite(col_2,  LOW);                 //apenas coluna 2 em nível baixo
         digitalWrite(col_3, HIGH);
         digitalWrite(col_4, HIGH);
         digitalWrite(col_5, HIGH);
         digitalWrite(col_6, HIGH);
         digitalWrite(col_7, HIGH);
         digitalWrite(col_8, HIGH);
        // Serial.println("2");
                
         
      // -- Testa qual tecla foi pressionada e armazena o valor --
         if     (!digitalRead(row_A))  store(2);
         else if(!digitalRead(row_B))  store(10);
         else if(!digitalRead(row_C))  store(18);
         else if(!digitalRead(row_D))  store(26);

//.
//. *Follow the same logic until col_8*

  
} //end readKeyboard
void store(char value)                   //Função para armazenar o valor digitado no teclado
{
   char i;                                //variável de interações
   
   //disable timer interrupts on the timer     
   TC2->TC_CHANNEL[1].TC_IER=~TC_IER_CPCS;  // IER = interrupt enable register
   TC2->TC_CHANNEL[1].TC_IDR=TC_IER_CPCS;  // IDR = interrupt disable register
   NVIC_DisableIRQ(TC2_IRQn);
   
     
   delay(350);
  
        
   number = value;                       //atualiza number

   numero();

   //enable timer interrupts on the timer
   TC2->TC_CHANNEL[1].TC_IER=TC_IER_CPCS;   // IER = interrupt enable register
   TC2->TC_CHANNEL[1].TC_IDR=~TC_IER_CPCS;  // IDR = interrupt disable register
   NVIC_EnableIRQ(TC2_IRQn);
   
} //end store


void numero()                                           //Função para imprimir o número digitado
{
   
   if     (number == 1) Serial.println("Test 1");
   else if(number == 2) Serial.println("Test 2");
   else if(number == 3) Serial.println("Test 3");
   else if(number == 4) Serial.println("Test 4");
   else if(number == 5) Serial.println("Test 5");
   else if(number == 6) Serial.println("Test 6");
   else if(number == 7) Serial.println("Test 7");
   else if(number == 8) Serial.println("Test 8");
   else Serial.println(number);                                    //Mostra número  
   
 
} //end numero

phfm30:
It's partially working but there's some minor bugs I would like to get rid of.

Using an interrupt would be the first!

I just wrote a simple block of code for a matrix of buttons i wired for my last project. I didnt use timers but it works well. I can post my simple working example if you want.

@phfm30

7 day timeout cross posting and wasting peoples time and efforts.

Some thoughts:

1/ control variable is never decremented in your code or set to 0 after initialization

2/ in void numero(), there is a test on variable number between 1 to 8, however number is set to 1,9,17,25,2,10,18 or 26 !