본문 바로가기
  • 오늘도 신나게
아빠가 개발자면 생기는 일

불어펜 3색 LED스틱 Upgrade #2/2(마무리)

by 앵그리선반장 2020. 4. 4.

앞 글에서 회로물을 준비했습니다.

 

 

불어펜 3색 LED스틱 Upgrade #1

며칠 전에 불어펜을 가지고 LED 스틱으로 개조하는 것을 해보았습니다. 3색 LED 각 다리에 3개의 Tact 스위치를 달아서 누르면 해당 색이 켜지는 단순한 LED 스틱을 만들었어요. 물론 아이는 팔짝팔짝 뛰면서 좋아..

r2adve.tistory.com

이제 원하는 동작을 프로그래밍해서 구현할 차례입니다.

사용한 MCU 는 STM32F051K8U6 입니다.

이것은 ARM Cortex-M0 시리즈의 제품 중에서도 좀 작은 편에 속합니다.

하지만 32비트 MCU이고, 다양한 IP를 제공하기 때문에 못 만들게 없는 강력한 MCU입니다.

Anyway~

동작을 어떻게 정의하느냐. 고민을 해봤습니다.

먼저 스위치는 전원 레귤레이터에 직접 연결되어 있기 때문에 누르고 있어야만 동작이 됩니다.

그래서 버튼을 누르고 있는 동안에만 동작하고 떼면 그냥 멈춘다고 정의했습니다.

다음은 LED 동작인데요.

전원 버튼을 누르고 있는 동안 순서대로 RED -> RED+GREEN -> GREEN -> GREEN+BLUE -> BLUE -> BLUE+RED 순으로 반복되게 하겠습니다.

다만 LED를 켤 때 ON/OFF 개념으로 켜면 색이 급변해서 멋스럽지 않기 때문에. Breathing 하듯이 스으윽~ 색이 변화하도록 구현해 볼까 합니다.

사실 이런 부분은 요즘 LED 제어용 드라이버 IC들이 있기 때문에 그렇게 하면 좋은데요. 지금은 굴러다니는 PCB 보드를 재활용하는 거라 그렇게 할 수 없으니. 대략 그 원리를 MCU로 구현해 봅니다.

바로 PWM 방식이지요.

GPIO에 연결된 각각의 LED에 공급하는 펄스폭을 제어해서 밝기를 제어한다는 뜻입니다.

Common Anode 타입이기 때문에 GPIO에 Low 가 출력되면 LED가 켜지므로, lOW 시간이 길고 HIGH 시간이 짧으면 밝기가 밝아지고 HIGH 시간이 길어지면 어두워지는 원리만 알면 됩니다.

먼저 GPIO 핀을 Define 합니다.

gpio.h 내용 일부 발췌

/*****************************************************************************************
  * @file    : gpio.h
  * @author  : r2adve@gmail.com(선성태)
  * @date    : 2020, 04, 03
  * @atten.  : 
******************************************************************************************/
//제어용 GPIO 
#define	PIN_LED_RED			GPIO_Pin_1	//GPA_Pin_1 , OUT, Red LED
#define	PIN_LED_GRN			GPIO_Pin_6	//GPB_Pin_6 , OUT, Green LED
#define	PIN_LED_BLU			GPIO_Pin_7	//GPB_Pin_7 , OUT, Blue LED

// Output gpio 메크로 함수
#define	OUT_LED_RED(x)		GPIO_WriteBit(GPIOA, PIN_LED_RED,(x))
#define	OUT_LED_GRN(x)		GPIO_WriteBit(GPIOB, PIN_LED_GRN,(x))
#define	OUT_LED_BLU(x)		GPIO_WriteBit(GPIOB, PIN_LED_BLU,(x))

이렇게 해당 gpio 들을 제어하기 위한 핀과 메크로 함수를 정의해 줍니다.

다음은 해당 gpio를 출력용으로 초기화해야겠지요

/*******************************************************************************************
  * @file    : gpio.c
  * @author  : r2adve@gmail.com(sun sungtae)
  * @date    : 2020, 04, 03
  * @atten.  : 
*******************************************************************************************/

#include "include.h"
#include "gpio.h"

//----------------------------------------------------------------------------------------
// 기능 : 출력용 gpio 설정 초기화
// 주의 : 
//----------------------------------------------------------------------------------------
void board_gpio_output_config(void)
{
	GPIO_InitTypeDef   gpio_ta, gpio_tb;
	
	gpio_ta.GPIO_Pin	= ( PIN_LED_RED) ;				   	   
	gpio_ta.GPIO_OType	= GPIO_OType_PP;
	gpio_ta.GPIO_Mode 	= GPIO_Mode_OUT;
	gpio_ta.GPIO_PuPd	= GPIO_PuPd_UP;
	gpio_ta.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpio_ta);
	
	//RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB,ENABLE);
	
	gpio_tb.GPIO_Pin	= (PIN_LED_GRN | PIN_LED_BLU);				   	   
	gpio_tb.GPIO_OType	= GPIO_OType_PP;
	gpio_tb.GPIO_Mode 	= GPIO_Mode_OUT;
	gpio_tb.GPIO_PuPd	= GPIO_PuPd_UP;
	gpio_tb.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &gpio_tb);
}

