ATmega128 선풍기 제작

JS·2023년 3월 8일

Project

목록 보기
1/4

ATmega 128을 이용해서 선풍기를 만들어보자

선풍기의 동작은 다음과 같이 설계를 할 것이다.

Button Fan MODE(버튼 1)를 누르면 기본 OFF 상태였던 선풍기의 풍력을 1로 변경하며 ON이 된다. 여기서 계속해서 Button Fan MODE를 누르면 선풍기의 단계가 순차적으로 1->2->3->4->5로 바뀌며 5단계에서 다시한 번 Button Fan MODE를 누르면 1단계로 돌아간다.


Button Timer(버튼 2)의 경우, 타이머가 설정되며 시간이 5초 추가되면서 FND(7segment)에 숫자가 표기됨. Button Timer를 누를 때마다, 5초씩 추가되며, 가만히 놔두면 시간은 Down count되며 숫자가 0이 될 경우, Fan을 OFF한다.
Button Fan Off(버튼 0)의 경우, 누르면 선풍기의 상태에 관계없이 무조건 OFF상태가 되며, 타이머 역시 0으로 초기화된다.


Buzzer의 경우, OFF 상태에서 Button Fan MODE를 누르면 ON이 되는 소리, Button Fan Off을 눌러 OFF하는 소리, Button Fan MODE를 눌러 Mode를 바꾸는 소리, Button Timer을 눌러 시간을 추가하는 소리, 타이머가 0이 되었을 때의 소리를 넣을 것이다.


LCD의 경우, 위쪽에는 현재의 시간을 표기해줄 것이며, 하단에는 FAN의 현재 상태를 표시할 것이다.


Timer의 상태를 표시하기 위해 Timer에 시간이 추가될 때마다 LED를 하나씩키며, 5초 단위로 LED를 커며, 8개의 LED를 이용하여 2진수 형태로 상태를 표현할 것이다.


이러한 Timer의 시간을 시각적으로 표현하기 위한 FND이다. 가장 좌측의 자리는 분을 표기해주며, 가운데 2자리는 초, 가장 우측의 자리는 mili초를 표기한다.

개발에 사용될 부품과 개발 환경은 다음과 같다

개발을 위한 S/W Stack을 설계해보자

프로젝트에 사용되는 Timer/Counter는 다음과 같다

FAN(moter): Timer/Counter 0번(8bit)을 사용
-> PWM 기능을 이용하여 moter의 속도를 조절

FND, LCD: Timer/Counter 2번(8bit)을 사용
-> 비교기 모드를 이용하여 시간을 1ms 단위로 count하여 FND와 LCD에 출력

Buzzer: Timer/Counter 0번(16bit)를 이용
-> 인간의 가청 주파수는 20Hz~20,000Hz이므로 8bit로 표현이 가능한 256으로는 턱없이 부족함
-> 따라서 65536까지 표현이 가능한 16bit의 Timer/Counter를 이용함

디지털 선풍기를 위한 Class Diagram은 다음과 같다.

위의 Class Diagram을 바탕으로 코드를 구성해보자

main.c

#include <avr/io.h>
#include "ap/apMain.h"

int main(void)
{
	apMain_init();
    while (1) 
    {
		apMain_excute();
    }
}
_______________________________________Application

apMain.c

#include "apMain.h"

ISR(TIMER2_COMP_vect)
{
	Presenter_ISR_Process();
	TimeClock_incMilisec();
	FanTimer_decMilisec();
}
void apMain_init()
{
	TimeClock_init();
	Listener_init();
	Presenter_init();
	Model_setFanSpeedStateData(FAN_OFF);
	Model_setFanTimerStateData(FANTIMER_OFF);
	TIM2_init();
	sei();
}
void apMain_excute()
{
	Listener_fanSpeedEvent();
	Listener_fanTimerEvent();
	TimeClock_run();
	FanTimer_run();
	FanSpeed_run();
}

apMain.h

#ifndef APMAIN_H_
#define APMAIN_H_

#include <avr/io.h>
#include <avr/interrupt.h>
#include "../periph/TIM/TIM.h"
#include "Listener/Listener.h"
#include "Model/Model_FanSpeedState/Model_FanSpeedState.h"
#include "Model/Model_FanTimerState/Model_FanTimerState.h"
#include "Presenter/Presenter.h"
#include "Service/Service_FanSpeed/Service_FanSpeed.h"
#include "Service/Service_TimeClock/Service_TimeClock.h"
#include "Service/Service_FanTimer/Service_FanTimer.h"

void apMain_init();
void apMain_excute();

#endif /* APMAIN_H_ */

Model_FanSpeedState.c

#include "Model_FanTimerState.h"

uint8_t fanTimerStateData;

uint8_t Model_getFanTimerStateData()
{
	return fanTimerStateData;
}
void Model_setFanTimerStateData(uint8_t state)
{
	fanTimerStateData = state;
}

Model_FanSpeedState.h

#ifndef MODEL_FANSPEEDSTATE_H_
#define MODEL_FANSPEEDSTATE_H_

#include <avr/io.h>

enum {FAN_OFF, FAN_LEVEL1, FAN_LEVEL2, FAN_LEVEL3, FAN_LEVEL4, FAN_LEVEL5};

uint8_t Model_getFanSpeedStateData();
void Model_setFanSpeedStateData(uint8_t state);

#endif /* MODEL_FANSPEEDSTATE_H_ */

Model_FanTimerState.c

#include "Model_FanTimerState.h"

uint8_t fanTimerStateData;

