LED 직접 제어 모듈 추가(BSP 대체)
- 전원 ON/OFF, 블루투스 스캐닝 초록 LED 적용 완료
This commit is contained in:
292
project/ble_peripheral/ble_app_bladder_patch/led_control.c
Normal file
292
project/ble_peripheral/ble_app_bladder_patch/led_control.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* @file led_control.c
|
||||
* @brief LED 직접 제어 드라이버 (BSP 미사용)
|
||||
* @date 2026-03-30
|
||||
*
|
||||
* app_timer 1개로 2색 LED(녹색/주황)의 복합 blink 패턴 구현
|
||||
* 단순 on/off 상태는 타이머 없이 즉시 GPIO 제어
|
||||
* 복합 패턴(에러 등)은 phase 기반 state machine으로 처리
|
||||
******************************************************************************/
|
||||
|
||||
#include "led_control.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "app_timer.h"
|
||||
|
||||
/*==============================================================================
|
||||
* 내부 상수
|
||||
*============================================================================*/
|
||||
#define MS_TO_TICKS(ms) APP_TIMER_TICKS(ms)
|
||||
|
||||
/*==============================================================================
|
||||
* 색상
|
||||
*============================================================================*/
|
||||
#define COLOR_NONE 0
|
||||
#define COLOR_GREEN 1
|
||||
#define COLOR_ORANGE 2
|
||||
|
||||
/*==============================================================================
|
||||
* 에러 패턴 상수 (No.7)
|
||||
* 3Hz 깜빡 3회 = 166ms on + 166ms off × 3 = ~1초, 이후 꺼짐 1초
|
||||
*============================================================================*/
|
||||
#define ERROR_BLINK_ON_MS 166
|
||||
#define ERROR_BLINK_OFF_MS 166
|
||||
#define ERROR_BLINK_COUNT 3
|
||||
#define ERROR_PAUSE_MS 1000
|
||||
|
||||
/*==============================================================================
|
||||
* 패턴 테이블 (단순 blink 용)
|
||||
*============================================================================*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t on_ms; /* LED 켜짐 시간 (ms) */
|
||||
uint32_t off_ms; /* LED 꺼짐 시간 (ms) */
|
||||
uint8_t color; /* COLOR_GREEN 또는 COLOR_ORANGE */
|
||||
bool repeat; /* true: 무한 반복, false: 1회 후 OFF */
|
||||
} led_pattern_t;
|
||||
|
||||
static const led_pattern_t m_patterns[LED_STATE_COUNT] =
|
||||
{
|
||||
[LED_STATE_OFF] = { 0, 0, COLOR_NONE, false },
|
||||
[LED_STATE_POWER_ON] = { 2000, 0, COLOR_GREEN, false }, /* 초록 점등 2초 → 유지 */
|
||||
[LED_STATE_POWER_OFF] = { 2000, 0, COLOR_GREEN, false }, /* 초록 점등 2초 → OFF */
|
||||
[LED_STATE_ADVERTISING] = { 1000, 1000, COLOR_GREEN, true }, /* 초록 점멸 1초 */
|
||||
[LED_STATE_DETACH_WARNING] = { 1000, 3000, COLOR_GREEN, true }, /* 초록 1초 on / 3초 off */
|
||||
[LED_STATE_ALIGN_SEARCHING] = { 1000, 1000, COLOR_ORANGE, true }, /* 주황 점멸 1초 */
|
||||
[LED_STATE_ALIGN_COMPLETE] = { 3000, 1000, COLOR_GREEN, true }, /* 초록 3초 on / 1초 off */
|
||||
[LED_STATE_ERROR] = { 0, 0, COLOR_ORANGE, true } /* 별도 state machine */
|
||||
};
|
||||
|
||||
/*==============================================================================
|
||||
* 모듈 변수
|
||||
*============================================================================*/
|
||||
APP_TIMER_DEF(m_led_timer);
|
||||
|
||||
static led_state_t m_current_state = LED_STATE_OFF;
|
||||
static bool m_phase_on; /* true: LED 켜진 구간, false: 꺼진 구간 */
|
||||
|
||||
/* 에러 패턴 전용 */
|
||||
static uint8_t m_error_blink_cnt; /* 현재까지 깜빡인 횟수 */
|
||||
static uint8_t m_error_phase; /* 0: blink-on, 1: blink-off, 2: pause */
|
||||
|
||||
/*==============================================================================
|
||||
* GPIO 헬퍼
|
||||
*============================================================================*/
|
||||
|
||||
static inline void led_green_on(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_clear(LED_PIN_GREEN);
|
||||
#else
|
||||
nrf_gpio_pin_set(LED_PIN_GREEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_green_off(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_set(LED_PIN_GREEN);
|
||||
#else
|
||||
nrf_gpio_pin_clear(LED_PIN_GREEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_orange_on(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_clear(LED_PIN_ORANGE);
|
||||
#else
|
||||
nrf_gpio_pin_set(LED_PIN_ORANGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_orange_off(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_set(LED_PIN_ORANGE);
|
||||
#else
|
||||
nrf_gpio_pin_clear(LED_PIN_ORANGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void led_all_off(void)
|
||||
{
|
||||
led_green_off();
|
||||
led_orange_off();
|
||||
}
|
||||
|
||||
static void led_color_on(uint8_t color)
|
||||
{
|
||||
led_all_off();
|
||||
if (color == COLOR_GREEN) led_green_on();
|
||||
else if (color == COLOR_ORANGE) led_orange_on();
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 타이머 시작 헬퍼
|
||||
*============================================================================*/
|
||||
static void timer_start_ms(uint32_t ms)
|
||||
{
|
||||
if (ms == 0) return;
|
||||
app_timer_start(m_led_timer, MS_TO_TICKS(ms), NULL);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 에러 패턴 state machine (No.7)
|
||||
* phase 0: LED ON (166ms) → phase 1
|
||||
* phase 1: LED OFF (166ms) → cnt++ → cnt<3 ? phase 0 : phase 2
|
||||
* phase 2: PAUSE (1000ms) → cnt=0, phase 0
|
||||
*============================================================================*/
|
||||
static void error_pattern_start(void)
|
||||
{
|
||||
m_error_blink_cnt = 0;
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
}
|
||||
|
||||
static void error_pattern_tick(void)
|
||||
{
|
||||
switch (m_error_phase)
|
||||
{
|
||||
case 0: /* ON 구간 끝 → OFF */
|
||||
led_all_off();
|
||||
m_error_phase = 1;
|
||||
timer_start_ms(ERROR_BLINK_OFF_MS);
|
||||
break;
|
||||
|
||||
case 1: /* OFF 구간 끝 */
|
||||
m_error_blink_cnt++;
|
||||
if (m_error_blink_cnt < ERROR_BLINK_COUNT)
|
||||
{
|
||||
/* 다시 ON */
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3회 완료 → pause */
|
||||
m_error_phase = 2;
|
||||
timer_start_ms(ERROR_PAUSE_MS);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* pause 끝 → 처음부터 */
|
||||
m_error_blink_cnt = 0;
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 타이머 콜백
|
||||
*============================================================================*/
|
||||
static void led_timer_handler(void * p_context)
|
||||
{
|
||||
(void)p_context;
|
||||
|
||||
/* 에러 상태는 별도 처리 */
|
||||
if (m_current_state == LED_STATE_ERROR)
|
||||
{
|
||||
error_pattern_tick();
|
||||
return;
|
||||
}
|
||||
|
||||
const led_pattern_t * p = &m_patterns[m_current_state];
|
||||
|
||||
if (m_phase_on)
|
||||
{
|
||||
/* ON→OFF 전환 */
|
||||
led_all_off();
|
||||
m_phase_on = false;
|
||||
|
||||
if (p->off_ms > 0)
|
||||
{
|
||||
timer_start_ms(p->off_ms);
|
||||
}
|
||||
else if (!p->repeat)
|
||||
{
|
||||
/* 1회성: off_ms == 0 이면 그냥 유지 (POWER_ON) 또는 끄기 (POWER_OFF) */
|
||||
if (m_current_state == LED_STATE_POWER_OFF)
|
||||
{
|
||||
led_all_off();
|
||||
m_current_state = LED_STATE_OFF;
|
||||
}
|
||||
/* POWER_ON: 점등 유지 상태 → 타이머 x */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OFF → ON 전환 */
|
||||
if (p->repeat)
|
||||
{
|
||||
led_color_on(p->color);
|
||||
m_phase_on = true;
|
||||
timer_start_ms(p->on_ms);
|
||||
}
|
||||
/* repeat == false && off_ms > 0 인 경우는 현재 없음 */
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 공개 함수
|
||||
*============================================================================*/
|
||||
|
||||
void led_init(void)
|
||||
{
|
||||
/* GPIO 출력 설정 */
|
||||
nrf_gpio_cfg_output(LED_PIN_GREEN);
|
||||
nrf_gpio_cfg_output(LED_PIN_ORANGE);
|
||||
led_all_off();
|
||||
|
||||
/* 타이머 생성 (single-shot) */
|
||||
app_timer_create(&m_led_timer, APP_TIMER_MODE_SINGLE_SHOT, led_timer_handler);
|
||||
|
||||
m_current_state = LED_STATE_OFF;
|
||||
}
|
||||
|
||||
void led_set_state(led_state_t state)
|
||||
{
|
||||
if (state >= LED_STATE_COUNT) return;
|
||||
|
||||
/* 이전 패턴 중단 */
|
||||
app_timer_stop(m_led_timer);
|
||||
led_all_off();
|
||||
|
||||
m_current_state = state;
|
||||
m_phase_on = false;
|
||||
|
||||
const led_pattern_t * p = &m_patterns[state];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case LED_STATE_OFF:
|
||||
/* 이미 all off */
|
||||
break;
|
||||
|
||||
/* 에러 패턴: 별도 state machine */
|
||||
case LED_STATE_ERROR:
|
||||
error_pattern_start();
|
||||
break;
|
||||
|
||||
/* 그 외: on 구간부터 시작 */
|
||||
default:
|
||||
led_color_on(p->color);
|
||||
m_phase_on = true;
|
||||
if (p->on_ms > 0)
|
||||
{
|
||||
timer_start_ms(p->on_ms);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
led_state_t led_get_state(void)
|
||||
{
|
||||
return m_current_state;
|
||||
}
|
||||
52
project/ble_peripheral/ble_app_bladder_patch/led_control.h
Normal file
52
project/ble_peripheral/ble_app_bladder_patch/led_control.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* @file led_control.h
|
||||
* @brief LED 직접 제어 드라이버 (BSP 미사용)
|
||||
* @date 2026-03-30
|
||||
*
|
||||
* 녹색(P0.12) + 주황(P0.29) 2색 LED를 app_timer 기반으로 제어
|
||||
* 각 상태별 on/off 시간, 색상, 반복 패턴을 테이블로 관리
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LED_CONTROL_H__
|
||||
#define LED_CONTROL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*==============================================================================
|
||||
* LED 핀 정의
|
||||
*============================================================================*/
|
||||
#define LED_PIN_GREEN NRF_GPIO_PIN_MAP(0, 12) /* 녹색 LED */
|
||||
#define LED_PIN_ORANGE NRF_GPIO_PIN_MAP(0, 29) /* 주황 LED */
|
||||
#define LED_ACTIVE_LOW 1 /* 1 = Active Low (GPIO LOW에서 LED 켜짐) */
|
||||
|
||||
/*==============================================================================
|
||||
* LED 상태 열거형
|
||||
*============================================================================*/
|
||||
typedef enum
|
||||
{
|
||||
LED_STATE_OFF = 0, /* 모든 LED 소등 */
|
||||
LED_STATE_POWER_ON, /* 1: 전원 ON - 초록 소등 → 녹색 점등 2초 */
|
||||
LED_STATE_POWER_OFF, /* 2: 전원 OFF - 초록 점등 2초 → 소등 */
|
||||
LED_STATE_ADVERTISING, /* 3: 블루투스 스캐닝 - 초록 점멸 1초 간격(반복) */
|
||||
LED_STATE_DETACH_WARNING, /* 4: 정상 작동중(미부착 시) - 초록 점등 1초 / 소등 3초 (반복) */
|
||||
LED_STATE_ALIGN_SEARCHING, /* 5: 정렬모드(탐지중) - 주황 점멸 1초 간격 (반복) */
|
||||
LED_STATE_ALIGN_COMPLETE, /* 6: 정렬모드(탐지 완료) - 초록 점등 3초 / 소등 1초 */
|
||||
LED_STATE_ERROR, /* 7: 오류 발생 - 주황 3Hz 깜빡 3회 / 꺼짐 1초 (반복) */
|
||||
LED_STATE_COUNT /* 배열 크기 */
|
||||
} led_state_t;
|
||||
|
||||
/*==============================================================================
|
||||
* 공개 함수
|
||||
*============================================================================*/
|
||||
|
||||
/** @brief LED GPIO 초기화 + 타이머 생성 - main()에서 1회 호출 */
|
||||
void led_init(void);
|
||||
|
||||
/** @brief LED 상태 변경 - 이전 패턴을 즉시 중단하고 새 패턴 시작 */
|
||||
void led_set_state(led_state_t state);
|
||||
|
||||
/** @brief 현재 LED 상태 조회 */
|
||||
led_state_t led_get_state(void);
|
||||
|
||||
#endif /* LED_CONTROL_H__ */
|
||||
@@ -114,6 +114,7 @@
|
||||
#include "debug_print.h" /* 디버그 출력 매크로 (DBG_PRINTF) */
|
||||
#include "fstorage.h" /* Flash Storage 래퍼 (FDS 초기화/저장/로드) */
|
||||
#include "dr_piezo.h" /* 피에조 초음파 드라이버 */
|
||||
#include "led_control.h" /* LED 직접 제어 드라이버 (BSP 미사용) */
|
||||
|
||||
|
||||
|
||||
@@ -439,7 +440,7 @@ static void t_power_off_timeout_handler(void * p_context)
|
||||
UNUSED_PARAMETER(p_context);
|
||||
APP_ERROR_CHECK(app_timer_stop(m_power_off_delay_timer_id));
|
||||
DBG_PRINTF("[PWR] Off timeout\r\n");
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_OFF); /* LED OFF */
|
||||
led_set_state(LED_STATE_OFF); /* LED OFF */
|
||||
power_control_handler(OFF); /* P0.8 LOW → 전원 차단 */
|
||||
}
|
||||
|
||||
@@ -798,7 +799,7 @@ static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
|
||||
switch (ble_adv_evt)
|
||||
{
|
||||
case BLE_ADV_EVT_FAST:
|
||||
bsp_indication_set(BSP_INDICATE_ADVERTISING);
|
||||
led_set_state(LED_STATE_ADVERTISING);
|
||||
DBG_PRINTF("[ADV] Fast\r\n");
|
||||
break;
|
||||
case BLE_ADV_EVT_IDLE:
|
||||
@@ -1067,8 +1068,7 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
led_set_state(LED_STATE_OFF); /* 연결 완료 → LED OFF */
|
||||
|
||||
break;
|
||||
|
||||
@@ -1191,7 +1191,7 @@ void bsp_event_handler(bsp_event_t event)
|
||||
if (processing == false)
|
||||
{
|
||||
DBG_PRINTF("[BSP] Power\r\n");
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
|
||||
led_set_state(LED_STATE_POWER_OFF);
|
||||
go_device_power_off = true;
|
||||
main_timer_start();
|
||||
}
|
||||
@@ -1206,14 +1206,16 @@ void bsp_event_handler(bsp_event_t event)
|
||||
* 유틸리티 함수
|
||||
*============================================================================*/
|
||||
|
||||
/** @brief BSP 버튼/LED 초기화 (부트 Phase 5) */
|
||||
/** @brief BSP 버튼 초기화 + LED 직접 초기화 (부트 Phase 5) */
|
||||
static void buttons_leds_init(bool * p_erase_bonds)
|
||||
{
|
||||
bsp_event_t startup_event;
|
||||
|
||||
uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
|
||||
uint32_t err_code = bsp_init(BSP_INIT_BUTTONS, bsp_event_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
led_init();
|
||||
|
||||
err_code = bsp_btn_ble_init(NULL, &startup_event);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
@@ -1342,7 +1344,7 @@ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
|
||||
*/
|
||||
void sleep_mode_enter(void)
|
||||
{
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
|
||||
led_set_state(LED_STATE_POWER_OFF);
|
||||
DBG_PRINTF("[SYS] Sleep\r\n");
|
||||
APP_ERROR_CHECK(app_timer_start(m_power_off_delay_timer_id, APP_TIMER_TICKS(POWER_OFF_DELAY), NULL));
|
||||
}
|
||||
@@ -1355,7 +1357,7 @@ void sleep_mode_enter(void)
|
||||
*/
|
||||
void device_power_off(void)
|
||||
{
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
|
||||
led_set_state(LED_STATE_POWER_OFF);
|
||||
APP_ERROR_CHECK(app_timer_start(m_power_off_delay_timer_id, APP_TIMER_TICKS(POWER_OFF_DELAY), NULL));
|
||||
}
|
||||
|
||||
@@ -1612,7 +1614,7 @@ static void main_s(void * p_context)
|
||||
if ((cnt_s < 150) && (m_reset_status != 2))
|
||||
{
|
||||
DBG_PRINTF("[BTN] Short->OFF\r\n");
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_OFF);
|
||||
led_set_state(LED_STATE_OFF);
|
||||
power_control_handler(OFF);
|
||||
cnt_s = 0;
|
||||
}
|
||||
@@ -1654,7 +1656,7 @@ static void main_s(void * p_context)
|
||||
device_reset = false;
|
||||
|
||||
if (cnt_s == 150) {
|
||||
bsp_indication_set(BSP_INDICATE_USER_STATE_ON);
|
||||
led_set_state(LED_STATE_POWER_ON);
|
||||
DBG_PRINTF("[BTN] 1.5s\r\n");
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -493,6 +493,11 @@
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\..\..\..\..\..\pc_firm\dr_w25q32\dr_w25q32.h</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>led_control.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\led_control.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
@@ -4696,6 +4701,11 @@
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\..\..\..\..\..\pc_firm\dr_w25q32\dr_w25q32.h</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>led_control.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\led_control.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
|
||||
Reference in New Issue
Block a user