본문 바로가기

아두이노

시프트 레지스터 (MAX 7219)를 이용한 세븐 시그먼트 8개 표시하기 - 튜토리얼(코딩4)

반응형

 

 

여친과의 기념일을 보낸다고 한 이틀 쉬었더니 벌써 몇개는 까먹은 듯 하다..

그래도 한번 이해를 하고 나니 어렵지 않게 진행을 할 수 있는 것 같다.

 

이번에는 이전 설명에도 여러번 등장하였던 putByte함수에 대해서 알아보자!

 

우선 putByte함수는 아래와 같다.

 

void putByte(int data)

{

 int i = 8; 
 int mask;
 while(i > 0)

{
     mask = 0x01 << (i - 1);     
     digitalWrite(clock, LOW);   
     if ( ( data & mask ) != 0 )

{    

digitalWrite(dataIn, HIGH);

}

else

{
     digitalWrite(dataIn, LOW);

}

digitalWrite(clock, HIGH);   

--i;                         // move to lesser bit

 }

}

 

우선 putByte는 리턴값이 없는 함수로써 data라는 int형식의 변수를 받아 들이는 함수이다.

 

다른 함수 내에서 putByte(int data)가 호출 되었을 때 어떤일이 일어나는지 알아보도록 하자

 

void putByte(int data)

{

 int i = 8; // 우선 i라는 int형식의 변수를 선언 한 후 8을 할당한다.
 int mask; //mask라는 변수를 int형식으로 선언한다.
 while(i > 0) // i가 0보다 클 동안 while내부의 함수를 실행한다. 처음 실행 시 8이고 제일 아랫쪽에 보면 --i라고 되어 있으니 총 8번 수행인 것을 유추가능

{
     mask = 0x01 << (i - 1);     //mask값에 0x01을 할당 (16진수로 1이며 2진수로는 0000 0001)하고 '<<' 명령어로써 비트를 왼쪽으로 i-1만큼 이동시킨다.(>>는 오른쪽으로 이동시키는 것) 즉, 현재의 비트는 2진수로 0000 0001인데 첫 시행 시 i가 8이므로 i-1은 7이기 때문에 비트를 왼쪽으로 7칸이동시키면 1000 0000 이 된다.

i값이 점차 작아지므로 첫시행때의 mask값은 1000 0000이되고, 두번째는0100 0000, 세번째는 0010 0000 이다. 왜 이렇게 하는건지는 조금 더 진행하며 알아가자 
     digitalWrite(clock, LOW);   // clock을 LOW로 설정하여 레지스터로의 입력을 활성화 한다.
     if ( ( data & mask ) != 0 ) // data&mask의 뜻는 변수 data와 mask를 논리곱을 하라고 하는 명령어이다. 논리곱에 대해서 설명하자면 0&0=0, 1&0=0, 0&0=0, 1&1=1이 되는 과정이라고 할 수 있다. 그리하여 data와 mask의 논리곱이 != 0 (0이 아님, 등호 앞에 ! 가 붙어서 부정의 의미가 된다.) 이 되면 실행을 하는 if함수이다.

{    

digitalWrite(dataIn, HIGH); // 논리곱을 한 결과값이 0이 아닐 경우 dataIn에 HIGH값을 걸어준다. 즉, 2번핀에 5v를 걸어준다는 뜻

}

else

{
     digitalWrite(dataIn, LOW); // 논리곱을 한 결과값이 0일 경우 dataIn에 LOW값을 걸어준다. 즉, 2번핀에 0v를 걸어준다는 뜻

}

digitalWrite(clock, HIGH);   // clock에 HIGH를 걸어줌으로써 레지스터로의 입력을 비활성화 한다.

--i;                         // i값을 1 줄여서 그 다음 시행을 위한 준비를 한다.

 }

}

 

하필이면 왜 putByte를 쓰는 것일까?

함수의 이름만 본다면 레지스터에 데이터를 넣어주는 그런 함수로 보이는데

넣어주기만 하면 되는데 왜 일부러 mask라는 변수를 선언해서 비트를 이동시키고 하는 것일까?

그 이유는 받은 데이터의 비트를 분석을 하기위한 것이라고 할 수 있다.

 

우선 예를들어 putByte(3)이 호출 된 경우를 들어보겠다.

만약 putByte(3)이 호출이 된다면.

맨 처음 mask값이 0000 0001에서 비트이동을 하여 1000 0000이 된다. 그 다음 하는것이 if구문의 조건에서 data와 mask의 논리곱을 시행하는 것인데

3과 mask의 논리곱을 보도록 하자 (3의 2진수는 0000 0011이다.)

 

1000 0000  ->mask

0000 0011  ->data

 

0000 0000 ->논리곱

 

이 되며 논리곱은 0이 되어 결과에 따라 dataIn에는 LOW값이 출력이 되고 --i에 의해 i 는 7이된다.

그 다음 시행시 i는 7 이 되므로 mask의 비트는 왼쪽으로 6칸만 가면 되기 때문에

