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의 모습을 담은 영상