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