Вы находитесь на странице: 1из 5

/*--------------------------------------------------*/

/* 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(;;);
}

Вам также может понравиться