반응형

이게 버튼이다
결선 방법은 아래와 같다

버튼 코드 작성 전에 채터링과 디바운스에 대해서 먼저 알아보고자 한다
채터링이란 버튼을 눌렀을 때 버튼의 물리적 특성으로 인하여 일시적으로 값이 불안정한 것을 의미한다
MCU는 이러한 불안정한 값도 입력으로 받아들이기 때문에 채터링을 바로잡지 않고 버튼을 사용하면 원하지 않는 결과를 얻을 수도 있다

버튼을 안전하게 사용하기 위해서는 이러한 채터링을 잡아야 하는데, 이렇게 채터링을 잡는 방법을 디바운스이라고 하고 하드웨어적 또는 소프트웨어적으로 잡을 수 있다
우리는 여기서 소프트웨어적으로 디바운스하는 법을 먼저 알아볼 것이다
소프트웨어적으로 디바운스한다고 하면 딜레이를 주는 방법으로 디바운스를 진행한다
먼저 버튼을 사용하기 위해 ioc에서 버튼에 사용할 핀을 GPIO_Input으로 활성화해주고 라벨링으로 이름을 바꿔준다


설정을 끝내고 저장을 누르면 코드가 생성되는데, main.h에서 확인할 수 있다

이제 아래처럼 코드를 작성하자
// button.h
#include "main.h" // for GPIO handling
#define BUTTON_RELEASE 1 // 버튼을 뗀 상태 normal : High
#define BUTTON_PRESS 0 // 버튼을 누른 상태 Active-low
#define BUTTON_NUMBER 4 // 버튼 갯수 : 4
int get_button(GPIO_TypeDef *GPIO, uint16_t GPIO_Pin, uint8_t button_number);
// button.c
#include "button.h"
// 초기 버튼 상태 table
char button_status[BUTTON_NUMBER] = {BUTTON_RELEASE, BUTTON_RELEASE, BUTTON_RELEASE, BUTTON_RELEASE};
// get_button(gpio, pin, button)
// 눌렀다 떼면 BUTTON_RELEASE를 리턴
int get_button(GPIO_TypeDef *GPIO, uint16_t GPIO_Pin, uint8_t button_number)
{
unsigned char curr_state;
curr_state = HAL_GPIO_ReadPin(GPIO, GPIO_Pin);
// 버튼이 눌러졌으나 처음 상태 = noise
if (curr_state == BUTTON_PRESS && button_status[button_number] == BUTTON_RELEASE)
{
HAL_Delay(80); // noise가 지나가기를 기다림
button_status[button_number] = BUTTON_PRESS; // 현재 버튼 상태를 저장
return BUTTON_RELEASE; // 버튼이 눌러진 상태지만 아직 noise 상태로 인정
}
// 이전에 버튼이 눌려진 상태고 지금은 버튼을 뗀 상태이면
else if (curr_state == BUTTON_RELEASE && button_status[button_number] == BUTTON_PRESS)
{
button_status[button_number] = BUTTON_RELEASE; // button_status table을 초기화
HAL_Delay(80);
return BUTTON_PRESS; // 버튼을 1번 눌렀다 뗀 것으로 인정
}
return BUTTON_RELEASE;
}
이렇게 코드를 작성하고 버튼을 누를 때 실행할 기능을 get_button()을 이용해 호출하면 디바운스를 완화할 수 있다
그럼 이제 버튼을 사용해서 LED BAR를 점들할건데, led.c로 가서
#include "main.h" // for GPIO, HAL
#include "button.h" // for get_button()
void led_all_on(void)
{
// HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7, 1);
HAL_GPIO_WritePin(GPIOD, 0xff, 1);
}
void led_all_off(void)
{
// HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7, 0);
HAL_GPIO_WritePin(GPIOD, 0xff, 0);
}
void led_on_up(void)
{
for (int i = 0; i < 8; i++)
{
led_all_off();
HAL_GPIO_WritePin(GPIOD, 0x01 << i, 1);
HAL_Delay(200);
}
}
void led_on_down(void)
{
for (int i = 0; i < 8; i++)
{
led_all_off();
HAL_GPIO_WritePin(GPIOD, 0x80 >> i, 1);
HAL_Delay(200);
}
}
void led_main(void)
{
while (1)
{
// BTN 0
if (get_button(BUTTON0_GPIO_Port, BUTTON0_Pin, 0) == BUTTON_PRESS)
{
led_all_off();
}
// BTN 1
if (get_button(BUTTON1_GPIO_Port, BUTTON1_Pin, 1) == BUTTON_PRESS)
{
led_all_on();
}
// BTN 2
if (get_button(BUTTON2_GPIO_Port, BUTTON2_Pin, 2) == BUTTON_PRESS)
{
led_on_up();
}
// BTN 3
if (get_button(BUTTON3_GPIO_Port, BUTTON3_Pin, 3) == BUTTON_PRESS)
{
led_on_down();
}
}
}
위와 같이 작성하고
main.c의 main에서 led_main()을 호출해서 무한 루프들 돌며 버튼이 눌리는 것을 확인할 것이다


버튼이 잘 작동하는 것을 확인할 수 있당
반응형
'임베디드 > STM32 (ARM Cortex - M4)' 카테고리의 다른 글
| [STM32] 타이머 (1) | 2023.10.21 |
|---|---|
| [STM32] UART (0) | 2023.10.20 |
| [STM32] LED BAR 제어 (0) | 2023.10.16 |
| [STM32] 기존 프로젝트 그대로 복사해서 프로젝트 생성하기 (0) | 2023.10.16 |
| [STM32] ERROR : NO ST-LINK detected! (0) | 2023.10.16 |