__________

Designing the Future with Circuits

반도체 회로설계 취준기

하만(Harman) 세미콘 반도체 설계 과정/임베디드 시스템을 위한 SW 구조설계

하만(Harman) 세미콘 아카데미 7일차 - SW 구조설계(ATmega128, 과제 수행)

semicon_circuitdesigner 2024. 3. 15. 09:45

[2024.03.15.금] 인천인력개발원 하만 세미콘 아카데미


임베디드 시스템을 위한 SW 구조설계


ATmega128


수업 시작에 앞서 ATmega128 기본 모듈을 지급받았다.
다음주부터는 이 모듈을 이용하여 실습을 진행할 예정인데, 그에 앞서 ATmega128 모듈에 대해 알아보고자 한다.

ATmega128 기본 모듈
  • AVR 마이크로컨트롤러
    • 고성능, 저전력 AVR 8비트 마이크로컨트롤러 사용
    • 산업 제어, 스마트 홈, 자동화 시스템 등에 활용
  • 주요 특징
    • CPU 성능: 최대 16MIPS(Million Instructions Per Second)의 처리속도와 16MHz의 클록 속도
    • 메모리: 128kb의 플래시 메모리를 사용하여 대용량의 코드 저장 가능. 또한 4kb의 SRAM과 4kb의 EEPROM을 내장하여 데이터 저장과 접근에 용이
    • 입출력(I/O) 포트: 다수의 디지털 입출력 포트를 제공하며 일부는 PWM출력, 외부 인터럽트 지원. 다양한 센서, 모터 등의 주변 장치 제어 가능
    • 통신 인터페이스: UART, SPI, I2C 등 여러 종류의 시리얼 통신  지원. 이를 통해 다른 마이크로컨트롤러, 컴퓨터, 다양한 통신 모듈과의 데이터 교환 가능
    • 전원: 저전력 설계->배터리로 구동하는 시스템에 적합

[ 용어 정리 ]

  • 마이크로컨트롤러: 중앙처리장치(CPU), 메모리(RAM, ROM), 입출력 I/O포트 등이 하나의 칩 위에 통합된 소형 컴퓨터로, IC내에 구현되어 제어장치나 임베디드 시스템에 널리 사용
  • MIPS: 프로세서의 성능을 나타내는 단위. 매초 처리할 수 있는 백만개의 명령어 수를 의미
  • 클록 속도: 마이크로 컨트롤러, 디지털 시스템의 프로세서가 명령을 처리하는 속도. 1MHz는 1초동안 1백만 사이클을 의미
  • 플래시 메모리: 전원이 끊겨도 데이터를 보존하는 반도체 메모리
    • 비휘발성: 전원 공급이 중단되어도 데이터 유지
    • 재프로그램 가능: 데이터를 저장하기 전에 기존의 데이터를 지우고 새로운 데이터를 여러번 쓰기 가능
    • 빠른 접근 속도: HDD보다 데이터 접근 속도가 빠르며  SSD나 USB메모리와 같은 저장 장치에서 유용
  • SRAM(Static Random Access Memory, 정적 램): 데이터 저장에 사용되는 반도체 메모리의 한 종류
    • 빠른 접근 속도: DRAM에 비해 접근 속도가 빨라 CPU의 캐시 메모리 등 고속으로 데이터에 접근할 때 사용
    • 저전력 소모: 데디터를 유지하기 위한 새로고침이 불필요하므로 DRAM에 비해 저전력 소모
    • 단순 구조: 한 비트를 저장하기 위해 4~6개의 트랜지스터를 사용하여 구조적으로 단순하며 이를 통해 고속 데이터 접근이 가능
  • EEPROM(Electrically Erasable Programmable Read-Only Memory)
    • 비휘발성: 전원 공급이 중단되어도 데이터 유지
    • 재프로그래밍 가능: 데이터를 전기적으로 지우고 다시 쓸 수 있어 데이터 수정이 용이
    • 단위별 데이터 조작: 데이터를 바이트 단위로 읽고쓰기가 가능하며, 개별적인 데이터 수정이 가능
  • PWM(Pulse Width Modulation 출력, 펄스 폭 변조): 전기 신호 폭의 변조를 통해 전력 양을 제어하는 방식
     
    • 일정한 주파수를 갖는 사각파 형태의 펄스로 구성. 각 펄스의 "Duty Cycle"이라 불리는 '켜짐'상태의 지속 시간을 조절하여 출력 전력 제어(Duty Cycle은 펄스의 전체 주기 대비 켜진 상태가 차지하는 비율료 표현)
    • 고효율: 전력 손실을 최소화하는 방식으로 전력을 제어하여 에너지 효율이 매우 높음
    • 정밀 제어: 모터의 속도, LED의 밝기 등을 정밀하게 제어 가능
    • 유연성: 주파수와 Duty Cycle을 조절하여 다양한 출력 요구 사항 만족 가능

 
