자바의 자료형은 크게 기본형(primitive type)과 참조형(referene type)으로 나뉜다. 그리고 기본형은 다시 정수형, 실수형, 문자형, 논리형 네 가지로 분류할 수 있다. 이것들을 다음 표에 정리하였다.


[표 1] 자바의 기본 자료형(primitive type)의 종류

분류

이름

바이트 수

비고

정수형

byte

1

-127 ~ +128

short

2

-32,768 ~ + 32,767

int

4

-2,147,483,648 ~ +2,147,483,647

long

8

-9,223,372,036,854,775,808~

+9,223,372,036,854,775,807

실수형

float

4

단정도 실수형 (유효 자리는 7 정도임)

double

8

배정도 실수형 (유효 자리는 15정도)

문자형

char

2

유니코드 문자열

논리형

boolean

1

true, false


 정수형은 정수를 저장하는 자료형으로서 byte, short, int, long 네 가지가 있으며 각각에 저장할 수 있는 정수의 범위가 다르다 ([표 1] 참조) 한 가지 알아둘 것은 C/C++ 과 다르게 자바의 정수형에는 unsigned 형이 없고 부호 있는 정수형만 있다는 것이다. (자료 구조의 단순함을 유지하기 위해서 이렇게 설계했다고 한다.) 그리고 C/C++의 long long int 가 자바의 long형에 해당된다. 숫자 상수끝에 L/l 접미어가 붙으면 long형으로 저장된다.


 실수형은 실수(소숫점이나 e/E를 포함하는 수)를 저장하는 자료형으로서 float와 double 형이 있다. (이것은 C/C++과 동일하다.) 숫자 상수 끝에 f/F 접미어가 붙으면 float형으로 저장된다.


 컴퓨터에서는 모든 문자에 번호를 할당하고 문자를 정수로 바꿔서 저장한다. 어떤 문자에 어떤 번호를 할당하는 가는 여러 방법이 있으며 자바는 유니코드(unicode)라는 세계 표준 규격을 따른다. 유니코드는 국제적으로 사용되는 모든 문자를 0~65,535 범위(2 바이트)의 정수에 할당한 것이라고 이해하면 된다. 자바의 char형은 유니코드 한 문자를 표현할 수 있는 자료형으로서 2 byte 크기이다. 문자상수는 작은 따옴표를 사용하여 표시한다. 예를 들면 ‘a’, ‘가’, ‘3’ 등이다. (C/C++에서는 char형이 1byte이다. 혼동하면 안된다.)


 논리형은 true(참)과 false(거짓) 단 두 개의 값만을 가지는 자료형이다. 조건 검사에서 사용되는 논리식의 결과값을 저장하는 용도로 사용된다.




Posted by 살레시오
,

 이전 포스트에서 C++의 double형 연산과 long long int 형 연산 속도를 측정한 적이 있는데 똑같은 일을 JAVA에서 수행하고 시간을 측정해 보았다. (JAVA는 long형이 64비트 정수형이고 c++의 long long int 형에 대응한다.)


package javaapplication5;
public class JavaApplication5 {
   public static void main(String[] args) {
       long iter = 100000000; //1억번
       
       System.out.println("Start");
       long ls, le;
       double da=12.3, db=45.6;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) da *= db;
       le = System.nanoTime();
       double tm1 = (le-ls)/1e9;
       System.out.println("elapsed time 1 = "+tm1);
       
       long la=2, lb=2;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) la *= lb;
       le = System.nanoTime();
       double tm2 = (le-ls)/1e9;
       System.out.println("elapsed time 2 = "+tm2);
       
       System.out.println(tm1/tm2 + " times faster.");
   }   
}


수행 결과는 의외였다.



JAVA로 실행한 결과가 훨씬 더 수행시간이 짧다. 당연히 JAVA가 수행시간이 더 걸릴 줄 알았는데 아니었다. 아래가 g++ 로 컴파일하여 수행시간 결과다. 똑 같은 일은 c++ 은 14.591초, 자바는 0.357초 걸렸다.



