2025-04-15 10:20 PM
Good day
I am using a NUCLEO-STMG0B1RE board and i am trying to handle a 4x3 matrix keypad inputs using interrupts to switch menus on an OLED screen. The keypad inputs worked when I used continuous polling for keypad inputs. The OLED needs to continuously update (at least once per second) with data from ADC. This also worked when I used continuous polling, but the keypad inputs was a bit sluggish and I am scared it will slow my processor down for future use.
With the current code I am trying to do the following:
With the current code I have to spam keys to get a input.
I will add code for relevant sections as well as my main.c file
Private variables:
/* USER CODE BEGIN PV */
const char keymap[4][3] = { { '1', '2', '3' }, { '4', '5', '6' }, { '7', '8',
'9' }, { '*', '0', '#' } };
GPIO_TypeDef *row_ports[4] = { GPIOC, GPIOB, GPIOB, GPIOB };
uint16_t row_pins[4] = { GPIO_PIN_0, GPIO_PIN_2, GPIO_PIN_6, GPIO_PIN_15 };
GPIO_TypeDef *col_ports[3] = { GPIOA, GPIOA, GPIOC };
uint16_t col_pins[3] = { GPIO_PIN_12, GPIO_PIN_11, GPIO_PIN_1 };
volatile char last_key = '\0';
volatile int col = -1;
typedef enum {
PAGE_DEFAULT,
PAGE_1,
PAGE_2,
PAGE_3,
MENU_LV1,
MENU_LV1_LOAD,
MENU_LV1_UNITS,
MENU_LV2_COUNT,
MENU_LV2_ADD,
MENU_ADD_UNITS_INPUT
} AppState;
volatile uint32_t KeypadtriggerDetected = 0;
volatile uint32_t KeypadtriggerTick = 0;
static AppState currentState = PAGE_DEFAULT;
int desired_load_state = -1; // -1 = none, 0 = OFF, 1 = ON
static uint32_t last_adc_update = 0;
uint8_t force_oled_refresh = 0;
in main:
ssd1306_Init(); // Initialize the OLED display
displayMenuOLED(PAGE_DEFAULT); // default page on startup
// set row pins high (output)
for (int i = 0; i < 4; i++)
HAL_GPIO_WritePin(row_ports[i], row_pins[i], GPIO_PIN_SET);
int start = HAL_GetTick();
uint32_t debounceTime = 80;
in while(1):
// Handle keypad press (triggered by column interrupt)
if (KeypadtriggerDetected == 1) {
// Scan each row to identify which key is pressed
for (int row = 0; row < 4; row++) {
// Set all rows LOW before driving one HIGH
for (int i = 0; i < 4; i++) {
HAL_GPIO_WritePin(row_ports[i], row_pins[i], GPIO_PIN_RESET);
}
// Set the current row HIGH
HAL_GPIO_WritePin(row_ports[row], row_pins[row], GPIO_PIN_SET);
// Check if the column pin that triggered interrupt is still HIGH
if (col >= 0 && col < 3 && HAL_GPIO_ReadPin(col_ports[col], col_pins[col]) == GPIO_PIN_SET) {
// Key at (row, col) is being pressed
char key = keymap[row][col];
last_key = key; // Store the key for processing
break; // Exit once key is found
}
}
// Restore all rows to HIGH after scanning
for (int i = 0; i < 4; i++) {
HAL_GPIO_WritePin(row_ports[i], row_pins[i], GPIO_PIN_SET);
}
// Debounce and finalize the key detection
if (last_key != '\0' && (HAL_GetTick() - KeypadtriggerTick > debounceTime)) {
process_key_press(last_key);
force_oled_refresh = 1;
last_key = '\0';
KeypadtriggerDetected = 0;
col = -1; // Clear column index for next interrupt
}
// Check if ADC data is ready and if enough time (500 ms) has passed since last processing
if (adc_ready && HAL_GetTick() - last_adc_update >= 500) {
process_adc_buffer(); // Process ADC data: calculate voltage, current, power, energy, etc.
update_LED_D3_UnitsStatus(); // Update LED D3 based on remaining energy units
update_LED_D5_PowerAlarm(); // Update LED D5 based on power threshold (e.g. > 3800W)
// Only update the OLED display if user is on one of the real-time data screens
if (currentState == PAGE_DEFAULT || currentState == PAGE_1 ||
currentState == PAGE_2 || currentState == PAGE_3) {
displayMenuOLED(currentState); // Refresh OLED with updated values
}
last_adc_update = HAL_GetTick(); // Update timestamp for next sampling window
}
}
in EXTI_Rising_Callback:
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_4 || GPIO_Pin == B1_Pin) {
ButtontriggerDetected = 1;
ButtontriggerTick = HAL_GetTick();
return;
}
if (GPIO_Pin == GPIO_PIN_1 || GPIO_Pin == GPIO_PIN_11 || GPIO_Pin == GPIO_PIN_12) {
KeypadtriggerDetected = 1;
KeypadtriggerTick = HAL_GetTick();
// Set global col index (NOT a local variable)
if (GPIO_Pin == GPIO_PIN_12)
col = 0;
else if (GPIO_Pin == GPIO_PIN_11)
col = 1;
else if (GPIO_Pin == GPIO_PIN_1)
col = 2;
}
}
Thank you in advace.