<함수 선언 및 메인함수 형성>

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <math.h>

//함수 선언 모음
void work01();
void work02();	//ASCII 코드표 출력
void work03();	//swap 함수 실습
void work04();	//printf 실습
void work05();	//최대공약수 출력
void work06();	//수학 함수 사용
void work07();

//사용자 정의 함수
void swap(int *a, int *b);
int Factors(int a);
int cont(void);	//m을 누르면 cont값을 1을 반환하여 메뉴로 돌아오고, 그 외의 값을 누르면 프로그램 재실행

int main()
{
	int n;
	void* pf[] = { work01, work02, work03, work04, work05, work06, work07 };//type이 정해지지 않은 포인터 배열, 내부의 배열요소는 함수의 주소
	void (*pfunc)();								//return값이 없고 인자도 필요 없는 포인터 함수 선언

	while (1) {
		printf("\n<실행 기능 선택>\n");
		printf("1. scanf 함수 실습\n ");
		printf("2. ASCII 코드표 출력\n");
		printf("3. swap 함수 실습\n");
		printf("4. 입력한 숫자만큼 * 출력)\n");
		printf("5. 문자를 입력받아 개수를 줄여가며 출력)\n");
		printf("6. 최대공약수 출력\n");
		printf("7. 수학 함수 사용\n");
		printf("0. 종료\n");
		printf("=====================================\n > ");
		scanf("%d", &n);
		printf("\n");

		if (n == 0)	return;	//0 입력 시 함수 종료

		pfunc = pf[n - 1];	//배열은 0부터 시작하므로 1을 빼줌
		pfunc();			//위에서 지정한 함수를 호출
	}
}

 
<가장 아랫부분에 반복 실행 여부 확인하는 cont함수 본체 정의>

int cont(void) {

	printf("\n\n[실행이 끝났습니다. 메뉴로 돌아가려면 \"m\", 계속하려면 다른 키를 입력하세요.]\n>");
	char select = _getch();
	printf("select = %c\n", select);

	if (select == 109) {
		printf("\n[메뉴로 돌아갑니다.]\n\n"); return 1;
	}
	else {
		printf("\n[다시 실행합니다.]\n\n");	return 0;
	}
}

과제 1. scanf함수 실습


  • 첫 번째 줄: scanf함수를 이용하여 문자열을 입력받고 한 문자씩 띄어서 출력(char 배열 이용)
  • 두 번째 줄: 첫 번째 줄에서 대소문자가 혼합된 경우 문자열을 모두 대문자로 변환하여 출력
  • 코드 작성
    void work01() {
    	while (1) {
    		char string[100];	//입력받을 문자열 메모리공간
    		char blank[200];	//띄어쓰기 수행할 메모리공간
    		printf("\n 문자열을 입력하세요.\n>");
    		scanf("%s", &string);	//문자열을 입력받아 string에 저장
    
    		printf("\n입력된 문자열은 다음과 같습니다: %s\n", string);
    
    		int length;
    
    		for (length = 0; length < sizeof(string); length++)	//입력한 문자열의 길이 확인
    		{
    			if (*(string + length) == NULL) break;
    		}
    
    
    		printf("\n문자열의 한 칸씩 띄워 출력합니다.\n");
    
    		for (int i = 0; i < length * 2; i++) {	//띄어쓰기 포함 시 원래 문자열 길이의 두 배의 공간이 필요하므로 그에 해당하는 수만큼 반복실행
    			*(blank + i) = 32;	//모든 요소에 빈 칸(아스키코드 32) 입력
    			if (i % 2 == 0)	//짝수번째에는 글자 입력
    			{
    				*(blank + i) = *(string + (i / 2));
    			}
    
    			*(blank + i + 1) = NULL;			//마지막 종료 반복 시 끝에 null을 붙여 끝점 지정
    		}
    		printf(">%s", blank);
    
    		printf("\n\n모든 문자를 대문자로 변환합니다.\n>");
    
    		for (int j = 0; j < length * 2; j += 2)
    		{
    			if (*(blank + j) > 96 && *(blank + j) < 123) {	//입력된 문자가 소문자이면
    				*(blank + j) = *(blank + j) - 32;
    			}
    		}
    		printf("%s", blank);
    
    		if (cont() == 1) break;
    	}
    }
  • 실행 화면