윈도에서는 g++ 성능이 낮고 최적화를 전혀 하지 않았음을 감안하더라도 성능 차이가 이렇게 날 줄 몰랐다. 자바도 중간어를 JIT 컴파일해서 실행하므로 c++과의 실행 속도 차이가 그다지 크지 않다고 알고는 있었는데 직접 해보니 사실이었다. 한 가지 자바에서는 정수형과 실수형의 연산 속도 차이가 c++에서만큼 크지 않다는 것도 알 수 있었다.


 그렇다면 c++을 고집할 필요가 없는 것 아닌가 싶다. JAVA를 이용하는 것이 훨씬 더 편하고 쉽다. 더군다나 CUDA4J 같은 GPU를 사용할 수 있는 라이브러리도 있으니 성능 향상이 필요할 때는 이것을 사용하면 되지 않을까.


 실수 연산과 정수 연산의 시간 차이를 알아보기 위해서 자바로 실험을 조금 더 해 보았다.


package javaapplication5;
import static java.lang.Math.exp;
public class JavaApplication5 {
   public static void main(String[] args) {
       long iter = 100000000;
       
       System.out.println("Start");
       long ls, le;
       double da=12.3, db=45.6, dc=0, dd=0;
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) {
           dd = da*db;
           dc = exp(dd);
           da += 1e-8;
       }
       le = System.nanoTime();
       //System.out.println(da + ", " + dc);
       double tm1 = (le-ls)/1e9;
       System.out.println("elapsed time 1 = "+tm1);
       
       long la=2, lb=2, lc = 0, ld=0;
       long[] larr = new long[2000];
       
       ls = System.nanoTime();
       for(long k=0;k<iter;k++) {
           long ll = k%2000;
           ld = la*lb;
           lc = larr[(int)ll];
           la++;
       }
       le = System.nanoTime();
       double tm2 = (le-ls)/1e9;
       System.out.println("elapsed time 2 = "+tm2);
       
       System.out.println(tm1/tm2 + " times faster.");
   }
}


이 연산에서는 30배 정도 속도에서 차이가 난다.


Posted by 살레시오
,

 러플(RUR-PLE, RUR - Python Learning Environment)은 파이썬을 이용한 교용용 프로그래밍 언어 환경이다. 사용자는 명령을 통해 화면에 있는 로봇을 움직이며 프로그램잉의 개념에 대해 학습을 할 수 있다.



러플의 특징은 다음과 같다. 프로그래밍을 처음 접하는 학생들에게 추상적인 수치를 다루는 내용보다는 간단한 명령의 조합을 통해 눈에 보이는 로봇을 조작함으로써 프로그래밍을 보다 쉽게 이해할 수 있도록 한다. 사용 문법은 초보자도 쉽게 익힐 수 있을 정도로 간단하지만 강력한 기능을 지원하고 다양한 분야에 이용되는 파이썬 언어를 학습할 수 있다. 혼자서도 학습할 수 있는 튜토리얼이 많다. 파이썬을 별도로 설치하지 않아도 기본적으로 파이썬 쉘과 에디터를 제공한다.



그리고 다양한 운영체제에서 실행할 수 있는 배포판을 제공한다.


 개인적으로 스크래치와 함께 프로그래밍의 개념을 학습할 수 있는 좋은 도구라고 생각된다.



Posted by 살레시오
,

 여기에서는 이전 포스트들 (part 1, part 2, part 3)에 이어서 plot()함수에 대해서 더 알아보도록 하겠다.  plot()함수에서 그림의 제목과 x축 라벨 그리고 y축 라벨을 써주는 함수는 각각 title(), xlabel(), ylabel()함수이며 이들은 문자열을 입력 파라메터로 받아들여서 그래프에 도시하는 함수이다. 예로서 함수 sin(x)/x 그래프를 그려보자.


>> x=0:0.1:10
>> y=sin(x)./x
>> plot(x,y)


여기서 두 번째 줄에서 y값을 계산하는데 (./)연산자를 사용했음에 주의해야 한다. sin(x)도 벡터이고 x도 벡터이므로 각각의 요소간 나눗셈을 수행해야 하므로 (./)연산자를 사용한다. 이제 이렇게 생성된 그래프에 제목과 x축 라벨 그리고 y축 라벨을 추가해 보자.


>> title('graph of sin(x)/x')
>> xlabel('x')
>> ylabel('y')


결과 그림을 확인해 보면 그래프 상단에 타이틀이 하단에 x축 라벨이 그리고 오른편에 y축 라벨이 표기되어 있음을 확인할 수 있다.