0100 0000  ->mask

0000 0011  ->data

 

0000 0000  ->논리곱

다시 논리곱의 값은 0이 되어 dataIn에는 Low값이 출력이 된다. 이런 시행을 여러번 거친 후 

i가 2일때는 마스크는 한칸만 왼쪽으로 가면 된다.

 

0000 0010  ->mask

0000 0011  ->data

 

0000 0010  ->논리곱

이때, 논리곱은 2진수로 2가되며 0이 아닌 수가 처음으로 나타나게 된다.

논리곱의 결과값이 0이 아닐 때  dataIn에는 HIGH값이 출력이 되고 그 다음 시행에서는

 

0000 0001  ->mask

0000 0011  ->data

 

0000 0001  ->논리곱

논리곱의 결과값은 1이 되어 dataIn에는 HIGH값이 출력이 되고 --i에의해 i는 0이 됨으로 while구문은 더이상 시행 될 수가 없다.

 

즉 putByte(3)이 호출 될 경우

 

1번(i=8) 시행에서 clock low 뒤 '0'입력 후  clock high

2번(i=7) 시행에서 clock low 뒤 '0'입력 후  clock high

3번(i=6) 시행에서 clock low 뒤 '0'입력 후  clock high

4번(i=5) 시행에서 clock low 뒤 '0'입력 후  clock high

 

5번(i=4) 시행에서 clock low 뒤 '0'입력 후  clock high

6번(i=3) 시행에서 clock low 뒤 '0'입력 후  clock high

7번(i=2) 시행에서 clock low 뒤 '1'입력 후  clock high

8번(i=1) 시행에서 clock low 뒤 '1'입력 후  clock high

 

가 되고 7219의 첫 장에서 설명 한 것과 같이

clock low와 clock high사이에 입력된 비트가 레지스터에 입력이 되는것이기 때문에

시프트 레지스터에 출력되는 값은 000 0011이 되는 것이다.

 

 

 

앞서 설명한 maxSingle함수와 같이 연관지어서 생각해 보면

 

 void maxSingle(int reg, int col)

{    

        digitalWrite(load, LOW);    

  putByte(reg);               
  putByte(col);

       digitalWrite(load, LOW);    
       digitalWrite(load, HIGH);
 }

 

우선 digitalWrite(load, LOW)로 시프트 레지스터에 시동을 걸고

putByte(reg)로 시프트 레지스터로 입력되는 16비트의 데이터 중 앞의 8비트 데이터를 레지스터에 입력하고(마스크에 의한 논리곱으로 clock low와 clock high사이사이에 비트가 입력됨)

putByte(col)로 시프트 레지스터로 입력되는 뒤의 8비트 데이터를 레지스터에 입력하고(마스크에 의한 논리곱으로 clock low와 clock high사이사이에 비트가 입력됨)

digitalWrite(load,HIGH)로 시프트 레지스터에 입력하는 일렬의 과정을 마치는 것이다.

여기서 putbyte(reg)와 putByte(col)은 연결되어 있는것으로 봐도 무관하다.

 

그래서 한번 바꿔보았다.

 

 

 void maxSingle(int reg, int col)

{    

       digitalWrite(load, LOW);    

 putByte(reg, col);              

       digitalWrite(load, LOW);    
       digitalWrite(load, HIGH);
 }

 

// putByte두번 실행을 그냥 putByte에서 각각의 실행때의 변수를 입력으로 받도록 한 뒤 putByte함수내에서 변수 data와 col을 받아 data, datados에 입력 한 후

data는 왼쪽으로 8칸이동하고 datados를 더해서 16비트의 연속적인 수 datareult를 만들어 mask를 16번 시행하도록 바꿔보았다.

 

void putByte(int data, int datados)

{

 int i = 16; 
 long mask;

 long dataresult;
 while(i > 0)

{

     data = data << (8) ;

     dataresult = datados + data ;
     mask = 0x01 << (i - 1);     
     digitalWrite(clock, LOW);   
     if ( ( dataresult & mask ) != 0 )

{    

digitalWrite(dataIn, HIGH);

}

else

{
     digitalWrite(dataIn, LOW);

}

digitalWrite(clock, HIGH);   

--i;        

 }

}

 

근데안됨

처음에 안될때는 1111 1111 1111 1111 이 되었을 경우에 그 숫자의 크기는 약 2의 17승이며 int변수가 감당하는 범위 -32768~32767을 벗어나서 long 변수 (-2147483648~2147783647)을 써봤으나 실패, 혹시나 이진수가 음수가 되지 않을까 싶어(2진수의 음수는 한참전에 배워서 잘 기억이 안난다... ) unsigned int로 변수를 선언하려고 하니 VBB에서 인식하지를 않는다...

우선 이 것은 접어두도록 하고..

어쨋든 7219의 사용에 있어서 코딩 시 함수들이 어떻게 상호작용하는지 알았으므로

튜토리얼을 참고하여 내가 직접 코딩을 해 보도록 해야겠다.

 

반응형