관리 메뉴

거북이처럼 천천히

GPIO - LED control (2) 본문

Embedded Programming (AVR)/Atmega 128A (실습)

GPIO - LED control (2)

유로 청년 2024. 5. 25. 13:02

1) 환경 : Microchip studio

2.) 목표 : 0핀 -> 3핀 -> 0핀, 7핀 -> 4핀 -> 7핀 LED를 Shift하여 출력

3) Source code

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define TIME 150

int main(void) {
   // PORTD의 8핀을 출력으로 설정
   // PORTD = 1111 1111
   DDRD = 0xff;
   
   while(1) {
      for(uint8_t i=0; i<4; i++) {
         // 7번째 핀과 0번째 핀에서부터 시작해서 
         // 7번쩨 핀은 Left Shift, 0 번째 핀은 Right Shift
         
         // OR 연산을 통해 서로 다른 Binary을 합쳐 동시에 출력을 발생시키게 만든다.
         PORTD = (PORTD1<<i) | (0x80>>i);
         _delay_ms(TIME);
      }
      
      // i의 값을 1 ~ 3으로 설정한 이유
      // 0 ~ 4까지로 설정할 경우, 0, 3, 4, 7핀이 중복해서 불이 들어오기 때문에 
      // 이를 방지하기 위해 1 ~ 3으로 설정
      for(uint8_t i=1; i<3; i++) {
         // 4번째 핀과 3번째 핀에 도착하면 방향 전환을 하여 다시 시작점으로 돌아가기.
         PORTD = (0x10<<i) | (0x08>>i);
         _delay_ms(TIME); 
      }
   }
}

 

4) 구현 

 

Shift연산자와 OR연산자를 통해 구현

 


 

2.) 목표 : 0핀 -> 3핀 -> 0핀, 7핀 -> 4핀 -> 7핀 LED를 Shift하여 출력하는데, Shift 하는 비트를 제외하고,

               나머지 비트에서만 불이 들어오도록 설계

3) Source code

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define TIME 150

int main(void) {
   // PORTD의 모든 핀을 출력으로 설정
   DDRD = 0xff;
   
   while(1) {
      
      // ~, NOT 연산자를 통해 특정 비트의 값을 0, 나머지 비트 값들을 1로 만들어 줌으로서
      // 특정 비트만 LED가 안나오고, 나머지 비트에서는 LED가 나오도록 설계
      for(int i=0; i<8; i++) {
         PORTD = ~(PORTD1<<i);
         _delay_ms(TIME);
      }
      
      for(int i=1; i<7; i++) {
         PORTD = ~(0x80>>i);
         _delay_ms(TIME);
      }
   }
}

 

※ ~ (NOT 연산자)를 이용하여 반전을 발생시킬 수 있다.

 

4) 구현 

 

Shift연산자, OR 연산자, NOT 연산자를 사용하여 구현

 


 

2.) 목표 : 0핀 -> 3핀 -> 0핀, 7핀 -> 4핀 -> 7핀 LED를 Shift하여 출력하는데, Shift 비트에서는 LED가 들어오지 않고, 나머지 비트에서만 LED가 출력되어야 한다.

3) Source code

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define TIME 150

int main(void) {
   // PORTD의 8핀 전부를 출력으로 설정
   DDRD = 0xff;
   
   while(1) {
      // 0번째핀은 Right Shift, 7번째 핀은 Left Shift연산 수행
      for(int i=0; i<4; i++) {
         // Shift 연산자가 OR Bit 연산자보다 우선순위가 높다.
         PORTD = ~(PORTD1<<i  | 0x80>>i); 
         _delay_ms(TIME);
      }
      
      // 4번째핀은 Left Shift, 3번째 핀은 Right Shift연산 수행
      for(int i=1; i<3; i++) {
         PORTD = ~(0x10<<i | 0x08>>i);
         _delay_ms(TIME);
      }
   }
}

 

 

4) 구현

 

첫 번째 구현에서 반전을 추가한 경우