[그림 1] 실행 결과 (gnu octave 를 캡처)


각 축의 화면에 보여지는 범위를 조절하는 함수로서 axis()함수가 있으며 이 함수의 문법은 다음과 같다.


>> axis([XMIN XMAX YMIN YMAX])


여기서 XMIN와 XMAX는 각각 x축의 최소값과 최대값을 그리고 YMIN와 YMAX는 각각 y축의 최소값과 최대값을 표기한다. 예를 들면 다음과 같다.


>> axis([2 8 -0.2 0.6])


이렇게 하면 그래프의 x축 범위가 2에서 8로 그리고 y축 범위가 -0.2에서 0.6으로 조정된다. 또한 axis()함수가 입력파라메터 없이 사용되면 현재 그래프의 xy축의 범위를 반환한다.


>> axis
2.0000 8.0000 -0.2000 0.6000

 MATLAB이 자동으로 축의 범위를 설정하게 하려면 axis auto 명령을 사용한다.


 이제 하나의 그림창에 여러 함수의 그래프를 도시하는 다른 방법을 살펴보자. 먼저 다음과 같은 두함수를 x∈[0,10]의 구간에 대해서 도시하고자 한다.

도시할 데이터를 다음과 같이 생성한다.


>> x = linspace(0,10,50)
>> y1= -0.5*x.^2+1;
>> y2= 2*sqrt(x)-10;


그리고 다음과 같이 그래프를 생성한다.


>> plot(x,y1,'k')
>> hold on
>> plot(x,y2,'k--')
>> grid on
>> legend('-0,5*x^2+1','2*sqrt(x)-10')


여기서 ‘hold on’ 이라는 명령어가 사용되었다. 이 명령어는 지금 활성화된 그래프 창의 내용을 그대로 유지하라는 명령어이다. 그렇기 때문에 두 번째 plot()함수에 의해서 처음에 그려진 그림이 지워지지 않고 그 위에 덧그려진다. 만약 hold on 명령어가 없었다면 첫 번째 그림은 지워지고 두 번째 그림만 남았을 것이다. hold off명령어를 내리지 않는 이상 이후에 호출되는 plot()함수에 의한 결과는 계속 그 위에 덧그려진다. 그리고 grid on 이라는 명령어는 그림에 격자 표시를 하라는 명령어이다. 격자를 지우고 싶으면 grid off라고 하면 된다. 마지막으로 legend()함수는 문자열들을 입력으로 받아서 그래프들에 대한 설명을 생성하는 명령어이다.

[그림 2] 실행 결과 (gnu octave 를 캡처)

 현재 그래프 창의 내용을 지우는 명령은 clf이고 새로운 그래프 창을 생성하는 함수는 figure()함수이다. 위의 예로 다시 설명하면 두 함수를 각각 다른 창에 도시하고 싶을 때는 다음과 같이 하면 된다.


>> plot(x,y1)
>> figure(2), plot(x,y2,'k')


첫 번째 plot()함수로 첫 번째 그림창이 생성되므로 이 그래프 창이 1번의 번호를 가지게 된다. figure(2)라는 명령어로 두 번째 새로운 그래프 창이 생성이 되며 이후의 plot()함수에 의한 그림은 두 번째 창에 그려지게 된다. (캡션바에 그래프 창 번호가 표시됨)


[그림 3] 실행 결과 (gnu octave 를 캡처)

 현재 열려있는 특정한 그림창을 없애는 명령어는 close(n)명령어이다. 이 명령어로 n번 그래프 창이 소멸된다. 현재 생성되어 있는 모든 그림창들을 닫고 싶으면 close all 명령을 내리면 된다.



Posted by 살레시오
,

 이전 포스트들(part 1, part 2)에 이어서 plot()함수데 대해서 더 알아보도록 하겠다. plot()함수의  자세한 온라인 설명은 help plot 명령으로 볼 수 있으며 다음 표에 옵션을 정리하였다.


[표 1] plot() 함수의 그래프 모양을 정하는 옵션

심벌

색상

심벌

표시자

심벌

선의종류

y

노란색

.

.

-

실선

m

진홍색

o

:

점선

c

청록색

x

x

-.

실선과 점선

