Wednesday, February 16, 2011

LED matrix schematic
Arduino Nano connections (jumpered, no soldering)


1:  // http://orpex.blogspot.com  
2:  // ATmega168  
3:  // PIN DEFINITIONS:  
4:  // PB1-4 ROW DRIVERS (0-3)  
5:  // PC0-5,PD2-3: COLUMN DRIVERS (0-7)  
6:  // PD7 BUTTON  
7:  #define F_CPU 14745600  
8:  #define ROWS 4  
9:  #define COLS 16  
10:  #include <stdio.h>  
11:  #include <inttypes.h>  
12:  #include <avr/io.h>  
13:  #include <avr/interrupt.h>  
14:  #include <avr/pgmspace.h>  
15:  #include <util/delay.h>  
16:  volatile uint8_t la_row, real_row;  
17:  volatile uint8_t la_data[COLS];  
18:  inline uint8_t ledarray_get(uint8_t i, uint8_t j)   
19:  {  
20:   if(i < ROWS && j < COLS)   
21:   {  
22:    if((la_data[j] & (1<<i)) != 0)   
23:    {  
24:     return 1;  
25:    }   
26:   }   
27:   return 0;  
28:  }  
29:  inline void ledarray_set(uint8_t i, uint8_t j, uint8_t onoff)   
30:  {  
31:   if(i < ROWS && j < COLS)   
32:   {  
33:    if(onoff)   
34:    {  
35:     la_data[j] |= (1<<i);  
36:    }   
37:    else   
38:    {  
39:     la_data[j] &= ~(1<<i);  
40:    }  
41:   }  
42:  }  
43:  //sense variable indicates direction of LED: sense == 1 indicates COL wire must be  
44:  //high for LED to turn on. sense == 0, COL wire must be low to turn LED on  
45:  inline void ledarray_set_columndriver(uint8_t j, uint8_t onoff, uint8_t sense)   
46:  {  
47:   // cols 0-5: PC0-5  
48:   // cols 6-7: PD2-3  
49:   if(j < 6)   
50:   {  
51:    if(onoff)  
52:    { //led on  
53:     DDRC |= (1 << (PC0 + j));  
54:     if(sense)   
55:     {  
56:      PORTC |= (1 << (PC0 + j));  
57:     }   
58:     else   
59:     {  
60:      PORTC &= ~(1<< (PC0 + j));  
61:     }  
62:    }   
63:    else   
64:    { // led off, pins to high impedance  
65:     DDRC &= ~(1 << (PC0 + j));  
66:     PORTC &= ~(1 << (PC0 + j));  
67:    }  
68:   }   
69:   else   
70:   {  
71:    if(onoff)  
72:    { //led on  
73:     DDRD |= (1 << (PD2 + (j-6)));  
74:     if(sense)   
75:     {  
76:      PORTD |= (1 << (PD2 + (j-6)));  
77:     }   
78:     else   
79:     {  
80:      PORTD &= ~(1 << (PD2 + (j-6)));  
81:     }  
82:    }   
83:    else   
84:    { // led off, pins to high impedance  
85:     DDRD &= ~(1 << (PD2 + j));  
86:     PORTD &= ~(1 << (PD2 + j));  
87:    }  
88:   }  
89:  }  
90:  inline void ledarray_all_off()   
91:  {  
92:   // turn off all row drivers  
93:   DDRB &= ~( (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) );  
94:   PORTB &= ~( (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) );  
95:   // turn off all column drivers  
96:   DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );  
97:   PORTC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );  
98:   DDRD &= ~( (1<<PD2) | (1<<PD3) );  
99:   PORTD &= ~( (1<<PD2) | (1<<PD3) );   
100:  }  
101:  SIGNAL(SIG_OVERFLOW0)   
102:  {  
103:   // turn off old row driver  
104:   DDRB &= ~(1 << (PB1 + real_row));  
105:   PORTB &= ~(1 << (PB1 + real_row));  
106:   ledarray_all_off();  
107:   // increment row number  
108:   if (++la_row == 2*ROWS) la_row = 0;  
109:   // set column drivers appropriately  
110:   uint8_t j;  
111:   if (la_row%2 == 0)   
112:   {  
113:    // even la_row number: fill even columns  
114:    real_row = la_row / 2;  
115:    for(j=0; j<COLS/2; j++)   
116:    {  
117:     ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);  
118:    }  
119:    // activate row driver SINK  
120:    PORTB &= ~(1 << (PB1 + real_row));  
121:    DDRB |= (1 << (PB1 + real_row));  
122:   }   
123:   else   
124:   {  
125:    // odd la_row number: fill odd columns  
126:    real_row = (la_row-1)/2;  
127:    for(j=0; j<COLS/2; j++)   
128:    {  
129:     ledarray_set_columndriver(j, ledarray_get(real_row, 2*j + 1), 0);  
130:    }  
131:    // activate row driver SOURCE  
132:    PORTB |= (1 << (PB1 + real_row));  
133:    DDRB |= (1 << (PB1 + real_row));  
134:   }   
135:  }  
136:  void ledarray_init()   
137:  {  
138:   // Timer0 CK/64 (900Hz)  
139:   TCCR0B = (1<<CS01) | (1<<CS00);  
140:   TIMSK0 = (1<<TOIE0);  
141:   // outputs (set row drivers high for off)  
142:   DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) );  
143:   DDRD &= ~( (1<<PD2) | (1<<PD3) );  
144:   DDRB &= ~( (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) );  
145:  }  
146:  void powerup_sequence()   
147:  {  
148:   uint8_t j;  
149:   for(j=0; j<COLS; j++)   
150:   {  
151:    ledarray_set(0, j, 1);  
152:    _delay_ms(262);  
153:   }  
154:  }  
155:  void back_inner_c()   
156:  {  
157:   uint8_t j;  
158:   for(j=0; j<COLS; j++)   
159:   {  
160:    ledarray_set(1, j, 1);  
161:   }  
162:  }  
163:  void ledarray_testpattern()   
164:  {  
165:   uint8_t i, j;  
166:   for(i=0;i<ROWS;i++)   
167:   {  
168:    for(j=0;j<COLS;j++)   
169:    {  
170:     ledarray_set(i,j, 0);  
171:    }  
172:   }  
173:   while (1)  
174:   {  
175:    for(i=0;i<ROWS;i++)   
176:    {  
177:     for(j=0;j<COLS;j++)   
178:     {  
179:      ledarray_set(i,j, 1 - ledarray_get(i,j));  
180:      _delay_ms(60);  
181:     }  
182:    }  
183:   }  
184:  }  
185:  int main()   
186:  {  
187:   ledarray_init();  
188:   // activate interrupts  
189:   sei();  
190:   DDRD &= ~(1<<PD7); // set PD7 as input  
191:   PORTD |= (1<<PD7); // turn on internal pull up resistor for PD7  
192:   // if we don't incur a delay here we read the last state of PD7  
193:   _delay_ms(150);  
194:   if (PIND & (1<<PD7))  
195:   {  
196:    powerup_sequence();  
197:    _delay_ms(1049);  
198:    back_inner_c();  
199:   }  
200:   else  
201:   {  
202:    ledarray_testpattern();  
203:   }  
204:   while (1)  
205:   {  
206:    while (PIND & (1<<PD7))  
207:    {  
208:     // loop waiting for button press  
209:    }  
210:    _delay_ms(150);  
211:    while (!(PIND & (1<<PD7)))  
212:    {  
213:     // loop waiting for button release  
214:    }  
215:    // blade activation  
216:    uint16_t j, r = 4900,cyc=0;  
217:    for(j=0; j<COLS; j++)   
218:    {  
219:     // all on  
220:     ledarray_set(2, j, 1);  
221:     ledarray_set(3, j, 1);  
222:    }  
223:    _delay_ms(300);  
224:    while ((PIND & (1<<PD7)))  
225:    {  
226:     // loop waiting for button press  
227:     for(j=0; j<COLS; j++)   
228:     {  
229:      ledarray_set(2, j, (j%3!=cyc));  
230:      ledarray_set(3, j, (j%3!=cyc));  
231:     }  
232:     _delay_us(r);  
233:     if (++r > 5300) r = 5300;  
234:     if (++cyc==3) cyc=0;  
235:    }  
236:    // blade deactivation  
237:    for(j=0; j<COLS; j++)   
238:    {  
239:     // all off  
240:     ledarray_set(2, j, 0);  
241:     ledarray_set(3, j, 0);  
242:    }  
243:    _delay_ms(300);  
244:    while (!(PIND & (1<<PD7)))  
245:    {  
246:     // loop waiting for button release  
247:    }  
248:   }  
249:   return 0;  
250:  }  

3 comments:

  1. Nice work. I'm going to start prepping my disc next week, cutting the plastic out and what not. Excited to give this a shot.

    I'm assuming that row 3 and 4 are for each of the inner rings?

    ReplyDelete
  2. I actually just posted the code - in that version I was using row 1 (index 0) for everything since that is all I had wired up at that point. Row 1 is the front inner C, row 2 is the back inner C (if installed), row 3 is the right half of the blade starting at the index hole, row 4 is the left half of the blade starting where row 3 left off.

    ReplyDelete
  3. So I used a Dremel with a cut-off disc to remove the excess plastic. On the back half of the disc I left the screw posts (and about a eighth of an inch of the "tripod" plastic around it for support) that attaches the front half and the blade index hole as a guide. I left the top of the disc mostly unmodified (speaker holder and the button mount). The battery compartment was fun...

    ReplyDelete