Recent Posts
printf("ho_tari\n");
9일차 본문
2025.04.04
오늘의 학습 목표
1. code review
2. keypad matrix application
3. project 수행
KEYPAD
키 매트릭스
- 버튼을 매트릭스 형태로 배치
- 적은 수의 입력 핀으로 많은 버튼 입력 검사
- LED 매트릭스의 잔상효과와 기본적으로 동일한 방식 사용
- LED 매트릭스는 출력, 키 매트릭스는 입력을 위한 방법임에 차이가 있음
키 매트릭스의 회로도
키 매트릭스 열 단위 스캔
풀다운 저항 추가
루프 형성1
루프 형성2
다이오드 추가 - 루프 형성 방지
4x4 키 매트릭스 회로도
키 매트릭스 모듈
키 매트릭스 모듈 연결 회로도
타이머 인터럽트 코드
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
volatile int TIM11_keypad_scan_timer = 0;
/* USER CODE END Callback 0 */
if (htim->Instance == TIM10) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
if (htim->Instance == TIM11) {
TIM11_1ms_counter++;
TIM11_keypad_scan_timer++;
if(TIM11_keypad_scan_timer >= 60) // 60ms
{
unsigned char key_value;
TIM11_keypad_scan_timer = 0;
key_value = keypadScan();
if(key_value)
{
insert_queue(key_value); // circular queue에 insert
}
}
}
/* USER CODE END Callback 1 */
}
<keypad.c>
#include "keypad.h"
GPIO_TypeDef* keypadRowPort[4] = {GPIOC, GPIOC, GPIOC, GPIOC}; //R1~R4
GPIO_TypeDef* keypadColPort[4] = {GPIOC, GPIOC, GPIOC, GPIOC}; //C1~C4
uint16_t keypadRowPin[4] = {GPIO_PIN_4, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7}; //R1~R4 GPIO Input & Pull-up으로 설정을 해야 한다.
uint16_t keypadColPin[4] = {GPIO_PIN_8, GPIO_PIN_9, GPIO_PIN_10, GPIO_PIN_11}; //C1~C4 GPIO Output
void keypadInit()
{
for(uint8_t col = 0; col < 4; col++)
{
HAL_GPIO_WritePin(keypadColPort[col], keypadColPin[col], SET); //초기 값 1로 셋팅
}
}
uint8_t getKeypadState(uint8_t col, uint8_t row)
{
#if 1
uint8_t keypadChar[4][4] = {
{'1', '4', '7', ' '},
{'2', '5', '8', '0'},
{'3', '6', '9', '='},
{'/', '*', '-', '+'},
};
#else
uint8_t keypadChar[4][4] = {
{'1', '2', '3', '/'},
{'4', '5', '6', '*'},
{'7', '8', '9', '-'},
{' ', '0', '=', '+'},
};
#endif
static uint8_t prevState[4][4] = {
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
};
uint8_t curState = 1;
HAL_GPIO_WritePin(keypadColPort[col], keypadColPin[col], RESET);
curState = HAL_GPIO_ReadPin(keypadRowPort[row], keypadRowPin[row]);
HAL_GPIO_WritePin(keypadColPort[col], keypadColPin[col], SET);
if(curState == PUSHED && prevState[col][row] == RELEASED)
{
prevState[col][row] = curState;
return 0;
}
else if (curState == RELEASED && prevState[col][row] == PUSHED)
{
prevState[col][row] = curState;
return keypadChar[col][row];
}
return 0;
}
uint8_t keypadScan()
{
uint8_t data;
for(uint8_t col=0; col<4; col++)
{
for(uint8_t row=0; row<4; row++)
{
data = getKeypadState(col, row);
if(data != 0)
{
return data;
}
}
}
return 0;
}
<keypad.h>
#ifndef DEVICE_KEYPAD_H_
#define DEVICE_KEYPAD_H_
#include "stm32f4xx_hal.h"
#define PUSHED 0
#define RELEASED 1
void keypadInit();
uint8_t getKeypadState(uint8_t col, uint8_t row);
uint8_t keypadScan();
#endif /* DEVICE_KEYPAD_H_ */
<circularQueue.c>
/*
* circularQueue.c
*/
#include <stdio.h>
#include <stdlib.h>
#include "circularQueue.h"
#define TRUE 1
#define FALSE 0
#define QUEUE_MAX 100
int front1=-1; // read index
int rear1=-1; // insert index
unsigned char queue[QUEUE_MAX];
int queue_empty(void)
{
if (front1==rear1) //front와 rear가 같으면 큐는 비어있는 상태
return TRUE;
else return FALSE;
}
int queue_full(void)
{
int tmp=(rear1+1)%QUEUE_MAX; //원형 큐에서 rear+1을 MAX로 나눈 나머지값이
if (tmp == front1) //front와 같으면 큐는 가득차 있는 상태
return TRUE;
else
return FALSE;
}
void insert_queue(unsigned char value)
{
if (queue_full())
{
printf("Queue is Full.\n");
}
else
{
rear1 = (rear1+1) % QUEUE_MAX;
queue[rear1]=value;
}
}
unsigned char read_queue()
{
if (queue_empty())
printf("Queue is Empty.\n");
else
{
front1 = (front1+1) % QUEUE_MAX;
//printf("%c ", queue[front]);
return queue[front1];
}
}
void queue_init() // 텅 빈 경우 front와 rear은 동일위치 가리킴
{
front1 = -1;
rear1 = -1;
}
<circularQueue.h>
/*
* circularQueue.h
*
*/
#ifndef CIRCULARQUEUE_H_
#define CIRCULARQUEUE_H_
#define TRUE 1
#define FALSE 0
#define QUEUE_MAX 100
int queue_empty(void);
int queue_full(void);
void insert_queue(unsigned char value);
unsigned char read_queue();
#endif /* CIRCULARQUEUE_H_ */
<실행 결과>
keypad로부터 입력을 받아 단위의 숫자만 연산하도록 구현(계산기)
<main.c>
keypadInit();
int num1 = -1;
int num2 = -1;
char op = '\0';
while(1)
{
if(!queue_empty())
{
uint8_t key_value;
key_value = read_queue();
if(key_value >= '0' && key_value <= '9')
{
int digit = key_value - '0';
if(num1 == -1)
{
num1 = digit;
printf("num1: %d\n", num1);
}
else if(op != '\0' && num2 == -1)
{
num2 = digit;
printf("num2: %d\n", num2);
}
}
else if(key_value == '+' || key_value == '-' || key_value == '*' || key_value == '/')
{
if(num1 != -1 && op == '\0')
{
op = key_value;
printf("operation: %c\n", op);
}
}
else if(key_value == '=')
{
if(num1 != -1 && op != '\0' && num2 != -1)
{
int result = 0;
switch(op)
{
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if(num2 != 0)
{
result = num1 / num2;
}
else
{
printf("Error : Can't divide with 0.\n");
num1 = -1;
op = '\0';
num2 = -1;
continue;
}
break;
}
printf("result: %d\n", result);
num1 = -1;
op = '\0';
num2 = -1;
}
}
}
}
<실행 결과>
'(Telechips) AI 시스템 반도체 SW 개발자 교육 > STM32CubeIDE' 카테고리의 다른 글
14일차 (0) | 2025.04.09 |
---|---|
13일차 (0) | 2025.04.09 |
8일차 (0) | 2025.04.03 |
7일차 (0) | 2025.04.02 |
6일차 (0) | 2025.04.01 |