g

녹색

+

+

--

실선과실선

b

청색

*

*

k

검은색

^

r

빨간색

v

w

흰색

<

>

s(quare)

d(iamond)

p(entagram)

h(exagram)


위의 표에 소개된 옵션은 다음과 같이 지정할 수 있다.


>> plot(x,y,'option')


만약 option을 지정하지 않으면 기본 설정으로 ‘파란색 실선’의 그래프가 그려지게 되며 위의 option자리에 [표 1]에 소개된 색과 표시자 그리고 선의 종류를 지정하면 된다. 다음의 예를 보자.


>> a=1:0.1:10;
>> b=cos(a);
>> c=sin(a);
>> plot(a,b,'*',a,c,'k')


이 예는 코사인함수는 별표로 그리고 사인함수는 검은색 실선으로 그리는 예제이다. 여기에서 심벌로 지정한 경우는 점의 위치에 그 기호를 표시한다. (선의 경우는 점과 점사이를 잇는다.)

[그림 1] 실행 결과 (gnu octave에서 캡처)

지정자는 색과 표시자 그리고 선의 종류를 동시에 지정할 수도 있다.


>> plot(a,b,'b:',a,c,'m+') 󰎠


이 예에서 ‘b:'지정자는 ‘파란색 점선’으로 그리라는 것이고 ’m+'는 ‘진홍색 십자’로 그리라는 지정이다.


[그림 2] 실행 결과 (gnu octave에서 캡처)

 다음에 몇가지 예제를 더 들었다. 각각을 직접 실행시켜서 짐작대로 그림이 그려지는지 확인해 보자.


plot(x,y,'-.c')

plot(x,y,':r')

plot(x,y,'-sg')

plot(x,y1,'-r',x,y2,'--c')

plot(x,y1,'b',x,y2,'oy')

plot(x,sin(x),'-kp')


위에서 마지막 예를 이용해 보면 다음과 같다.


>> x=linspace(0,2*pi,30);
>> plot(x,sin(x),'-kp')


[그림 3] 실행 결과 (gnu octave에서 캡처)


여기에서 ‘실선’과 ‘펜타그렘’이 동시에 지정되어 있으므로 점의 위치에는 펜타그램이 그려지고 그것들을 실선으로 잇게 되는 것이다. (‘k’지정자에 의해서 색은 검은색)




Posted by 살레시오
,

 여기에서는 이전 포스트에 이어서 계속 plot()함수에 대해서 설명하도록 하겠다. 만약 sin(x)cos(x)함수를 그리고자 한다면 다음과 같이 하면 될 것이다.


>> x = 0:0.1:2*pi;
>> y = sin(x).*cos(x);
>> plot(x,y)


두 번째 줄에서 sin(x)와 cos(x)두 벡터의 곱에 (.*)연산자를 사용했음에 주의해야 한다. 계산하고자 하는 것이 두 벡터의 요소들 사이의 곱이기 때문이다.


[그림 1] 실행 결과 (gnu octave 에서 캡쳐)


또 다른 예로 x2+xsinx+1 이라는 함수를 도시하고자 한다면 다음과 같이 입력하면 된다.


>> x = -10:0.1:10;
>> y = x.^2 + x .*sin(x) + 1;
>> plot(x,y)


여기에서도 두 번째 줄에 (.^)연산자와 (.*)연산자가 쓰였음을 주의해서 보기 바란다. 요소간 연산을 수행해야 하기 때문이다.


[그림 2] 실행 결과 (gnu octave 에서 캡쳐)


두 번째 입력 파라메터가 행렬인 경우는 각각의 행을 서로 다른 그래프로 보여주게 된다. 다음 예를 보자.


>> x=linspace(0,2*pi,30);
>> y1=sin(x);
>> y2=cos(x);
>> Y=[y1;y2];
>> plot(x,Y)


의 예에서 linspace()함수는 0부터 까지 30개의 등간격 점을 생성하여 반환해주는 함수이다. plot()함수의 두 번째 파라메터 Y는 행렬이다. 아래  결과를 보면 각각의 행에 해당하는 그래프가 따로 도시됨을 알 수 있다.


[그림 3] 실행 결과 (gnu octave 에서 캡쳐)

 

또는 다음과 같이 따로따로 입력해도 같은 결과를 얻을 수 있다.


