tiny24 version
This commit is contained in:
parent
eacfc70af9
commit
cd560f4268
6
Makefile
6
Makefile
@ -1,6 +1,6 @@
|
|||||||
PRG = lipo-charger
|
PRG = lipo-charger
|
||||||
OBJ = lipo-charger.o
|
OBJ = lipo-charger.o
|
||||||
MCU_TARGET = atmega8
|
MCU_TARGET = attiny24
|
||||||
OPTIMIZE = -Os
|
OPTIMIZE = -Os
|
||||||
|
|
||||||
DEFS =
|
DEFS =
|
||||||
@ -47,5 +47,5 @@ bin: $(PRG).bin
|
|||||||
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||||
|
|
||||||
install: text
|
install: text
|
||||||
uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex
|
# 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
|
avrdude -p t24 -c butterfly -b 115200 -P /dev/ttyUSB0 -u -e -U flash:w:$(PRG).hex
|
||||||
|
340
lipo-charger.c
340
lipo-charger.c
@ -22,37 +22,21 @@
|
|||||||
#define F_CPU 8000000
|
#define F_CPU 8000000
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#define ADC_REF PORTA0
|
||||||
|
#define ADC_U PORTA1
|
||||||
|
#define ADC_IM PORTA2
|
||||||
|
#define ADC_IP PORTA3
|
||||||
|
#define SUMMER PORTA7
|
||||||
|
|
||||||
#define BAUDRATE 19200
|
#define LEDRT PORTB0
|
||||||
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)(F_CPU) / ((uint32_t)(baudRate)*16) -1)
|
#define LEDGN PORTB1
|
||||||
|
#define PWM PORTB2
|
||||||
|
|
||||||
/*
|
/* ADC_U vs GND: voltage with prescaler (12V -> 2V; 15mV -> 2.5mV/bit), ref 2.56V */
|
||||||
* LCD:
|
#define CH_U ((1<<REFS0) | 0x01)
|
||||||
* - 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))
|
|
||||||
|
|
||||||
/*
|
/* ADC_IP vs ADC_IM: current sense (1A -> 100mV; ??mA -> ?mV/bit), gain x20, ref 5V */
|
||||||
* power supply:
|
#define CH_I ((0<<REFS0) | 0x31)
|
||||||
* - CH0 - voltage with prescaler (12V -> 2V; 15mV -> 2.5mV/bit)
|
|
||||||
* - CH1 - current with (1A -> 1000mV; 2.5mA -> 2.5mV/bit)
|
|
||||||
* - 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_WAITING 0x00
|
||||||
#define MOD_CHARGING 0x01
|
#define MOD_CHARGING 0x01
|
||||||
@ -60,173 +44,37 @@
|
|||||||
|
|
||||||
#define VOLTAGE_CONNECT 9000
|
#define VOLTAGE_CONNECT 9000
|
||||||
#define VOLTAGE_CHARGE 12450
|
#define VOLTAGE_CHARGE 12450
|
||||||
#define CURRENT_CHARGE 16000
|
#define CURRENT_CHARGE 17500
|
||||||
#define CURRENT_READY 2000
|
#define CURRENT_READY 2000
|
||||||
#define VOLTAGE_REMOVE 1000
|
#define VOLTAGE_REMOVE 1000
|
||||||
|
|
||||||
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 voltage;
|
||||||
static uint16_t current;
|
static uint16_t current;
|
||||||
|
|
||||||
ISR(ADC_vect)
|
ISR(ADC_vect)
|
||||||
{
|
{
|
||||||
if (ADMUX & 0x01) {
|
if (ADMUX == CH_I) {
|
||||||
current = ADCW * 25;
|
current = ADCW * 25;
|
||||||
ADMUX = CH0;
|
ADMUX = CH_U;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
voltage = ADCW * 15;
|
voltage = ADCW * 15;
|
||||||
ADMUX = CH1;
|
ADMUX = CH_I;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(TIM1_OVF_vect)
|
||||||
|
{
|
||||||
|
/* Come back in 1ms */
|
||||||
|
TCNT1 = 0xFFFF - 8000;
|
||||||
|
|
||||||
/* start ADC again */
|
/* start ADC again */
|
||||||
ADCSRA |= (1<<ADSC);
|
ADCSRA |= (1<<ADSC);
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t lcd_update;
|
static uint8_t pwm;
|
||||||
static uint8_t mode = MOD_WAITING;
|
static uint8_t mode = MOD_WAITING;
|
||||||
static uint8_t pwm;
|
|
||||||
|
|
||||||
ISR(TIMER0_OVF_vect)
|
/* charge with constant voltage and current limit */
|
||||||
{
|
|
||||||
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.6A
|
|
||||||
*/
|
|
||||||
if (mode == MOD_CHARGING) {
|
if (mode == MOD_CHARGING) {
|
||||||
if (voltage < (VOLTAGE_CHARGE -25) && current < (CURRENT_CHARGE -500))
|
if (voltage < (VOLTAGE_CHARGE -25) && current < (CURRENT_CHARGE -500))
|
||||||
if (pwm < 0xff)
|
if (pwm < 0xff)
|
||||||
@ -236,27 +84,71 @@ ISR(TIMER0_OVF_vect)
|
|||||||
if (pwm > 0x00)
|
if (pwm > 0x00)
|
||||||
pwm--;
|
pwm--;
|
||||||
|
|
||||||
OCR1A = pwm;
|
OCR0A = pwm;
|
||||||
TCCR1A |= (1<<COM1A1);
|
TCCR0A |= (1<<COM1A1);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pwm = 0;
|
pwm = 0;
|
||||||
TCCR1A &= ~(1<<COM1A1);
|
TCCR0A &= ~(1<<COM1A1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t led_timer;
|
||||||
|
led_timer = (led_timer +1) & 0x3FF;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case MOD_WAITING:
|
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) */
|
/* start charging when a voltage > 9V is detected (lipo connected) */
|
||||||
if (voltage > VOLTAGE_CONNECT)
|
if (voltage > VOLTAGE_CONNECT)
|
||||||
mode = MOD_CHARGING;
|
mode = MOD_CHARGING;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_CHARGING:
|
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 */
|
/* end charging if voltage > 12.45V and current < 200mA */
|
||||||
if (voltage >= VOLTAGE_CHARGE && current < CURRENT_READY)
|
if (voltage >= VOLTAGE_CHARGE && current < CURRENT_READY)
|
||||||
mode = MOD_READY;
|
mode = MOD_READY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_READY:
|
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 */
|
/* wait for lipo disconnect */
|
||||||
if (voltage < VOLTAGE_REMOVE)
|
if (voltage < VOLTAGE_REMOVE)
|
||||||
mode = MOD_WAITING;
|
mode = MOD_WAITING;
|
||||||
@ -266,89 +158,29 @@ ISR(TIMER0_OVF_vect)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
DDRB = (1<<CS) | (1<<RS) | (1<<PWM);
|
/* digital outputs */
|
||||||
DDRD = (LCD_DATA_MASK) | (1<<RW);
|
DDRA = (1<<SUMMER);
|
||||||
|
DDRB = (1<<LEDGN) | (1<<LEDRT) | (1<<PWM);
|
||||||
|
|
||||||
/* Set baud rate 19200 */
|
/* analog inputs */
|
||||||
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
|
DIDR0 = (1<<ADC_REF) | (1<<ADC_U) | (1<<ADC_IM) | (1<<ADC_IP);
|
||||||
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
|
|
||||||
|
|
||||||
/* USART: rx/tx enable, 19200, 8n1 */
|
/* timer0: running with F_CPU, 8bit Fast PWM (32khz) */
|
||||||
UCSRB = (1<<TXEN) | (1<<RXEN);
|
TCCR0A = (1<<WGM00) | (1<<WGM01);
|
||||||
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
|
TCCR0B = (1<<CS00);
|
||||||
|
|
||||||
/* timer0: running with F_CPU/64 (125kHz) */
|
/* timer1: running with F_CPU */
|
||||||
TCCR0 = (1<<CS01) | (1<<CS00);
|
TCCR1B = (1<<CS00);
|
||||||
|
|
||||||
/* timer1: running with F_CPU, 8bit Phase Correct PWM (16kHz) */
|
/* enable iimer1 OVF Interrupt */
|
||||||
TCCR1A = (1<<WGM10);
|
TIMSK1 = (1<<TOIE1);
|
||||||
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 */
|
/* enable ADC with interrupts, 125kHz clk */
|
||||||
|
ADMUX = CH_I;
|
||||||
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);
|
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);
|
||||||
|
|
||||||
sei();
|
sei();
|
||||||
|
|
||||||
lcd_init();
|
while (1);
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user