이렇게 GPIO를 3개의 LED에 맞게 출력용으로 설정해 줍니다.

이제 로직만 짜면 되겠지요.

사실 다른 기능도 동시에 사용해야 할 경우 LED의 동작은 타이머 카운터를 통해 그 Duty를 제어하는 것이 맞습니다.

하지만, 딱히 다른 기능을 동시에 처리할 일도 없기 때문에 굳이 복잡한 코딩은 하지 않습니다.

아주 단순히 켜지는 순서를 for 루프로 구현해 버립니다.

여담으로 간혹 어떤분들은 간단한 기능을 굳이 복잡한 형태로 만드는 경향이 있는데요. 어려운 방식들을 썼다고 해서 코딩을 잘하는게 아닙니다. 

if 문만 쓰더라도 명확하고 간단하면 좋은 코드 입니다.

//----------------------------------------------------------------------------------------
// 기능 : RED breathing up
// 주의 : 
//----------------------------------------------------------------------------------------
void r_led_up(void)
{
	uint32_t i;
	
	DA("R up\n");

	OUT_LED_RED(_OFF_);	
	for(i=0; i<700; i++)
	{
		OUT_LED_RED(_ON_);	
		udelay(i);
		OUT_LED_RED(_OFF_);
		udelay(700-i);
	}
	OUT_LED_RED(_ON_);
}

//----------------------------------------------------------------------------------------
// 기능 : BLUE breathing down
// 주의 : 
//----------------------------------------------------------------------------------------
void r_led_dn(void)
{
	uint32_t i;
	
	DA("R down\n");
	for(i=0; i<700; i++)
	{
		OUT_LED_RED(_OFF_);	
		udelay(i);
		OUT_LED_RED(_ON_);
		udelay(700-i);
	}
	OUT_LED_RED(_OFF_);	
}

이렇게 각 LED를 점점 켜지게 하는 함수와 점점 꺼지게 하는 함수를 만들어 둡니다.

물론 위에서는 RED 한 가지만 예시로 했지만, GREEN, BLUE 도 같은 방식으로 만들어 줍니다.

그러고는 메인에서 호출할 때 그 순서대로 믹스해버리면 되는 거지요. 개간단 ㅋ

//----------------------------------------------------------------------------------------
// 기능 : LED DISPLAY
// 주의 : 
//----------------------------------------------------------------------------------------
void led_display(void)
{
	if(sys_info.led_mode)
	{
		g_led_up();
		r_led_dn();
		
		b_led_up();
		g_led_dn();
		
		r_led_up();
		b_led_dn();
	}
	else
	;
}

바로 이렇게 led_display() 가 호출되면 위 6 개의 함수가 순서대로 돌아가는 거죠.

이제 main 함수에서 호출만 하면 땡.

//****************************************************************************************
// 기능 : 메인 함수
// 주의 : 
//****************************************************************************************
int main(void)
{	
	//제품의 동작을 위한 주변장치들을 초기화 한다.     
	sys_peripheral_init();
	
	//시스템 초기화
	sys_init();

	printf("\r\n]#");
	mdelay(10);
	
	r_led_up();
	while(1)
	{
		led_display();
		check_console_cmd();
    }
}

main 함수에서 초기화 후 whle() 루프에서 위에서 만들어 두었던 led_display()를 호출하는 것을 볼 수 있습니다.

이제 코딩까지 다 했고요.

펌웨어를 다운로드한 후에 동작을 확인해 보았습니다.

동작 시험

조립을 하기 전에 최종 동작을 시험해 보았습니다.

아주 만족스러워요 ~ 

자 이제 조립을 시작합니다.

불어펜 손잡이부분에 회로물 결합

회로물을 모두 집어넣고 스위치를 달아주었습니다.

원래 구멍을 내서 스위치를 안쪽에서 누르는 부분만 나오게 하려고 했는데. 실패했어요.

그래서 그냥 외부에서 글루건으로 고정시켰어요. (보기가 좀 안 좋아요)

이제 조립된 최종 형태를 보겠습니다.

만족 스럽네요.

마지막으로 선물을 받고 오버하는 딸내미입니다. ㅎㅎ

좋아서 오버를 막 하는군요

끊어진 와이어만 고쳐갈까 하다가. 아이가 좋아하던 모습이 떠올라, 빛의 속도로 개조를 완성했습니다.

다행히 잘 동작되어 아이가 좋아하는 모습을 볼 수 있었어요 ~ 

이 맛에 삽니다.,

댓글