>> plot(x,y1,x,y2)


다음과 같이 x와 y값을 바꾸어서 입력하면 90도 회전시킨 그림을 도시하게 된다.


>> plot(Y,x)

[그림 4] 실행 결과 (gnu octave 에서 캡쳐)


이제까지 예제에서 그래프의 모양은 기본형이 실선으로 되어 있기 때문에 실선으로 그려졌으나 사용자가 임의로 지정할 수도 있다. 즉 선의 색상, 선의 모양 그리고 선의 종류를 사용자가 직접 지정할 수도 있다. 이것에 대해서는 다음 포스트에서 자세히 알아보도록 하겠다.



'프로그래밍언어.Lib > MATLAB' 카테고리의 다른 글

MATLAB의 plot()함수 (part 4)  (0) 2015.06.30
MATLAB의 plot()함수 (part 3)  (0) 2015.06.30
MATLAB의 plot()함수 (part 1)  (0) 2015.06.30
MATLAB의 ezplot()함수  (1) 2015.06.27
MATLAB의 기본적인 수학 함수들  (0) 2015.06.27
Posted by 살레시오
,

 여기에서는 2차원 그래프를 작성하는데 많이 쓰이는 plot()함수의 사용법에 대해서 자세히 알아보도록 하겠다.(이후 예제는 gnu octave로 모두 실행 가능함) 먼저 다음 예제를 실행해 보자.


>> y=(-3:3).^3; 󰎠
>> plot(y); 󰎠

[그림 1] 실행 결과 (gnu octave 에서 캡쳐)

plot()함수는 입력 파라메터(일단은 벡터라고 가정한다)가 하나일 때는 x축에는 인덱스 값을, y축에는 그 입력 파라메터를 도시한다. 즉 위 예제의 경우

y = [ -27 -8 -1 0 1 8 27]
인덱스  1  2  3  4 5 6 7

이므로 이를 (x,y)쌍으로 나타내면 (1,-27), (2,-8), (3,-1), (4,0), (5,1), (6,8), (7,27) 이고 plot()함수는 이 위치에 점을 찍은 후 이들을 선으로 연결한다. [그림 1]을 자세히 관찰해 보면 이해가 갈 것이다. 만약 점들의 간격이 충분히 좁다면 마치 곡선처럼 보일 것이다.


>> y=(-3:0.1:3).^3;
>> plot(y) 󰎠


[그림 2] 실행 결과 (gnu octave 에서 캡쳐)


점과 점의 간격이 작기 때문에 마치 곡선처럼 보이지만 기본적인 원리는 앞에서 설명한 바와 같다.

 또 다른 예로서 한 주기 동안 시간 t와 시간함수인 사인 함수 y=sin(t)를 그래프로 그려보자. 먼저 기준 축인 시간함수의 벡터를 정해야 한다.


>> t = 0:0.1:2*pi ; %t축 데이터 생성
>> y = sin(t); %y축 데이터 생성
>> plot(t,y)

[그림 3] 실행 결과 (gnu octave 에서 캡쳐)


입력 파라메터가 두개인 경우 두 입력은 크기가 같은 벡터여야 하며 첫 번째 파라메터를 x축에 그리고 두 번째 파라메터를 y축에 대응시켜서 그래프를 그리게 된다.


>> x=-2:5;
>> y=exp(x);
>> plot(x,y)


위의 예에서 다음과 같은 행벡터들을 얻을 수 있다.

x=[ -2 -1 0 1 2 3 4 5]

y=[ 0.14 0.36 1 2.72 7.39 20.09 54.60 148.41]

따라서 plot()함수는 (x,y)순서쌍 (-2,0.14),  (-1,0.36), (0,1), (1,2.72), (2,7.39), (3,20.09), (4,54.60), (5,148.41)의 위치에 점을 찍은 후 이들을 서로 실선으로 연결하게 된다. [그림 4]에 결과가 도시되어 있다.


[그림 4] 실행 결과 (gnu octave 에서 캡쳐)

좀 더 부드러운 곡선을 얻기 위해서는 행벡터 x의 간격만 줄여주면 된다.


>> x=-2:0.01:5;
>> y=exp(x);
>> plot(x,y)