uint8_t Model_getFanTimerStateData()
{
	return fanTimerStateData;
}
void Model_setFanTimerStateData(uint8_t state)
{
	fanTimerStateData = state;
}

Model_FanTimerState.h

#ifndef MODE_FANTIMERSTATE_H_
#define MODE_FANTIMERSTATE_H_

#include <avr/io.h>

enum {FANTIMER_OFF,FANTIMER_UP,FANTIMER_DOWN};

uint8_t Model_getFanTimerStateData();
void Model_setFanTimerStateData(uint8_t state);

#endif /* MODE_FANTIMERSTATE_H_ */

Listener.c

#include "Listener.h"

button_t btnFanOff, btnFanMode, btnTimer;

void Listener_init()
{
	Button_init(&btnFanOff, &DDRA, &PINA, 0);
	Button_init(&btnFanMode, &DDRA, &PINA, 1);
	Button_init(&btnTimer, &DDRA, &PINA, 2);
}
void Listener_fanSpeedEvent()
{
	uint8_t fanModeState = Model_getFanSpeedStateData();

	switch( fanModeState )
	{
		case FAN_OFF:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL1;
			Model_setFanSpeedStateData(fanModeState);
		}
		Model_setFanTimerStateData(FANTIMER_OFF);
		break;

		case FAN_LEVEL1:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL2;
			Model_setFanSpeedStateData(fanModeState);
		}
		else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
			fanModeState = FAN_OFF;
			Model_setFanSpeedStateData(fanModeState);
			Model_setFanTimerStateData(FANTIMER_OFF);
		}
		break;

		case FAN_LEVEL2:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL3;
			Model_setFanSpeedStateData(fanModeState);
		}
		else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
			fanModeState = FAN_OFF;
			Model_setFanSpeedStateData(fanModeState);
			Model_setFanTimerStateData(FANTIMER_OFF);
		}
		break;

		case FAN_LEVEL3:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL4;
			Model_setFanSpeedStateData(fanModeState);
		}
		else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
			fanModeState = FAN_OFF;
			Model_setFanSpeedStateData(fanModeState);
			Model_setFanTimerStateData(FANTIMER_OFF);
		}
		break;

		case FAN_LEVEL4:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL5;
			Model_setFanSpeedStateData(fanModeState);
		}
		else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
			fanModeState = FAN_OFF;
			Model_setFanSpeedStateData(fanModeState);
			Model_setFanTimerStateData(FANTIMER_OFF);
		}
		break;

		case FAN_LEVEL5:
		if (Button_getState(&btnFanMode) == ACT_PUSHED) {
			fanModeState = FAN_LEVEL1;
			Model_setFanSpeedStateData(fanModeState);
		}
		else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
			fanModeState = FAN_OFF;
			Model_setFanSpeedStateData(fanModeState);
			Model_setFanTimerStateData(FANTIMER_OFF);
		}
		break;
	}
}
void Listener_fanTimerEvent()
{
	uint8_t timerState = Model_getFanTimerStateData();
	uint8_t fanModeState = Model_getFanSpeedStateData();

	if(fanModeState != FAN_OFF)
	{
		switch( timerState )
		{
			case FANTIMER_OFF:
			if (Button_getState(&btnTimer) == ACT_PUSHED) {
				timerState = FANTIMER_UP;
				Model_setFanTimerStateData(timerState);
			}
			break;

			case FANTIMER_UP:
			break;

			case FANTIMER_DOWN:
			if (Button_getState(&btnTimer) == ACT_PUSHED) {
				timerState = FANTIMER_UP;
				Model_setFanTimerStateData(timerState);
			}
			else if (Button_getState(&btnFanOff) == ACT_PUSHED) {
				timerState = FANTIMER_OFF;
				Model_setFanTimerStateData(timerState);
			}
			break;
		}
	}
}

Listener.h

#ifndef LISTENER_H_
#define LISTENER_H_

#include <avr/io.h>
#include "../../driver/Button/Button.h"
#include "../Model/Model_FanSpeedState/Model_FanSpeedState.h"
#include "../Model/Model_FanTimerState/Model_FanTimerState.h"

void Listener_init();
void Listener_fanSpeedEvent();
void Listener_fanTimerEvent();

#endif /* LISTENER_H_ */

Presenter.c

#include "Presenter.h"

