본문 바로가기
# Semiconductor/- Semicon Academy

[Harman 세미콘 아카데미] 44일차 - Embedded Project(선풍기 만들기 / ATmega128 / AVR)

by Graffitio 2023. 8. 29.
[Harman 세미콘 아카데미] 44일차 - Embedded Project(선풍기 만들기 / ATmega128 / AVR)
728x90
반응형
[Mission]

 

Main Project

 

1. Button을 활용하여 stop, 1단, 2단, 3단 기능 구현

2. DC Motor를 활용하여 Fan 구현

3. LCD로 현재 status 출력

4. 각 stage별로 LED Lamp 출력

 


 

Advanced mission

 

1. Servo motor를 활용하여 Head 회전 기능 구현

2. 내부 clock을 활용하여 Timer 기능 구현

3. 초음파 센서를 활용한 Em'cy Stop 기능 구현

 


 

[Result]

 

Flow Chart

 

 


 

Pin Configuration

 

Pin Configuration

 

Tactile Button & DC Motor Driver

 

Servo Motor & I2C LCD

 


 

Code

 

<Header File 모음>

 

Button_structure.h

더보기
#ifndef INCFILE1_H_
#define INCFILE1_H_
#include <stdint.h>

// LED LAMP 입출력 방향 설정 레지스터와 포트 지정
#define LED_DDR			DDRA // LED LAMP 입출력 방향 설정 레지스터
#define LED_PORT		PORTA // LED LAMP PORT 지정

// BUTTON 입출력 방향 설정 레지스터와 핀 설정
#define BUTTON_DDR		DDRC // BUTTON 입출력 방향 설정 레지스터
#define BUTTON_PIN		PINC // BUTTON을 연결할 PORT의 PIN

// 버튼 동작에 대한 정의
#define BUTTON_STOP		0	// Stop
#define BUTTON_1stage	1	// 1단 25%
#define BUTTON_2stage	2	// 2단 50%
#define BUTTON_3stage	3	// 3단 100%
#define BUTTON_spin		4	// spin

// 버튼 상태 및 액션 상태 정의
enum{PUSHED, RELEASED};
enum{NO_ACT, ACT_PUSH, ACT_RELEASED};
// enum : 일종의 data type으로,
// 일련의 이름을 갖는 상수들의 집합(순서대로 0, 1, 2 ....의 값을 가진다.)

// 버튼 구조체 정의
typedef struct _button{
	volatile uint8_t *ddr; // volatile : 최적화 하지 마라
	volatile uint8_t *pin;
	uint8_t btnPin; // 버튼 핀 번호
	uint8_t prevState; // 이전 버튼 상태
}Button;
int spin_cnt; // 버튼 하나로 Spin On/Off하기 위한 cnt 변수


void Button_init(Button *button, volatile uint8_t *ddr, volatile uint8_t *pin, uint8_t pinNum);
uint8_t BUTTON_getState(Button *button);
uint8_t BUTTON_spin_getState(Button *button);

#endif /* INCFILE1_H_ */

 

I2C_LCD.h

더보기
#ifndef I2C_LCD_H_
#define I2C_LCD_H_

#include "I2C.h" // I2C 관련 헤더 파일 포함

#define LCD_RS	0 // LCD의 Register Select 핀 번호, Control reg : 0 / Data Reg : 1
#define LCD_RW	1 // LCD의 Read/Write 핀 번호
#define LCD_E	2 // LCD의 Enable 핀 번호
#define LCD_BACKLIGHT	3 // LCD의 백라이트 핀 번호

#define LCD_DEV_ADDR	(0x27<<1) // I2C LCD의 디바이스 주소, <<1 : Write 모드 유지

#define COMMAND_DISPLAY_CLEAR	0x01 // 디스플레이 지우기 명령
#define COMMAND_DISPLAY_ON		0x0c // 디스플레이 켜기 명령
#define COMMAND_DISPLAY_OFF		0x08 // 디스플레이 끄기 명령
#define COMMAND_4_BIT_MODE		0x28 // 4비트 모드로 설정 명령
#define COMMAND_ENTRY_MODE		0x06 // 엔트리 모드 설정 명령