[그림 5] 실행 결과 (gnu octave 에서 캡쳐)



Posted by 살레시오
,

 실험에서는 AVCC 를 단순히 5V에 연결하고 AREF는 연결을 하지 않았으며 [그림 1] 에 A/D변환기의 전원부를 도시하였다. 데이터쉬트에 의하면 AVCC는 LC필터를 이용하여 안정화시킬 것을 권장하고 있다.(여기에서는 사용하지 않음) 또한 앞으로의 실습에서는 기준전압을 AVCC로 사용할 것이기 때문에 AREF핀은 연결하지 않았다. 데이터쉬트에서는 AREF핀을 사용하지 않을 경우 GND와 0.1uF의 커패시터를 연결할 것을 권하고 있으나 이 역시 A/D변환 회로부에 들어가게 될지도 모르는 전원 잡음을 조금이라도 줄이기 위한 방편이며, 연결하지 않아도 실습하는데 있어서 크게 문제될 것은 없다.

[그림 1] 그림 8.3.1 데이터쉬트의 권장 회로(좌)와 실험키트의 회로(우)


Cds광센서를 이용한 ADC 실험

 여기에서는 Cds광센서를 이용하여 A/D변환 실험을 수행해 보겠다. 설명의 편의를 위해 회로도를 [그림2]에 도시하였다.


[그림 2] CdS 셀 회로도


Cds는 빛의 양에 따라 저항값이 반비례하는 가변 저항으로 보면 된다. 따라서 내부 풀업 저항을 연결한다면 광량에 따라서 PC4핀의 전압값이 달라질 것이다. 극단적인 경우로 Cds의 저항이 무한대라면(빛이 하나도 없는 경우) PC4핀의 전압은 5V일 것이다. 반대로 저항이 0이라면 (빛이 매우 많은 경우이다) PC4핀의 전압은 0V일 것이고 그 중간의 경우는 광량에 따라서 PC4핀의 전압값이 반비례할 것이다. 즉, 광량이 많으면 PC4핀의 전압은 낮아지고, 광량이 적어질수록 전압은 높아진다.


 이러한 특성을 이용하여 밝으면 LED가 꺼지고 어두워질수록 LED가 더 많이 켜지는 프로그램을 작성해 보자.


#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "Am8USBasp.h"
int main(void) {
   uint uiA;
   uchar ucB;
   InitAM8();
   ADMUX = 0b01000100; // AVCC, right-align, ADC4
   ADCSRA = 0b10100111; // free running, no interrupt, Div128
   sbi(ADCSRA, ADSC); // start conversion
   while(1) {
       uiA = ADC;// read ADC register value
       if (uiA < 256)
           ucB = 0b00000000;
       else if (uiA < 384)
           ucB = 0b00000011;
       else if (uiA < 512)
           ucB = 0b00001111;
       else
           ucB = 0b11111111;
       LED(ucB);
   }
}


이 예제에서는 기준전압을 AVCC로, 변환 데이터 저장 방식은 우측 정렬로 그리고 핀은 ADC4번 핀으로 선택하여 ADMUX레지스터에 설정하였다. 그리고 인터럽트는 사용하지 않고 연속 변환 모드와 128분주된 클럭으로 선택하여 ADCSRA레지스터에 설정하였다. 그리고 ADCSRA레지스터의 ADSC비트를 세트시켜서 변환을 시작시켰으며 그 이후에는 자동으로 A/D변환을 수행하여 ADC레지스터의 값이 실시간으로 갱신이 된다. 따라서 while(1) 반복문 안에는 단순히 ADC레지스터 값을 읽어서 그것의 범위에 따라서 LED의 숫자를 조절하는 프로그램이 작성되어 있다. A/D변환값이 10비트이기 때문에 그 값의 범위는 0~1023일 것이다.

 

 이 프로그램을 컴파일 한 후에 실행시켜서 만약 밝은 환경이라면 LED가 하나도 안 켜지지만 손바닥으로 센서를 많이 가릴수록 LED가 더 많이 켜지는 것을 확인할 수 있을 것이다.



Posted by 살레시오
,

 여기에서는 이전 포스트들 (ADC 개요, 관련 레지스터들) 에 이어서 A/D변환을 실제로 수행하는 절차에 대해서 정리하였다.

