initial commit
This commit is contained in:
commit
18cb2f29c7
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
*.o
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
*.lst
|
||||||
|
*.map
|
51
Makefile
Normal file
51
Makefile
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
PRG = lipo-charger
|
||||||
|
OBJ = lipo-charger.o
|
||||||
|
MCU_TARGET = atmega8
|
||||||
|
OPTIMIZE = -Os
|
||||||
|
|
||||||
|
DEFS =
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
# You should not have to change anything below here.
|
||||||
|
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
# Override is only needed by avr-lib build system.
|
||||||
|
|
||||||
|
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
|
||||||
|
override LDFLAGS = -Wl,-Map,$(PRG).map
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin
|
||||||
|
|
||||||
|
lst: $(PRG).lst
|
||||||
|
|
||||||
|
%.lst: %.elf
|
||||||
|
$(OBJDUMP) -h -S $< > $@
|
||||||
|
|
||||||
|
# Rules for building the .text rom images
|
||||||
|
|
||||||
|
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
|
||||||
|
uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex
|
||||||
|
# avrdude -p m8 -c butterfly -b 19200 -P /dev/ttyUSB0 -u -e -U flash:w:$(PRG).hex
|
354
lipo-charger.c
Normal file
354
lipo-charger.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 09/2007 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 <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#define F_CPU 8000000
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define BAUDRATE 19200
|
||||||
|
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)(F_CPU) / ((uint32_t)(baudRate)*16) -1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LCD:
|
||||||
|
* - CS Chip Select
|
||||||
|
* - RS Register Select
|
||||||
|
* - RW Read/Write
|
||||||
|
*/
|
||||||
|
#define RS PORTB6
|
||||||
|
#define CS PORTB7
|
||||||
|
#define RW PORTD3
|
||||||
|
#define LCD_D4 PORTD4
|
||||||
|
#define LCD_D5 PORTD5
|
||||||
|
#define LCD_D6 PORTD6
|
||||||
|
#define LCD_D7 PORTD7
|
||||||
|
#define LCD_DATA_MASK ((1<<LCD_D4) | (1<<LCD_D5) | (1<<LCD_D6) | (1<<LCD_D7))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* power supply:
|
||||||
|
* - CH0 - voltage with 10:1 prescaler
|
||||||
|
* - CH1 - current with 10mA -> 1mA
|
||||||
|
* - PWM - high-active output to buckconverter
|
||||||
|
*/
|
||||||
|
#define CH0 PORTC0
|
||||||
|
#define CH1 PORTC1
|
||||||
|
#define PWM PORTB1
|
||||||
|
|
||||||
|
#define NOP asm volatile ("nop")
|
||||||
|
|
||||||
|
#define MOD_WAITING 0x00
|
||||||
|
#define MOD_CHARGING 0x01
|
||||||
|
#define MOD_READY 0x02
|
||||||
|
|
||||||
|
static void lcd_wait_busy(void)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
DDRD &= ~(LCD_DATA_MASK);
|
||||||
|
PORTD |= (1<<RW);
|
||||||
|
|
||||||
|
do {
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
status = (PIND & LCD_DATA_MASK);
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
status |= ((PIND & LCD_DATA_MASK) >> 4);
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
} while (status & 0x80);
|
||||||
|
|
||||||
|
DDRD |= LCD_DATA_MASK;
|
||||||
|
PORTD &= ~(1<<RW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lcd_write_ctrl(uint8_t val)
|
||||||
|
{
|
||||||
|
PORTD &= ~(LCD_DATA_MASK);
|
||||||
|
PORTD |= (val & 0xF0);
|
||||||
|
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
PORTD &= ~(LCD_DATA_MASK);
|
||||||
|
PORTD |= ((val<<4) & 0xF0);
|
||||||
|
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
lcd_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lcd_write_data(uint8_t val)
|
||||||
|
{
|
||||||
|
PORTD &= ~(LCD_DATA_MASK);
|
||||||
|
PORTD |= (val & 0xF0);
|
||||||
|
PORTB |= (1<<RS);
|
||||||
|
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
PORTD &= ~(LCD_DATA_MASK);
|
||||||
|
PORTD |= ((val<<4) & 0xF0);
|
||||||
|
|
||||||
|
PORTB |= (1<<CS);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PORTB &= ~(1<<CS);
|
||||||
|
|
||||||
|
PORTB &= ~(1<<RS);
|
||||||
|
|
||||||
|
lcd_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* heartbeat chars */
|
||||||
|
static const uint8_t mychars[] = {
|
||||||
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
|
||||||
|
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void lcd_init(void)
|
||||||
|
{
|
||||||
|
_delay_ms(25);
|
||||||
|
|
||||||
|
lcd_wait_busy();
|
||||||
|
|
||||||
|
/* 4bit, 2lines, 5x7 font */
|
||||||
|
lcd_write_ctrl(0x28);
|
||||||
|
|
||||||
|
/* display on, cursor off, blink off */
|
||||||
|
lcd_write_ctrl(0x0C);
|
||||||
|
|
||||||
|
/* cursor increments */
|
||||||
|
lcd_write_ctrl(0x06);
|
||||||
|
|
||||||
|
lcd_write_ctrl(0x40 | 0x00);
|
||||||
|
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < sizeof(mychars); i++)
|
||||||
|
lcd_write_data(mychars[i]);
|
||||||
|
|
||||||
|
/* clear & home pos */
|
||||||
|
lcd_write_ctrl(0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uart_putchar(char c, FILE *stream)
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
uart_putchar('\r', stream);
|
||||||
|
|
||||||
|
loop_until_bit_is_set(UCSRA, UDRE);
|
||||||
|
UDR = c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lcd_putchar(char c, FILE *stream)
|
||||||
|
{
|
||||||
|
lcd_write_data(c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE lcd = FDEV_SETUP_STREAM(lcd_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||||
|
static FILE log = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||||
|
|
||||||
|
static uint16_t voltage;
|
||||||
|
static uint16_t current;
|
||||||
|
|
||||||
|
ISR(ADC_vect)
|
||||||
|
{
|
||||||
|
if (ADMUX & 0x01) {
|
||||||
|
current = ADCW * 25;
|
||||||
|
ADMUX = CH0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
voltage = ADCW * 15;
|
||||||
|
ADMUX = CH1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADCSRA |= (1<<ADSC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t lcd_update;
|
||||||
|
static uint8_t mode = MOD_WAITING;
|
||||||
|
static uint8_t pwm;
|
||||||
|
|
||||||
|
ISR(TIMER0_OVF_vect)
|
||||||
|
{
|
||||||
|
static uint8_t cnt;
|
||||||
|
|
||||||
|
/* Come back in 1ms */
|
||||||
|
TCNT0 = 0xFF - 125;
|
||||||
|
|
||||||
|
/* update LCD every 250ms */
|
||||||
|
cnt++;
|
||||||
|
if (cnt == 250) {
|
||||||
|
cnt = 0;
|
||||||
|
lcd_update = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* charge with constant voltage of 12.45V
|
||||||
|
* and a current limit of 1.6V
|
||||||
|
*/
|
||||||
|
if (mode == MOD_CHARGING) {
|
||||||
|
if (voltage < 12425 && current < 15500)
|
||||||
|
if (pwm < 0xff)
|
||||||
|
pwm++;
|
||||||
|
|
||||||
|
if (voltage > 12450 || current > 16000)
|
||||||
|
if (pwm > 0x00)
|
||||||
|
pwm--;
|
||||||
|
} else {
|
||||||
|
pwm = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwm > 0) {
|
||||||
|
OCR1A = pwm;
|
||||||
|
TCCR1A |= (1<<COM1A1);
|
||||||
|
} else {
|
||||||
|
TCCR1A &= ~(1<<COM1A1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MOD_WAITING:
|
||||||
|
/*
|
||||||
|
* start charging when a voltage > 9V is detected (lipo connected)
|
||||||
|
*/
|
||||||
|
if (voltage > 9000)
|
||||||
|
mode = MOD_CHARGING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_CHARGING:
|
||||||
|
/*
|
||||||
|
* end charging if voltage > 12.42V and current < 200mA
|
||||||
|
*/
|
||||||
|
if (voltage > 12425 && current < 2000)
|
||||||
|
mode = MOD_READY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_READY:
|
||||||
|
/* wait for lipo disconnect */
|
||||||
|
if (voltage < 1000)
|
||||||
|
mode = MOD_WAITING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
DDRB = (1<<CS) | (1<<RS) | (1<<PWM);
|
||||||
|
DDRD = (LCD_DATA_MASK) | (1<<RW);
|
||||||
|
|
||||||
|
/* Set baud rate 19200 */
|
||||||
|
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
|
||||||
|
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
|
||||||
|
|
||||||
|
/* USART: rx/tx enable, 19200, 8n1 */
|
||||||
|
UCSRB = (1<<TXEN) | (1<<RXEN);
|
||||||
|
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
|
||||||
|
|
||||||
|
/* timer0: running with F_CPU/64 (125kHz) */
|
||||||
|
TCCR0 = (1<<CS01) | (1<<CS00);
|
||||||
|
|
||||||
|
/* timer1: running with F_CPU, 8bit Phase Correct PWM (16kHz) */
|
||||||
|
TCCR1A = (1<<WGM10);
|
||||||
|
TCCR1B = (1<<CS10) | (1<<WGM12);
|
||||||
|
|
||||||
|
/* enable Timer0 OVF Interrupt */
|
||||||
|
TIMSK = (1<<TOIE0);
|
||||||
|
|
||||||
|
/* external 2.56V reference, channel 0 */
|
||||||
|
ADMUX = CH0;
|
||||||
|
|
||||||
|
/* enable ADC with interrupts, 125kHz clk */
|
||||||
|
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);
|
||||||
|
|
||||||
|
sei();
|
||||||
|
|
||||||
|
lcd_init();
|
||||||
|
|
||||||
|
uint8_t step = 0;
|
||||||
|
uint8_t hours = 0, minutes = 0, seconds = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (lcd_update) {
|
||||||
|
/* first line, first char */
|
||||||
|
lcd_write_ctrl(0x80 | 0x00);
|
||||||
|
fprintf(&lcd, "%2d.%03dV ", voltage / 1000, voltage % 1000);
|
||||||
|
fprintf(&lcd, "%1d.%04dA ", current / 10000, current % 10000);
|
||||||
|
fprintf(&lcd, "0x%02x", pwm);
|
||||||
|
|
||||||
|
step = (step +1) & 0x03;
|
||||||
|
if (step == 0 && mode == MOD_CHARGING) {
|
||||||
|
seconds++;
|
||||||
|
if (seconds == 60) {
|
||||||
|
seconds = 0;
|
||||||
|
minutes++;
|
||||||
|
if (minutes == 60) {
|
||||||
|
minutes = 0;
|
||||||
|
hours++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(&log, "%02d:%02d:%02d %05d %05d %03d\n",
|
||||||
|
hours, minutes, seconds, voltage, current, pwm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* second line, first char */
|
||||||
|
lcd_write_ctrl(0x80 | 0x40);
|
||||||
|
fprintf(&lcd, "%02d:%02d:%02d ", hours, minutes, seconds);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MOD_WAITING:
|
||||||
|
fprintf(&lcd, " waiting ");
|
||||||
|
hours = minutes = seconds = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_CHARGING:
|
||||||
|
fprintf(&lcd, " charging");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_READY:
|
||||||
|
fprintf(&lcd, " ready ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* second line, last char */
|
||||||
|
lcd_write_ctrl(0x80 | 0x40 | 19);
|
||||||
|
lcd_write_data(step);
|
||||||
|
|
||||||
|
lcd_update = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user