圣源电子制作
标题:
AtTiny26简易照度计DIY-LMV772-AtTiny26-S1087-制作DIY
[打印本页]
作者:
sydz
时间:
2011-10-15 22:33
标题:
AtTiny26简易照度计DIY-LMV772-AtTiny26-S1087-制作DIY
(, 下载次数: 73)
上传
点击文件名下载附件
照度是受照平面上接受的光通量的面密度。照度计是用于测量被照面上的光照度的仪器。
跟动辄几千元的商用照度计相比,这个成本不足15元的简易照度计,其超值程度可想而知了。
这个玩具级的照度计作好以后,我都能想到怎么用,第一件事儿就是拿这个照度计,挨个房间的闯,看看每个房间的照度有什么不同。测过以后呢,不要停,因为关于住宅照明是有标准的。对比一下看看。
如果将这个照度计加以扩展,做一个照度记录仪,用来测量自己居室、或者植物温室等特定场所一年四季的光照情况,也是很不错的想法,这些科学数据可以用来进行更加深入的研究。
硬件原理图
闲话少扯,先看看这个简易照度计的原理图。
其中,以U1 LMV772为核心器件的I-V转换电路将光电管S1087的电流信号转换成电压信号,送入U2 AtTiny26的内置ADC。R5决定了转换系数,为50mV/µA;C5用来增益修正,滤除高频信号。
原理图顶部的Q1用来防止电池接反,等效于常进的二极管;Q2、Q3、Q4组成电源开关电路,控制电源的通断。
(, 下载次数: 74)
上传
点击文件名下载附件
软件代码
软件的主要功能,就是将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(;;);
}
复制代码
(, 下载次数: 24)
上传
点击文件名下载附件
作者:
◤奋斗◥
时间:
2013-7-22 22:20
顶贴 强烈支持一下
欢迎光临 圣源电子制作 (https://syyyd.com/)
Powered by Discuz! X3.4