① 기준전압, 입력핀, 그리고 저장방식을 결정한 후 ADMUX 레지스터를 적절히 설정한다.

② 클럭분주비, 인터럽트 허용 여부 등을 결정한 후 ADCSRA 레지스터를 설정하여 A/D 변환기의 동작을 허용한다.

③ ADSC비트를 ‘1’로 써서 A/D변환을 시작한다.

④(A) 만약 변환 완료 인터럽트를 사용하지 않는다면 ADIF비트가 ‘1’이 될 때 까지 기다린 후 ADC레지스터 값을 읽는다. 그후 ADIF비트를 다시 클리어(‘0’)시킨다.

④(B) 만약 변환 완료 인터럽트를 사용한다면 ISR()함수에서 ADC레지스터 값을 읽는다.

 위에서 ④(A)번을 보면 A/D변환을 시작한 이후 완료되었는지를 검사하는 비트는 보통 ADIF를 사용함에 유의해야 한다. ADIF비트가 ‘1’로 세트되었다는 것은 A/D변환이 완료되고 그 변환값이 ADC레지스터에 저장되었음을 의미한다. 따라서 ADIF가 ‘1’이 될 때 까지 기다렸다가 그 이후에 변환값을 저장한다.


 만약 인터럽트를 사용하지 않는다면 ADIF 비트를 수동으로 클리어(‘0’)시켜야 하는데 데이터쉬트에 의하면 이를 위해서는 ADIF비트에 ‘1’을 써야한다는 것에 유의해야 한다. 만약 인터럽트를 사용하여 ISR(ADC_vect)가 호출된다면 자동으로 ADIF는 ‘0’으로 클리어된다.




Posted by 살레시오
,

 여기에서는 이전 포스트에 이어서 ACD에 관련된 레지스터들에 대해서 알아보도록 하겠다.

[ADCH:ADCL] 레지스터

 A/D 변환 결과는 10비트이기 때문에 SFR 두 개가 필요한데 ADCH과 ADCL 두개의 레지스터가 변환된 값이 저장되는 레지스터이다. 변환값의 상위 바이트와 하위 바이트를 저장하는데 각각 사용되고 ADC의 최대 분해능이 10비트이기 때문에 이중에 10개의 비트만이 변환 값을 저장하는데 사용된다. 뒤에 설명할 ADMUX 레지스터의 ADLAR 비트의 값에 따라 저장하는 방식은 두 가지가 있는데 이를 [그림 1]과 [그림 2]에 도시하였다.


[그림 1] ADLAR='0' 일 때 변환 결과를 저장하는 방식 (우측 정렬)


[그림 2] ADLAR='1' 일 때 변환 결과를 저장하는 방식 (좌측 정렬)


변환 값을 10비트 모두 사용하고자 한다면 [그림 1]과 같이 ADLAR='0'으로 설정한 후 상위 6개의 비트는 무시하고 사용하면 된다. 하지만, 변환 결과를 8비트만 쓰고 싶을 때에는 [그림 2]와 같이 ADLAR='1'로 설정한 후 ADCH 값만을 취하여 사용하면 된다. 이후로는 16비트 메모리 [ADCH:ADCL]을 줄여서 ADC라고 표기한다. A/D 변환 결과는 다음과 같은 식으로 계산할 수 있다.

여기서 Vin 은 선택된 입력핀의 전압값이고 Vref 는 기준전압이다.

ADCSRA 레지스터

 ADCSRA (ADC Control and Status Register) 레지스터는 ADC의 전반적인 동작을 제어하는 기능을 수행한다. 구조는 다음과 같다.


[그림 3] ADCSRA 레지스터의 구조


• ADEN (ADc ENable) 비트는 ‘1’로 설정해야 ADC의 모든 동작이 허용된다. ‘0’으로 설정하면 ADC의 모든 동작이 금지되며 만약 변환 중에 ‘0’으로 클리어되면 변환이 즉시 중지된다.

• ADSC (ADc Start Conversion) 비트가 ‘1’로 세트되면 ADC가 시작된다. 연속 변환 모드에서는 이 비트가 세트되면 첫 번째 변환이 수행된 이후 자동으로 계속 변환이 수행된다. ADEN 비트가 ‘1’로 설정된 이후의 최초의 변환은 ADC의 초기화 때문에 25 클럭이 소요되고 두 번째 변환부터는 13클럭이 소요된다. 변환이 진행 중이라면 이 비트를 읽으면 ‘1’ 값이 읽혀지고 변환이 완료되면 ‘0’값으로 되돌아간다.

