728x90

변수


전역변수 : 함수밖 선언 - Data

지역변수 : 함수내 선언 - Stack




전역 변수 사용

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int A;

int main()
{
    printf("%d\n",A);
    return 0;
}



Output:

1
0


전역변수는 0으로 초기화(bss)

지역변수는 stack의 쓰레기 값이 표시됨






두번째 예제

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int A;

int main()
{
    int A = 100;
    printf("%d\n",A);
    return 0;
}

printf가 속한 곳이 우선, 없으면 전역변수의 값이 표시

Output:

1
100



전역변수 사용은 아래와 같은 이유 때문에 최소화하는 것이 좋다.

  • 실행파일 용량 증가

  • 변수 관리의 어려움 (값을 어떤걸 대입하게 될지 모르기에 헷갈릴 수가 있다)

  • 전역변수는 프로그램 종료시까지 메모리를 차지한다.


Code(text)

 .EXE


Compile

Time

Data

BSS

Heap

 실행시

Run

Time

Stack


unsigned int가 메모리에 최적화된 가장 빠른 변수이다.




전역, 지역변수의 주소를 출력하고 할당된 메모리 공간 나누기
#include <stdio.h>

int D;
int E=98;
int F;
int G;
int H;

int main()
{
	int A=0;
	int B;
	int C=100;

	printf("--------stack--------------------\n");
	printf("A의 주소	: %p\n", &A);
	printf("B의 주소	: %p\n", &B);
	printf("C의 주소	: %p\n", &C);
	printf("---------data---------------------\n");
	printf("G의 주소	: %p\n", &G);
	printf("E의 주소	: %p\n", &E); 
	printf("---------bss-----------------------\n");
	printf("H의 주소	: %p\n", &H);
	printf("F의 주소	: %p\n", &F);
	printf("D의 주소	: %p\n", &D); 
	printf("---------code-----------------------\n");
	printf("printf의 주소   : %p\n", printf); 
	printf("main의 주소     : %p\n", main);

	return 0;
}



Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--------stack--------------------
A의 주소	: 0xfffcd00c
B의 주소	: 0xfffcd008
C의 주소	: 0xfffcd004
---------data---------------------
G의 주소	: 0x8049950
E의 주소	: 0x8049934
---------bss-----------------------
H의 주소	: 0x8049948
F의 주소	: 0x804994c
D의 주소	: 0x8049944
---------code-----------------------
printf의 주소   : 0x80483c0
main의 주소     : 0x80484a4




Atmega 카운터 인터럽트실습


14일에 배운 것을 응용하여 Switch를 통한 인터럽트를 추가해준다. 


main.h / main.c

#ifndef __MAIN_H__ 
#define __MAIN_H__

void Init(void);
void Port_Init(void);
void INT_Init(void);

#define PINA (*((volatile unsigned char *)0x20))
#define DDRA (*((volatile unsigned char *)0x21))
#define PORTA (*((volatile unsigned char *)0x22))

#define EICRA (*((volatile unsigned char *)0x69))
#define EICRB (*((volatile unsigned char *)0x6A))
#define EIMSK (*((volatile unsigned char *)0x3D))

#define SREG (*((volatile unsigned char *)0x5F))

#define INT7 7
#define INT6 6
#define INT5 5
#define INT4 4
#define INT3 3
#define INT2 2
#define INT1 1
#define INT0 0

#define ISC7 6
#define ISC6 4
#define ISC5 2
#define ISC4 0
#define ISC3 6
#define ISC2 4
#define ISC1 2
#define ISC0 0

#define sei()   __asm__ __volatile__ ("sei" ::) //sei(); 어셈블리어로 7번비트만 1로 만듬
#define sleep() __asm__ __volatile__ ( "sleep" "\n\t" :: )

void __vector_1(void) __attribute__((signal, used, externally_visible)); //신호사용 외부호출 INT0.
void __vector_2(void) __attribute__((signal, used, externally_visible)); // INT1.

#endif //__MAIN_H__

#include "main.h" volatile unsigned int uiState; int main(void) { volatile unsigned int uiCnt; volatile unsigned int uiloop; uiCnt = 0; Init(); uiState = 1; while(1) { PORTA = ((uiCnt/10)<<4)|(uiCnt%10); for(uiloop = 0; uiloop < 45000; ++uiloop); for(uiloop = 0; uiloop < 50000; ++uiloop); if(1==uiState) { ++uiCnt; } if(uiCnt > 99) //세그먼트에서 앞자리가 9를 넘어가면 지워지는 이유는 uiCnt가 100을 넘어갔을 때이다. 그래서 if문으로 재정의. { uiCnt = 0; } } return 0; } void Init(void) { INT_Init(); Port_Init(); } void Port_Init(void) { DDRA = 0xff; PORTA = 0x00; } void INT_Init(void) { EICRA=(3<<ISC0)|(3<<ISC1); // INT0 0000 0011 3 (2진수 11 = rising edge) INT1도 마찬가지 EIMSK=(1<<INT0)|(1<<INT1); // INT0,1 Enable SREG=SREG|(1<<7); // sei(); 전역 인터럽트 활성화 } void __vector_1(void) { volatile unsigned int uiCnt; uiState = 1; } void __vector_2(void) { volatile unsigned int uiCnt; uiState = 0; }



