这是一款利用了红外靠近传感器的小桌子,加上 LED 的光照效果,犹如互
动式的梦幻餐桌。
这个项目包含了三个 8x8 独立的模块,每个模块包含 4 个“光点”,每个光点

由 21 个 LED、2 个红外发射二极管以及 2 个红外光电二极管组成。
第 1 1 步 材料准备
元器件列表如下,格式为:
型号(Part number)
厂商
描述
556-ATMEGA48-20PU
Atmel 微掌握器(MCU)
4kB Flash 0.256kB
638-IR204-A
Everlight 红外发射管
红外 LED 940nm
512-QSD2030F
Fairchild 光电二极管
光电二极管
757-ULN2803APG(5,M)
Toshiba 达林顿晶体管
8CH. 50V/.5A IFD IC
595-TLC274CN
TI Op Amps
Quad LiMCMOS
511-L7805CV
ST 标准线性调节器
5.0V 1.0A Positive
571-1-390261-3
Tyco IC 插座
14P ECONOMY TIN
571-1-390261-5
Tyco IC 插座
18P ECONOMY TIN
571-1-390261-9
Tyco IC 插座
28P ECONOMY TIN SKT
第 2 2 步 制作红外传感器
我所采取的传感器因此逆向偏压形式并联的 IR 光电二极管,形成一个大略
的分压电路。当光电二极管逆向连接时(就像 LED 倒接一样),就可以随着光
线(紧张是红外光)的强弱改变电阻值。
V-in 是 5V。
第 3 3 步 红外发射管
我用的是 3mm 红外 LED。为了得到更大的感应范围,IR 发射管要非常亮,
以是须要大电流。
我把 IR 发射管连接到达林顿芯片上,这样在开或关时掌握器可以被触发。
由于 ADC 转换切换得很快,以是先打开 IR 发射管,等 IR 传感器设置好后,让
ADC 进行读数,然后关闭。
定时器 1 从 0 数到 65535。而 8MHz 的 fCPU 使掌握器在 8.2 毫秒内从 0 数
到 65535。这样每 8.2 毫秒发生一次 IR 感应序列。
每一束光里面的两个 IR 发射管之间串联起来,电源电压是 5V。
波形图如上图所示。
第 4 4 步 编写代码
代码见附件
001 /
002 PIN ASSIGNMENTS ON ATMEGA48
003
004 PC6 (PCINT14/RESET)
005 PC5 (ADC5/SCL/PCINT13) // I2C 时钟输入
006 PC4 (ADC4/SDA/PCINT12) // I2C 数据输入
007 PC3 (ADC3/PCINT11) //传感器 4 IR 吸收器
008 PC2 (ADC2/PCINT10)
009 PC1 (ADC1/PCINT9)
010 PC0 (ADC0/PCINT8)
011
012 PB7 (PCINT7/XTAL2/TOSC2) //IR 4 触发
013 PB6 (PCINT6/XTAL1/TOSC1) //IR 3 触发
014 PB5 (SCK/PCINT5)
015 PB4 (MISO/PCINT4)
016 PB3 (MOSI/OC2A/PCINT3) //PWM 3
017 PB2 (SS/OC1B/PCINT2)
018 PB1 (OC1A/PCINT1)
019 PB0 (PCINT0/CLKO/ICP1)
020
021 PD0 (PCINT16/RXD)
022 PD1 (PCINT17/TXD)
023 PD2 (PCINT18/INT0)
024 PD3 (PCINT19/OC2B/INT1) //PWM 4
025 PD4 (PCINT20/XCK/T0)
026 PD5 (PCINT21/OC0B/T1) //PWM 2
027 PD6 (PCINT22/OC0A/AIN0) //PWM 1
028 PD7 (PCINT23/AIN1)
029 /
030
031 #define IR_1_ON PORTB |= (1<<4)
032 #define IR_2_ON PORTB |= (1<<5)
033 #define IR_3_ON PORTB |= (1<<6)
034 #define IR_4_ON PORTB |= (1<<7)
035 #define IR_1_OFF PORTB &= ~(1<<4)
036 #define IR_2_OFF PORTB &= ~(1<<5)
037 #define IR_3_OFF PORTB &= ~(1<<6)
038 #define IR_4_OFF PORTB &= ~(1<<7)
039
040 #define PWM1 6 //PORTD PWM 引脚分配
041 #define PWM2 5 //PORTD
042 #define PWM3 3 //PORTB
043 #define PWM4 3 //PORTD
044
045 #define F_CPU 8000000UL
046
047 #include
048 #include
049 #include
050 //#include
051
052 /Function Declarations/
053 int ADC_read(void);
054 void A2D_Channel_Select(unsigned char channel);
055 void Init_ADC(void);
056 void Init_Timer0(void);
057 void Init_Timer1(void);
058 void Init_Timer2(void);
059 void Delay(void);
060 void Calibrate_Sensors(void);
061 //void Init_I2C_Slave_Rx(void);
062
063
064 /Global Variable Declarations/
065 volatile char Sensor_Values_Updated = 0;
066 volatile char Timer1_Overflow = 0;
067 volatile unsigned char channel = 0;
068
volatile int Amb_Sensor_1 = 0, Amb_Sensor_2 = 0, Amb_Sensor_3 = 0,
Amb_Sensor_4 = 0;
069 volatile int Sensor_1 = 0, Sensor_2 = 0, Sensor_3 = 0, Sensor_4 = 0;
070
volatile int Initial_1 = 0, Initial_2 = 0, Initial_3 = 0, Initial_4
= 0;
071
volatile int New_PWM1 = 0, New_PWM2 = 0, New_PWM3 = 0, New_PWM4 =
0;
072 volatile int Old_PWM1 = 0, Old_PWM2 = 0, Old_PWM3 = 0, Old_PWM4 = 0;
073
074 unsigned char buffer = 8;
075
076 int main(void)
077 {
078 DDRB = 0xff;
079 //make sure IR emitters are turned off, and PWM 3
080
PORTB &= ~((1 << 7)|(1 << 6)|(1 << 5)|(1 << 4)|(1 <<
3));
081 DDRC = 0x00;
082
083 DDRD = 0xff;
084 PORTD = 0x00; //使所有 PORT D 为低
085
086 Init_ADC();
087
088 sei();
089
090 Calibrate_Sensors();
091
092 PORTD |= (1 << PWM1);
093 _delay_ms(600);
094 PORTD &= ~(1 << PWM1);
095
096 Init_Timer0();
097 Init_Timer2();
098
099 //Init_I2C_Slave_Rx();
100
101 while(1)
102 {
103 //do something?
104 //. . .
105 }
106
107 }
108
109
110 ISR(TIMER1_OVF_vect)
111 {
112 Timer1_Overflow++;
113 switch(Timer1_Overflow)
114 {
115 case 1:
11
6
A2D_Channel_Select(0);
//select ADC channel 0
117 Amb_Sensor_1 = ADC_read();
11
8
IR_1_ON;
//turn on IR 1 LED, PORTB |= (1<<4)
11
9
Delay();
//delay for the IR receiver to settle
120
Sensor_1 =
ADC_read(); //take active ADC reading of
IR receiver
12
1
IR_1_OFF;
//turn off IR 1 LED
122
123
New_PWM1 = (Sensor_1 - Amb_Sensor_1) -
Initial_1; //condition readings
124
if(New_PWM1 <= 0) { New_PWM1 =
0; }
125
New_PWM1 = ((7Old_PWM1)>>3) +
(New_PWM1>>3);
126
127 if(OCR0A >= 1) {DDRD |= (1 << PWM1);}
128
else { DDRD &= ~(1 <<
PWM1); } New_PWM1 <<=
2;
129 if(New_PWM1 > 255) { New_PWM1 = 255; }
130 OCR0A = New_PWM1;
131 New_PWM1 >>= 2;
132
133
134 / //Trigger sequence
135 if(New_PWM1 > Initial_1)
136 {
137 DDRD |= (1 << PWM1);
138
139 if(OCR0A < 255)
140 {
141 OCR0A += (255 - OCR0A)>>2 ;
142 //OCR0A++;
143 }
144
145 if (New_PWM1 < (Initial_1 + 8))
146 {
147
Initial_1 = ((7Initial_1)>>3)
+ (New_PWM1>>3);
148 }
149 }
150
151 else if(New_PWM1 < Initial_1)
152 {
153 if(OCR0A > 0)
154 {
155 OCR0A -= (OCR0A >> 4)+1;
156 //OCR0A--;
157 }
158 else if(OCR0A <= 0)
159 {
160 DDRD &= ~(1 << PWM1);
161 }
162 }
163 /
164 Old_PWM1 = New_PWM1;
165 break;
166
167 case 2:
16
8
A2D_Channel_Select(1);
//select ADC channel 1
169 Amb_Sensor_2 = ADC_read();
17
0
IR_2_ON;
//turn on IR 2 LED, PORTB |= (1<<5)
17
1
Delay();
//delay for the IR receiver to settle
172 Sensor_2 =
ADC_read(); //take ADC reading
17
3
IR_2_OFF;
//turn off IR 2 LED
174
175
New_PWM2 = (Sensor_2 - Amb_Sensor_2) -
Initial_2;
176 if(New_PWM2 < 0) { New_PWM2 = 0; }
177
178 New_PWM2 = ((7Old_PWM2)>>3) + (New_PWM2>>3);
179 if(OCR0B >= 1) {DDRD |= (1 << PWM2);}
180 else { DDRD &= ~(1 << PWM2); }
181
182 New_PWM2 <<= 2;
183 if(New_PWM2 > 255) { New_PWM2 = 255; }
184 OCR0B = New_PWM2;
185 New_PWM2 >>= 2;
186 /
187 if(New_PWM2 > Initial_2)
188 {
189 DDRD |= (1 << PWM2);
190
191 if(OCR0B < 255)
192 {
193 OCR0B += (255 - OCR0B)>>2 ;
194 //OCR0B++;
195 }
196
197 if (New_PWM2 < (Initial_2 + 8))
198 {
199
Initial_2 = ((7Initial_2)>>3)
+ (New_PWM2>>3);
200 }
201 }
202
203 else if(New_PWM2 < Initial_2)
204 {
205 if(OCR0B > 0)
206 {
207 OCR0B -= (OCR0B >> 4)+1;
208 //OCR0B--;
209 }
210 else if(OCR0B <= 0)
211 {
212 DDRD &= ~(1 << PWM2);
213 }
214 }
215 /
216 Old_PWM2 = New_PWM2;
217 break;
218
219 case 3:
22
0
A2D_Channel_Select(2);
//select ADC channel 2
221 Amb_Sensor_3 = ADC_read();
22
2
IR_3_ON;
//turn on IR 3 LED, PORTB |= (1<<6)
22
3
Delay();
//delay for the IR receiver to settle
224
Sensor_3 =
ADC_read(); //take ADC reading
22
5
IR_3_OFF;
//turn off IR 3 LED
226
227
New_PWM3 = (Sensor_3 - Amb_Sensor_3) -
Initial_3;
228 if(New_PWM3 < 0) { New_PWM3 = 0; }
229
230 New_PWM3 = ((7Old_PWM3)>>3) + (New_PWM3>>3);
231 if(OCR2A >= 1) {DDRB |= (1 << PWM3);}
232 else { DDRB &= ~(1 << PWM3); }
233 New_PWM3 <<= 2;
234 if(New_PWM3 > 255) { New_PWM3 = 255; }
235 OCR2A = New_PWM3;
236 New_PWM3 >>= 2;
237 /
238 if(New_PWM3 > Initial_3)
239 {
240 DDRB |= (1 << PWM3);
241
242 if(OCR2A < 255)
243 {
244 OCR2A += (255 - OCR2A)>>2 ;
245 //OCR2A++;
246 }
247
248 if (New_PWM3 < (Initial_3 + 8))
249 {
250
Initial_3 = ((7Initial_3)>>3)
+ (New_PWM3>>3);
251 }
252 }
253
254 else if(New_PWM3 < Initial_3)
255 {
256 if(OCR2A > 0)
257 {
258 OCR2A -= (OCR2A >> 4)+1;
259 //OCR2A--;
260 }
261 else if(OCR2A <= 0)
262 {
263 DDRB &= ~(1 << PWM3);
264 }
265 }
266 /
267 Old_PWM3 = New_PWM3;
268 break;
269
270 case 4:
27
1
A2D_Channel_Select(3);
//select ADC channel 3
272 Amb_Sensor_4 = ADC_read();
27
3
IR_4_ON;
//turn on IR 4 LED, PORTB |= (1<<7)
27
4
Delay();
//delay for the IR receiver to settle
275
Sensor_4 =
ADC_read(); //take ADC reading
27
6
IR_4_OFF;
//turn off IR 4 LED
277
278
New_PWM4 = (Sensor_4 - Amb_Sensor_4) -
Initial_4;
279 if(New_PWM4 < 0) { New_PWM4 = 0; }
280
281 New_PWM4 = ((7Old_PWM4)>>3) + (New_PWM4>>3);
282 if(OCR2B >= 1) {DDRD |= (1 << PWM4);}
283 else { DDRD &= ~(1 << PWM4); }
284 New_PWM4 <<= 2;
285 if(New_PWM4 > 255) { New_PWM4 = 255; }
286 OCR2B = New_PWM4;
287 New_PWM4 >>= 2;
288 /
289 if(New_PWM4 > Initial_4)
290 {
291 DDRD |= (1 << PWM4);
292
293 if(OCR2B < 255)
294 {
295 OCR2B += (255 - OCR2B)>>2 ;
296 //OCR2B++;
297 }
298
299 if (New_PWM4 < (Initial_4 + 8))
300 {
301
Initial_4 = ((7Initial_4)>>3)
+ (New_PWM4>>3);
302 }
303 }
304
305 else if(New_PWM1 < Initial_4)
306 {
307 if(OCR2B > 0)
308 {
309 OCR2B -= (OCR2B >> 4)+1;
310 //OCR2B--;
311 }
312 else if(OCR2B <= 0)
313 {
314 DDRD &= ~(1 << PWM4);
315 }
316 }
317 /
318 Old_PWM4 = New_PWM4;
319
320
Timer1_Overflow =
0;
321 Sensor_Values_Updated = 1;
322
323 break;
324 }//end switch
325 }//end ISR
326
327
328 /
329 ISR(TWI_vect) //to include later when I get this figured
out
330 {
331 switch(TWSR)
332 {
333
case TW_SR_SLA_ACK: //0x60 //Own
address Rx
334 Byte_Number == 1;
335 break;
336
337
case TW_SR_DATA_ACK: // 0x80 , data in
TWDR
338 switch(Byte_Number)
339 {
340 case 1:
341 Reg_Addr = TWDR;
342 Byte_Number++;
343 break;
344
345 case 2:
346 Reg_Val = TWDR;
347
Byte_Number = 0; //reset, unless
more bytes are coming
348 break;
349
350 case Max_Bytes_Expected:
351 Reg_Val = TWDR;
352
Byte_Number = 0; //reset, unless
more bytes are coming
353 break;
354 }
355 break;
356
357 case TW_SR_GCALL_DATA_ACK: // 0x90
358 if(Byte_Number == 1)
359 {
360 Reg_Addr = TWDR;
361 Byte_Number++;
362 }
363 else if(Byte_Number == 2)
364 {
365 Reg_Val = TWDR;
366
Byte_Number = 0; //reset, unless
more bytes are coming
367 }
368 break;
369 }//end switch
370 }//end ISR
371
372
373 void Init_I2C_Slave_Rx(void)
374 {
375 //Set Device Address in TWAR
376 TWAR = 10;
377
378 TWCR |= ((1 << TWEA)|(1 << TWEN));
379 TWCR &= ~((1 << TWSTA)|(1 << TWSTO));
380 }
381 /
382
383
384
void Calibrate_Sensors(void) //establish initial ambient sensor
values
385 {
386 char q = 0;
387
388 Init_Timer1();
389
390 for(q=0; q<32; q++) //should take one second-ish
391 {
392 //wait for Sensor cycle to be done, then gather
sensors values
393 while(Sensor_Values_Updated == 0) {}
394
395
Initial_1 += (Sensor_1 -
Amb_Sensor_1); //initial difference
396 Initial_2 += (Sensor_2 - Amb_Sensor_2);
397 Initial_3 += (Sensor_3 - Amb_Sensor_3);
398 Initial_4 += (Sensor_4 - Amb_Sensor_4);
399
400 Sensor_Values_Updated = 0; //reset
401 }
402
403 //condition Initial Ambient Sensor values, plus a buffer
404 Initial_1 = (Initial_1 >> 5) + buffer;
405 Initial_2 = (Initial_2 >> 5) + buffer;
406 Initial_3 = (Initial_3 >> 5) + buffer;
407 Initial_4 = (Initial_4 >> 5) + buffer;
408 }
409
410 void Init_ADC(void)
411 {
412
ADMUX |= 1 << REFS0; //AVCC with external
capacitor at AREF pin
413 ADMUX |= (1<
414 }
415
416 void Init_Timer0(void)
417 {
418
//Fast PWM, non-inverting, WGM02-WGM00 == 011, no overflow
interrupt
419
TCCR0A |= ((1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 <<
WGM00));
420 TCCR0B |= (1 << CS00); //start clock, no prescale
421 }
422
423 void Init_Timer1(void)
424 {
425 //no PWM, enable overflow interrupt,
426
//TOP == 0xFFFF == 65536 cycles == roughly 122 overflow
interrupts/sec
427 TCCR1B |= (1 << CS10);
428 TIMSK1 |= (1 << TOIE1);
429 }
430
431
void Init_Timer2(void) //PWM for sensors
3 & 4
432 {
433
//Fast PWM, non-inverting, WGM22-WGM20 == 011, no overflow
interrupt
434
TCCR2A |= ((1 << COM2A1)|(1 << COM2B1)|(1 << WGM21)|(1 <<
WGM20));
435 TCCR2B |= (1 << CS20); //start clock, no prescale
436 }
437
438
439
int ADC_read(void) /select ADC channel
prior to calling this function/
440 {
441 int ADC_value = 0;
442 int ADCsample;
443 char i;
444
445
ADCSRA |= (1< ADCSRA |= (1< while ((ADCSRA
& ADSC));
446
447 for (i=0; i<64; i++)
448 {
449
ADCSRA |= (1< while ((ADCSRA &
ADSC)); //wait for conversion to finish
450
//change back to ADCL for 10 bit precision, and remove left-shift bit
setting
451 ADCsample = ADCH;
452 //ADCsample += (ADCH<<8);
453
ADC_value += ADCsample; //add ADCsample
to ADC_sensor
454 }
455
456
457 return ADC_value;
458
459 ADCSRA &= ~(1<
460 void A2D_Channel_Select(unsigned char channel)
461 {
462
463 switch (channel)
464 {
465 case 0:
466 ADMUX &= ~((1 << 3)|(1 << 2)|(1 << 1)|(1 << 0));
467 break;
468
469 case 1:
470 ADMUX &= ~((1 << 3)|(1 << 2)|(1 << 1));
471 ADMUX |= (1 << 0);
472 break;
473
474 case 2:
475 ADMUX &= ~((1 << 3)|(1 << 2)|(1 << 0));
476 ADMUX |= (1 << 1);
477 break;
478
479 case 3:
480 ADMUX &= ~((1 << 3)|(1 << 2));
481 ADMUX |= ((1 << 1)|(1 << 0));
482 break;
483 / I am not using these for this project
484 case 4:
485 ADMUX &= ~((1 << 3)|(1 << 1)|(1 << 0));
486 ADMUX |= (1 << 2);
487 break;
488
489 case 5:
490 ADMUX &= ~((1 << 3)|(1 << 1));
491 ADMUX |= ((1 << 2)|(1 << 0));
492 break;
493 /
494 }//end switch
495 }
496
497 void Delay(void)
498 {
499 _delay_us(100);
500 }
第 5 5 步 电路
电路图和制成后的电路板如下图。