[2024.03.21.목] 인천인력개발원 하만 세미콘 아카데미
임베디드 시스템을 위한 SW 구조설계
디지털 데이터 입출력
1. 디지털 데이터 출력
- PORT 레지스터 (출력 레지스터)
- 포트: 8개의 핀을 하나로 묶어 관리하는 것
- PORTA, PRTAB, ... PORTG까지의 레지스터
- PORTA~PORTF에는 0~7까지 8개의 비트가 존재
- 비트 표현: PORTA1, PORTA2, ... PORTXn으료 표시 가능(X는 포트 종류, n은 비트) - PORTG에는 5개의 비트만 존재하므로 상위 3개의 비트 사용 불가
- 특정 비트를 1로 설정 시: 1<<PORTA4사용
- DDR(Data Direction Register): 핀의 입출력 방향 선택
- 데이터 핀을 사용하기 전에 입력 또는 출력 중 사용 용도를 결정하는 레지스터
- Bit OR( | )로 세팅 가능
- ex) DDRA의 0번째 비트를 입력으로 사용하기 위해 => DDRA |= 0x01; - DDRx(x = A, B, ..., G) = 0 or 1로 설정(0은 입력상태, 1은 출력상태)
- 하나의 포트를 하나의 용도로 사용 권장
2. 디지털 데이터 입력
- DDR 레지스터
- 포트를 입력상태로 설정 시 0을 설정 -> 해당 포트 중 입력으로 사용하는 비트만 0으로 설정 필요
- 특정 비트만 입력상태 0으로 만들기 위해 해당 부분만 1, 나머지는 0인 비트에서 bitNOT과 AND를 통해 구현 가능
- ex) DDRA의 0번째 비트를 출력으로 사용하기 위해 => DDRB &= ~0x01;
- PIN 레지스터(입력 레지스터)
- PINA, PINB, ..., PING까지의 레지스터
- PINx 레지스터는 DDR, PORT 레지스터와 다르게 읽기전용, 초깃값이 N/A(Not Available)
- 풀업 / 풀다운 저항
- 스위치가 open된 경우, GPIO 핀에는 아무런 회로가 연결되지 않은 것과 같은 상태
- 플로팅 상태: 개방된 핀의 입력에 무작위의 값이 가해질 수 있는 상태
- 풀업 / 풀다운 저항을 통해 플로팅 상태 해결 가능
- 풀업 저항: 저항을 Vdd쪽 회로에 설치 -> 스위치 ON(0) / OFF(1)
- 풀다운 저항: 저항을 GND쪽 회로에 설치 -> 스위치 ON(1) / OFF(0)
- 디바운스
- 바운스 현상(채터링): 기계적인 현상으로, 버튼을 누르면 내부 스프링의 진동에 의해 버튼을 여러 번 누른 효과가 나타나는 현상
채터링 현상 / 스위치를 누르고 뗄 때 탄성에 의해 상태가 빠르게 변화 - 디바운스: 바운스 현상의 제거
- 소프트웨어 이용: 시간지연을 통해 버튼의 빠른 상태 변화 무시
- 하드웨어 이용: 캐퍼시터를 통해 버튼의 빠른 상태 변화 무시(간단하고 효율적)
- 바운스 현상(채터링): 기계적인 현상으로, 버튼을 누르면 내부 스프링의 진동에 의해 버튼을 여러 번 누른 효과가 나타나는 현상
실습 1: 버튼이 눌리면 LED 순차 점멸
- 사용한 메인함수(스위치가 안눌리면 LED 순차 점멸, 눌리면 정지)
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
DDRB &= ~0x01; //B port의 0번째 비트는 입력용(0)으로, 나머지는 출력용(1)로 설정 (1111 1110 = NOT 0000 0001)
int i = 0;
while (1)
{
if(PINB & 0x01 == 1){ //B port의 0번 비트의 값이 0이라면(스위치가 눌리면)
//togglepinA(0); //0번째 비트(LED)를 점멸
//togglepinA(1); //1번째 비트(LED)를 점멸
//togglepinA(2); //2번째 비트(LED)를 점멸
}
else { //B port의 0번 비트의 값이 0이라면(스위치가 눌리면)
togglepinA(0); //0번째 비트(LED)를 점멸
togglepinA(1); //1번째 비트(LED)를 점멸
togglepinA(2); //2번째 비트(LED)를 점멸
}
}
}
- if(PINB & 0x01 == 1): 스위치가 눌리지 않을 때가 1, 눌리면 0인 상태(Pullup 저항에 의해)
- 이 조건을 0으로 하여 스위치를 눌렸을 때 점멸 실행되게 해도, 정상 작동 X (N/A 상태이므로)
- -> 전체에 대하여 NOT 연산으로 수행 가능
- 수정한 메인함수(스위치가 눌리면 작동하는 코드)
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
DDRB &= ~0x01; //B port의 0번째 비트는 입력용(0)으로, 나머지는 출력용(1)로 설정 (1111 1110 = NOT 0000 0001)
int i = 0;
while (1)
{
//if(PINB & 0x01 == 1) 스위치가 안눌리면 TRUE
if(!(PINB & 0x01 == 1)){ //스위치가 눌리면 TRUE
togglepinA(0); //0번째 비트(LED)를 점멸
togglepinA(1); //1번째 비트(LED)를 점멸
togglepinA(2); //2번째 비트(LED)를 점멸
}
}
}
실습 2: 버튼이 눌릴 때 다음 LED 점멸
- 수정한 메인함수(스위치가 눌릴 때 다음 LED를 점멸하는 코드)
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
DDRB &= ~0x01; //B port의 0번째 비트는 입력용(0)으로, 나머지는 출력용(1)로 설정 (1111 1110 = NOT 0000 0001)
int i = 0;
while (1)
{
if(!(PINB & 0x01 == 1)){ //B port의 0번 비트의 값이 0이라면(스위치가 눌리면)
int on = 1;
while(on == 1){
togglepinA(i); //0번째 비트(LED)를 점멸
if(!(PINB & 0x01 == 1)) on = 0;
}
i++;
if (i>2) i=0; //2번째 LED 점멸 후 다시 0번째부터 실행해야 하므로 i 초기화
}
}
}
- 실행 확인