void Presenter_init()
{
	FND_init();
	LCD_init();
	FAN_init();
	Led_initPort(&LED_DDR);
	Buzzer_init();
}
void Presenter_fanSpeedData(uint8_t fanSpeedData)
{
	if(fanSpeedData == 0)
	{
		FAN_Off();
	}
	else
	{
		FAN_On();
		FAN_speed(fanSpeedData);
	}
}
void Presenter_led(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec)
{
	uint32_t fanTimerData;
	uint8_t ledData = 0x00;
	fanTimerData = (hour * 60 * 60) + (min * 60) + sec;
	Led_writePort(&LED_PORT, ledData);
	while(1)
	{
		if(ledData == 0xff) break;
		if((fanTimerData > 0) && (fanTimerData < 5))
		{
			ledData = ledData + 0x01;
			Led_writePort(&LED_PORT, ledData);
		}
		if(fanTimerData >= 5)
		{
			ledData = ledData + 0x01;
			Led_writePort(&LED_PORT, ledData);
			fanTimerData = fanTimerData - 5;
		}
		else break;
	}
	if((fanTimerData == 0) && (milisec > 0))
	{
		ledData = 0x01;
		Led_writePort(&LED_PORT, ledData);
	}
}
void Presenter_dispTimeClock(uint8_t hour,uint8_t min, uint8_t sec, uint16_t milisec)
{
	static uint8_t prevMilisec = 0xff;         //
	if((milisec/10) == prevMilisec) return;      //milisec는 990까지
	prevMilisec = milisec/10;
	
	char buff[30];
	
	sprintf(buff,"Time:%02d:%02d:%02d:%02d" , hour,min,sec,milisec/10);         //buff에 해당 문구를 print해라
	LCD_writeStringXY(0,0,buff);      //buff의 0,0에 써라
}
void Presenter_dispFanSpeed()
{
	uint8_t fanSpeedMode = Model_getFanSpeedStateData();
	
	static uint8_t prevFanSpeedMode = 0xff;         //
	if(fanSpeedMode == prevFanSpeedMode) return;      //milisec는 990까지
	prevFanSpeedMode = fanSpeedMode;
	
	char buff[30];

	sprintf(buff,"Speed Level : %01d" , fanSpeedMode);
	LCD_writeStringXY(1,0,buff);
}
void Presenter_dispFanTimerData(uint8_t min, uint8_t sec, uint16_t milisec)
{
	uint32_t fanTimerData;
	
	fanTimerData = (min * 1000) + (sec * 10) + (milisec / 100);
	FND_setFndData(fanTimerData);
}
void Presenter_speedButtonSound()
{
	Buzzer_speedButtonSound();
}
void Presenter_timerButtonSound()
{
	Buzzer_timerButtonSound();
}
void Presenter_fanPowerOnSound()
{
	Buzzer_powerOnSound();
}
void Presenter_fanPowerOffSound()
{
	Buzzer_powerOffSound();
}
void Presenter_timerOffSound()
{
	Buzzer_TimerSound();
}
void Presenter_ISR_Process()
{
	FND_ISR_Process();
}

Presenter.h

#ifndef PRESENTER_H_
#define PRESENTER_H_

#include <avr/io.h>
#include <stdio.h>
#include "../../driver/FAN/FAN.h"
#include "../../driver/FND/FND.h"
#include "../../driver/LCD/LCD.h"
#include "../../driver/LED/Led.h"
#include "../../driver/Buzzer/Buzzer.h"
#include "../Model/Model_FanSpeedState/Model_FanSpeedState.h"

#define LED_DDR		DDRD
#define LED_PORT	PORTD

void Presenter_init();
void Presenter_fanSpeedData(uint8_t fanSpeedData);
void Presenter_led(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec);
void Presenter_dispTimeClock(uint8_t hour,uint8_t min, uint8_t sec, uint16_t milisec);
void Presenter_dispFanSpeed();
void Presenter_dispFanTimerData(uint8_t min, uint8_t sec, uint16_t milisec);
void Presenter_speedButtonSound();
void Presenter_timerButtonSound();
void Presenter_fanPowerOnSound();
void Presenter_fanPowerOffSound();
void Presenter_timerOffSound();
void Presenter_ISR_Process();

#endif /* PRESENTER_H_ */

Service_FanSpeed.c

#include "Service_FanSpeed.h"

void FanSpeed_run()
{
	uint8_t fanSpeedState = Model_getFanSpeedStateData();
	uint8_t fanTimerState = Model_getFanTimerStateData();
	static uint8_t preFanSpeedState;
	static uint8_t preFanOnOffState;

	switch(fanSpeedState)
	{
		case FAN_OFF:
		Presenter_fanSpeedData(0);
		if(fanTimerState)
		{
			Presenter_timerOffSound();
		}
		if(preFanOnOffState != fanSpeedState)
		{
			Presenter_fanPowerOffSound();
		}	
		preFanSpeedState = fanSpeedState;
		preFanOnOffState = fanSpeedState;
		Model_setFanTimerStateData(FANTIMER_OFF);
		break;

		case FAN_LEVEL1:
		Presenter_fanSpeedData(30);
		if(preFanOnOffState != fanSpeedState)
		{
			Presenter_fanPowerOnSound();
		}
		else if(preFanSpeedState != fanSpeedState)
		{
			Presenter_speedButtonSound();
		}
		preFanSpeedState = fanSpeedState;
		preFanOnOffState = fanSpeedState;
		break;

		case FAN_LEVEL2:
		Presenter_fanSpeedData(40);
		if(preFanSpeedState != fanSpeedState)
		{
			Presenter_speedButtonSound();
		}
		preFanSpeedState = fanSpeedState;
		break;

		case FAN_LEVEL3:
		Presenter_fanSpeedData(60);
		if(preFanSpeedState != fanSpeedState)
		{
			Presenter_speedButtonSound();
		}
		preFanSpeedState = fanSpeedState;
		break;

		case FAN_LEVEL4:
		Presenter_fanSpeedData(80);
		if(preFanSpeedState != fanSpeedState)
		{
			Presenter_speedButtonSound();
		}
		preFanSpeedState = fanSpeedState;
		break;

		case FAN_LEVEL5:
		Presenter_fanSpeedData(100);
		if(preFanSpeedState != fanSpeedState)
		{
			Presenter_speedButtonSound();
		}
		preFanSpeedState = fanSpeedState;
		break;		
	}	
	Presenter_dispFanSpeed();
}

Service_FanSpeed.h

#ifndef SERVICE_FANSPEED_H_
#define SERVICE_FANSPEED_H_

#include <avr/io.h>
#include "../../Model/Model_FanSpeedState/Model_FanSpeedState.h"
#include "../../Model/Model_FanTimerState/Model_FanTimerState.h"
#include "../../Presenter/Presenter.h"

