[2024.03.20.수] 인천인력개발원 하만 세미콘 아카데미
임베디드 시스템을 위한 SW 구조설계
마이크로 컨트롤러 & CISC / RISC
- 마이크로 컨트롤러(칩 위의 컴퓨터)
- ex) ATmega128, 아두이노 등
- 컴퓨터의 메인보드+메
- 마이크로 프로세서+메모리+입출력 인터페이스
- 컴퓨터 메인보드와 하드디스크 기능을 하나의 IC칩으로 집적시켜 만든 반도체 소자
- 특수 목적용 낮은 사양의 컴퓨터 / 작고 간단한 제어장치 제작에 사용
- 임베디드 시스팀: 다른 시스템의 일부로 사용
- 마이크로컨트롤러 VS. 데스크톱 컴퓨터
항목 마이크로컨트롤러 데스크톱 컴퓨터 CPU ATmega128 인텔 Core i7 비트 8 64 메모리 128KB 8GB 클록 16MHz 3.4GHz(Quad Core)
- 마이크로 프로세서
- 중앙처리장치(CPU)를 하나의 IC칩으로 집적시킨 반도체 소자
- 직렬 통신
- 동기식(Sync): 여러 번에 걸쳐 전송되는 데이터 비트 구분을 위해 동기화 클록 사용(SPI, I2C 방식 사용)
- 비동기식(Async): 전송 속도를 약속하여 사용하고 별도의 클록을 사용하지 않음. 동일 속도로 송수신하지 않으면 잘못된 데이터 전달 (UART 방식 사용)
- 교차 개발 환경
- 교차 컴파일러(아트멜 스튜디오)에서 개발된 기계어 파일을 ISP/시리얼 방식으로 프로그램 다운/업로드
- CISC VS. RISC: 하드웨어 수준에서 지원되는 명령어의 개수로 구분
- CISC(Complex Instruction Set Computer)
- 복잡한 명령 한 번에 처리 가능하나 하드웨어가 복잡
- 명령어에 따라 필요한 클록 수가 다름 - RISC (Reduced Instruction Set Computer)
- 하드웨어가 간단하지만 복잡한 명령을 여러번 간단한 명령으로 처리
- 명령어가 동일한 수의 클록을 필요로 하므로 파이프라인 도입 간단 - CISC와 RISC 비교
구분 CISC RISC 명령어 개수 많음(1000개 내외) 적음(100개 내외) 프로그램 크기 작음 큼 하드웨어 복잡도 높음 낮음 소프트웨어(컴파일러) 복잡도 낮음 높음 명령어당 클록 수 가변 고정 전력소모 많음 적음 호환성 높음 낮음 대표적 CPU 제조사 인텔 ARM
- CISC(Complex Instruction Set Computer)
ATmega 128 소개
1. ATmega128: 고성능, 저전력 마이크로 컨트롤러
2. ATmega128 핀
- 전원 핀 7개: GND, VCC(디지털 전원) / AVCC(아날로그 전원), AREF(아날로그 기준 전압)
- 크리스털 연결 핀 2개(XTALn)
- 리셋 핀 1개
- PEN 핀 1개
- 데이터 입출력 핀 53개: 포트(A~G)단위로 8개 핀(8Bti 표현)을 묶어서 관리. G포트만 5개 핀 할당
- 주로 하나의 핀이 두 개 이상의 기능
- - ex) 40번 핀은 PC5(Port C의 5번 핀)과 A13(Analog 데이터 입력을 위한 13번 핀) 두 개의 이름을 가짐
3. 입출력 레지스터
- 8비트의 메모리
- 실행 명령어, 피연산자, 계산 결과 등의 임시 저장 공간
4. 메모리 주소
- 플래시메모리, SRAM, EEPROM은 각각 별도의 메모리 주소를 가짐
5. 플래시메모리
- 128KB의 메모리에 2바이트 단위로 명령어 저장
- 16비트의 0X0000~0XFFFF주소 사용
- 애플리케이션 프로그램 영역+부트로더 영역
6. 시스템 클록
- 클록: 디지털 시스템에서 동작의 기준이 되는 신호
7. 명령어 실행
- 명령어 읽기&명령어 실행의 2단계가 파이프라인에 의해 중첩되어 실행(1클록에 1개 명령 실행 가능, RISC구조이므로 가능)
- 파이프 라인: 한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조
개발 환경 설정[Atmel Studio(=Microchip Studio) 설치]
1. 아트멜 스튜디오 설치
- 아트멜 스튜디오(AVR Studio): ATmega128개발사 아트멜에서 제공하는 무료 통합 개발환경
- 다운로드 위치: https://www.microchip.com/en-us/tools-resources/develop/microchip-studio
- 상단 카테고리 - Tools and Resources - Develop - Microchip Studio for AVR and SAM Devices
스크롤을 내려 Microchip Studio for AVR and SAM Devices- Web Installer 설치
2. ATmega128을 브레드보드에 연결하고, 전원 선 연결
3. 장치관리자 - 포트 확인
4.sillabs.com 사이트 - Downloads - CP210x_Windows_Drivers.zip 다운로드
CP210x USB to UART Bridge VCP Drivers - Silicon Labs
The CP210x USB to UART Bridge Virtual COM Port (VCP) drivers are required for device operation as a Virtual COM Port to facilitate host communication with CP210x products. These devices can also interface to a host using the direct access driver.
www.silabs.com
5. 압축 해제 후 컴퓨터 비트에 맞게 설치
6. ATmega128 컴퓨터에 연결 후 장치관리자의 포트 재확인
7. 1번 과정에서 설치한 Microchip Studio 실행
8. Menu 탭 - File - New - Project
9. New Project 창에서 GCC C Executable Project 선택 - 이름 설정(test01)
10. Location은 C:\Users\SYSTEM-00\source\repos\Work에 ATmega 폴더 생성 후 선택
11. Device Selection: ATmega128 선택
12. Visual Studio와 유사한 프로젝트가 생성됨
13, 상단 메뉴 - Projects - test01 properties - 아래 내용 입력
14. 상단 메뉴 - Tools - Add Target
15. 다음과 같이 설정(COM 포트는 장치관리자에서 확인한 포트 설정) - Apply
16. Tools - Device Programming - Tool에 STK500, Device에 ATmega128, Interface에 ISP 선택 후 Apply
17. 에러 발생 시 보드의 파란색 스위치 이동(Interface를 ISP로 바꾸는 과정) 후 재시도
18. 코드 작성 후 실행 시 Output에 Build succeeded.와 같은 문구가 나오면 test01.elf파일 생성
19. Tools - Device Programming - Memories 탭에서 Program을 클릭하면 ATmega128에 프로그래밍
- Embeded Program에서는 무한 Loop가 기본(동작을 반복 실행해야 하므로)
20. 코드 작성 후 상단 메뉴 - Build - Rebuild Solution을 통해 elf파일 재생성
21. 파일 생성 후 Device Programming - Apply - Read - Read한 후 좌측 Memories 탭에서 프로그램 클릭
- LED 점멸 코드 예시
#define F_CPU 16000000L #include <avr/io.h> #include <util/delay.h> int main(void){ DDRA |= 0x01; //PA0(Port A의 0번째 비트) 핀을 출력으로 설정. DDR뒤의 A가 포트를 뜻함. while(1){ PORTA |= 0x01; // PA0핀에 연결된 LED 켜기(HIGH 신호 전달) _delay_ms(500); //0.5초 대기, ms(milli second)는 1/1000초 PORTA &= ~0x01; //PA0핀에 연결된 LED 끄기(LOW신호 전달) _delay_ms(500); } return 0; }
- DDRA : 입출력 레지스터. 값이 0x01이면 출력모드, 0x00이면 입력모드
- PORTA : 포트 레지스터
- ~0x01에서 ~은 BitNOT을 의미 => ~0x01: 최하위 비트를 0으로 만들어라
0x01은 0000 0001이므로, ~0x01은 1111 1110을 의미.
ATmega128 실습 1: 점등 LED 작동
[ 사용 소자 ]
1. 회로 구성
2. 코드 입력 후 컴파일
3. Tools - Device Programming - Memories - program
4. 작동 확인
5, delay_ms 시간의 오차를 수정하기 위해 코드의 가장 윗줄에 #define F_CPU 16000000L 정의
#include <avr/io.h>
#include <avr/delay.h> //delay를 실행하기 위한 헤더파일
#define F_CPU 16000000L
int main(void)
{
DDRA = 0x01; //A port의 0번째 비트(PA0)를 출력용(1)으로 사용, 나머지는 입력용(0)
int i = 0;
while (1)
{
PORTA = 0x01; //Port A의 최하위비트(0번째 비트)를 1(HIGH)로 설정
_delay_ms(1000);
PORTA = 0x00; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정
_delay_ms(1000);
}
}
6. Build - Rebuild solution
7. Tools - Device Programming - Memories에서 Program
8. 정상 작동 확인
9. Delay 시간을 0.5초로 수정
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/delay.h> //delay를 실행하기 위한 헤더파일
int main(void)
{
DDRA = 0x01; //A port의 0번째 비트(PA0)를 출력용(1)으로 사용, 나머지는 입력용(0)
int i = 0;
while (1)
{
PORTA = 0x01; //Port A의 최하위비트(0번째 비트)를 1(HIGH)로 설정
_delay_ms(500);
PORTA = 0x00; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정
_delay_ms(500);
}
}
- 코드가 다음과 같이 =이 아닌 |=인 경우 의미: 특정 비트만 조작하기 위함(특정 비트를 1과 OR 연산 -> 무조건 1이 됨)
int main(void)
{
DDRA |= 0x01; //A port의 0번째 비트(PA0)를 출력용(1)으로 사용, 나머지는 입력용(0)
int i = 0;
while (1)
{
PORTA |= 0x01; //Port A의 최하위비트(0번째 비트)를 1(HIGH)로 설정
_delay_ms(500);
PORTA |= 0x00; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정
_delay_ms(500);
}
} - 특정 비트를 0으로 만둘어주기 위해서는 0과 AND 연산 진행(나머지를 그대로 유지하기 위해 나머지 비트는 1과 AND 연산) -> 복잡하므로 다음 과정으로 진행
- 특정 비트를 0으로 만들기 위해 비트 NOT 연산자 사용
- [example] xxxx xxxx비트에서
- 세번째 비트(0x04)를 출력으로 바꿀 때: 0000 0100과 OR 연산 수행(PORTA |= 0x04)
- 세번째 비트를 입력으로 바꿀 때
- 1111 1011과 AND연산 수행
- PORTA &= ~0x04 연산 수행(위 과정과 동일한 결과)
ATmega128 실습 2: LED 2개 동시 작동
코드에 DDRA |= 0x02;를 추가하여 A포트의 1번째 비트를 출력용으로 사용, 나머지는 입력용
다음과 같이 main 함수 변경
int main(void)
{
DDRA |= 0x01; //A port의 0번째 비트(PA0)를 출력용(1)으로 사용, 나머지는 입력용(0)
DDRA |= 0X02;
int i = 0;
while (1)
{
PORTA |= 0x01; //Port A의 최하위비트(0번째 비트)를 1(HIGH)로 설정
PORTA |= 0x02; //Port A의 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA &= ~0x02; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정
PORTA &= ~0x01; //Port A의 1번째 비트를 0(LOW)로 설정
_delay_ms(500);
}
}
1. LED와 저항 추가
2. 컴파일 후 실행 확인
3. 위 코드에서 각 비트를 출력으로 선언한 것을 DDRA |= 0x03으로 동시에 출력 선언할 수 있다.
4. 마찬가지로 PORTA 출력도 동시에 PORTA |= 0x03으로 선언할 수 있다.
ATmega128 실습 3: LED 여러개 순차적으로 작동
1. 코드 수정
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/delay.h> //delay를 실행하기 위한 헤더파일
int main(void)
{
DDRA |= 0x03; //A port의 0번째 비트(PA0)와 1번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
int i = 0;
while (1)
{
PORTA |= 0x01; //Port A의 최하위비트(0번째 비트)와 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA |= 0x02; //Port A의 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA &= ~0x01; //Port A의 최하위비트(0번째 비트)와 1번째 비트를 0(LOW)로 설정
_delay_ms(500);
PORTA &= ~0x02; //Port A의 최하위비트(0번째 비트)와 1번째 비트를 0(LOW)로 설정
_delay_ms(500);
}
}
2. Device Programming 수행 후 작동 확인
3. LED와 저항 추가 후 코딩
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/delay.h> //delay를 실행하기 위한 헤더파일
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
int i = 0;
while (1)
{
PORTA |= 0x01; //Port A의 최하위비트(0번째 비트)와 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA &= ~0x01; //Port A의 최하위비트(0번째 비트)를 0(LOW)로 설정
PORTA |= 0x02; //Port A의 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA &= ~0x02; //Port A의 1번째 비트를 0(LOW)로 설정
PORTA |= 0x04; //Port A의 1번째 비트를 1(HIGH)로 설정
_delay_ms(500);
PORTA &= ~0x04; //Port A의 1번째 비트를 0(LOW)로 설정
}
}
4. 작동 확인
ATmega128 실습 4: 스위치를 통해 Input 작동
- Pull-up 저항
- 플로팅 현상: 스위치 사용 시 스위치가 열려있는 경우, 핀이 0과 1 사이에서 불안정 상태로 변동
- 플로팅 현상을 방지하기 위해 Pull-up 또는 Pull-down 저항을 사용하여 핀을 고전압 상태 또는 저전압 상태로 유지
- Pull-up 저항을 Vcc와 스위치 사이에 위치시켜 플로팅 현상을 방지할 수 있음
1. Switch 및 Pull-up 저항 설치
2. LED를 점멸하는 함수 정의
- char b = 1 << n; //n번만큼 비트를 왼쪽으로 이동하라 (n이 1이면 10이 되어 2, n이 2이면 100이 되어 4 표현)
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); }
3. main 함수 변경
int main(void)
{
DDRA |= 0x07; //A port의 0번째 비트(PA0), 1번째 비트, 2번째 비트를 출력용(1)으로 사용(0000 0011), 나머지는 입력용(0)
int i = 0;
while (1)
{
togglepinA(0); //0번째 비트(LED)를 점멸
togglepinA(1); //1번째 비트(LED)를 점멸
togglepinA(2); //2번째 비트(LED)를 점멸
}
}
4. 입력을 받는 코드 작성
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)를 점멸
}
}
}
5. 입력이 있을 때 실행하는 코드를 while문 내에 작성
- PIN~ : 입력 레지스터
- 전체 코드
#define F_CPU 16000000L #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이라면(스위치가 눌리면) //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)를 점멸 } } }
6. 풀업저항에 의해 스위치를 누르면 Port B에 입력되는 값이 0이 됨 -> 조건이 pinb가 1이 아니면 실행되도록 설정 및 실행
'하만(Harman) 세미콘 반도체 설계 과정 > 임베디드 시스템을 위한 SW 구조설계' 카테고리의 다른 글
하만(Harman) 세미콘 아카데미 12일차 - SW 구조설계( 7세그먼트 - 16진수 출력, 스톱워치 구현) (23) | 2024.03.22 |
---|---|
하만(Harman) 세미콘 아카데미 11일차 - SW 구조설계( 데이터 입출력, 버튼 LED 점멸, 7세그먼트 출력 ) (22) | 2024.03.21 |
하만(Harman) 세미콘 아카데미 7일차 - SW 구조설계(ATmega128, 과제 수행) (48) | 2024.03.15 |
하만(Harman) 세미콘 아카데미 6일차 - SW 구조설계(문자와 문자열 처리 / 사용자 정의 함수 구현 ) (56) | 2024.03.14 |