// 함수 원형 선언
void LCD_Data4bit(uint8_t data); // 4비트 데이터 전송 함수
void LCD_EnablePin(); // Enable 핀을 제어하는 함수
void LCD_WriteCommand(uint8_t commandData); // 명령어를 LCD에 전송하는 함수
void LCD_WriteData(uint8_t charData); // 데이터를 LCD에 전송하는 함수
void LCD_BackLight(); // LCD 백라이트 제어 함수
void LCD_gotoXY(uint8_t row, uint8_t col); // LCD 화면 커서 위치 설정 함수
void LCD_WriteString(char *string); // 문자열을 LCD에 출력하는 함수
void LCD_WriteStringXY(uint8_t row, uint8_t col, char *string); // 특정 위치에 문자열 출력 함수
void LCD_Init(); // LCD 초기화 함수

#endif /* I2C.LCD_H_ */

 

Fan.h

더보기
#ifndef FAN_H_
#define FAN_H_

#include <avr/io.h> // AVR 입출력 헤더 파일
#include <util/delay.h> // 딜레이 함수 헤더 파일
#include <avr/interrupt.h> // 인터럽트 헤더 파일
#include "Button_structure.h" // 버튼 관련 헤더 파일
#include "I2C_LCD.h" // I2C LCD 관련 헤더 파일
#include "UART_2.h" // UART 통신 관련 헤더 파일

#define Fan_stop	0
#define Fan_1st		1
#define Fan_2nd		2
#define Fan_3rd		3
#define Fan_initial 4

// 버튼 객체들 선언
Button btnStop;
Button btn_1stage;
Button btn_2stage;
Button btn_3stage;
Button btn_spin;
int Fan_run_status;

// 함수 원형 선언
void Fan_Init(); // 팬 초기화 함수
void Fan_Stage(); // 팬 스테이지 동작 함수
void Fan_Start_signal(); // 팬 시작 신호 출력 함수
void Spin_stop(); // 회전 정지 함수
void Spin_start(uint8_t degree); // 회전 시작 함수
void Fan_continue_run();
void Display_LCD();
void Head_spin_op();
void Spin_status_LED();

#endif /* FAN_H_ */

 

<Source File 모음>

 

Button_structure.c

더보기
/*
 * Button_structure.c
 *
 * Created: 2023-07-11 오후 3:36:35
 *  Author: USER
 */ 
#include "Button_structure.h"
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>

// 버튼 초기화 함수 정의
void Button_init(Button *button, volatile uint8_t *ddr, volatile uint8_t *pin, uint8_t pinNum)
{
	button->ddr = ddr; // 버튼의 입출력 방향 레지스터 설정
	button->pin = pin; // 버튼의 상태를 읽을 포트 레지스터 설정
	button->btnPin = pinNum; // 버튼 핀 번호 설정
	button->prevState = RELEASED; // 초기화, 아무것도 안 누른 상태
	*button->ddr &= ~(1 << button->btnPin); // 버튼 핀을 입력으로 설정, ->가 *보다 빠름
}

// 버튼 상태 반환 함수 정의
uint8_t BUTTON_getState(Button *button)
{
	uint8_t curState = *button->pin & (1<<button->btnPin); // 버튼 상태를 읽어옴
	
	if ((curState == PUSHED) && (button->prevState == RELEASED)) // 버튼을 안 누른 상태에서 누르면,
	{
		_delay_ms(50); // 디바운스 코드
		button->prevState = PUSHED; // 버튼을 누른 상태로 변환
		return ACT_PUSH; // 버튼이 눌려 있음을 반환
	}
	else if((curState != PUSHED) && (button->prevState == PUSHED)) // 버튼을 누른 상태에서 떼면,
	{
		_delay_ms(50); // 디바운스 코드
		button->prevState = RELEASED; // 버튼을 땐 상태로 변환
		return ACT_RELEASED; // 버튼이 떨어진 것을 반환
	}
	return NO_ACT; // 아무 것도 안 했을 때
}