• ADFR (ADc Free Running select) 비트는 ADC를 연속 변환 모드로 설정한다. 연속 변환 모드에서는 ADC 변환이 자동으로 연속적으로 일어나므로 임의의 시점에서 최신 변환 결과를 읽어들일 수 있다.

• ADIF (ADc Interrupt Flag) 비트는 A/D 변환이 완료되어 ADC 레지스터 값이 갱신되고 나면 ‘1’로 세트되며, 만약 ADIE 비트가 ‘1’로 세트된 상태라면 인터럽트를 요청하게 된다. 해당 ISR이 호출되면 ADIF 비트는 자동으로 ‘0’으로 리셋되며, 만약 사용자가 강제로 이 비트를 ‘0’으로 클리어하려면 이 비트에 ‘1’을 써주어야 한다.

• ADIE (ADc Interrupt Enable) 비트를 ‘1’로 설정하면 A/D 변환완료 인터럽트를 허용한다. 실제로 인터럽트가 발생하려면 SREG 레지스터의 I비트가 ‘1’로 설정되어 있어야 한다.

• ADPS2:0 비트들은 ADC에 인가되는 클럭의 분주비를 선택한다. A/D변환기에서 사용하는 클럭은 10비트 연속 변환 모드가 정상적으로 수행되기 위해서 50~200KHz 범위 이내이어야 한다고 데이터쉬트에 기록되어 있다. 따라서 본 실습키트의 경우처펌 시스템클럭이 16MHz일 때에는 정상적인 A/D변환을 위해서는 <표 8.3.1>에 표시한 바와 같이 ADSP2:0='110' 혹은 ADSP2:0='111' 이어야 한다.

단, 10비트보다 낮은 분해능으로 사용할 경우에는 200KHz보다 더 높은 주파수를 사용할 수 있다고 되어 있다.


[표 1] ADC로 인간되는 클럭의 분주비

ADSP2

ADSP1

ADSP0

분주비

clksys=16MHz 일 경우

0

0

0

2

8,000KHz

0

0

1

2

8,000KHz

0

1

0

4

4,000KHz

0

1

1

8

1,000KHz

1

0

0

16

500KHz

1

0

1

32

250KHz

1

1

0

64

125KHz

1

1

1

128

62.5KHz


ADMUX 레지스터

 ADMUX (ADc MUltipleXer selection register) 레지스터는 ADC의 입력 핀을 선택하는 기능과 기준 전압원을 선택하거나 변환 결과를 레지스터에 저장하는 형식을 지정하는 기능을 수행한다.


[그림 4] ADMUX레지스터의 구조


• REFS1:0 두 비트는 A/D 변환의 기준 전압을 선택한다.


[표 2] ADC 기준 전압 선택

REFS1

REFS0

기준전압 선택

0

0

AREF에 인가되는 전압

0

1

AVCC에 인가되는 전압 (1)

1

0

-

1

1

내부 2.56V 전압 (1)

(1) AREF핀에 외부 전압을 인가하지 않고 GND와 0.1uF의 커패시터를 연결할 것.


• ADLAR (ADc Left Adjust Result) 비트는 ‘1’로 설정되면 A/D 변환 결과가 ADC레지스터에 저장될 때 <그림 8.2.2>와 같이 정렬되고 ‘0’으로 설정되면 <그림 8.2.1.>과 같이 정렬된다.

• MUX3:0 비트들은 ADC의 입력핀을 선택한다. PDIP패키지는 외부 핀이 ADC5번까지만 있고, TQFP/MLF 패키지는 ADC7번까지 있다.


[표 3] 입력 채널 선택

MUX3:0

단극성입력

(single ended input)

비고

0000

ADC0

PDIP 패키지

0001

ADC1

0010

ADC2

0011

ADC3

0100

ADC4

0101

ADC5

0110

ADC6

TQFP/MLF 패키지에만 있음

0111

ADC7

1000

~1101

-

1110

1.30V (VBG)

1111

0V (GND)



Posted by 살레시오
,