void FanSpeed_run();

#endif /* SERVICE_FANSPEED_H_ */

Service_FanTimer.c

#include "Service_FanTimer.h"

static uint16_t milisec;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;

void FanTimer_init()
{
	milisec = 0;
	sec = 0;
	min = 0;
	hour = 0;
}
void FanTimer_decMilisec()
{
	uint8_t fanTimerState = Model_getFanTimerStateData();

	if (fanTimerState != FANTIMER_DOWN) return;

	if(milisec == 0)
	{
		if(sec == 0)
		{
			if(min == 0)
			{
				if(hour > 0)
				{
					min = 60;
					hour = hour - 1;
				}
			}
			else if(min > 0)
			{
				min = min -1;
				sec = 60;
			}
		}
		else if(sec > 0)
		{
			sec = sec - 1;
			milisec = 1000;
		}	
	}
	else if(milisec > 0)
	{
		milisec = milisec - 1;
	}
}
void FanTimer_run()
{
	uint8_t fanTimerState = Model_getFanTimerStateData();
	uint8_t preFanTimerState = FANTIMER_OFF;

	switch(fanTimerState)
	{
		case FANTIMER_OFF:
		FanTimer_init();
		preFanTimerState = fanTimerState;
		break;

		case FANTIMER_UP:
		if(preFanTimerState != fanTimerState) Presenter_timerButtonSound();
		sec = sec +5;
		FanTimer_convertTime();
		preFanTimerState = fanTimerState;
		fanTimerState = FANTIMER_DOWN;
		Model_setFanTimerStateData(fanTimerState);
		break;
	
		case FANTIMER_DOWN:
		if ((hour == 0) && (min == 0) && (sec == 0) && (milisec == 0))
		{
			Model_setFanSpeedStateData(FAN_OFF);
		}
		preFanTimerState = fanTimerState;
		break;
	}
	Presenter_led(hour, min, sec, milisec);
	Presenter_dispFanTimerData(min, sec, milisec);
}
void FanTimer_convertTime()
{
	if (sec >= 60)
	{
		min = min + 1;
		sec = sec - 60;
	}
	if (min >= 60)
	{
		hour = hour + 1;
		min = min - 60;
	}
	if (hour >= 24)
	{
		hour = 24;
	}
}

Service_FanTimer.h

#ifndef SERVICE_FANTIMER_H_
#define SERVICE_FANTIMER_H_

#include <avr/io.h>
#include "../../Model/Model_FanTimerState/Model_FanTimerState.h"
#include "../../Model/Model_FanSpeedState/Model_FanSpeedState.h"
#include "../../Presenter/Presenter.h"

void FanTimer_init();
void FanTimer_decMilisec();
void FanTimer_run();
void FanTimer_convertTime();

#endif /* SERVICE_FANTIMER_H_ */

Service_TimeClock.c

#include "Service_TimeClock.h"

static uint16_t milisec;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;

void TimeClock_init()
{
	milisec = 0;
	sec = 0;
	min = 0;
	hour = 12;
}
void TimeClock_incMilisec()
{
	milisec = (milisec + 1) % 1000;
	if(milisec) return;

	sec = (sec + 1) % 60;
	if(sec) return;

	min = (min + 1) % 60;
	if(min) return;

	hour = (hour + 1) % 24;
}
void TimeClock_run()
{
	Presenter_dispTimeClock(hour, min, sec, milisec);
}

Service_TimeClock.h

#ifndef SERVICE_TIMECLOCK_H_
#define SERVICE_TIMECLOCK_H_

#include <avr/io.h>
#include "../../Presenter/Presenter.h"

void TimeClock_init();
void TimeClock_incMilisec();
void TimeClock_run();

#endif /* SERVICE_TIMECLOCK_H_ */

___Driver

Button.c

#include "Button.h"

void Button_init(button_t *btn, volatile uint8_t *DDR, volatile uint8_t *PIN, uint8_t pinNum)
{
	btn->DDR = DDR;
	btn->PIN = PIN;
	btn->pinNum = pinNum;
	btn->prevState = RELEASED;
	Gpio_initPin(btn->DDR, btn->pinNum, INPUT);
}
uint8_t Button_getState(button_t *btn)
{
	uint8_t curState = Gpio_readPin(btn->PIN, btn->pinNum);

	if ((curState == PUSHED) && (btn->prevState == RELEASED)) {
		_delay_ms(10); //debounce code
		btn->prevState = PUSHED;
		return ACT_PUSHED;
	}
	else if ((curState != PUSHED) && (btn->prevState == PUSHED)){
		_delay_ms(10); //debounce code
		btn->prevState = RELEASED;
		return ACT_RELEASED;
	}
	return ACT_NONE;
}

Button.h

#ifndef BUTTON_H_
#define BUTTON_H_

#define F_CPU 16000000UL //설정하지 않으면 Default 값이 10M(10000000) UL:Unsigned Long
#include <avr/io.h>
#include <util/delay.h>
#include "../../periph/GPIO/Gpio.h"

enum {PUSHED, RELEASED}; // 해당 변수가 가지는 값은 순서대로 0, 1
enum {ACT_NONE, ACT_PUSHED, ACT_RELEASED}; // 해당 변수가 가지는 값은 순서대로 0, 1, 2

