bikegenerator/display/software/powerboard_v2/src/main.c

205 lines
4.9 KiB
C

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "utils.h"
#include "main.h"
#include "adc.h"
#include "uart.h"
volatile uint16_t syscounter = 0;
uint16_t voltage_bat = 0;
uint16_t voltage_gen = 0;
uint16_t current_in = 0;
uint8_t overvoltage_counter = 0;
uint8_t overvoltage_off_counter = 0;
uint8_t undervoltage_counter = 0;
uint8_t undervoltage_off_counter = 0;
uint8_t generator_counter = 0;
uint8_t generator_off_counter = 0;
static void timer_init(void) {
// clock is 8MHz
TCCR1B |= _BV(WGM12) | _BV(CS11) | _BV(CS10) ; // CTC Mode for Timer 1 (16Bit) with prescale of 64
OCR1A = 1250; // 100Hz
TIMSK = _BV(OCIE1A);
sei(); // enable interrupts
}
static void ports_init(void) {
DDR_SW |= _BV(LOADSW) | _BV(GENSW);
PORT_SW &= ~(_BV(LOADSW) | _BV(GENSW));
}
void measure(void) {
static int16_t temp;
voltage_bat = adc_read_avg(AD_V_BAT, 4);
voltage_bat *= VOLTAGE_PER_TICK;
voltage_bat += 790;
voltage_gen = adc_read_avg(AD_V_GEN, 4);
voltage_gen *= VOLTAGE_PER_TICK;
temp = adc_read_avg(AD_I_GEN, 4);
temp -= CURRENT_OFFSET;
if(temp < 0) temp = 0;
current_in = temp * CURRENT_PER_TICK;
}
uint16_t get_power(uint16_t voltage, int16_t currents) {
return (voltage/100 * (currents/100)) / 100 ;
}
void pretty_print_all_values(void) {
uart_puts_P("Battery Voltage: ");
uart_print_uint16(voltage_bat);
uart_puts_P("mV\r\n");
uart_puts_P("Generator Voltage: ");
uart_print_uint16(voltage_gen);
uart_puts_P("mV\r\n");
uart_puts_P("Generator: ");
uart_print_uint16(current_in);
uart_puts_P("mA ");
uart_print_uint16(get_power(voltage_bat, current_in));
uart_puts_P("W\r\n");
uart_puts_P("switches (load, gen): ");
uart_putc(48 + (IS_LOAD_ON >> LOADSW));
uart_putc(',');
uart_putc(48 + (IS_GEN_ON >> GENSW));
uart_puts_P("\r\n");
}
void handle_over_and_undervoltage(void) {
if(voltage_bat < UNDERVOLTAGE) {
undervoltage_off_counter = 0;
if(undervoltage_counter<UNDERVOLTAGE_TIMEOUT) undervoltage_counter++;
} else {
undervoltage_counter = 0;
if(undervoltage_off_counter<UNDERVOLTAGEOFF_TIMEOUT) undervoltage_off_counter++;
}
if(voltage_gen > GENERATOR) {
generator_off_counter = 0;
if(generator_counter<GENERATOR_TIMEOUT) generator_counter++;
} else {
generator_counter = 0;
if(generator_off_counter<GENERATOR_OFF_TIMEOUT) generator_off_counter++;
}
if(undervoltage_counter >= UNDERVOLTAGE_TIMEOUT) {
// spannung zu niedrig => abschalten
undervoltage_off_counter = 0;
LOAD_OFF;
} else {
// spannung ist okay
// ist die spannung schon lange genug okay?
if(undervoltage_off_counter >= UNDERVOLTAGEOFF_TIMEOUT) {
undervoltage_counter = 0;
// ja, also schauen ob der generator schon lange genug läuft
if(generator_counter >= GENERATOR_TIMEOUT) {
// ja, also einschalten
LOAD_ON;
} else {
// nein, generator nicht lange genug an
// ist er vielleicht schon lange aus?
if(generator_off_counter >= GENERATOR_OFF_TIMEOUT) {
// ja, also abschalten, egal ob akku okay
LOAD_OFF;
}
}
}
}
#ifdef DEBUG
uart_puts_P("ov1=");
uart_print_uint8(overvoltage_counter1);
uart_puts_P(" ovo1=");
uart_print_uint8 (overvoltage_off_counter1);
uart_puts_P("\r\n");
uart_puts_P("uv =");
uart_print_uint8(undervoltage_counter);
uart_puts_P(" uvo =");
uart_print_uint8(undervoltage_off_counter);
uart_puts_P("\r\n");
#endif
}
static void work_uart(void) {
uint16_t uart_char = uart_getc();
if(uart_char != UART_NO_DATA) {
switch(uart_char & 0xff) {
case 'p':
pretty_print_all_values();
break;
case 'a':
uart_putc('A');
uart_print_uint16(voltage_bat);
uart_putc(',');
uart_print_uint16(current_in);
uart_putc(',');
uart_print_uint16(0);
uart_putc(',');
uart_print_uint16(get_power(voltage_bat, current_in));
uart_putc(',');
uart_print_uint16(0);
uart_putc(',');
uart_putc(48 + (IS_LOAD_ON >> LOADSW));
uart_putc(',');
uart_putc(48);
uart_putc(',');
uart_putc(48 + (IS_GEN_ON >> GENSW));
uart_putc('B');
break;
}
}
}
int main(void) {
ports_init();
adc_init();
timer_init();
uart_init(UART_BAUD_SELECT(19200,F_CPU));
LOAD_OFF;
GEN_ON;
while(1) {
if(syscounter >= 100) {
syscounter = 0;
measure();
//pretty_print_all_values();
handle_over_and_undervoltage();
}
work_uart();
}
return(0);
}
// system timer
SIGNAL(TIMER1_COMPA_vect) {
syscounter++;
syscounter %= 60000;
}