결과.

두 스위치를 통해 카운터를 시작/정지할 수 있게 된다.


'Study > Embedded' 카테고리의 다른 글

20160317-펌웨어(타이머 카운터)  (0) 2016.03.17
20160316-LCD출력  (0) 2016.03.17
20160314-펌웨어 분석(외부 인터럽트)  (0) 2016.03.15
20160311-펌웨어분석 (FND, LED Test)  (0) 2016.03.12
20160310-CPU 모듈2  (0) 2016.03.10
728x90
스위치를 사용한 외부 인터럽트

상승엣지(rising edge) - 버튼을 누를 때       (L->H)
하강엣지(falling edge) - 버튼에서 손을 뗄 때 (H->L)
High 0V
Low 5V


EICRA,EICRB - 외부 인터럽트 트리거 방식 설정


EICRA (0x69)

 INT3 

 INT2 

 INT1

 INT0

 ISC31

 ISC30

 ISC21

 ISC20

 ISC11

 ISC10

 ISC01

 ISC00


0 0 : INTn의 low 레벨에서 인터럽트
0 1 : Any edge
1 0 : INTn의 falling edge에서 인터럽트
1 1 : INTn의 rising edge에서 인터럽트


EICRB (0x6A)

 INT7

 INT6

 INT5

 INT4

 ISC71

 ISC70

 ISC61

 ISC60

 ISC51

 ISC50

 ISC41

 ISC40

0 1 : 논리값 변화에 의한 인터럽트 



EIMSK (0X3D)
외부인터럽트 INT0~INT7를 개별적으로 허용하는 레지스터 
(여러문을 관할하는 관문이라고 할 수 있음)


EIMSK=(1<<INT0);  // INT 0 활성화


EIMSK=(1<<INT0) | (1<<INT3);   // INT 0, 3 활성화
 


SREG (0x5F)


인터럽트를 열기위한 마지막 관문이라고도 할 수 있음.
7번째 bit를 1로 바꾸면 전역 인터럽트 활성화


Interrupt Vector Table

address의 $는 16진수(0x)를 의미

vector number와 주소, 소스, 그리고 인터럽트 정의를 볼 수 있다.




실습







SW6 을 누를때 인터럽트, LED에 불이 들어오고 나가도록 실습한다.

채터링 현상은 하드웨어적으로 개선할 수 없다면 지연을 통해 소프트웨어적으로 해결한다. 




실습 예제

#define DDRA (*((volatile unsigned char *)0x21)) #define PORTA (*((volatile unsigned char *)0x22)) #define PINA (*((volatile unsigned char *)0x20)) #define EICRA (*((volatile unsigned char *)0x69)) #define EICRB (*((volatile unsigned char *)0x6A)) #define EIMSK (*((volatile unsigned char *)0x3D)) #define SREG (*((volatile unsigned char *)0x5F)) #define INT7 7 #define INT6 6 #define INT5 5 #define INT4 4 #define INT3 3 #define INT2 2 #define INT1 1 #define INT0 0 #define ISC7 6 #define ISC6 4 #define ISC5 2 #define ISC4 0 #define ISC3 6 #define ISC2 4 #define ISC1 2 #define ISC0 0 #define sei() __asm__ __volatile__ ("sei" ::) //sei(); 어셈블리어로 7번비트만 1로 만듬 #define sleep() __asm__ __volatile__ ( "sleep" "\n\t" :: ) void __vector_1 (void) __attribute__((signal, used, externally_visible)); //신호 사용,외부 호출