typedef struct _button
{
	volatile uint8_t *DDR; // PORT DDR / volatile : Compiler가 최적화하지 않게 하는 명령어
	volatile uint8_t *PIN; // PORT IN
	uint8_t pinNum; // pin number
	uint8_t prevState; // static
}button_t; // struct _button ~~~ 를 button_t ~~~ 로 줄여서 쓸 수 있게 하는 것 typedef 앞에 붙여줘야함.

void Button_init(button_t *btn, volatile uint8_t *ddr, volatile uint8_t *pin, uint8_t pinNum);
uint8_t Button_getState(button_t *btn);

#endif /* BUTTON_H_ */

Buzzer.c

#include "Buzzer.h"

void Buzzer_makeHerz(uint16_t herz)
{      //0~ 65535 범위에서
		//100hz ~ 4kz 만 내보내기위해 아래와 같이 예외처리
	if (herz<100) herz=100;
	else if (herz>4000) herz=4000;

	BUZZER_ICR = (250000/herz) -1;         //250000/1000 -1 = 1000Hz .. 분모에 원하는 herz넣으면 됨.
	BUZZER_OCR = BUZZER_ICR / 2;                     //ICR3값이 계속 바뀌니까
}

void Buzzer_soundOn()
{
	BUZZER_TCCRA |= (1<<BUZZER_COM1) | (0<<BUZZER_COM0);      //COM3A1, 0 => PWM 출력 모드 설정 -> 비반전 모드
}

void Buzzer_soundOff()
{
	BUZZER_TCCRA &= ~((1<<BUZZER_COM1) | (1<<BUZZER_COM0));      //COM3A1, 0 => PWM 출력 모드 설정 -> disconnected 연결 X 모드 -> 출력 X
}

void Buzzer_init()
{
	Gpio_initPin(&BUZZER_DDR, 3, OUTPUT);
	//TIM3, Fast PWM mode, top값은 ICR3로 조정, DutyCycle->OCR3A를 기준으로 사용, Prescaler-> 64, 출력모드 - 비반전모드 Non-Invert Output
	BUZZER_TCCRB |= (1<<BUZZER_WGM3) | (1<<BUZZER_WGM2);   //Fast PWM 모드로 설정
	BUZZER_TCCRA |= (1<<BUZZER_WGM1) | (0<<BUZZER_WGM0);   //Fast PWM 모들 설정 -> WGM3 2 1 0 = 1 1 1 1
	BUZZER_TCCRB |= (0<<BUZZER_CS2) | (1<<BUZZER_CS1) | (1<<BUZZER_CS0);         //prescaler 64로 설정
	//ICR3 = 250 - 1;               //top값 설정 -> ICR3 사용 카운트가 250이게 되려면 250-1로 잡아야함
	//OCR3A = ICR3 / 2;//기준값 설정
	
	//BUZZER_TCCRA |= (1<<BUZZER_COM1) | (0<<BUZZER_COM0);      //COM3A1, 0 => PWM 출력 모드 설정 -> 비반전 모드로
	
}

void Buzzer_powerOnSound()
{
	Buzzer_soundOn();
	TCNT3 =0;               //TCNT3 =0 왜?
	Buzzer_makeHerz(1046);
	_delay_ms(80);
	TCNT3 =0;
	Buzzer_makeHerz(1318);
	_delay_ms(80);
	TCNT3 =0;
	Buzzer_makeHerz(1568);
	_delay_ms(80);
	TCNT3 =0;
	Buzzer_makeHerz(2093);
	_delay_ms(80);
	Buzzer_soundOff();
}

void Buzzer_powerOffSound()
{
	Buzzer_soundOn();
	TCNT3 = 0;
	Buzzer_makeHerz(2093);
	_delay_ms(80);
	TCNT3 = 0;
	Buzzer_makeHerz(1568);
	_delay_ms(80);
	TCNT3 = 0;
	Buzzer_makeHerz(1318);
	_delay_ms(80);
	TCNT3 = 0;
	Buzzer_makeHerz(1046);
	_delay_ms(80);
	Buzzer_soundOff();
}

void Buzzer_speedButtonSound()
{
	Buzzer_soundOn();
	TCNT3 =0;               //TCNT3 =0 왜?
	Buzzer_makeHerz(2093);
	_delay_ms(80);
	Buzzer_soundOff();
}

void Buzzer_timerButtonSound()
{
	Buzzer_soundOn();
	TCNT3 =0;
	Buzzer_makeHerz(1568);
	_delay_ms(80);
	TCNT3 =0;               //TCNT3 =0 왜?
	Buzzer_makeHerz(2093);
	_delay_ms(80);
	Buzzer_soundOff();
}

void Buzzer_TimerSound()
{
	for(int i=0; i<2; i++){
		Buzzer_soundOn();
		TCNT3 =0;               //TCNT3 =0 왜?
		Buzzer_makeHerz(2093);
		_delay_ms(200);
		TCNT3 =0;               //TCNT3 =0 왜?
		Buzzer_makeHerz(1479);
		_delay_ms(200);
		Buzzer_soundOff();
	}
}

Buzzer.h

#ifndef BUZZER_H_
#define BUZZER_H_

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "../../periph/GPIO/Gpio.h"

#define BUZZER_ICR		ICR3
#define BUZZER_OCR		OCR3A
#define BUZZER_TCCRA	TCCR3A
#define BUZZER_TCCRB	TCCR3B
#define BUZZER_COM0		COM3A0
#define BUZZER_COM1		COM3A1
#define BUZZER_DDR		DDRE
#define BUZZER_WGM0		WGM30
#define BUZZER_WGM1		WGM31
#define BUZZER_WGM2		WGM32
#define BUZZER_WGM3		WGM33
#define BUZZER_CS0		CS30
#define BUZZER_CS1		CS31
#define BUZZER_CS2		CS32