- 위치를 누르지 않으면 해당 LED가 계속 점멸하도록 코드 수정
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h> //delay를 실행하기 위한 헤더파일
void togglepinA(int n){ //n: n번째 비트, dl: delay in mili-second
char b = 1 << n; //n번만큼 비트를 왼쪽으로 이동하라 (n이 1이면 10이 되어 2, n이 2이면 100이 되어 4 표현)
PORTA |= b; //위의 식을 따라 b번째 비트를 HIGH로 출력
_delay_ms(500);
PORTA &= ~b; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정}
_delay_ms(500);
}
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
DDRB &= ~0x01; //B port의 0번째 비트는 입력용(0)으로, 나머지는 출력용(1)로 설정 (1111 1110 = NOT 0000 0001)
int i = 0;
while (1)
{
if(!(PINB & 0x01 == 1)){ //B port의 0번 비트의 값이 0이라면(스위치가 눌리면)
int on = 1;
while(on == 1){
togglepinA(i); //0번째 비트(LED)를 점멸
if(!(PINB & 0x01 == 1)) on = 0;
}
i++;
if (i>2) i=0; //2번째 LED 점멸 후 다시 0번째부터 실행해야 하므로 i 초기화
}
}
}
- 작동 확인
실습 3: 세그먼트 출력 실습
1. 7세그먼트 표시장치
- 2개의 공통핀과 8개의 세그먼트 제어핀으로 구성
- - 공통핀에 Vcc/GND를 가하고 제어핀에 GND/Vcc를 가하면 해당 세그먼트가 켜지는 공통 양극/음극 방식으로 나눔



2. 7세그먼트 숫자 표현
숫자 | 세그먼트 | 제어값 | ||||||||
DP | G | F | E | D | C | B | A | 2진수 값 | 16진수 값 | |
0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0011 1111 | 3F |
1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0000 0110 | 06 |
2 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0101 1011 | 5B |
3 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0100 1111 | 4F |
4 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0110 0110 | 66 |
5 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0110 1101 | 6D |
6 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0111 1101 | 7D |
7 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0010 0111 | 27 |
8 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0111 1111 | 7F |
9 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0110 0111 | 67 |
3. 실습에 사용할 부품

