lipo-charger/lipo-charger.c

187 lines
4.6 KiB
C

/***************************************************************************
* 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>
#define ADC_REF PORTA0
#define ADC_U PORTA1
#define ADC_IM PORTA2
#define ADC_IP PORTA3
#define SUMMER PORTA7
#define LEDRT PORTB0
#define LEDGN PORTB1
#define PWM PORTB2
/* ADC_U vs GND: voltage with prescaler (12V -> 2V; 15mV -> 2.5mV/bit), ref 2.56V */
#define CH_U ((1<<REFS0) | 0x01)
/* ADC_IP vs ADC_IM: current sense (1A -> 100mV; ??mA -> ?mV/bit), gain x20, ref 5V */
#define CH_I ((0<<REFS0) | 0x31)
#define MOD_WAITING 0x00
#define MOD_CHARGING 0x01
#define MOD_READY 0x02
#define VOLTAGE_CONNECT 9000
#define VOLTAGE_CHARGE 12450
#define CURRENT_CHARGE 17500
#define CURRENT_READY 2000
#define VOLTAGE_REMOVE 1000
static uint16_t voltage;
static uint16_t current;
ISR(ADC_vect)
{
if (ADMUX == CH_I) {
current = ADCW * 25;
ADMUX = CH_U;
} else {
voltage = ADCW * 15;
ADMUX = CH_I;
}
}
ISR(TIM1_OVF_vect)
{
/* Come back in 1ms */
TCNT1 = 0xFFFF - 8000;
/* start ADC again */
ADCSRA |= (1<<ADSC);
static uint8_t pwm;
static uint8_t mode = MOD_WAITING;
/* charge with constant voltage and current limit */
if (mode == MOD_CHARGING) {
if (voltage < (VOLTAGE_CHARGE -25) && current < (CURRENT_CHARGE -500))
if (pwm < 0xff)
pwm++;
if (voltage > VOLTAGE_CHARGE || current > CURRENT_CHARGE)
if (pwm > 0x00)
pwm--;
OCR0A = pwm;
TCCR0A |= (1<<COM1A1);
} else {
pwm = 0;
TCCR0A &= ~(1<<COM1A1);
}
static uint16_t led_timer;
led_timer = (led_timer +1) & 0x3FF;
switch (mode) {
case MOD_WAITING:
/* green flashing, red off */
if (led_timer < 0x3F)
PORTB &= ~(1<<LEDGN);
else
PORTB |= (1<<LEDGN) | (1<<LEDRT);
PORTA |= (1<<SUMMER);
/* start charging when a voltage > 9V is detected (lipo connected) */
if (voltage > VOLTAGE_CONNECT)
mode = MOD_CHARGING;
break;
case MOD_CHARGING:
/* current limit */
if (voltage < (VOLTAGE_CHARGE -50)) {
/* green on, red fast blinking */
if (led_timer & 0x80)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
/* voltage limit */
} else {
/* green on, red slow blinking */
if (led_timer & 0x200)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
}
PORTA |= (1<<SUMMER);
/* end charging if voltage > 12.45V and current < 200mA */
if (voltage >= VOLTAGE_CHARGE && current < CURRENT_READY)
mode = MOD_READY;
break;
case MOD_READY:
/* green on, red flashing */
if (led_timer < 0x3F)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
/* beeping */
if (led_timer < 0x07)
PORTA &= ~(1<<SUMMER);
else
PORTA |= (1<<SUMMER);
/* wait for lipo disconnect */
if (voltage < VOLTAGE_REMOVE)
mode = MOD_WAITING;
break;
}
}
int main(void)
{
/* digital outputs */
DDRA = (1<<SUMMER);
DDRB = (1<<LEDGN) | (1<<LEDRT) | (1<<PWM);
/* analog inputs */
DIDR0 = (1<<ADC_REF) | (1<<ADC_U) | (1<<ADC_IM) | (1<<ADC_IP);
/* timer0: running with F_CPU, 8bit Fast PWM (32khz) */
TCCR0A = (1<<WGM00) | (1<<WGM01);
TCCR0B = (1<<CS00);
/* timer1: running with F_CPU */
TCCR1B = (1<<CS00);
/* enable iimer1 OVF Interrupt */
TIMSK1 = (1<<TOIE1);
/* enable ADC with interrupts, 125kHz clk */
ADMUX = CH_I;
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);
sei();
while (1);
return 0;
}