void Buzzer_makeHerz(uint16_t herz);
void Buzzer_soundOn();
void Buzzer_soundOff();
void Buzzer_init();
void Buzzer_powerOnSound();
void Buzzer_powerOffSound();
void Buzzer_speedButtonSound();
void Buzzer_timerButtonSound();
void Buzzer_TimerSound();

#endif /* BUZZER_H_ */

FAN.c

#include "FAN.h"

void FAN_init()
{
	Gpio_initPin(&FAN_DDR, 4, OUTPUT);
	// TIM0, Fast PWM Mode, top 0xFF, Duty Cycle OCR0, Prescaler 1/64, Non-Invert OutPut(비반전 출력)
	FAN_TCCR |= (1 << FAN_WGM1) | (1 << FAN_WGM0); // Fast PWM Mode
	FAN_TCCR |= (1 << FAN_CS2) | (0 << FAN_CS1) | (0 << FAN_CS0); // Prescaler 1/64
}
void FAN_speed(uint8_t data)
{
	uint8_t percent;
	if(data < 23) data = 23;
	percent = 255 * data / 100;	
	FAN_OCR = percent;
}
void FAN_On()
{
	FAN_TCCR  |= (1 << FAN_COM1) | (0 << FAN_COM0); // Non-Invert OutPut
}
void FAN_Off()
{
	FAN_TCCR &= ~((1 << FAN_COM1) | (1 << FAN_COM0)); // Disconnected
}

FAN.h

#ifndef FAN_H_
#define FAN_H_

#define F_CPU 16000000UL
#include <avr/io.h>
#include "../../periph/GPIO/Gpio.h"

#define FAN_OCR		OCR0
#define FAN_TCCR	TCCR0
#define FAN_COM0	COM00
#define FAN_COM1	COM01
#define FAN_DDR		DDRB
#define FAN_WGM0	WGM00
#define FAN_WGM1	WGM01
#define FAN_CS0		CS00
#define FAN_CS1		CS01
#define FAN_CS2		CS02

void FAN_init();
void FAN_speed(uint8_t percent);
void FAN_On();
void FAN_Off();

#endif /* FAN_H_ */

FND.c

#include "FND.h"

uint16_t fndData = 0;
uint8_t fndColonFlag = 0;
uint8_t fnd1Dot = 0;
uint8_t fnd3Dot = 0;

void FND_setFndData(uint16_t data)
{
	fndData = data;
}
void FND_init()
{
		Gpio_initPin(&FND_DIGIT_DDR, FND_DIGIT_1, OUTPUT);	// D1 출력모드
		Gpio_initPin(&FND_DIGIT_DDR, FND_DIGIT_2, OUTPUT);	// D2 출력모드
		Gpio_initPin(&FND_DIGIT_DDR, FND_DIGIT_3, OUTPUT);	// D3 출력모드
		Gpio_initPin(&FND_DIGIT_DDR, FND_DIGIT_4, OUTPUT);	// D4 출력모드
		Gpio_initPort(&FND_DATA_DDR, OUTPUT);	// FND 출력모드
}
void FND_colonOn()
{
	fndColonFlag = 1;
}
void FND_colonOff()
{
	fndColonFlag = 0;
}
void FND_dispNum(uint16_t fndNum)
{

	uint8_t fndFont[11] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x80};

	static uint8_t fndDigitState = 0; // 데이터값을 0부터 저장하기위해 static을 사용.

	fndDigitState = (fndDigitState + 1) % 6;

	FND_DIGIT_PORT |= ((1 << FND_DIGIT_1) | (1 << FND_DIGIT_2) | (1 << FND_DIGIT_3) | (1 << FND_DIGIT_4));

	switch(fndDigitState)
	{
	
		case 0:
		Gpio_writePort(&FND_DATA_PORT, fndFont[fndNum / 1000 % 10]);	// 천의 자리
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_1, GPIO_PIN_RESET);
		break;
	
		case 1:
		Gpio_writePort(&FND_DATA_PORT, fndFont[fndNum / 100 % 10]);		// 백의 자리
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_2, GPIO_PIN_RESET);
		break;

	
		case 2:
		Gpio_writePort(&FND_DATA_PORT,fndFont[fndNum / 10 % 10]);		// 십의 자리
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_3, GPIO_PIN_RESET);
		break;
		
		case 3:
		Gpio_writePort(&FND_DATA_PORT, fndFont[fndNum % 10]);			// 일의 자리
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_4, GPIO_PIN_RESET);
		break;	
		
		case 4:
		if (fndColonFlag) Gpio_writePort(&FND_DATA_PORT, fndFont[FND_DP]);	// Colon on
		else  Gpio_writePort(&FND_DATA_PORT, 0x00);							// Colon off
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_2, GPIO_PIN_RESET);
		break;
		
		case 5:
		if (fnd3Dot) Gpio_writePort(&FND_DATA_PORT, fndFont[FND_DP]);	// FND3 Dot on
		else  Gpio_writePort(&FND_DATA_PORT, 0x00);							// FND3 Dot off
		Gpio_writePin(&FND_DIGIT_PORT, FND_DIGIT_3, GPIO_PIN_RESET);
		break;
	}
}
void FND_ISR_Process()
{
	FND_dispNum(fndData);
}
void FND3_dotOn()
{
	fnd3Dot = 1;
}
void FND3_dotOff()
{
	fnd3Dot = 0;
}

