< LED_div >
저번 블로그 글에서의 LED에 관하여 내용을 이어가보면, 이번에도 총 3개의 파일이 필요하다.
또한, 아래 사진과 같은 LED_bar를 사용하여 결과값을 확인한다.
/*
* led.h
*/
#ifndef LED_H_
#define LED_H_
#include <avr/io.h>
typedef struct LED
{
volatile uint8_t *port; // LED가 연결될 포트
uint8_t pinNumber; // LED가 연결될 핀번호
}LED; // 내가 만든 LED라는 데이터형
// 사용자 정의 함수
void ledInit(LED *led);
void ledOn(LED *led);
void ledOff(LED *led);
#endif /* LED_H_ */
/*
* led.c
*/
#include "led.h"
void ledInit(LED *led)
{
//DDRC = 0x01; //포트에 대한 방향 설정 0b00000001
//포트에 해당하는 핀을 출력으로 설정
*(led->port - 1) |= (1<<led->pinNumber);
//*(led->port - 1) = *(led->port - 1) | (1<<led->pinNumber)
// DDR레지스터는 PORT레지스터보다 1낮게 위치하므로
// *(led->port - 1)를 이용해서 PORT에서 DDR로 접근
}
void ledOn(LED *led)
{
// 해당 핀을 켜기
*(led->port) |= (1<<led->pinNumber);
// 내가 원하는 위치에 1을 넣기 위해
}
void ledOff(LED *led)
{
*(led->port) &= ~(1<<led->pinNumber);
// 내가 원하는 위치에 0을 넣기 위해
}
/*
* LED_div.c
*/
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "led.h"
int main(void)
{
LED ledBar; // 구조체 LED의 데이터형을 갖는 ledBar변수 선언
ledBar.port = &PORTC;
for (uint8_t i = 0; i < 8; i++)
{
ledBar.pinNumber = i;
ledInit(&ledBar);
}
//ledBar.pinNumber = 5;
//
//ledInit(&ledBar); // DDRC pinNumber핀을 출력으로 설정
while (1)
{
for (uint8_t i = 0; i < 8; i++)
{
ledBar.pinNumber = i;
ledOn(&ledBar);
_delay_ms(100);
//for (uint8_t i = 0; i < 8; i++)
//{
//ledBar.pinNumber = i;
//ledOff(&ledBar);
//}
}
_delay_ms(1000);
for (uint8_t i =0; i < 8; i++)
{
ledBar.pinNumber = i;
ledOff(&ledBar);
_delay_ms(100);
}
//for (uint8_t i = 0; i < 8; i++)
//{
//ledBar.pinNumber = i;
//ledOn(&ledBar);
//_delay_ms(100);
//ledOff(&ledBar);
//_delay_ms(100);
//}
//ledOn(&ledBar);
//_delay_ms(300);
//ledOff(&ledBar);
//_delay_ms(300);
}
}
저번의 LED_pointer와 다르게 이번에는 시간이 지나도 다른 LED가 꺼지는 것이 아니라
차례대로 모두 켜진후 유지했다가 다시 차례대로 모두 꺼지는 것을 구현하는 것이다.
< BUTTON >
이번에는 버튼을 이용하여 LED_bar가 작동되도록 구현한다.
버튼은 기본적으로 핀에 연결하여 버튼이 눌려지면 Vcc(논리 1), 버튼이 눌려지지 않으면 0이 가해지도록 한다.
버튼 입력을 읽어 들일때도 GPIO 핀을 입력 또는 출력으로 사용할 수 있도록 설정하는 DDRx 레지스터를 사용한다.
/*
* Button.c
*/
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRC = 0xff; // LED연결된곳
DDRD &= ~(1<<DDRD0); // DDRD0번핀을 입력으로 설정
DDRD &= ~(1<<DDRD1); // DDRD1번핀을 입력으로 설정
DDRD &= ~(1<<DDRD2); // DDRD2번핀을 입력으로 설정
//PORTD |= (1<<PORTD0); // 내부풀업 활성화
uint8_t ledData = 0x01;
uint8_t buttonData; // PIND
PORTC = 0x00; // LED 꺼진 상태로 출발해서
while (1)
{
buttonData = PIND;
// 0번핀 버튼 눌르면 LED 좌측이동(delay 300) 하고 꺼짐
if ((buttonData & (1<<0)) == 0)
{
// 비트시프트
for (uint8_t i = 0; i < 8; i++)
{
PORTC = ledData;
ledData = (ledData >> 7) | (ledData << 1);
_delay_ms(300);
}
PORTC = 0x00;
}
// 1번핀 버튼 눌르면 LED 우측이동(delay 300) 하고 꺼짐
if ((buttonData & (1<<1)) == 0)
{
// 비트시프트
for (uint8_t i = 0; i < 8;i++)
{
PORTC = ledData;
ledData = (ledData >> 1) | (ledData << 7);
_delay_ms(300);
}
PORTC = 0x00;
}
// 2번핀 버튼 눌르면 LED 점멸 3번(delay 300)
if ((buttonData & (1<<2)) == 0)
{
for (uint8_t i = 0; i < 3; i++)
{
PORTC = 0xff;
_delay_ms(300);
PORTC = 0x00;
_delay_ms(300);
}
}
}
}
소스코드에서는 0번 버튼을 눌렀을때 LED가 좌측으로 순서대로 켜졌다 꺼짐을 반복하고
1번 버튼을 눌렀을때 LED가 우측으로 순서대로 켜졌다 꺼짐을 반복하고
2번핀을 눌렀을때 LED 8개 모두 점멸을 3번하는 것을 구현했다.
< Button_toggle >
이번에는 버튼 0번은 LED가 켜지도록하고, 버튼 1번은 LED가 꺼지도록 하며,
버튼 2번은 버튼을 누를때마다 켜졌다가 꺼졌다가를 반복하는 것을 구현했다.
/*
* button.h
*/
#ifndef BUTTON_H_
#define BUTTON_H_
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#define LED_DDR DDRC
#define LED_PORT PORTC
#define BUTTON_DDR DDRD
#define BUTTON_PIN PIND
#define BUTTON_ON 0
#define BUTTON_OFF 1
#define BUTTON_TOGGLE 2
enum
{
PUSHED, // 0
RELEASED // 1
};
enum
{
NO_ACT, // 0
ACT_PUSHED, // 1
ACT_RELEASE // 2
};
typedef struct _button{
volatile uint8_t *ddr; // 버튼 연결 방향 설정 포트
volatile uint8_t *pin; // 연결된 핀
uint8_t btnPin; // 핀번호
uint8_t prevState; // 버튼의 상태 플래그(깃발)
}Button;
void buttonInit(Button *button, volatile uint8_t *ddr, volatile uint8_t *pin, uint8_t pinNum);
uint8_t buttonGetState(Button *button);
#endif /* BUTTON_H_ */
/*
* button.c
*/
#include "button.h"
void buttonInit(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); // pinNum 번호를 입력으로 방향 설정
}
uint8_t buttonGetState(Button *button)
{
uint8_t curState = *button->pin & (1<<button->btnPin);
if((curState == PUSHED) && (button->prevState == RELEASED)) // 안누른 상태에서 누르면
{
_delay_ms(50); // debounce code(채터링현상 방지)
button->prevState = PUSHED; // 이전상태를 누른 상태로 변화
return ACT_PUSHED; // 눌럿다고 반환
}
else if((curState != PUSHED) && (button->prevState == PUSHED)) // 누른 상태에서 떼면
{
_delay_ms(50);
button->prevState = RELEASED; // 이전상태를 뗀 상태로 변화
return ACT_RELEASE; // 떼었다고 반환
}
return NO_ACT; // 아무것도 안할 때...
}
/*
* Button_1.c
*/
#include "button.h"
int main(void)
{
LED_DDR = 0xff; // LED 출력방향 설정
Button btnOn;
Button btnOff;
Button btnToggle;
buttonInit(&btnOn, &BUTTON_DDR, &BUTTON_PIN, BUTTON_ON);
buttonInit(&btnOff, &BUTTON_DDR, &BUTTON_PIN, BUTTON_OFF);
buttonInit(&btnToggle, &BUTTON_DDR, &BUTTON_PIN, BUTTON_TOGGLE);
while (1)
{
if (buttonGetState(&btnOn) == ACT_RELEASE)
{
LED_PORT = 0xff;
}
if (buttonGetState(&btnOff) == ACT_RELEASE)
{
LED_PORT = 0x00;
}
if (buttonGetState(&btnToggle) == ACT_RELEASE)
{
LED_PORT ^= 0xff;
}
}
}
LED_div, Button, Button_toggle 끝!
'Harman 세미콘 아카데미 > Atmega128a' 카테고리의 다른 글
[ATmega 128a]⑥ - LCD 8bit, LCD 8bit counter, LCD 4bit (0) | 2024.06.18 |
---|---|
[ATmega 128a]⑤ - CTC, NOMAL, FastPWM, PWM16BIT, dalay 함수 (0) | 2024.06.18 |
2024.6.4 이전(3) [ATmega 128a]④ - FND (0) | 2024.06.18 |
2024.6.4 이전(1) [ATmega 128a]② - 데이터 핀, LED_shift, LED_pointer (0) | 2024.06.18 |
[ATmega 128a]① - Microchip Studio 다운로드 & 기본 설정법 (0) | 2024.06.18 |