// Spin 동작 버튼 상태 함수
uint8_t BUTTON_spin_getState(Button *button)
{
	uint8_t curState = *button->pin & (1<<button->btnPin); // 버튼 상태를 읽어옴
	
	if ((curState == PUSHED) && (button->prevState == RELEASED)) // 버튼을 안 누른 상태에서 누르면,
	{
		_delay_ms(50); // 디바운스 코드
		button->prevState = PUSHED; // 버튼을 누른 상태로 변환
		return ACT_PUSH; // 버튼이 눌려 있음을 반환
	}
	else if((curState != PUSHED) && (button->prevState == PUSHED)) // 버튼을 누른 상태에서 떼면,
	{
		_delay_ms(50); // 디바운스 코드
		button->prevState = RELEASED; // 버튼을 땐 상태로 변환
		spin_cnt++;
		return ACT_RELEASED, spin_cnt; // spin_cnt 증가
	}
	return NO_ACT; // 아무 것도 안 했을 때
}

I2C_LCD.c

더보기
#include "I2C_LCD.h"

uint8_t I2C_LCD_Data;

void LCD_Data4bit(uint8_t data)
{
	I2C_LCD_Data = (I2C_LCD_Data & 0x0f) | (data & 0xf0); // 상위 4bit 출력
	// 이전 상위 비트는 다 날라감 | data의 상위 비트는 살림 
	LCD_EnablePin();
	I2C_LCD_Data = (I2C_LCD_Data & 0x0f) | ((data & 0x0f)<<4); // 하위 4bit
	LCD_EnablePin();
	// 상위 4bit 받고 -> Enable해서 출력하고 -> 하위 4bit 받고 상위로 시프트하고 -> Enabla해서 출력하고
	// [7:4] 핀만 사용해서 반반 나눠서 출력하면, 총 8bit를 출력할 수 있다.
}

void LCD_EnablePin()
{
	I2C_LCD_Data &= ~(1<<LCD_E); // E low 설정
	I2C_TxByte(LCD_DEV_ADDR, I2C_LCD_Data);
	
	I2C_LCD_Data |= (1<<LCD_E); // High 설정
	I2C_TxByte(LCD_DEV_ADDR, I2C_LCD_Data);
	
	I2C_LCD_Data &= ~(1<<LCD_E); // E low 설정
	I2C_TxByte(LCD_DEV_ADDR, I2C_LCD_Data);
	
	// 0->1 일때, data 출력 -> 다음 출력을 위해 0으로 다시 설정
	
	_delay_us(1600);
}

void LCD_WriteCommand(uint8_t commandData)
{
	I2C_LCD_Data &= ~(1<<LCD_RS); // Command일 때는 control register(TWCR)을 쓰고
	I2C_LCD_Data &= ~(1<<LCD_RW); // Write 모드
	LCD_Data4bit(commandData);
}

void LCD_WriteData(uint8_t charData)
{
	I2C_LCD_Data |= (1<<LCD_RS); // Data받을 때는 Data Register(TWDR) 쓰고
	I2C_LCD_Data &= ~(1<<LCD_RW); // Write 모드
	LCD_Data4bit(charData);
}


void LCD_BackLight()
{
	I2C_LCD_Data |= (1<<LCD_BACKLIGHT);
	I2C_TxByte(LCD_DEV_ADDR, I2C_LCD_Data);
}

