照度是受照平面上接受的光通量的面密度。照度计是用于测量被照面上的光照度的仪器。
跟动辄几千元的商用照度计相比,这个成本不足15元的简易照度计,其超值程度可想而知了。
这个玩具级的照度计作好以后,我都能想到怎么用,第一件事儿就是拿这个照度计,挨个房间的闯,看看每个房间的照度有什么不同。测过以后呢,不要停,因为关于住宅照明是有标准的。对比一下看看。
如果将这个照度计加以扩展,做一个照度记录仪,用来测量自己居室、或者植物温室等特定场所一年四季的光照情况,也是很不错的想法,这些科学数据可以用来进行更加深入的研究。
硬件原理图
闲话少扯,先看看这个简易照度计的原理图。
其中,以U1 LMV772为核心器件的I-V转换电路将光电管S1087的电流信号转换成电压信号,送入U2 AtTiny26的内置ADC。R5决定了转换系数,为50mV/µA;C5用来增益修正,滤除高频信号。
原理图顶部的Q1用来防止电池接反,等效于常进的二极管;Q2、Q3、Q4组成电源开关电路,控制电源的通断。
软件代码
软件的主要功能,就是将ADC的读数,经过一定的运算,送入显示器件LED数码管。AD转换器的输入为0 -2.56V,据此推算,可测量的最强光照约30000 lux。开机60秒后,自动关闭电源。
- /*--------------------------------------------------*/
- /* Lux meter control program (C)ChaN, 2005 */
- #include <avr/io.h>
- #include <avr/signal.h>
- #include <avr/interrupt.h>
- #include <avr/pgmspace.h>
- #include <avr/eeprom.h>
- #include <string.h>
- #include "xitoa.h"
- #define SYSCLK 1000000
- /* Bit definition for status flags */
- #define F_800 (_BV(0)) // 800 Hz timer event
- #define F_LVD (_BV(1)) // Low battery
- #define F_POW (_BV(2)) // Power event
- #define F_PB (_BV(3)) // Power button
- /*------------------------------------------------*/
- /* Global variables */
- uint8_t Leds[5]; // LED display buffer
- volatile uint8_t flags; // Status flags
- volatile uint16_t OffTimer; // Auto power off timer
- uint32_t Gain[2];
- uint16_t Ofs20;
- /*------------------------------------------------*/
- /* Interval Timer (800Hz) */
- SIGNAL(SIG_OVERFLOW1)
- {
- static uint8_t bltimer; // LED blink timer
- static uint8_t Col; // Dynamic scan pointer
- if(++Col >= sizeof(Leds)) Col = 0;
- PORTA &= 0b00000100;
- PORTB = 0;
- bltimer++;
- if((bltimer & 7) == 0) { // Check power button every 8 (100/sec)
- PORTA |= _BV(3);
- DDRA &= ~_BV(3);
- DDRA &= ~_BV(3);
- DDRA &= ~_BV(3);
- if(PINA & _BV(3)) {
- flags |= F_PB;
- } else {
- if(flags & F_PB)
- flags |= F_POW;
- flags &= ~F_PB;
- }
- PORTA &= 0b00000100;
- DDRA |= _BV(3);
- }
- if((bltimer & 0xC0) || !(flags & F_LVD)) // Blink control
- PORTB = Leds[Col];
- PORTA |= (0b00001000 << Col);
- if(--OffTimer == 0) flags |= F_POW; // Auto power-off timer
- flags |= F_800;
- }
- /* Character output function for LED display (called by xitoa module) */
- void putled(char c)
- {
- static uint8_t wp; // Write index
- static const prog_uint8_t seg7[] // Segment pattern
- = {0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, 0};
- if(c == '\r') { // Return index to left
- wp = 0;
- return;
- }
- c -= '0'; // Put a segment pattern into display buffer
- if((uint8_t)c > 9) c = 10;
- Leds[wp++] = pgm_read_byte(&seg7[(uint8_t)c]);
- }
- void delay (uint16_t dly)
- {
- do {
- cli(); flags &= ~F_800; sei();
- while((flags & F_800) == 0);
- } while(--dly);
- }
- uint16_t adconv(uint8_t ch)
- {
- ADMUX = ch;
- ADCSR = 0b11010011;
- while(bit_is_clear(ADCSR, ADIF));
- return ADC;
- }
- /*------------------------------------------------*/
- /* Main Process */
- int main(void)
- {
- uint16_t n, d;
- uint32_t v, u;
- /* Initialize ports */
- PORTA = 0b00000100;
- DDRA = 0b11111110;
- PORTB = 0b00000101;
- DDRB = 0b01111111;
- /* Start TC1 with 800Hz OC-A */
- OCR1C = SYSCLK/8/800-1;
- TCCR1B = _BV(CTC1) | 0b0100;
- TIMSK = _BV(TOIE1);
- eeprom_read_block(Gain, 0, sizeof(Gain));
- xfunc_out = putled; // Join xitoa molule and my output function
- OffTimer = 48000; // Auto power off timer (60sec)
- sei();
- /* Lamp test */
- memset(Leds, 0x7F, sizeof(Leds));
- delay(400);
- delay(10);
- Ofs20 = adconv(0x80 + 13);
- delay(10);
- cli();
- PORTA &= 0b00000100;
- PORTB = 0b00000101;
- DDRB = 0b01111010;
- DDRB = 0b01111010;
- DDRB = 0b01111010;
- /* MOSI is tied to GND. Low range calibration (1250 lux at -100 mV) */
- if((PINB & _BV(0)) == 0) {
- adconv(0x80 + 11);
- Gain[0] = 1250 * 65536 / (uint32_t)(adconv(0x80 + 11) - Ofs20);
- eeprom_write_block(Gain, 0, sizeof(Gain));
- Leds[0] = 0;
- }
- /* SCK is tied to GND. High range calibration (12500 lux at -1 V) */
- if((PINB & _BV(2)) == 0) {
- adconv(0x80 + 0);
- Gain[1] = 12500 * 65536 / (uint32_t)(adconv(0x80 + 0));
- eeprom_write_block(Gain, 0, sizeof(Gain));
- Leds[1] = 0;
- }
- DDRB = 0b01111111;
- sei();
- /* Measurement loop continued until any power event occure */
- while(!(flags & F_POW)) {
- v = 0;
- for(n = 0; n < 256; n++) // 256 times averaging to filter-out flicker
- {
- d = adconv(0x80 + 11);
- while(!(flags & F_800));
- cli(); flags &= ~F_800; sei();
- d = adconv(0x80 + 11);
- if(d < 1023) {
- d -= Ofs20;
- u = Gain[0];
- } else {
- d = adconv(0x80 + 0);
- u = Gain[1];
- }
- d = (u * (uint32_t)d) >> 16;
- v += d;
- }
- /* Refresh lux value */
- xputc('\r');
- xitoa(v / 256, 10, 5);
- /* Check battrey voltage */
- DDRA &= ~_BV(1);
- d = adconv(0x80 + 1);
- cli();
- if(d >= 23)
- flags &= ~F_LVD;
- else
- flags |= F_LVD;
- sei();
- DDRA |= _BV(1);
- }
- /* Power off */
- memset(Leds, 0, sizeof(Leds)); // Clear display
- PORTA &= ~_BV(2); // Release power hold
- for(;;);
- }
复制代码
C程序.zip
(54.74 KB, 下载次数: 24)
|