과제 2. ASCII 코드표 출력 - 미완성


  • 다음과 같은 형식으로 출력(가로 3열)
  • [10진수]   [16진수]   문자
  • 코드 작성
    void work02() {
    	while (1) {
    		printf(" Dec     Hx    Char\n");
    		for (int i = 1; i < 128; i++) {
    			printf("[%4d]   [%4X]   %4c    ", i, i, i);
    
    			if ((i) % 3 == 0) printf("\n");
    		}
    		if (cont() == 1) break;
    	}
    }
  • 실행 화면


과제 3. swap 함수 실습


  • 두 개의 수를 입력받아 각각의 변수에 저장하여 출력하고, 두 변수의 값을 교환하여 다시 저장하고 출력
  • 코드작성
    void work03() {
    	while (1) {
    		char buf[100];
    		int* pbuf;
    		int num1;
    		int num2;
    
    		printf("[두 숫자를 입력받아 변수에 저장하고, 이를 교환하여 출력합니다.]\n");
    		printf("num1에 저장할 숫자를 입력하세요.\n>");
    		scanf("%d", &num1);
    
    		//printf("num1의 주소값은 %08x\n", &num1);
    
    		printf("\nnum2에 저장할 숫자를 입력하세요.\n>");
    		scanf("%d", &num2);
    
    		printf("\nnum1: %d, num2: %d\n\n", num1, num2);
    		printf("두 변수의 값을 교환하여 출력합니다.\n\n");
    
    		//printf("num2의 주소값은 %08x   \n", &num2);
    
    		int* a = &num1;
    		int* b = &num2;
    
    		//printf("a의 주소값은 %08x\n", a);
    		//printf("b의 주소값은 %08x\n", b);
    
    		swap(a, b);
    
    		//printf("a의 주소값은 %08x\n", a);
    		//printf("b의 주소값은 %08x\n", b);
    
    		printf("교환된 값 num1: %d, num2: %d\n", *a, *b);
    
    
    		if (cont() == 1) break;
    	}
    }
    
    //사용자 정의 함수
    void swap(int* a, int* b) {
    	int* pBuf;
    	int temp[500];
    	//printf("a 값 보기: %x\n", a);
    	pBuf = temp;
    	//printf("\n%x가 pBuf의 주소, %x가 a의 주소, %x가 b의 주소!!!\n\n", &pBuf, &a, &b);
    	*pBuf = *b;
    	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);
    	//printf("pBuf의 값 %d, b의 값 %d\n", *pBuf, *b);
    	*b = *a;
    	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);
    	*a = *pBuf;
    	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);
    
    }
  • 실행 화면

과제 4. 홀수를 입력받아 가장 아랫줄이 입력받은 홀수개의 *로 이루어진 피라미드 출력


  • 홀수를 입력받아 가장 아랫줄이 입력받은 홀수개의 *로 이루어진 피라미드 출력
    • 예) 숫자(홀수)를 입력하시오 > 5
            *
           ***
          *****
  • 코드 작성
    void work04() {
    	while (1) {
    		int n;
    
    		printf("숫자(홀수)를 입력하시오 >");
    		scanf("%d", &n );
    
    
    		printf("\n");
    		for (int repeat = 0; repeat < (n - 1) / 2 + 1; repeat++)
    		{
    			for (int i = (n - 1) / 2 - repeat; i > 0; i--) {
    				printf(" ");
    			}
    			for (int j = 1; j < (repeat+1) * 2; j++)
    			{
    				printf("*");
    			}
    			printf("\n");
    		}
    
    		if (cont() == 1) break;
    	}
    }
  • 실행 화면

과제 5. 문자를 입력받아 다음의 형태로 출력


  • 예) 문자를 입력하시오 > E
    AAAAA
       BBBB
        CCC
           DD
              E
  • 코드작성
    void work05() {
    	while (1) {
    		int character = 0;
    		printf("문자를 입력하시오 >");
    		scanf(" %c", &character);
    		int A = 65;
    
    		for (int i = 64; i < character; i++) {
    			for (int blank = 65; blank < A; blank++)
    			{
    				printf(" ");
    			}
    			for (int wr = A - 1; wr < character; wr++)
    			{
    				printf("%c", A);
    			}
    			printf("\n");
    			A++;
    		}
    		if (cont() == 1) break;
    	}
    }
  • 실행 화면