void LCD_gotoXY(uint8_t row, uint8_t col) // LCD 화면의 커서를 지정된 행(row)과 열(col) 위치로 이동시키는 함수
{
	col %= 16; // 0~15 사이의 값 지정 가능
	row %= 2; // 0~1 사이의 값 지정 가능
	uint8_t address = (0x40 * row) + col; // 주어진 row와 col 값을 이용하여 LCD 화면의 주소(address, 커서 위치)룰 계산한다.
	// 첫 번째 행(row 0)의 주소 범위는 0x00 ~ 0x0f(0~15)
	// 두 번째 행(row 1)의 주소 범위는 0x40 ~ 0x4f(64~79)
	// 예시 : row 1, col 3 -> address = 0x43
	uint8_t command = 0x80 + address; // 계산된 주소를 이용하여 이동시키는 명령어 command 생성
	// 0x80을 사용하는 이유는 특정 주소값이 아닌, 첫 번째 행의 시작을 나타내는 상징적인 값으로 사용된다,
	// 이렇게 함으로써 코드의 가독성을 높이고, 행과 열 값을 쉽게 결합하여 원하는 주소 값을 계산할 수 있다.
	LCD_WriteCommand(command);
}

void LCD_WriteString(char *string)
{
	for (uint8_t i = 0 ; string[i] ; i++) // 받은 문자열의 포인터가 보는 곳을 한 비트씩 분해해서 LCD_WriteData 함수에 하나씩 뿌려줌
	{
		LCD_WriteData(string[i]);
	}
}

void LCD_WriteStringXY(uint8_t row, uint8_t col, char *string)
{
	LCD_gotoXY(row,col); // 행과 열의 위치를 받음. -> 어디서부터 쓸 것인지를 좌표를 받음
	LCD_WriteString(string); // 문자열 입력을 받음
}

void LCD_Init()
{
	I2C_Init();
	
	_delay_ms(20);
	LCD_WriteCommand(0x03);
	_delay_ms(10);
	LCD_WriteCommand(0x03);
	_delay_ms(1);
	LCD_WriteCommand(0x03);
	
	LCD_WriteCommand(0x02);
	LCD_WriteCommand(COMMAND_4_BIT_MODE);
	LCD_WriteCommand(COMMAND_DISPLAY_OFF);
	LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
	LCD_WriteCommand(COMMAND_ENTRY_MODE);
	LCD_WriteCommand(COMMAND_DISPLAY_ON);
	LCD_BackLight();
}

Fan.c

더보기
#include "Fan.h"

void Fan_Init()
{
	// I2C LCD 초기화
	LCD_Init();
	
	// Button Setting
	LED_DDR = 0xff; // PORTA 출력 설정
	
	Button_init(&btnStop, &BUTTON_DDR, &BUTTON_PIN, BUTTON_STOP); // PORTC 0번 핀 입력 활성화
	Button_init(&btn_1stage, &BUTTON_DDR, &BUTTON_PIN, BUTTON_1stage); // PORTC 1번 핀 입력 활성화
	Button_init(&btn_2stage, &BUTTON_DDR, &BUTTON_PIN, BUTTON_2stage); // PORTC 2번 핀 입력 활성화
	Button_init(&btn_3stage, &BUTTON_DDR, &BUTTON_PIN, BUTTON_3stage); // PORTC 3번 핀 입력 활성화
	Button_init(&btn_spin, &BUTTON_DDR, &BUTTON_PIN, BUTTON_spin); // PORTC 4번 핀 입력 활성화
	
	// PWM Setting
	DDRF |= (1<<PINF4) | (1<<PINF5); // PINF4, 5 출력 설정
	TCCR0 |= (1<<CS02) | (1<<CS01) | (0<<CS00); // 256분주
	TCCR0 |= (1<<WGM01) | (1<<WGM00); // Fast PWM mode
	TCCR0 |= (1<<COM01) | (0<<COM00); // 비반전 모드
	DDRB |= (1<<DDRB4); // MOTOR 제어
	
	// Head Spin
	TCCR1A |= (1<<WGM11) | (0<<WGM10); // Fast PWM(mode 14) 세팅
	TCCR1B |= (1<<WGM13) | (1<<WGM12);
	TCCR1A |= (1<<COM1A1) | (0<<COM1A0);
	TCCR1B |= (0<<CS12) | (1<<CS11) | (1<<CS10);
	TCCR1C = 0x00; // default가 0이라 안 써줘도 됨		
	ICR1 = 4999;
}

