/*************************************************************************** * Copyright (C) 11/2012 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License, * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #define F_CPU 8000000 #include #define OSCCAL_VALUE 0xA4 /* * attiny26 * lfuse: 0xe4 (internal 8MHz) * hfuse: 0x14 (BOD enabled) * * PA0 => current sense (0-2.56V => 0-25.6A) * PA1 => volatage sense (0-2.56V => 0-30.72V) * PA2 => mode button (low active) * PA3 => ext. 2.56V reference * PA4-7 => LCD D4-7 * PB0 => MOSI (ISP) * PB1 => MISO (ISP) * PB2 => SCK (ISP) * PB3 => free * PB4 => LCD RS * PB5 => LCD RW * PB6 => LCD EN * PB7 => /RST (ISP) */ #define LCD_DATA_MASK 0xF0 #define LCD_RS PORTB4 #define LCD_RW PORTB5 #define LCD_EN PORTB6 #define BUTTON PORTA2 #define ADC_CURRENT 0 #define ADC_VOLTAGE 1 #define ADC_COMPLETE 0xFE #define ADC_IDLE 0xFF /* 8ms @8MHz / 256 */ #define TIMER_TICK_RELOAD (256 - 250) /* 25 * 8ms => 200ms */ #define TIMER_LCD_UPDATE 25 /* 125 * 8ms => 1s */ #define TIMER_SECOND 125 /* autosave every minute */ #define TIMER_NVRAM_SAVE 60 /* bargraph 20 - 28V */ #define VOLTAGE_BAR_MIN 2000 #define VOLTAGE_BAR_MAX 2800 /* bargraph 0 - 20A */ #define CURRENT_BAR_MIN 0 #define CURRENT_BAR_MAX 2000 /* minimum discharge current 100mA */ #define CURRENT_IDLE 10 #define BUTTON_TIMER_IDLE 0xFF #define EVENT_NONE 0 #define EVENT_BUTTON_PRESSED 1 #define EVENT_BUTTON_RELEASED 2 #define EVENT_BUTTON_TIMEOUT 3 #define STATE_IDLE 0 #define STATE_PRESSED 1 #define STATE_WARNING 2 struct _nvdata { uint8_t nvram_size; /* first */ uint16_t discharge_time; uint32_t discharge_product; uint16_t nvram_crc; /* last */ }; static uint8_t nvram_write_pos; static struct _nvdata nvram_data; static struct _nvdata nvram_eeprom EEMEM; static struct _nvdata nvram_defaults PROGMEM = { 0 }; /* create crc and store nvram data to eeprom */ static void nvram_start_write(void) { uint8_t i; uint16_t crc = 0x0000; uint8_t *tmp = (uint8_t *)&nvram_data; /* write in progress? */ if (EECR & (1<> 4); return retval; } static void lcd_write_no_busy_check(uint8_t reg, uint8_t data) { if (reg) { PORTB |= (1< max) value = max; /* scale to bargraph length */ value = ((value - min) * (len * 5)) / (max - min) ; while (len--) { if (value >= 5) { lcd_write(0x01, 0x05); value -= 5; } else { lcd_write(0x01, value); value = 0; } } } static void lcd_write_stringP(const char *ptr) { while (1) { uint8_t data = pgm_read_byte_near(ptr++); if (data == 0x00) break; lcd_write(0x01, data); } } static volatile uint8_t adc_state; static volatile uint16_t adc_value[2]; static void adc_start(uint8_t channel) { adc_state = channel; /* ext. 2.56V ref, start, irq enable, F_CPU/64 -> ~225us conversion time */ ADMUX = (1<> 1; if (discharging) { discharge_product += current; } if (current >= CURRENT_IDLE) { discharging = 1; } else if (sec_timer == 0) { discharging = 0; } } if (lcd_timer == TIMER_LCD_UPDATE) { lcd_timer = 0; if (lcd_page) { lcd_write(0x00, 0x80 | 0); lcd_print_dec2p2(voltage); lcd_write(0x01, 'V'); lcd_write(0x00, 0x80 | 40); lcd_print_dec2p2(current); lcd_write(0x01, 'A'); if (lcd_page == 2) { lcd_write(0x00, 0x80 | 8); lcd_print_time(discharge_time); lcd_write(0x00, 0x80 | 48); /* 125 ticks per second, 3600s per hour, 10mA Steps */ lcd_print_dec2p3(discharge_product / (TIMER_SECOND * 3600ULL / 10ULL)); lcd_write(0x01, 'A'); lcd_write(0x01, 'h'); } else if (lcd_page == 3) { lcd_write(0x00, 0x80 | 7); lcd_bargraph(9, VOLTAGE_BAR_MIN, VOLTAGE_BAR_MAX, voltage); lcd_write(0x00, 0x80 | 47); lcd_bargraph(9, CURRENT_BAR_MIN, CURRENT_BAR_MAX, current); } } } if (nvram_save) { nvram_save = 0; nvram_data.discharge_time = discharge_time; nvram_data.discharge_product = discharge_product; nvram_start_write(); } } }