위의 계층구조를 기반으로 Stand Light를 설계해보자.
레지스터 DDR, PORT, PIN
DDR 레지스터:
- 포트의 입출력을 결정 -> 0(Low)이면 INPUT, 1(High)이면 OUTPUT이며, A ~ G의 포트 중 선택할 수 있음.
- 기본 값은 0이다.
PORT:
- DDR을 통해 출력으로 설정될 경우, PORT 레지스터를 통해서 포트의 값을 출력한다.
- 읽고 쓰는 것이 모두 가능한 레지스터
PIN:
- DDR을 통해 입력으로 설정될 경우, PIN 레지스터를 통해서 포트의 값을 입력한다.
- 읽고 쓰는 것만 가능한 레지스터
main code
//Stand_Light main
#include <avr/io.h>
#include "ap/Stand_Light/StandLight.h"
int main(void)
{
StandLight_init();
while (1)
{
StandLight_excute();
}
}
StandLight code
#include "StandLight.h"
uint8_t standLightState;
button_t btnMode, btnOff;
void StandLight_init()
{
Button_init(&btnOff, &DDRA, &PINA, 0);
Button_init(&btnMode, &DDRA, &PINA, 1);
Led_initPort(&LIGHT_DDR);
standLightState = LIGHT_OFF;
}
void StandLight_excute()
{
StandLight_eventCheck();
StandLight_run();
}
void StandLight_eventCheck()
{
switch (standLightState)
{
case LIGHT_OFF:
if (Button_getState(&btnMode) == ACT_RELEASED) {
standLightState = MODE_1;
}
break;
case MODE_1:
if (Button_getState(&btnMode) == ACT_RELEASED) {
standLightState = MODE_2;
}
else if (Button_getState(&btnOff) == ACT_RELEASED) {
standLightState = LIGHT_OFF;
}
break;
case MODE_2:
if (Button_getState(&btnMode) == ACT_RELEASED) {
standLightState = MODE_3;
}
else if (Button_getState(&btnOff) == ACT_RELEASED) {
standLightState = LIGHT_OFF;
}
break;
case MODE_3:
if (Button_getState(&btnMode) == ACT_RELEASED) {
standLightState = MODE_4;
}
else if (Button_getState(&btnOff) == ACT_RELEASED) {
standLightState = LIGHT_OFF;
}
break;
case MODE_4:
if (Button_getState(&btnMode) == ACT_RELEASED) {
standLightState = LIGHT_OFF;
}
else if (Button_getState(&btnOff) == ACT_RELEASED) {
standLightState = LIGHT_OFF;
}
break;
}
}
void StandLight_run()
{
switch (standLightState)
{
case LIGHT_OFF:
StandLight_off();
break;
case MODE_1:
StandLight_Mode_1();
break;
case MODE_2:
StandLight_Mode_2();
break;
case MODE_3:
StandLight_Mode_3();
break;
case MODE_4:
StandLight_Mode_4();
break;
}
}
void StandLight_off()
{
Led_allOff(&LIGHT_PORT);
}
void StandLight_Mode_1()
{
Led_writePort(&LIGHT_PORT, 0b00000011);
}
void StandLight_Mode_2()
{
Led_writePort(&LIGHT_PORT, 0b00001111);
}
void StandLight_Mode_3()
{
Led_writePort(&LIGHT_PORT, 0b00111111);
}
void StandLight_Mode_4()
{
Led_writePort(&LIGHT_PORT, 0xff);
}
StandLight 헤더파일
#ifndef STANDLIGHT_H_
#define STANDLIGHT_H_
#include <avr/io.h>
#include "../../driver/Button/Button.h"
#include "../../driver/Led/Led.h"
#define LIGHT_DDR DDRD
#define LIGHT_PORT PORTD
enum {LIGHT_OFF, MODE_1, MODE_2, MODE_3, MODE_4};
void StandLight_init();
void StandLight_excute();
void StandLight_eventCheck();
void StandLight_run();
void StandLight_off();
void StandLight_Mode_1();
void StandLight_Mode_2();
void StandLight_Mode_3();
void StandLight_Mode_4();
#endif /* STANDLIGHT_H_ */
Led code
#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_allOn(volatile uint8_t *PORT)
{
Gpio_writePort(PORT, 0xff);
}
void Led_allOff(volatile uint8_t *PORT)
{
Gpio_writePort(PORT, 0x00);
}
Led 헤더파일
#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_allOn(volatile uint8_t *PORT);
void Led_allOff(volatile uint8_t *PORT);
#endif /* LED_H_ */
Button code
#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 헤더파일
#ifndef BUTTON_H_
#define BUTTON_H_
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "../../periph/GPIO/Gpio.h"
enum {PUSHED, RELEASED};
enum {ACT_NONE, ACT_PUSHED, ACT_RELEASED};
typedef struct _button {
volatile uint8_t *DDR;
volatile uint8_t *PIN;
uint8_t pinNum;
uint8_t prevState;
}button_t;
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_ */
GPIO code
#include "Gpio.h"
void Gpio_initPort(volatile uint8_t *DDR, uint8_t dir)
{
if (dir == OUTPUT) {
*DDR = 0xff;
}
else {
*DDR = 0x00;
}
}
void Gpio_initPin(volatile uint8_t *DDR, uint8_t pinNum, uint8_t dir)
{
if (dir == OUTPUT) {
*DDR |= (1 << pinNum); // OUTPUT mode
}
else {
*DDR &= ~(1 << pinNum); // INPUT mode
}
}
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
}
else {
*PORT &= ~(1 << pinNum); // GPIO_PIN_RESET
}
}
uint8_t Gpio_readPin(volatile uint8_t *PIN, uint8_t pinNum)
{
return ((*PIN & (1 << pinNum)) != 0); // xxx1xxxx & 00010000 => 16
}
GPIO 헤더파일
#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 dir);
void Gpio_initPin(volatile uint8_t *DDR, uint8_t pinNum, uint8_t dir);
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_ */