2.) 목표 : 0핀 -> 3핀으로 Shift할 때는 일반적인 출력이 나오지만, 4핀 -> 7핀으로 Shift할 때는 반전 출력이 나온다.7핀 -> 4핀으로 Shift할 때는 반전 출력이 나오지만, 3핀 -> 0핀으로 Shift할 때는 일반적인 출력이 나온다.

3) Source code    (Pointer + separate compilation으로 구현)

 

#include "personal.h"

int main(void) {
   // Initialization Data Direction Register.
   init_DDR();
   
   // Define start point.
   uint8_t data = PORTD0;
   
   while(1) {
      // Left Shift
      for(uint8_t i=0; i<8; i++)
         left_shift(&data, i);
      
      // Right Shift
      for(uint8_t i=1; i<7; i++)
         right_shift(&data, i);
   }
}

 

#include "personal.h"

// Initialization DDR(Data Direction Register)
void init_DDR() {
   LED_DDR = 0xff;
}

// GPIO Output
void GPIO_Output(uint8_t data) {
   LED_PORT = data;
   _delay_ms(TIME);
}

// Left Shift
void left_shift(uint8_t *data, uint8_t index_shift) {
   if(PORTD0<=index_shift && index_shift<PORTD4) *data = (*data>>PORTD7 | PORTD1<<index_shift);
   else *data = (*data<<PORTD7 | (~(PORTD1<<index_shift) & (0xf0)));
   
   GPIO_Output(*data);
}

// Right Shift 
void right_shift(uint8_t *data, uint8_t index_shift) {
   if(PORTD0<=index_shift && index_shift<PORTD4) *data = (*data<<PORTD7 | (~(0x80>>index_shift) & (0xf0)));
   else *data = (*data<<PORTD7 | 0x80>>index_shift);
   
   GPIO_Output(*data);
}

 

#ifndef COMMON_H_
#define COMMON_H_

// re-substitute CLK & include library file.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#endif /* COMMON_H_ */
#ifndef PERSONAL_H_
#define PERSONAL_H_

// Include common header file.
#include "common.h"

// Substitute constant
#define LED_DDR DDRD      
#define LED_PORT PORTD
#define TIME 200

// Function prototype
void init_DDR();
void GPIO_Output(uint8_t data);
void left_shift(uint8_t *data, uint8_t index_shift);
void right_shift(uint8_t *data, uint8_t index_shift);

#endif /* PERSONAL_H_ */

 

 

4) 구현

 

포인터와 분할 컴파일을 이용

 

 


※ 기타 

1) 경기인력개발원에서 수업중 필기 했던 코드 

    → 두 번째 구현과 유사한 코드이지만, 큰 차이 없음

     나중을 대비하여 Source code 첨부 

#define F_CPU 16000000UL 
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
   // F포트를 출력으로 사용하겠다는 것을 표현하기 위해 1로 설정
   // 만약 D포트를 출력으로 사용하겠다고 선언하고 싶으면 DDRD = 0xff;라고 선언 
   DDRF = 0xff; //0b11111111; F포트 전체를 출력으로 설정
   
    while (1) 
    {
      // F포트에서 몇번째 단자(비트)에 어떤 출력(High level? Low level? 어떤 단자에 어떤 출력을 줄 것인지?)
      // PORTF = 0xff; 는 F포트 전체 출력으로 High level로 주겠다는 의미
      PORTF = 0xff; // 8비트 전체를 출력(High)
      _delay_ms(500); // 0.5초 동안 정지.
      
      // PORTF = 0x00; 는 F포트 전체 출력으로 Low level로 주겠다는 의미
      PORTF = 0x00; // 8비트 전체를 끔(Low)
      _delay_ms(500); // 0.5초 동안 정지.
    }
}

 

 

2) Atmega128a Datasheet에서 DDRD, PORTD 

PORTD에 대한 데이터 시트
DDRD에 대한 데이터 시트

'Embedded Programming (AVR) > Atmega 128A (실습)' 카테고리의 다른 글

궁금증 정리 노트 - Atmega128A  (0) 2024.05.25
Pointer  (0) 2024.05.25
Separate Compilation  (0) 2024.05.25
Atmega128a의 변수 정리  (0) 2024.05.25
GPIO - LED control (1)  (0) 2024.05.25