void Fan_Start_signal()
{
	// Fan Start Sign
	LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
	LCD_WriteStringXY(0,0," Hello Modesty! ");
	LCD_WriteStringXY(1,0,"Please Press Btn");
	_delay_ms(3000);
	Fan_run_status = Fan_initial;
}

void Fan_Stage()
{
	if (BUTTON_getState(&btnStop) == ACT_RELEASED)
	{
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LED_PORT = 0x00;
		PORTF |= (1<<PINF4) | (1<<PINF5); // MOtor Break
		LCD_WriteStringXY(0,0,"   Stop mode    ");
		LCD_WriteStringXY(1,0,"  Power :   0%  ");
		Fan_run_status = Fan_stop;
		spin_cnt = 0;	
	}
	if(BUTTON_getState(&btn_1stage) == ACT_RELEASED)
	{
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LED_PORT = 0x00;
		LED_PORT |= (1<<PINA0);
		DDRB |= (1<<PINB4);
		OCR0 = 64; // 25%
		PORTF &= ~(1<<PINF4); // Motor 정방향 회전
		PORTF |= (1<<PINF5);
		LCD_WriteStringXY(0,0,"   1st Stage    ");
		LCD_WriteStringXY(1,0,"  Power :  25%  ");
		Spin_status_LED();
		Fan_run_status = Fan_1st;

	}
	if(BUTTON_getState(&btn_2stage) == ACT_RELEASED)
	{
		LED_PORT = 0x00;
		LED_PORT |= (1<<PINA0) | (1<<PINA1);
		DDRB |= (1<<PINB4);
		OCR0 = 120; // 50%
		PORTF &= ~(1<<PINF4); // Motor 정방향 회전
		PORTF |= (1<<PINF5);
		LCD_WriteStringXY(0,0,"   2nd Stage    ");
		LCD_WriteStringXY(1,0,"  Power :  50%  ");
		Spin_status_LED();
		Fan_run_status = Fan_2nd;
	}
	if(BUTTON_getState(&btn_3stage) == ACT_RELEASED)
	{
		LED_PORT = 0x00;
		LED_PORT |= (1<<PINA0) | (1<<PINA1) | (1<<PINA2);
		DDRB |= (1<<PINB4);
		OCR0 = 255; // 100%
		PORTF &= ~(1<<PINF4); // Motor 정방향 회전
		PORTF |= (1<<PINF5);
		LCD_WriteStringXY(0,0,"   3rd Stage    ");
		LCD_WriteStringXY(1,0,"  Power : 100%  ");
		Spin_status_LED();
		Fan_run_status = Fan_3rd;
	}
}

void Fan_continue_run()
{
	switch (Fan_run_status)
	{
		case 0:
			//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
			LED_PORT = 0x00;
			PORTF |= (1<<PINF4) | (1<<PINF5); // MOtor Break
			DDRB &= ~(1<<PINB4);
			LCD_WriteStringXY(0,0,"   Stop mode    ");
			LCD_WriteStringXY(1,0,"  Power :   0%  ");
			Fan_run_status = Fan_stop;
			spin_cnt = 0;
			Spin_status_LED();
			Fan_Stage();
			break;
		
		case 1 :
			//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
			LED_PORT = 0x00;
			LED_PORT |= (1<<PINA0);
			DDRB |= (1<<PINB4);
			OCR0 = 64; // 25%
			PORTF &= ~(1<<PINF4); // Motor 정방향 회전
			PORTF |= (1<<PINF5);
			LCD_WriteStringXY(0,0,"   1st Stage    ");
			LCD_WriteStringXY(1,0,"  Power :  25%  ");
			Fan_run_status = Fan_1st;
			Spin_status_LED();
			Fan_Stage();
		break;
		
		case 2 :
			//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
			LED_PORT = 0x00;
			LED_PORT |= (1<<PINA0) | (1<<PINA1);
			DDRB |= (1<<PINB4);
			OCR0 = 128; // 50%
			PORTF &= ~(1<<PINF4); // Motor 정방향 회전
			PORTF |= (1<<PINF5);
			LCD_WriteStringXY(0,0,"   2nd Stage    ");
			LCD_WriteStringXY(1,0,"  Power :  50%  ");
			Fan_run_status = Fan_2nd;
			Spin_status_LED();
			Fan_Stage();
		break;
		
		case 3 :
			//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
			LED_PORT = 0x00;
			LED_PORT |= (1<<PINA0) | (1<<PINA1) | (1<<PINA2);
			DDRB |= (1<<PINB4);
			OCR0 = 255; // 100%
			PORTF &= ~(1<<PINF4); // Motor 정방향 회전
			PORTF |= (1<<PINF5);
			LCD_WriteStringXY(0,0,"   3rd Stage    ");
			LCD_WriteStringXY(1,0,"  Power : 100%  ");
			Fan_run_status = Fan_3rd;
			Spin_status_LED();
			Fan_Stage();
		break;
		
		//case 4 :
			//Fan_Start_signal();
		//break;
	}
}