int main(void) { DDRA=0xFF; PORTA=0x00; EICRA=(3<<ISC0); // INT0 0000 0011 3 (2진수 11 = rising edge) EIMSK=(1<<INT0); // INT0 Enable SREG=SREG|(1<<7); // sei(); 와 같음 while(1) { sleep(); // cpu 부하를 줄임 } return 0; } void __vector_1 (void// $0002 INT0 외부 인터럽트 요청

{ volatile unsigned int uiCnt; for(uiCnt = 0; 30000>uiCnt ; ++uiCnt); // 채터링 현상을 s/w적으로 개선하기 위함 PORTA=~PORTA; // ~은 NOT 연산자, 비트반전

}


'Study > Embedded' 카테고리의 다른 글

20160316-LCD출력  (0) 2016.03.17
20160315-펌웨어 분석 및 학습  (0) 2016.03.16
20160311-펌웨어분석 (FND, LED Test)  (0) 2016.03.12
20160310-CPU 모듈2  (0) 2016.03.10
20160309-CPU 모듈  (0) 2016.03.09
728x90

카운터와 LED TEST



VCC는 빨간선, GND는 검은색 선임을 잘 확인하고 기판에 연결



seven segment에 00 이 출력된다.






 3

 2

 1

 0

 3

 2

 1

 0

 J

 1

 9

 L

 L

 L

 L

 H

 L 

 L 

 H 


0 | 9

09를 출력하기 위해선 PORTA에서 J19에 연결되는 핀을 위와 같이 연결한다. 






프로그래밍을 통한 숫자 바꾸기


숫자 34 출력



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#define DDRA (*((volatile unsigned long *)0x21)) #define PORTA (*((volatile unsigned long *)0x22)) #define PINA (*((volatile unsigned long *)0x20)) int main(void) //void 안적으면 컴파일시 warning isn't a prototype { volatile unsigned long uiCnt; DDRA=0xFF; // 모두 출력으로 쓴다. PORTA=0x00; PORTA=((34/10)<<4)|34%10; while(1) { } return 0; }


십자리에 3을 출력

34/10=3

3=0011  

0011<<4=00110000  // 0011의 비트를 왼쪽으로 4칸 이동 (shift 연산자)


일자리에 4를 출력

34/10의 몫은 3이고 "나머지는 4"


0011 0000

0000 0100

------------------비트 or연산 (논리합)

0011 0100




카운터 


#define DDRA	(*((volatile unsigned long *)0x21))
#define PORTA	(*((volatile unsigned long *)0x22))
#define PINA	(*((volatile unsigned long *)0x20))


int main(void) //void 안적으면 컴파일시 warning isn't a prototype
{
	volatile unsigned int uiCnt;
	volatile unsigned int uiLoop;

	DDRA=0xFF; // 모두 출력으로 쓴다.	
 	PORTA=0x00;

	uiCnt=0;
	while(1)
	{	
		for(uiLoop=0;60000>uiLoop;++uiLoop);
                PORTA=((uiCnt/10)<<4)|(uiCnt%10);
		++uiCnt;
	}
	return 0;
}



위 소스 그대로 프로그래밍시 카운터 앞자리가 사라지는 문제가 생긴다.



해결을 위해 while문 사이에 소스를 추가  if(uiCnt>99) { uiCnt=0; }
#define DDRA	(*((volatile unsigned long *)0x21))
#define PORTA	(*((volatile unsigned long *)0x22))
#define PINA	(*((volatile unsigned long *)0x20))


int main(void) //void 안적으면 컴파일시 warning isn't a prototype
{
	volatile unsigned int uiCnt;
	volatile unsigned int uiLoop;

	DDRA=0xFF; // 모두 출력으로 쓴다.	
 	PORTA=0x00;

	uiCnt=0;
	while(1)
	{	
                if(uiCnt>99)
		{
			uiCnt=0;
		}

		for(uiLoop=0;60000>uiLoop;++uiLoop);
                PORTA=((uiCnt/10)<<4)|(uiCnt%10);
		++uiCnt;
	}
	return 0;
}

앞자리 문제 해결



if, else문 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main()
{
	int iNum;
	printf("숫자를 입력하시오: \n");
	scanf("%d", &iNum);
	
	if(100<iNum)
	{
		printf("100보다 큰수입니다\n");
	}
	else
	{
		printf("100보다 작은수입니다\n");
	}
	return 0;
}

if()에서 괄호안이 조건


조건이 참일때 if {}의 내용들 수행

거짓일때 else {}의 내용들 수행



Output:





LED 교차 점등 TEST


#define DDRA (*((volatile unsigned char *)0x21)) #define PORTA (*((volatile unsigned char *)0x22)) #define PINA (*((volatile unsigned char *)0x20)) int main(void) //void 안적으면 컴파일시 warning isn't a prototype { volatile unsigned int uiCnt; unsigned int uiPos; uiPos=0; int iDir=1; DDRA=0xFF; // 모두 출력으로 쓴다. PORTA=0x00; // LED를 끈다. while(1) { if(1==iDir)// iDir(direction)이 1일때 { PORTA=~(1<<uiPos); //순방향 } else { PORTA=~(0x0080>>uiPos); //역방향 0x0080=1000 0000 } for(uiCnt=0;60000>uiCnt;++uiCnt); uiPos=uiPos+1; if(7<uiPos) { iDir=iDir*-1; // iDir이 -1이 되고 else{} 수행 uiPos=0; } } return 0; }


19번째 줄 PORTA=~(1<<uiPos);

~( )은 NOT 연산자


1<<uiPos   0000 0001을 왼쪽으로 uiPos(0~7)의 bit만큼 옮김

끝의 LED는 1000 0000이며, NOT 연산자인 ~()가 붙어서 0111 1111이 됨


PORTA


 L

 H

 H

 H

 H

 H

 H

 L

 0

 1

 1

 1

 1

 1

 1

 0



if(7<uiPos) { iDir=iDir*-1; uiPos=0; }

uiPos가 7을 초과할 시, iDir은 -1이 되고 else{} 수행


LED TEST



'Study > Embedded' 카테고리의 다른 글

20160316-LCD출력  (0) 2016.03.17
20160315-펌웨어 분석 및 학습  (0) 2016.03.16
20160314-펌웨어 분석(외부 인터럽트)  (0) 2016.03.15
20160310-CPU 모듈2  (0) 2016.03.10
20160309-CPU 모듈  (0) 2016.03.09
728x90

2016-03-10 <CPU 모듈>


Atmel ATmega 2560


Brown-out Detection 

특정 전압 이하로 떨어지는걸 방지, 자동으로 CPU를 리셋하는 회로.


Watchdog 

특정한 시간동안 시스템이 응답없으면 리셋시킴.


86 Programmable I/O Lines

86개의 제어가능한 입출력(Input/Output) 라인.



칩의 심박수가 곧 "Clock"


발진기(오실레이터)

발진회로 혹은 클럭발생기라고도 함


Crystal - XTAL  

수정발진자 혹은 수정진동자라고 함



16.000 MHz  

소수점 이하 0이 많이 붙을수록 정확한 진동자


1초에 16000000 개를 센다.


타이머 카운터(T/C) - 시간 측정회로, 기준이 되는 것은 동작 주파수




GPR(General Purpose Register)과 Data SRAM간의 Direct Addressing 

: Memory와 Register간 직접 주소 연결




AVR memories

256kb Flash Memory



0x7FFF(0~)-> 0x8000   -> 32768 /1024  -> 32

0xFFFF     -> 0X10000 -> 65536 /1024  -> 64

0x1FFFF    -> 0X20000 -> 131072/1024 -> 128


flash memory 한 Section에 2byte 공간을 가지기에 128 x 2 = 256kbyte를 가짐





인텔 CPU는 폰 노이만 구조. 폰 노이만은 컴퓨터 설계의 기본을 만든 천재 수학자.

하바드(Harvard) 구조는 양방향이라 효율적이고 빠르지만 단가가 비싸다. 



DDRA - Port A  Data Direction Register

데이터의 방향을 결정하는 레지스터


0-7번 비트까지 8bit Register를 가지며, 읽고 쓰기가 가능하다.

initial value(초기값)는 0이고 0과 1에 따라 Direction이 바뀐다. 


Port-출력과 방향

DDR-방향을 결정


Port에 값을 줄건지 말건지에 따라 5V 또는 0V 가 출력.




LED 두개, 교차 깜박임 실습


LED 두개의 한쪽 선을 각각 PORT A의 1번, 5번에 꼽음 (나머지 한쪽선은 각각 GND에 꼽음)




PORTA의 1번


 7

 6

 5

 4

 3

 2

 1

 0

 0

 0

 0

 0

 0

 0

 1

 0


0 | 2  


PORTA의 5번


 7

 6

 5

 4

 3

 2

 1

 0

 0

 0

 1

 0

 0

 0

 0

 0


| 0  




소스

#define DDRA	(*((volatile unsigned long *)0x21))
#define PORTA	(*((volatile unsigned long *)0x22))
#define PINA	(*((volatile unsigned long *)0x20))


int main(void) //void 안적으면 컴파일시 warning isn't a prototype
{
	volatile unsigned long uiCnt;
	DDRA=0xFF; // 출력으로 쓴다.	

	while(1)
	{
		for(uiCnt=0; 100000>uiCnt;++uiCnt);
		PORTA=0x02; //2번
		for(uiCnt=0; 100000>uiCnt;++uiCnt);
		PORTA=0x20; //5번		
	}
	return 0;
}



결과 - LED 두개가 번갈아 깜박거리는 것을 볼 수 있다.





전해 콘텐서는 순간적으로 전압이 떨어지는 걸 방지한다. (일종의 배터리)




'Study > Embedded' 카테고리의 다른 글

20160316-LCD출력  (0) 2016.03.17
20160315-펌웨어 분석 및 학습  (0) 2016.03.16
20160314-펌웨어 분석(외부 인터럽트)  (0) 2016.03.15
20160311-펌웨어분석 (FND, LED Test)  (0) 2016.03.12
20160309-CPU 모듈  (0) 2016.03.09
728x90


CPU 모듈


실습에 사용하는 장비 : Atmel ATmega 2560


135 instruction  - Cpu에게 내릴 수 있는 기계어 명령어 수


주파수 -> 초당 진동수, 이 주파수는 cpu에서 초당 계산 능력과도 연관된다.

 "주기(cycle)"가 1초에 몇번이냐에 따라 - Hz 등으로 표현  



전류 - 전기의 흐름

전압 - 전기의 압력


물탱크의 수압과 꼭지를 통해 흐르는 물을 생각하고 대입하면 이해하기 쉽다.


V=IR - 저항이 클수록 전류는 적게 흐름


일반적으로 한국은 AC(Alternating Current) 220v 60hz 

이는 1초동안 60번 +,- 극성이 바뀌는 것을 의미



P = VI

   = 220v * 1A

   = 220W = 0.22 KW



Atmel ATmega 2560 실습


개발 환경 구축


AVR Studio 설정




선이 연결되는 위치와 기반의 방향에 주의.

어댑터를 연결할 때는 전원을 꼭 내린채로 연결! 절대 주의!


windows 10 dll FILE

msys-1.0.zip

winavr문제해결.txt



AVR Studio 설정



Tools-Program AVR-Connect...  선택




STK500-COM3 연결

포트 연결은 시스템-장치관리자의 포트 항목에서도 확인 가능하다. 



Atmega2560을 선택한 후, Read Signature를 눌렀을 때 모두 OK!가 나오는지 확인.



Makefile 

각종 명령어가 담겨있으며 아래 항목들을 메모장으로 열어 환경에 맞게 수정해준다.


# MCU name

MCU = atmega2560  


# Processor frequency.

F_CPU = 16000000


# Target file name (without extension).

TARGET = main  // 항상 main.c를 기준으로 한다면 바꾸지 않음. main.c로 코딩하는 이유



LED제어를 위한 예제.

DDRA, PORTA, PINA 기능과 주소 부분은 Atmega25060의 datasheet 파일에서 확인 가능하다.


main.c 파일로 아래와 같이 소스를 짠다.

1
2
3
4
5
6
7
8
9
10
11
12
#define DDRA	(*((volatile unsigned char *)0x21))
#define PORTA	(*((volatile unsigned char *)0x22))
#define PINA	(*((volatile unsigned char *)0x20))

int main(void) //void 안적으면 컴파일시 warning isn't a prototype
{
	DDRA=0xFF; // 출력으로 쓴다.
	PORTA=0xFF; //모든 다리를 5v로 만듬
	
	while(1); //초기상태로 돌리지 않기위해 항상 씀. 	
return 0;
}


명령창에서 make를 입력후 엔터하면 위와 같이 파일들이 생성된다.



int main() 에서 괄호안에 void를 안 적으면 아래와 같이 Warning message가 출력




make clean은 main.c와 Makefile을 제외하고 모두 지우는 명령어



int main(void)라고 수정후 make.  Warning 뜨지 않음


컴파일이 성공적으로 되었으면 Program탭에서 Flash 항목에  HEX File을 선택후 Program을 누른다. (당연히 전원 들어온 상태에서만 쓰기가능)



LED 제어 실습

먼저 LED를 10번 GND부터 연결, 극성과 위치를 설계도를 보며 잘 확인할 것!


설계도를 볼때는 x,y축을 통해 원하는 정보의 위치를 대략적으로 찾을 수도 있다.



메인보드 뒤쪽에도 번호가 적혀있다.



LED가 극성에 맞게 모두 잘 연결되었다면 위와 같이 LED에 불빛이 들어온다.



깜박거리는 LED 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define DDRA	(*((volatile unsigned char *)0x21))
#define PORTA	(*((volatile unsigned char *)0x22))
#define PINA	(*((volatile unsigned char *)0x20))

int main(void) //void 안적으면 컴파일시 warning isn't a prototype
{
	volatile unsigned int uiCnt;
	DDRA=0xFF; // 출력으로 쓴다.

	while(1)
	{
		for(uiCnt=0; 60000>uiCnt;++uiCnt); //숫자가 낮으면 빨리 깜박임
		PORTA=0xFF;
		for(uiCnt=0; 60000>uiCnt;++uiCnt);
		PORTA=0x00;
	}
	return 0;
}


어제 배운 volatile을 응용한 예제이다. 의도적인 지연을 통해 불빛이 들어오고 나가는 시간을 조절할 수 있다.


make clean후 다시 make.

아까전 Program탭에서 Flash 항목에서 다시 Program을 누른다.


실습 결과 LED가 일정한 간격으로 깜박거리는 것을 볼 수 있다.




'Study > Embedded' 카테고리의 다른 글

20160316-LCD출력  (0) 2016.03.17
20160315-펌웨어 분석 및 학습  (0) 2016.03.16
20160314-펌웨어 분석(외부 인터럽트)  (0) 2016.03.15
20160311-펌웨어분석 (FND, LED Test)  (0) 2016.03.12
20160310-CPU 모듈2  (0) 2016.03.10
728x90

구구단 3단 소스 (http://codepad.org/ZT1RrUn5)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main()
{
	int iCnt;
	iCnt=1;  // 아래 소스에서 for 함수로 정리 ⓐiCnt=1;
	
	while(10>iCnt) // for 함수 정리ⓑ(10>iCnt);  
	{
		printf("3 x %d = %d\n", iCnt, 3*iCnt);
		iCnt=iCnt+1;  // for 함수 정리ⓒiCnt=iCnt+1
	}
	return 0;
}
 


iCnt=iCnt+1


iCnt=++iCnt;


iCnt=iCnt++


을 위의 소스에 대입해도 모두 같은 결과 값을 얻을 수 있지만 첫번째가 권장된다.


처리속도는 동일하기에 소스를 짤 때 인간(프로그래머)이 보기에 헷갈리지 않게, 

보기 편하게 소스를 짜는 것이 좋다. 




이제 위의 소스를 for 함수를 사용해 정리해보자 (http://codepad.org/NhNOP5Qt)

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
	int iCnt;
		
	for(iCnt=1;10>iCnt;iCnt=iCnt+1)
	{
		printf("3 x %d = %d\n", iCnt, 3*iCnt);
	}
	return 0;
}



for (); 




for ()

{

}




for () {}


모두 같은 값을 얻을 수 있다.




두 소스 모두 output이 동일하다.


Output:

1
2
3
4
5
6
7
8
9
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27




volatile 변수


volatile 휘발성의


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
 volatile int iCnt;  // volatile = 휘발성의
 for(;;) // = while(1)
 {
   for(iCnt=0;100000000>iCnt;iCnt=iCnt+1)
  { }
  printf("test\n");
 }
 return 0;
}



바로 위의 소스에서 volatile 변수를 쓰지 않는다면 CPU의 register내에서 모두 연산하고 Memory에 값을 저장하는 내부 최적화를 진행한다.


컴파일러가 자체적으로 메모리 접근을 최소화 시키는 것이다.


volatile은 이런 최적화를 하지않게 선언해서, CPU가 "매 값마다" 참/거짓을 판별, 연산하고 

메모리에 저장하고 가져오는 과정을 반복하게 한다.


명령창에서 실행해보면 volatile 변수를 쓴 것과 쓰지않은 것의 차이를 눈으로 확인할 수 있다.





UNION


여러 종류의 변수들을 같은 메모리 공간에 묶는다.


예제 소스 (http://codepad.org/vSaMCGCW)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

struct smart
{
    int A;
    short B;
    int C;
    char D;
};

int main()
{ 
    printf("Size of Smart: %d\n", sizeof(struct smart));
    
    return 0;
}


Output:

1
Size of Smart: 16




smart구조체를 UNION으로 수정 (http://codepad.org/rDFsMFkY

#include <stdio.h>

union smart 
//struct smart
{
    int A;
    short B;
    int C;
    char D;
};

int main()
{
    union smart obj;
    obj.A=0x12345678;
    obj.B=0x12345678;
    obj.C=0x12345678;
    obj.D=0x12345678;
 
  //printf("Size of Smart: %d\n", sizeof(struct smart));
    printf("Size of Smart: %d\n", sizeof(union smart));

    printf("%x\n", obj.A); 
    printf("%x\n", obj.B); 
    printf("%x\n", obj.C); 
    printf("%x\n", obj.D); 

    return 0;
}



Output:

1
2
3
4
5
Size of Smart: 4
12345678
5678
12345678
78


output 첫번째 줄을 보면 알 수 있듯이, size가 16에서 4로 바뀌었다.

smart 구조체를 union으로 바꿔주면 모두 4byte 안에 들어가게 된다. 

(int A; short B; int C; char D;)                         


각 데이터의 크기에 따라 각각 다른 값이 출력되게 되며, 다음과 같이 출력된다.


Little Endian

78 

 56

 34

 12


obj.A=12345678   // int A

obj.B=5678        // short B

obj.C=12345678  // int C

obj.D=78           // char D




함수 포인터를 사용하는 이유


①프로그램 코드의 간결


②중복 코드를 줄이기 위해서


③상황에 따라 해당되는 함수를 호출할 수 있음




type알아내기


type을 알아야 함수 포인터를 만들 수 있다.

아래와 같이 따라하면 원형에서 쉽게 type을 알아낼 수 있다.


1. void smart();   원형

2.        (*)

3. void (*) (); // void (*) ()가 type



int printf(const char *, ...);  // 원형

int (*)  (const char *, ...);  // Type



함수 포인터 예제 소스 (http://codepad.org/YiQTHzi9)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
void smart1()
{
 printf("1번함수\n");
}
void smart2()
{
 printf("2번함수\n");
}
int main()
{
 void (*test)( );
 test=smart1;
 test( );
 test=smart2;
 test( );
 return 0;
}


Output:

1
2
1번함수
2번함수


type 이름; 


1. void (*test) ();

2. test=smart1; 

3. test();




반도체 (Semi Conductor)


반/도체

Semi/Conductor


도체

전기 또는 열이 잘 통하는 물체


부도체

전기 또는 열에 대한 저항이 매우 커서 전기나 열을 잘 전달하지 못하는 물체


반도체

극성에 따라 전기가 흐르거나 흐르지 않는다.



마이크로 컨트롤러 제품군 중의 하나인 "AVR"


AVR 개발환경, Intel과 AVR의 교차개발 환경 구축을 위해 둘 사이에 WIN AVR이라는 컴파일러를 사용한다. 이를 Cross Compiler라고 한다.

윈도우에 visual studio가 있다면 avr은 avr studio가 있다.


아키텍처의 종류

RISC 

CISC  


장단점이 각각 있지만, 서로 단점을 보완하며 닮아가고 있다.




'Study > C' 카테고리의 다른 글

2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
20160329_C기초, 디버깅  (0) 2016.03.29
20160307_업무일지_파일 입출력  (0) 2016.03.07
728x90

- 파일 열기 


파일을 액세스하려면 먼저 대상 파일을 열어야(Open) 한다. 파일을 오픈한다는 것은 파일 입출력을 하기 위한 준비를 한다는 뜻이다. 

* 여기서 엑세스(Access)는 말 그대로 파일에 접근하는 것을 뜻한다.



스트림 입출력을 위해서는 파일의 데이터를 잠시 저장하는 내부 버퍼가 필요하며 파일의 현재 위치(FP)를 초기화해야 하는데 이런 준비를 하는 과정이 오픈이다. 

* Stream - 길이를 측정할 수 없는 특정한 data가 왔다갔다하는 것을 말하며, 이를 스트림 입출력이라고 한다. 

스트리밍 서비스의 음악, 동영상 감상 등이 이를 이용한 것이다. 받는 data의 양은 상황과 환경에 따라 유동적이다.


* 내부 버퍼 - 파일의 데이터를 잠시 임시로 저장하는 메모리 공간을 말한다.

모든 변수도 버퍼에 저장된다 볼 수 있다.


* 현재위치(File Pointer)  

                                   파일 (FILE)


탐색한다(SEEK) 

                         △ 여기서 파일을 탐색한 특정 지점을 FP라고 할 수 있다.




파일을 오픈할 때는 다음 함수를 사용한다. 

FILE *fopen(const char *filename, const char *mode);


먼저 인자의 갯수가 일치하는지 확인하고 인자의 Type이 서로 맞는지 확인한 다음, 최종적으로 반환값 일치여부를 확인한다.


  1.  #include <stdio.h>  
  2.   
  3. void smart(int Z); // int Z에서 type name Z는 컴파일에서 크게 중요하지 않음, 하지만 구분을 위해 의미있는 이름을 쓰기도 한다.  
  4.   
  5. int main()  
  6. {  
  7.     //FILE *fp;  
  8.     FILE *fp=fopen("A.txt""w");   
  9.     fprintf(fp, "파일입출력");  
  10.     //smart(printf);    
  11.     printf("파일입출력");  
  12.     fclose(fp);  // 파일을 닫음
  13.     return 0;  
  14. }  
  15. void smart(int A)  
  16. {  
  17. }  
다음의 예제 소스를 보자. 

파일경로에서 \\를 2개 쓰는 이유는 만약 \ 하나를 쓴다면 컴파일러에서 이를 개행(new line \n)으로 인식하고 컴파일하기 때문이다.

  1.  #include <stdio.h>  
  2.   
  3.   
  4. int main()  
  5. {  
  6.     FILE *f;  
  7.     f=fopen("c:\\영화\\코미디\\영구와땡칠이.avi","rb");  
  8.     if (f==NULL) {  
  9.                 printf("얼씨구. 파일이 안 보이네요\n");  
  10.              }  
  11.   
  12.     int fclose(FILE *stream);  // 사용한 stream 파일을 닫고, 버퍼를 비우게 된다.
  13.     return 0;  
  14. }  
컴파일 후 실행했을 때의 결과.

"c:\영화\코미디\" 디렉토리에 영구와땡칠이.avi 라는 파일을 읽을 수 없다면
(NULL) 을 리턴하고 ("얼씨구. 파일이 안 보이네요\n") 를 출력하게 된다.




여기서 도스 명령창을 통해 명령어와 절대 경로<->상대 경로를 배운다.

절대 경로가 변하지 않는 경로라면, 상대경로는 특정 위치를 기준으로 변화하는 경로이다. 



"c:\영화\코미디\"  디렉토리에서 cd c:\영화\ 명령어를 통해 이동한다면 

이는 절대경로를 이용한 것이다.




하지만 c:\영화\코미디\ 디렉토리에서 현재 위치를 기준으로 상위 디렉토리로 이동할 때,

cd .. 명령어를 통해 c:\영화로 이동할 수 있다. 

이는 상대경로를 이용한 것이다.



dir 명령어를 쳐보면 알 수 있지만 점 하나(.)는 은 현재 폴더 점 두개(..)는 상위 폴더를 의미한다.


도스, 윈도우즈에서는 대소문자의 구분을 하지 않으며, 여러 운영체제의 시초라고 할 수 있는 유닉스에서는 대소문자를 모두 구분한다.



개행 코드를 의미하는 CR/LF


ASCII 

 

 

 10

 CR

 Carriage Return

 18

 LF (\n)

 Line Feed


C언어에서 개행 코드를 의미하는 CR/LF 조합은 LF로 변환되어 읽혀지며 LF를 기록하면 CR/LF가 출력된다. 


CR(Carriage Return) : 커서를 맨 앞으로 이동한다. 

LF(Line Feed) : 다음 줄로 이동한다.


이런 변환을 해 주는 이유는 C 문자열 출력 함수들은 개행을 위해 확장열 LF(\n)를 사용하기 때문. 



파일의 끝을 의미하는 EOF = End Of File


Ctrl+Z(0x1A)는 EOF -1로 정의되며, 반환 파일의 끝을 표현하기 위한 상수 (-1)의 값을 지닌다.

명령어 Ctrl + Z는 ASCII Code로 0x1A이다.


안녕

하세요


-> 안 / 녕 / \n / 하 / 세 / 요 / 1A->EOF(-1)



NULL은 숫자 0을 의미

# define NULL 0

   주소  0을 리턴





실행파일을 2진파일(BIN)로 바꾸어서 열어보기


왼쪽부터 주소/ HEXA값 / ASCII 코드를 볼 수 있다. 헥사값을 바꿀시 아스키 코드도 따라서 바뀌는 것을 확인할 수 있을 것이다.




비트맵 파일(BMP)을 BIN파일로 바꾸고 열어보았을 때, HEXA값을 통해 파일의 확장자를 알 수 있다. 이를 MAGIC NUMBER라고 한다.



다음은 헥사값을 보기 위한 예제이다.


  1.  #include <stdio.h>  
  2.   
  3. void Hexaview(unsigned char *ucpData, unsigned int uiLen)  
  4. //void Hexaview(char *cpData, unsigned int uiLnt)  
  5. {  
  6.     unsigned int uiCnt;  
  7.     unsigned int ui16Cnt;     
  8.   
  9.     printf("====================Hexa Viewer============================\n");         
  10.     uiCnt=0;  
  11.     while(160>uiCnt)  
  12.     {  
  13.     printf("%p ", uiCnt);  
  14.   
  15.         ui16Cnt=0;  
  16.         while(16>ui16Cnt)  
  17.         {  
  18.             printf("%02x ", *ucpData);  // %02 -> 2자리로 출력하되 값이 없는 자리는 0으로 출력하라, %x는 16진수 출력을 의미
  19.             ui16Cnt=ui16Cnt+1;  
  20.             ucpData=ucpData+1;  
  21.         }         
  22.            
  23.         uiCnt=uiCnt+16;  
  24.         printf("\n");  
  25.     }  
  26.      printf("===========================================================\n");   
  27. }  
  28. int main()  
  29. {  
  30.     unsigned char ucBuff[ ]="1234567890ABCDEF";  // 헥사 값 16바이트. 즉, 한줄씩 저장되는 버퍼. 
  31.     //Hexaview(NULL, 0);  
  32.     Hexaview(ucBuff, 0);  
  33.     return 0;  
  34. }  

    cl hexa.c

    컴파일 후 실행 결과 


빨간선을 기준으로 왼쪽은 주소를 가리킨다. 아래로 내려오면서 16바이트씩 증가함을 볼 수 있다.

     오른쪽에 출력되는 부분은 아스키코드로 0x30은 문자 0이며, 0x31은 문자1과 같다.   (아스키 코드표 http://www.asciitable.com/)


    






'Study > C' 카테고리의 다른 글

2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
20160329_C기초, 디버깅  (0) 2016.03.29
20160308_업무일지_그 밖의 기초 학습  (0) 2016.03.08

+ Recent posts