Physical Computing for Artists & Designers 연세대학교디지털아트학과 Earl Park
시프트 레지스터 Shift Resistor 자, 이제 LED MATRIX 8x8 Board를 마이크로컨트롤러에 연결된 3개의 선으 로 제어해 보자. 이는 마이크로컨트롤러의 포트를 확장함과 동시에 프로그램 으로 제어를 더 쉽게 한다는 장점이 있다. 물론 포트를 절약하게 됨으로써 LED MATRIX 8x8 Board를 여러개 연결할 수도 있게 된다. 2주 전에 써봤던 74HC595 shift resistor chip을 저번주에 구성해 보았던 트랜지 스터 어레이인 ULN2803과 UDN2981회로에 연결해 보자. 하드웨어가 변경되면 프로그래밍 또한 바뀌어야 한다. 달라진 점을 살펴보자. 저번주 (마이크로컨트롤러 - 트랜지스터 어레이 - LED MATRIX) ULN2981, UDN2803(TR array) + 8x8 LED Matrix 회로도 하드웨어 : 8개씩 2개, 16개의 핀이 트랜지스터 어레이에서 마이크로컨트롤러 로 연결되어 있다. 프로그래밍 : 마이크로컨트롤러에 연결된 각각의 핀에 digitalwrite()로 1개의 비 트(0혹은 1)를 넣어주어 트랜지스터가 LED +, - line을 스위칭하게 만든다. 이번주 (마이크로컨트롤러 - shift resistor - 트랜지스터 어레이 - LED MATRIX) 하드웨어 : Clock, Latch, Data - 3개의 선이 shift resistor에서 마이크로 컨트롤러 로 연결되어 있다. 프로그래밍 : shiftout() 함수로 8개의 비트를 한꺼번에 보내주면 shift resistor가 병렬로 연결된 트랜지스터 어레이를 거쳐 각각의 LED +, - line을 제어하게 되므 로 프로그래밍에서 8개의 비트를 직렬로 보내주면 된다. 74HC595(Shift Resistor) + ULN2981, UDN2803(TR array) + 8x8 LED Matrix 회로도 Physical Computing 1
74HC595 + UDN2981 + ULN2803 회로 74HC595로 8-bit serial-in, serial or parallel-out shift register PINS Q0 ~ Output Pins 1~7, 15 Q7 PIN 8 GND Ground, Vss PIN 9 Q7" Serial Out PIN 10 MR Master Reclear, active low PIN 11 SH_CP Shift register clock pin PIN 12 ST_CP Storage register clock pin (latch pin) PIN 13 OE Output enable, active low PIN 14 DS Serial data input PIN 16 Vcc Positive supply voltage UDN2981 : 8-channel source drivers. pnp open-emitter dalington transistor array PINs in1 Base drive to driver input transistor 1~8 ~in8 PINs out8 Emitter of Darlington driver output. 11~18 ~out1 PIN 9 Vs Supply Input PIN 10 GND Ground ULN2803 : 8-channel sink drivers. npn open-collector dalington transistor array PINs in1 darlington base input 1~8 ~in8 PINs out8 darlington collector output 11~18 ~out1 PIN 9 GND Common Emmitter shared by all channels (typically tied to ground) Physical Computing 2
LED Matrix 켜보기 (basic) <Shift Resistor + TR array 프로그래밍 > data (9번 DS, serial data input pin) latch (10번 ST_CP, storage resistor clock pin) clock (11번 SH_CP, shift resistor clock pin) void setup() : 마이크로컨트롤러에연결된 data, latch, clock핀을아웃풋설정 void loop() : 순서대로가로, 세로각핀에이진수의값을하나씩넣어줌 1. 래치를 0으로만든다. ( 데이터입력받을준비를한다.) 2. ShiftOut명령어로 +line, -line으로보내줄 8개의데이터 (8-bit) 를각각저장해둠 3. 래치를 1로만든다. -> 레지스터에저장되어있던데이터가한꺼번에출력된다. shiftout(datapin, clockpin, MSBFIRST, B10011001); shiftout(datapin, clockpin, MSBFIRST, B11111111); <TR array 프로그래밍 ( 저번시간프로그래밍 )> xbits[] 변수배열 (array) 에 x줄 8개의아두이노핀넘버를저장 ybits[] 변수배열 (array) 에 y줄 8개의아두이노핀넘버를저장. void setup() : 마이크로컨트롤러에연결된핀을모두아웃풋으로설정 void loop() : 순서대로가로, 세로각핀에이진수의값을하나씩넣어줌 ( 각각핀에 8번반복 ) B10011001는이진수를표현하는방식 ( 표기법 ) 이다. B는 Binery의약자. 참고 ) 16진수 0x00, 10진수 00, 이진수 B00000000 byte xbits[] = {2,3,4,5,6,7,8,9; // arduino pin numbers for x byte ybits[] = {10,11,12,13,14,15,16,17; // arduino pin numbers for y for (int i = 0; i < 8; i++){ pinmode(xbits[i], OUTPUT); pinmode(ybits[i], OUTPUT); for (int i = 0; i < 8; i++){ digitalwrite(xbits[i], bitread(b10011001, i)); digitalwrite(ybits[i], bitread(b11111111, i)); Physical Computing 3
LED Matrix 켜보기 (basic, 사용자함수 ) < 프로그래밍 > data (9번 DS, serial data input pin) latch (10번 ST_CP, storage resistor clock pin) clock (11번 SH_CP, shift resistor clock pin) void setup() : 마이크로컨트롤러에연결된 data, latch, clock핀을아웃풋설정 void loop() : drawmatrix() 함수로매개변수 B10011001, B11111111을보내줌. drawmatrix() : 사용자함수로 int x = B10011001, int y = B11111111로받아순서대로가로, 세로각핀에이진수의값을하나씩넣어줌 1. 래치를 0으로만든다. ( 데이터입력받을준비를한다.) 2. ShiftOut명령어로 +line, -line으로보내줄 8개의데이터 (8-bit) 를각각저장해둠 3. 래치를 1로만든다. -> 레지스터에저장되어있던데이터가한꺼번에출력된다. drawmatrix(b10011001, B11111111); void drawmatrix(int x, int y) { shiftout(datapin, clockpin, MSBFIRST, x); shiftout(datapin, clockpin, MSBFIRST, y); * 앞장의코드와하는일은동일함. * 데이터를수정하기편함. 새로운함수 - 사용자함수 http://www.arduino.cc/en/reference/functiondeclaration drawmatrix() 은사용자함수이며, 매개변수의사용이가능하다. 사용자함수명은프로그램하는사람이변수를설정하듯이마음대로정할수있다. 자주사용하는명령들을묶어사용하면편리하다. Physical Computing 4
LED Matrix 켜보기 ( 패턴만들기 1) < 프로그래밍 > 대각선라인을순차적으로켜보는코드 diagonalline() : 받은데이터를바탕으로데이터처리방향결정 cal() : 스피드조절과데이터시프트, 잔상처리 drawmatrix() : 마이크로컨트롤러에서 2개의 8bit 데이터보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌 offall() : 마이크로컨트롤러에서 2개의 0(B00000000) 데이터를보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌. 결과는 LED 모두꺼짐. 한줄한줄켤경우에는 drawmatrix() 에서줄을켠다음에데이터를다지워줘야한다. 안그러면잔상이남는다. void diagonalline(int init, int fin, int j){ if (init > fin){ for(int i = init; i >= fin; i=i-j){ cal(300,i); else{ for(int i = init; i <= fin; i=i+j){ cal(300,i); void cal(int spd, int i){ for(int c = 0; c <= spd; c++) { for (int s = 0; s <= i; s++) { drawmatrix((1<<s),(1<<s)); delaymicroseconds(20); offall(); diagonalline(0, 7, 1); //(start, end, step) diagonalline(7, 0, 1); //(start, end, step) void drawmatrix(int x, int y) { shiftout(datapin, clockpin, MSBFIRST, x); shiftout(datapin, clockpin, MSBFIRST, y); void offall() { Physical Computing 5
LED Matrix 켜보기 ( 패턴만들기 2) < 프로그래밍 > 사각형을점점커졌다가작게만들어보는코드 diagonalsqure() : 행과열의데이터를 255(B11111111) 에서시프트해줌 drawmatrix() : 마이크로컨트롤러에서 2개의 8bit 데이터보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌 offall() : 마이크로컨트롤러에서 2개의 0(B00000000) 데이터를보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌. 결과는 LED 모두꺼짐. 한줄한줄켤경우에는 drawmatrix() 에서줄을켠다음에데이터를다지워줘야한다. 안그러면잔상이남는다. diagonalsquare(0, 7, 255, 100); //(start, end, max, microsecond delay) void diagonalsquare(int init, int fin, int num, int delaytime){ for(int i = fin; i >= init; i--){ drawmatrix((num >> i),(num >> i)); delay(delaytime); for(int i = init; i <= fin; i++){ drawmatrix((num >> i),(num >> i)); delay(delaytime); void drawmatrix(int x, int y) { shiftout(datapin, clockpin, MSBFIRST, x); shiftout(datapin, clockpin, MSBFIRST, y); void offall() { Physical Computing 6
LED Matrix 켜보기 ( 데이터스크롤 ) < 프로그래밍 > 미리저장된그림 ( 데이터 ) 들을바탕으로스크롤해주는코드 init_ddata() : LED Matrix에보여줄그림 ( 데이터 ) 를이진수로저장 draw() : 데이터와데이터길이를매개변수로받아한줄씩 drawmatirix() 에보내주고데이터를한줄씩뒤로밀어서저장함 drawmatrix() : 마이크로컨트롤러에서 2개의 8bit 데이터보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌 offall() : 마이크로컨트롤러에서 2개의 0(B00000000) 데이터를보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌. 결과는 LED 모두꺼짐. 한줄한줄켤경우에는 drawmatrix() 에서줄을켠다음에데이터를다지워줘야한다. 안그러면잔상이남는다. byte ddata[45]; //drawing data void init_ddata() { ddata[0] = B00000000; //blink ddata[1] = B00000000; ddata[2] = B00000000; ddata[3] = B00000000; ddata[4] = B00000000; ddata[5] = B00000000; ddata[6] = B00000000; ddata[7] = B00000000; ddata[8] = B11111111; //P ddata[9] = B00001001; ddata[10] = B00000110; ddata[11] = B00000000; ddata[12] = B11111111; //H ddata[13] = B00011000; ddata[14] = B11111111; ddata[15] = B00000000; ddata[16] = B00000111; //Y ddata[17] = B11111000; ddata[18] = B00000111; ddata[19] = B00000000; Physical Computing 7
ddata[20] = B01111110; //C ddata[21] = B11000011; ddata[22] = B01100110; ddata[23] = B00000000; ddata[24] = B01111110; //O ddata[25] = B11000011; ddata[26] = B01111110; ddata[27] = B00000000; ddata[28] = B11111111; //M ddata[29] = B00001100; ddata[30] = B11111111; ddata[31] = B00000000; void draw(byte data[], int length) { for (int i = 0; i <= length; i++){ for (int j = 0; j <= 30; j++){ for (int k = 0; k <= 7; k++){ drawmatrix(1<<k, ddata[k]); delaymicroseconds(1000); offall(); for(int d = 0; d <= 43; d++){ ddata[d] = ddata[d+1]; ddata[32] = B00000000; //blink ddata[33] = B00000000; ddata[34] = B00000000; ddata[35] = B00000000; ddata[36] = B00000000; ddata[37] = B00000000; ddata[38] = B00000000; ddata[39] = B00000000; ddata[40] = B00100100; //:) ddata[41] = B00000000; ddata[42] = B01000010; ddata[43] = B00111100; void drawmatrix(int x, int y) { shiftout(datapin, clockpin, MSBFIRST, x); shiftout(datapin, clockpin, MSBFIRST, y); void offall() { ddata[44] = B00000000; //Last line of data is blank to clear display as it scrolls init_ddata(); draw(ddata, 45); //(scroll data, data length) Physical Computing 8
LED Matrix 켜보기 ( 데이터스크롤 + 스피드조절 ) < 하드웨어 > 아날로그인풋 5번핀에가변저항트리머 103(10K) 을연결 < 프로그래밍 > 미리저장된그림 ( 데이터 ) 들을바탕으로스크롤해주는코드. 연결된포텐시오미터로스크롤되는속도를조절함 init_ddata() : LED Matrix에보여줄그림 ( 데이터 ) 를이진수로저장 draw() : 데이터와데이터길이를매개변수로받아한줄씩 drawmatirix() 에보내주고데이터를한줄씩뒤로밀어서저장함아날로그인풋 5번핀에연결한고정형가변저항의아날로그값에따라스크롤속도가 30단계로조절됨 drawmatrix() : 마이크로컨트롤러에서 2개의 8bit 데이터보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌 offall() : 마이크로컨트롤러에서 2개의 0(B00000000) 데이터를보내고 Shift Resistor에서받아 8개의포트로 LED Matrix +, -라인에각각의데이터를넣어줌. 결과는 LED 모두꺼짐. 한줄한줄켤경우에는 drawmatrix() 에서줄을켠다음에데이터를다지워줘야한다. 안그러면잔상이남는다. byte ddata[45]; //drawing data Serial.begin(9600); //for debug void init_ddata() { ddata[0] = B00000000; //blink ddata[1] = B00000000; ddata[2] = B00000000; ddata[3] = B00000000; ddata[4] = B00000000; ddata[5] = B00000000; ddata[6] = B00000000; ddata[7] = B00000000; ddata[8] = B11111111; //P ddata[9] = B00001001; ddata[10] = B00000110; ddata[11] = B00000000; ddata[12] = B11111111; //H ddata[13] = B00011000; ddata[14] = B11111111; ddata[15] = B00000000; ddata[16] = B00000111; //Y ddata[17] = B11111000; ddata[18] = B00000111; Physical Computing 9
ddata[19] = B00000000; ddata[20] = B01111110; //C ddata[21] = B11000011; ddata[22] = B01100110; ddata[23] = B00000000; ddata[24] = B01111110; //O ddata[25] = B11000011; ddata[26] = B01111110; ddata[27] = B00000000; ddata[28] = B11111111; //M ddata[29] = B00001100; ddata[30] = B11111111; ddata[31] = B00000000; ddata[32] = B00000000; //blink ddata[33] = B00000000; ddata[34] = B00000000; ddata[35] = B00000000; ddata[36] = B00000000; ddata[37] = B00000000; ddata[38] = B00000000; ddata[39] = B00000000; void draw(byte data[], int length) { for (int i = 0; i <= length; i++){ int scroll_speed = map(analogread(5),0,1023,0,30); Serial.println(scroll_speed); for (int j = 0; j <= scroll_speed; j++){ for (int k = 0; k <= 7; k++){ drawmatrix(1<<k, ddata[k]); delaymicroseconds(1000); offall(); for(int d = 0; d <= 44; d++){ ddata[d] = ddata[d+1]; void drawmatrix(int x, int y) { shiftout(datapin, clockpin, MSBFIRST, x); shiftout(datapin, clockpin, MSBFIRST, y); ddata[40] = B00100100; //:) ddata[41] = B00000000; ddata[42] = B01000010; ddata[43] = B00111100; ddata[44] = B00000000; //Last line of data is blank to clear display as it scrolls void offall() { init_ddata(); draw(ddata, 45); //(scroll data, data length) Physical Computing 10
포텐시오미터 2 개로 LED 제어하기 < 하드웨어 > 아날로그인풋 4, 5번핀에가변저항트리머 103(10K) 을연결 < 프로그래밍 > 2개의포텐시오미터로 LED Matrix Board의 X, Y축 (+,- 라인 ) 에해당하는 LED를제어하는프로그램. void setup() : 시리얼통신설정 : 마이크로컨트롤러에연결된 data, latch, clock핀을아웃풋설정 void loop() : 포텐시오미터로받은 0~1023의값을 map(); 함수를통해 0~7로바꾸어 pot_x, pot_y 변수에저장 : 시리얼통신으로 pot_x의값을보내줌. 아두이노 IDE의시리얼창을통해확인. : 2개의포텐시오미터를조작하기에따라 1<<pot_X = 1( 이진수 : B00000001) 을 pot_x번째만큼데이터를시프트, 128>>pot_Y = 128( 이진수 :B10000000) 을 pot_y번째만큼데이터를시프트해서 drawmatrix() 함수로매개변수 x, y에해당하는데이터를보내줌. (1이나 128을쓰는이유는포텐시오미터돌리는방향에따라 LED의위치를맞추기위해서임 ) Serial.begin(9600); int pot_x = map(analogread(5),0,1023,0,7); int pot_y = map(analogread(4),0,1023,0,7); Serial.println(pot_X); drawmatrix(1<<pot_x, 128>>pot_Y); //drawmatrix(b00000001<<pot_x, B10000000>>pot_Y); void drawmatrix(int x, int y) { shiftout(datapin, clockpin, LSBFIRST, x); shiftout(datapin, clockpin, LSBFIRST, y); drawmatrix() : 사용자함수로 int x, int y로해당되는데이터를받아순서대로 TR array를거쳐 LED Matrix의가로, 세로각핀에이진수의값을하나씩넣어줌 Physical Computing 11