void Display_LCD()
{
	switch (Fan_run_status)
	{
		case 0:
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LCD_WriteStringXY(0,0,"   Stop mode    ");
		LCD_WriteStringXY(1,0,"  Power :   0%  ");
		//Spin_status_LED();
		Fan_run_status = Fan_stop;
		Fan_Stage();
		break;
		
		case 1 :
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LCD_WriteStringXY(0,0,"   1st Stage    ");
		LCD_WriteStringXY(1,0,"  Power :  25%  ");
		//Spin_status_LED();
		Fan_run_status = Fan_1st;
		Fan_Stage();
		Fan_continue_run();
		break;
		
		case 2 :
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LCD_WriteStringXY(0,0,"   2nd Stage    ");
		LCD_WriteStringXY(1,0,"  Power :  50%  ");
		//Spin_status_LED();
		Fan_run_status = Fan_2nd;
		Fan_Stage();
		Fan_continue_run();
		break;
		
		case 3 :
		//LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
		LCD_WriteStringXY(0,0,"   3rd Stage    ");
		LCD_WriteStringXY(1,0,"  Power : 100%  ");
		//Spin_status_LED();
		Fan_run_status = Fan_3rd;
		Fan_Stage();
		Fan_continue_run();
		break;
		
		//case 4 :
		//Fan_Start_signal();
		//break;
	}
}

void Head_spin_op()
{
	BUTTON_spin_getState(&btn_spin);
	switch (spin_cnt)
	{
		case 1:
		//Spin_status_LED();
		Fan_continue_run();
		Display_LCD();
		DDRB = (1<<PINB5);
		BUTTON_spin_getState(&btn_spin);
		LED_PORT |= (1<<PINA3);
		while((spin_cnt == 1))
		{
			Spin_status_LED();
			for (int i = 0; i < 90 ; i++)
			{
				LED_PORT |= (1<<PINA3);
				BUTTON_spin_getState(&btn_spin);
				Fan_continue_run();
				Display_LCD();
				Spin_start(2*i);
				//_delay_ms(5);
				if (spin_cnt != 1)
				{
					Display_LCD();
					spin_cnt = 0;
					break;
				}
			}
			for (int j = 0; j < 90 ; j++)
			{
				//Spin_status_LED();
				LED_PORT |= (1<<PINA3);
				BUTTON_spin_getState(&btn_spin);
				Fan_continue_run();
				Display_LCD();
				Spin_start(180-2*j);
				//_delay_ms(5);
				if (spin_cnt != 1)
				{
					Display_LCD();
					spin_cnt = 0;
					break;
				}
			}
		}
		break;
	
		default:
		BUTTON_spin_getState(&btn_spin);
		Fan_continue_run();
		Display_LCD();
		Spin_stop();
		spin_cnt = 0;
		break;
	}
}

void Spin_status_LED()
{
	if (spin_cnt == 1)
	{
		LED_PORT |= (1<<PINA3);
	}
	// else LED_PORT &= ~(1<<PINA3);
}

