#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
//Declaring functions (JI)
void setup_gpio(); //This function initializes outputs and inputs. (JI)
char scan_keypad(); //This function continuously scans the keypad and responds on user input. (JI)
//Defining the matrix for the keypad (4x4). (JI)
#define ROWS 4
#define COLS 4
//Declaring arrays with GPIO pins for the rows and columns. (JI)
int scanRowPins[ROWS] = {38, 37, 36, 35};
int colPins[COLS] = {0, 45, 48, 47};
//Declaring a two-dimensional array using the rows and columns arrays created above. (JI)
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
void app_main() {
setup_gpio();
while (1) {
char key = scan_keypad(); //The returned values from the "scan_keypad()" function are stored in a variable named 'key'. (JI)
if (key != '\0') { //If the values returned from the keypad are NOT null, then proceed with the code below. (JI)
printf("You pressed: %c\n", key); //Print the button pressed by printing the value of 'key'. (JI)
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
//Function definition to initialize rows and columns as outputs and inputs. (JI)
void setup_gpio() {
for (int i = 0; i < ROWS; i++) {
gpio_set_direction(scanRowPins[i], GPIO_MODE_OUTPUT); //Initializing rows as outputs. (JI)
gpio_set_level(scanRowPins[i], 1);
}
for (int i = 0; i < COLS; i++) {
gpio_set_direction(colPins[i], GPIO_MODE_INPUT); //Initializing columns as inputs. (JI)
gpio_set_pull_mode(colPins[i], GPIO_PULLUP_ONLY); // all buttons are set as pullup configuration using the internal pullup resistor in the microcontroller
}
}
//Function definition for the keypad scanning. (JI)
char scan_keypad() {
uint8_t scanVal; //Declaring an unsigned 8-bit variable. The value of the button pressed will be stored in this variable. (JI)
for (int i = 0; i < ROWS; i++) { //Scan through the each row, one at a time to get their values. (JI)
scanVal = ~(1 << i); //One's complement the value of each row. If a button is pressed, only one row will be different. One's complement is required because the circuit is in a pull-up resistor configuration. (JI)
//This portion takes the newly updated value of the button press from scanVal, and iterates through each bit to read its binary value.
for (int j = 0; j < ROWS; j++) {
gpio_set_level(scanRowPins[j], (scanVal >> j) & 1); //Here, the button pressed is identified by extracting the bits from each row. The row with a zero in one of the bits means that specific button was pressed in that row. (JI)
}
vTaskDelay(pdMS_TO_TICKS(5));
//Debounce operation to prevent accidental additional inputs or errors. (JI)
for (int k = 0; k < COLS; k++) { //Iterate through each column. (JI)
if (gpio_get_level(colPins[k]) == 0) { //If any of the columns detect a '0', it means a button is being pressed.
while (gpio_get_level(colPins[k]) == 0) { //While that button is being pressed, continuously repeat a 50ms delay until the button is depressed. (JI)
vTaskDelay(pdMS_TO_TICKS(50));
}
return keys[i][k]; //Return the values of the intersecting column and row. These values will be stored in the 'key' variable in app_main.
}
}
}
return '\0';
}