과제 6. 최대공약수 출력


  • 두 수를 입력받아 각 수의 약수와 최대공약수를 출력
    • 예) > 6   15
      6: 1, 2, 3, 6
      15: 1, 3, 5, 15
      6과 15의 최대공약수는 3입니다.
  • 코드 작성(미완성)
    void work06() {
    	while (1) {
    
    		int num1; int num2;
    		printf("두 개의 숫자를 한 칸 띄어서 입력하세요.\n>");
    		scanf("%d %d", &num1, &num2);
    
    		//num1의 공약수 출력
    
    		Factors(num1);
    		Factors(num2);
    
    		//최대공약수 출력
    		printf("%d와 %d의 최대공약수는 %d입니다.\n", num1, num2, gcd(num1, num2));
    
    		if (cont() == 1) break;
    
    	}
    }
    
    int Factors(int a) {
    	int count = 0;
    	printf("%d의 약수: ", a);
    	for (int i = 1; i < a; i++)
    	{
    		if (a % i == 0) {
    			printf("%d, ", i);
    			count++;
    		}
    	}
    	printf("%d입니다.\n", a);
    
    	return count + 1;
    }
    
    int gcd(num1, num2) {
    	int gcd;
    	for (int i = 1; i <= num1 && i <= num2; ++i)
    	{
    		if (num1 % i == 0 && num2 % i == 0)
    			gcd = i;
    	}
    	return gcd;
    }
  • 실행 화면

 


과제 7. 수학 함수 사용-미완성


  • sin, cos, sqrt 함수 이용 (<math.h> 헤더파일 포함)
  • 공백을 이용하여 출력 위치를 변경하여 함수 곡선을 출력
  • sin, cos, tan곡선 출력
  • 원 출력
  • 원 내부에 sin곡선을 그려 태극마크 출력

1. pi값을 사용하기 위해 위줄에 PI 선언

#define PI 3.141592

 


과제 8. 헤더파일 생성


1. 헤더파일 생성을 위해 솔루션 탐색기의 헤더파일 우클릭 -> 추가 -> 새 항목 -> 헤더파일 선택

파일 이름을 headerfile.h로 설정 후 '추가' 선택

2. 생성한 headerfile.h에 함수 선언

#include <stdio.h>
#include <conio.h>
#include <string.h>

int Factors(int a);

int gcd(int num1, int num2);

int cont(void);

void swap(int* a, int* b);

 
3. 소스파일에 headerfile.c 생성하고 headerfile에 들어갈 함수 내용 입력

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include "headerfile.h"

int Factors(int a) {
	int count = 0;
	printf("%d의 약수: ", a);
	for (int i = 1; i < a; i++)
	{
		if (a % i == 0) {
			printf("%d, ", i);
			count++;
		}
	}
	printf("%d입니다.\n", a);

	return count + 1;
}

int gcd(int num1, int num2) {
	int gcd;
	for (int i = 1; i <= num1 && i <= num2; ++i)
	{
		if (num1 % i == 0 && num2 % i == 0)
			gcd = i;
	}
	return gcd;
}

int cont(void) {

	printf("\n\n[실행이 끝났습니다. 메뉴로 돌아가려면 \"m\", 계속하려면 다른 키를 입력하세요.]\n>");
	char select = _getch();
	printf("select = %c\n", select);

	if (select == 109) {
		printf("\n[메뉴로 돌아갑니다.]\n\n"); return 1;
	}
	else {
		printf("\n[다시 실행합니다.]\n\n");	return 0;
	}
}

void swap(int* a, int* b) {
	int* pBuf;
	int temp[500];
	//printf("a 값 보기: %x\n", a);
	pBuf = temp;
	//printf("\n%x가 pBuf의 주소, %x가 a의 주소, %x가 b의 주소!!!\n\n", &pBuf, &a, &b);
	*pBuf = *b;
	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);
	//printf("pBuf의 값 %d, b의 값 %d\n", *pBuf, *b);
	*b = *a;
	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);
	*a = *pBuf;
	//printf("pBuf의 주소 %08x, b의 주소 %08x, a의 주소 %08x\n", pBuf, b, a);

}

 
4. 형성한 헤더파일을 과제 파일에 포함(자체 제작 헤더파일은 #include "헤더파일.h"로 포함)

#include "headerfile.h"

 
5. 7일차 과제.c 파일 내부의 사용자 정의 함수를 모두 주석처리 후 실행 확인