FND.h

#ifndef FND_H_
#define FND_H_

#include <avr/io.h>
#include "../../periph/GPIO/Gpio.h"

#define	FND_DIGIT_DDR	DDRE
#define	FND_DIGIT_PORT	PORTE
#define	FND_DATA_DDR	DDRF
#define	FND_DATA_PORT	PORTF
#define	FND_DIGIT_1		4   //D1
#define	FND_DIGIT_2		5   //D2
#define	FND_DIGIT_3		6   //D3
#define	FND_DIGIT_4		7   //D4
#define FND_DP 10
#define USE_DP 5
#define NONUSE_DP 4

void FND_setFndData(uint16_t data);
void FND_init();
void FND_colonOn();
void FND_colonOff();
void FND_dispNum(uint16_t fndNum);
void FND_ISR_Process();
void FND3_dotOn();
void FND3_dotOff();

#endif /* FND_H_ */

LCD.c

#include "LCD.h"

uint8_t lcdControlData;

void LCD_init()
{
	Gpio_init();
	_delay_ms(15);
	LCD_writeCmdData(LCD_FUNCTION_SET);		// LCD Function Set		/ 0b00111000 / 8-bit / 2-line / 5*8 dots
	_delay_ms(5);
	LCD_writeCmdData(LCD_FUNCTION_SET);		// LCD Function Set		/ 0b00111000 / 8-bit / 2-line / 5*8 dots
	_delay_ms(1);
	LCD_writeCmdData(LCD_FUNCTION_SET);		// LCD Function Set		/ 0b00111000 / 8-bit / 2-line / 5*8 dots
	LCD_writeCmdData(LCD_FUNCTION_SET);		// LCD Function Set		/ 0b00111000 / 8-bit / 2-line / 5*8 dots
	LCD_writeCmdData(LCD_DISPLAY_OFF);		// LCD Display Off		/ 0b00001000
	LCD_writeCmdData(LCD_DISPLAY_CLEAR);	// LCD Display Clear	/ 0b00000001
	LCD_writeCmdData(LCD_ENTRY_MODE_SET);	// LCD Entry Mode Set	/ 0b00000110
	LCD_writeCmdData(LCD_DISPLAY_ON);		// LCD Display On		/ 0b00001000
}
void Gpio_init()
{
	Gpio_initPin(&LCD_CONTROL_DDR, LCD_RS, OUTPUT);
	Gpio_initPin(&LCD_CONTROL_DDR, LCD_RW, OUTPUT);
	Gpio_initPin(&LCD_CONTROL_DDR, LCD_E, OUTPUT);
	Gpio_initPort(&LCD_DATA_DDR, OUTPUT);
}
void Gpio_writeControlData(uint8_t data)
{
	LCD_CONTROL_PORT = data;
}
void Gpio_writeData(uint8_t data)
{
	LCD_DATA_PORT = data;
}
void LCD_cmdMode()
{
	lcdControlData &= ~(1 << LCD_RS);
	Gpio_writeControlData(lcdControlData);
}
void LCD_charMode()
{
	lcdControlData |= (1 << LCD_RS);
	Gpio_writeControlData(lcdControlData);
}
void LCD_writeMode()
{
	lcdControlData &= ~(1 << LCD_RW);
	Gpio_writeControlData(lcdControlData);
}
void LCD_enableHigh()
{
	lcdControlData |= (1 << LCD_E);
	Gpio_writeControlData(lcdControlData);
	_delay_ms(1);
}
void LCD_enableLow()
{
	lcdControlData &= ~(1 << LCD_E);
	Gpio_writeControlData(lcdControlData);
	_delay_ms(1);
}
void LCD_writeByte(uint8_t data)
{
	Gpio_writeData(data);
}
void LCD_writeCmdData(uint8_t data)
{
	LCD_cmdMode(); // RS에 대한 정보 : LCD 내부 명령 동작
	LCD_writeMode(); // RW에 Write 모드 세팅
	LCD_enableHigh();
	LCD_writeByte(data);
	LCD_enableLow();
}
void LCD_writeCharData(uint8_t data)
{
	LCD_charMode(); // RS에 대한 정보 : LCD에 글자 출력 동작
	LCD_writeMode(); // RW에 Write 모드 세팅
	LCD_enableHigh();
	LCD_writeByte(data);
	LCD_enableLow();
}
void LCD_writeString(char *str)//문자열을 주소로 반환해서 준다.
{
	for (int i=0; str[i]; i++)
	{
		LCD_writeCharData(str[i]);
	}
}
void LCD_gotoXY(uint8_t row, uint8_t col) //특정위치에 찍겠다.
{
	col %= 16;
	row %= 2;
	
	uint8_t lcdRegisterAddress = (0x40 * row) + col;
	uint8_t command = 0x80 + lcdRegisterAddress;
	LCD_writeCmdData(command);
}
void LCD_clearDisplay() //Display clear 하는 함수
{
	LCD_writeCmdData(LCD_DISPLAY_CLEAR);
}
void LCD_writeStringXY(uint8_t row, uint8_t col, char *str)
{
	LCD_gotoXY(row, col);
	LCD_writeString(str);
}

LCD.h

#ifndef LCD_H_
#define LCD_H_

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "../../periph/GPIO/Gpio.h"

#define LCD_CONTROL_PORT	PORTB
#define LCD_CONTROL_DDR		DDRB
#define LCD_DATA_PORT		PORTC
#define LCD_DATA_DDR		DDRC
#define LCD_RS		5
#define LCD_RW		6
#define LCD_E		7

