From f6e28df0b14768a1f445074271f29985bb72cf4b Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Sun, 11 Aug 2019 11:31:00 +0200 Subject: [PATCH] Working version --- .gitignore | 6 + Makefile | 55 ++++++ main.c | 550 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 611 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d36148 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.o +*.elf +*.bin +*.hex +*.lst +*.map diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c6d5011 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +PRG = powermeter +OBJ = main.o +MCU_TARGET = attiny26 +OPTIMIZE = -Os + +AVRDUDE_PROG = -c avr910 -b 115200 -P /dev/ttyUSB0 +#AVRDUDE_PROG = -c dragon_isp -P usb +AVRDUDE_MCU = attiny26 + +DEFS = +LIBS = + +# Override is only needed by avr-lib build system. +override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) +override LDFLAGS = -Wl,-Map,$(PRG).map + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size + +all: $(PRG).elf lst text + $(SIZE) -x -A $(PRG).elf + +$(PRG).elf: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.o: %.c $(MAKEFILE_LIST) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -rf *.o $(PRG).lst $(PRG).map $(PRG).elf $(PRG).hex $(PRG).bin + +lst: $(PRG).lst + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +text: hex bin + +hex: $(PRG).hex +bin: $(PRG).bin + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -O binary $< $@ + +install: text + avrdude $(AVRDUDE_PROG) -p $(AVRDUDE_MCU) -V -U flash:w:$(PRG).hex + +fuses: + avrdude $(AVRDUDE_PROG) -p $(AVRDUDE_MCU) -U hfuse:w:0x14:m + avrdude $(AVRDUDE_PROG) -p $(AVRDUDE_MCU) -U lfuse:w:0xe4:m diff --git a/main.c b/main.c new file mode 100644 index 0000000..fb3f000 --- /dev/null +++ b/main.c @@ -0,0 +1,550 @@ +/*************************************************************************** + * 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(); + } + } +}