void Spin_stop()
{
	LED_PORT &= ~(1<<PINA3);
	TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0)); // PWM 출력 안 되도록
}

void Spin_start(uint8_t degree)
{
	// 0도 : 125 / 180도 : 625
	LED_PORT |= (1<<PINA3);
	uint16_t degree_value;
	TCCR1A |= (1<<COM1A1); // PWM 다시 출력되도록
	if (degree_value < 0) // 제한 범위를 벗어나 고장나지 않도록 설정
	{
		degree = 0;
	}
	else if(degree > 180)
	{
		degree = 180;
	}
	degree_value = (uint16_t)((degree/180.0)*500 + 125); // 우리가 흔히 쓰는 각도로 표현하기 위한 식
	OCR1A = degree_value;
}

 

 

<main.c>

#include "Fan.h"

int main(void)
{
	Fan_Init();
	Fan_Start_signal();
	
	while (1)
	{
		Fan_Stage();
		Display_LCD();
		Head_spin_op();
	}
}

 

Full code Link(추가 업데이트 진행 중)
🐱Github
 

GitHub - Graffitio/Harman_Project_Fan: /* Update 진행 중 */

/* Update 진행 중 */. Contribute to Graffitio/Harman_Project_Fan development by creating an account on GitHub.

github.com

 


 

Operation

 

<1st Stage Run>

 

<2nd Stage Run>

 

<3rd Stage Run>

 

<Random Stage>

 

<Stop>

<Spin>

<Spin & Motor all stop>

 


 

[Review]

 

문제점 해결

 

 


 

느낀점

 

<Flow Chart>

이전까지는 플로우 차트 작성 단계를 생략하고 코드 작업에 바로 들어갔었는데, 이번 프로젝트를 통해 플로우 차트의 역할과 중요성을 비로소 깨닫게 되었다. 과거에는 플로우 차트 작성을 시간 낭비로 여겼었지만, 이번에 처음으로 그림을 그리고 나서 코딩 작업에 들어갔더니 작업 속도가 기하급수적으로 향상되었다. 지금까지는 비교적 단순한 기능들을 구현하는 작업이었기 때문에 플로우 차트 없이도 진행할 수 있었으나, 실무에서는 여러 명이 함께 협업하여 대규모 프로젝트를 진행하는 경우가 많은데, 이런 경우에는 플로우 차트가 반드시 필요한 작업임을 깨달았다.

 

<파일 분할>

초기 작업 시에는 main 함수 내에서 코딩이 이루어졌기에 코드가 중구난방이었다.

하지만 코드를 소스 파일과 헤더 파일로 분류하여 정리하고 나니, 가독성도 좋아지고 나만의 라이브러리도 만들 수 있어 추후에 관련 기능을 훨씬 더 수월하게 사용할 수 있게 되었고, 실무에서도 이와 같이 작업을 수행한다면 본인 뿐만 아니라 같이 작업하는 팀원들의 능률 상승에도 기여하게 될 것이라 느꼈다.

 

<아쉬웠던 점>

짧은 기간에 수행된 프로젝트다 보니,

메인 과제는 완료했지만 추가로 진행하고 싶었던 기능들을 구상만 해놓고 구현하지 못해 아쉬움이 남았다.

  - 초음파 센서를 활용한 Em’cy stop 기능

  - 내부 clock을 활용한 Timer 기능

  - Timer 잔여 시간 4bit FND로 출력

  - 오실로스코프를 이용한 파형 검출(장비의 부재)

 

하지만 만약 실력이 좀 더 쌓아뒀더라면, 찗은 시간일지라 위 기능들을 충분히 구현하지 않았을까 하는 생각이 들었고

이를 자기반성의 기회로 여겨 더욱 더 노력하는 내 자신이 되고자 다짐하는 계기가 되었으며,

다음 프로젝트는 아마 AVR로 도어락을 구현하는 팀프로젝트가 될 것 같은데, 능력 부족으로 인한 아쉬움이 남지 않도록더더욱 실력을 갈고 닦아야 겠다.

 


728x90
반응형