4. 회로 연결

5. Solution Explorer의 Solution 우클릭- New - Project

6. 이름 입력 후 생성

7. ATmega 128 선택 후 OK

8. Soluteion 탐색기에 test02-7seg 생성 확인

9. while loop을 통해 네자리 중 한 자리에 숫자를 번갈아가며 출력하는 코드 작성
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h>
int main(void)
{
uint8_t numbers[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67
};
int i, j;
DDRD = 0xFF; //세그먼트 제어 핀 8개를 출력으로 설정
DDRC = 0x0F; //자릿수 선택 핀 4개를 출력으로 설정
while (1) //한 번의 while loop 내에서 네자리 중 한 자리에 숫자를 번갈아가며 출력하는 코드
{
for (i = 0; i < 4; i++){ //해당 자리에만 0(GND)를 출력하고 나머지에는 1을 출력하여 자리 선택
PORTC |= 0X0f;
PORTC &= ~(1 << i); //
for (j = 0; j < 10; j++){
PORTD = numbers[j];
_delay_ms(500);
}
}
}
}
주의사항! test02를 현재의 active project로 바꿔야 하므로, 프로젝트 우클릭 - Set as a Startup Project 선택

10. 컴파일을 누르면 나오는 경고창에서 확인 후, 뒤 내용 입력


11. 상단의 Tool - Rebuild solution 뒤, Add target

12. Device programming

13. 코드 작성: 한 번의 while loop 내에서 네자리 중 한 자리에 숫자를 번갈아가며 출력하는 코드
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h>
int main(void)
{
uint8_t numbers[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67
};
int i, j;
DDRD = 0xFF; //세그먼트 제어 핀 8개를 출력으로 설정
DDRC = 0x0F; //자릿수 선택 핀 4개를 출력으로 설정
while (1) //한 번의 while loop 내에서 네자리 중 한 자리에 숫자를 번갈아가며 출력하는 코드
{
for (i = 0; i < 4; i++){ //해당 자리에만 0(GND)를 출력하고 나머지에는 1을 출력하여 자리 선택
PORTC |= 0X0f;
PORTC &= ~(1 << i); //
for (j = 0; j < 10; j++){
PORTD = numbers[j];
_delay_ms(500);
}
}
}
}
14. 작동 확인
15. 세그먼트 네자리에 1234를 표시하는 코드 작성
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h>
int main(void)
{
uint8_t numbers[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67
};
int i, j;
DDRD = 0xFF; //세그먼트 제어 핀 8개를 출력으로 설정
DDRC = 0x0F; //자릿수 선택 핀 4개를 출력으로 설정
void display_digit(int position, int number){
PORTC |= 0x0F;
PORTC &= ~(1 << (position - 1));
PORTD = numbers[number];
}
while(1){
display_digit(1, 1);
_delay_ms(5);
display_digit(2, 2);
_delay_ms(5);
display_digit(3, 3);
_delay_ms(5);
display_digit(4, 4);
_delay_ms(5);
}
}
16. 작동 확인

'하만(Harman) 세미콘 반도체 설계 과정 > 임베디드 시스템을 위한 SW 구조설계' 카테고리의 다른 글
하만(Harman) 세미콘 아카데미 15일차 - SW 구조설계(Pullup 저항, ATmega128 인터럽트, 스탑워치 설계) (20) | 2024.03.27 |
---|---|
하만(Harman) 세미콘 아카데미 12일차 - SW 구조설계( 7세그먼트 - 16진수 출력, 스톱워치 구현) (23) | 2024.03.22 |
하만(Harman) 세미콘 아카데미 10일차 - SW 구조설계(ATmega128, Atmel Studio 설치, Microchip Studio 설치) (23) | 2024.03.20 |
하만(Harman) 세미콘 아카데미 7일차 - SW 구조설계(ATmega128, 과제 수행) (48) | 2024.03.15 |