#define LCD_FUNCTION_SET	0x38
#define LCD_DISPLAY_OFF		0x08
#define LCD_DISPLAY_ON		0x0C
#define LCD_DISPLAY_CLEAR	0x01
#define LCD_ENTRY_MODE_SET	0x06

void LCD_init();
void Gpio_init();
void Gpio_writeControlData(uint8_t data);
void Gpio_writeData(uint8_t data);
void LCD_cmdMode();
void LCD_charMode();
void LCD_writeMode();
void LCD_enableHigh();
void LCD_enableLow();
void LCD_writeByte(uint8_t data);
void LCD_writeCmdData(uint8_t data);
void LCD_writeCharData(uint8_t data);
void LCD_writeString(char *str);
void LCD_gotoXY(uint8_t row, uint8_t col);
void LCD_clearDisplay();
void LCD_writeStringXY(uint8_t row, uint8_t col, char *str);

#endif /* LCD_H_ */

LED.c

#include "LED.h"

void Led_initPort(volatile uint8_t *DDR)
{
	Gpio_initPort(DDR, OUTPUT);
}
void Led_writePort(volatile uint8_t *PORT, uint8_t data)
{
	Gpio_writePort(PORT, data);
}
void Led_allOff(volatile uint8_t *PORT)
{
	Gpio_writePort(PORT, 0x00);
}
void Led_allOn(volatile uint8_t *PORT)
{
	Gpio_writePort(PORT, 0xff);
}
void Led_allToggle(volatile uint8_t *PORT)
{
	Gpio_writePort(PORT, (*PORT ^= 0xff));
}

LED.h

#ifndef LED_H_
#define LED_H_

#include <avr/io.h>
#include "../../periph/GPIO/Gpio.h"

void Led_initPort(volatile uint8_t *DDR);
void Led_writePort(volatile uint8_t *PORT, uint8_t data);
void Led_allOff(volatile uint8_t *PORT);
void Led_allOn(volatile uint8_t *PORT);
void Led_allToggle(volatile uint8_t *PORT);

#endif /* LED_H_ */

___Peripheral

GPIO.c

#include "Gpio.h"

void Gpio_initPort(volatile uint8_t *DDR, uint8_t direction)
{
	if (direction == OUTPUT)
	{
		*DDR = 0xff;
	}
	else
	{
		*DDR = 0x00;
	}
}
void Gpio_initPin(volatile uint8_t *DDR, uint8_t pinNum, uint8_t dirction)
{
	if (dirction == OUTPUT)
	{
		*DDR |= (1 << pinNum); // OUTPUT_MODE 1
	}
	else
	{
		*DDR &= ~(1 << pinNum); // INPUT_MODE 0
	}
}
void Gpio_writePort(volatile uint8_t *PORT, uint8_t data)
{
	*PORT = data;
}
uint8_t Gpio_readPort(volatile uint8_t *PIN)
{
	return *PIN;
}
void Gpio_writePin(volatile uint8_t *PORT, uint8_t pinNum, uint8_t state)
{
	if (state == GPIO_PIN_SET)
	{
		*PORT |= (1 << pinNum); // GPIO_PIN_SET 1
	}
	else
	{
		*PORT &= ~(1 << pinNum); // GPIO_PIN_RESET 0
	}
}
uint8_t Gpio_readPin(volatile uint8_t *PIN, uint8_t pinNum)
{
	return ((*PIN & (1 << pinNum)) != 0);
}

GPIO.h

#ifndef GPIO_H_
#define GPIO_H_

#include <avr/io.h>

enum {INPUT, OUTPUT};
enum {GPIO_PIN_RESET, GPIO_PIN_SET};

void Gpio_initPort(volatile uint8_t *DDR, uint8_t direction);
void Gpio_initPin(volatile uint8_t *DDR, uint8_t pinNum, uint8_t dirction);
void Gpio_writePort(volatile uint8_t *PORT, uint8_t data);
uint8_t Gpio_readPort(volatile uint8_t *PIN);
void Gpio_writePin(volatile uint8_t *PORT, uint8_t pinNum, uint8_t state);
uint8_t Gpio_readPin(volatile uint8_t *PIN, uint8_t pinNum);

#endif /* GPIO_H_ */

TIM.c

#include "TIM.h"

void TIM0_init()
{
	TCCR0 |= (1 << CS02) | (0 << CS01) | (1 << CS00); // prescaling / 1024로 동작을 의미한다.
	TIMSK |= (1 << TOIE0); // 타이머0 오버플로우 인터럽트 사용 설정.
	TCNT0 = 130;
}
void TIM2_init()
{
	TCCR2 |= (0 << CS22) | (1 << CS21) | (1 << CS20); // prescaling / 64로 동작을 의미한다.
	TCCR2 |= (1 << WGM21) | (0 << WGM20); // CTC모드
	TIMSK |= (1 << OCIE2); // OutCopare Interrupt Enable
	OCR2 = 250 - 1; // period 1ms
}

TIM.h

#ifndef TIM_H_
#define TIM_H_

#define  F_CPU 16000000UL //제일 위에 선언해줘야함. 또는 delay.h보다 위에 선언.
#include <avr/io.h>
#include <avr/interrupt.h> //인터럽트 관련한 명령을 추가할때 쓰는 헤더파일.

void TIM0_init();
void TIM2_init();

#endif /* TIM_H_ */

구현한 FAN의 모습을 담은 영상

0개의 댓글