327 lines
7.4 KiB
C
327 lines
7.4 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"
|
|
|
|
enum states_k2k3 {
|
|
EX_ON,
|
|
EX_OFF,
|
|
Q_ON,
|
|
Q_OFF
|
|
} current_state_k2k3;
|
|
|
|
enum states_k1 {
|
|
G_ON,
|
|
G_OFF
|
|
} current_state_k1;
|
|
|
|
enum opmode_t {
|
|
QUICK,
|
|
EXHAUST
|
|
} mode;
|
|
|
|
volatile uint16_t syscounter = 0;
|
|
uint16_t u_r = 0;
|
|
uint16_t u_g = 0;
|
|
uint16_t i_g = 0;
|
|
|
|
#define UR_MIN 10900
|
|
#define UR_MAX 14500
|
|
|
|
#define UG_MIN 18000
|
|
#define UG_MAX 35000
|
|
|
|
|
|
static void statemachine_k2_k3() {
|
|
enum states_k2k3 next;
|
|
|
|
switch(current_state_k2k3) {
|
|
case EX_ON:
|
|
if(mode == EXHAUST && (u_r <= UR_MIN || u_r >= UR_MAX)) {
|
|
next = EX_OFF;
|
|
} else if(mode == QUICK && (u_g > UG_MIN && u_g < UG_MAX)) {
|
|
next = Q_ON;
|
|
} else if(mode == QUICK && (u_g <= UG_MIN || u_g >= UG_MAX)) {
|
|
next = Q_OFF;
|
|
} else {
|
|
next = EX_ON;
|
|
}
|
|
break;
|
|
case EX_OFF:
|
|
if(mode == QUICK && (u_g <= UG_MIN || u_g >= UG_MAX)) {
|
|
next = Q_OFF;
|
|
} else if(mode == QUICK && (u_g > UG_MIN && u_g < UG_MAX)) {
|
|
next = Q_ON;
|
|
} else if(mode == EXHAUST && (u_r > UR_MIN && u_r < UR_MAX)) {
|
|
next = EX_ON;
|
|
} else {
|
|
next = EX_OFF;
|
|
}
|
|
|
|
break;
|
|
case Q_ON:
|
|
if(mode == EXHAUST && (u_r <= UR_MIN || u_r >= UR_MAX)) {
|
|
next = EX_OFF;
|
|
} else if(mode == EXHAUST && (u_r > UR_MIN && u_r < UR_MAX)) {
|
|
next = EX_ON;
|
|
} else if(mode == QUICK && (u_g <= UG_MIN || u_g >= UG_MAX)) {
|
|
next = Q_OFF;
|
|
} else {
|
|
next = Q_ON;
|
|
}
|
|
break;
|
|
default:
|
|
case Q_OFF:
|
|
if(mode == EXHAUST && (u_r <= UR_MIN || u_r >= UR_MAX)) {
|
|
next = EX_OFF;
|
|
} else if(mode == EXHAUST && (u_r > UR_MIN && u_r < UR_MAX)) {
|
|
next = EX_ON;
|
|
} else if(mode == QUICK && (u_g > UG_MIN && u_g < UG_MAX)) {
|
|
next = Q_ON;
|
|
} else {
|
|
next = Q_OFF;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if(current_state_k2k3 != next) uart_puts_P("new state: ");
|
|
#endif
|
|
|
|
switch(next) {
|
|
default:
|
|
case Q_OFF:
|
|
//BAT_OFF;
|
|
BAT_ON;
|
|
LOAD_OFF;
|
|
#ifdef DEBUG
|
|
if(current_state_k2k3 != next) uart_puts_P("Q_OFF\r\n");
|
|
#endif
|
|
break;
|
|
case Q_ON:
|
|
//BAT_OFF;
|
|
BAT_ON;
|
|
LOAD_ON;
|
|
#ifdef DEBUG
|
|
if(current_state_k2k3 != next) uart_puts_P("Q_ON\r\n");
|
|
#endif
|
|
break;
|
|
case EX_OFF:
|
|
BAT_ON;
|
|
LOAD_OFF;
|
|
#ifdef DEBUG
|
|
if(current_state_k2k3 != next) uart_puts_P("EX_OFF\r\n");
|
|
#endif
|
|
break;
|
|
case EX_ON:
|
|
BAT_ON;
|
|
LOAD_ON;
|
|
#ifdef DEBUG
|
|
if(current_state_k2k3 != next) uart_puts_P("EX_ON\r\n");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
current_state_k2k3 = next;
|
|
|
|
}
|
|
|
|
static void statemachine_k1() {
|
|
enum states_k1 next;
|
|
|
|
switch(current_state_k1) {
|
|
default:
|
|
case G_OFF:
|
|
if(u_g > UG_MIN && u_g < UG_MAX) {
|
|
next = G_ON;
|
|
} else {
|
|
next = G_OFF;
|
|
}
|
|
break;
|
|
case G_ON:
|
|
if(u_g <= UG_MIN || u_g > UG_MAX) {
|
|
next = G_OFF;
|
|
} else {
|
|
next = G_ON;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if(current_state_k1 != next) uart_puts_P("new state k1: ");
|
|
#endif
|
|
|
|
switch(next) {
|
|
default:
|
|
case G_OFF:
|
|
GEN_OFF;
|
|
#ifdef DEBUG
|
|
if(current_state_k1 != next) uart_puts_P("G_OFF\r\n");
|
|
#endif
|
|
break;
|
|
case G_ON:
|
|
GEN_ON;
|
|
#ifdef DEBUG
|
|
if(current_state_k1 != next) uart_puts_P("G_ON\r\n");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
current_state_k1 = next;
|
|
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
static void ports_init(void) {
|
|
// set all switch port to output mode
|
|
DDR_SW |= _BV(LOADSW) | _BV(GENSW) | _BV(BATSW);
|
|
|
|
// set all ports to low
|
|
PORT_SW &= ~(_BV(LOADSW) | _BV(GENSW) | _BV(BATSW));
|
|
|
|
// set inputs
|
|
DDR_TP &= ~(_BV(TP1));
|
|
|
|
// enable pullups for inputs
|
|
PORT_TP |= _BV(TP1);
|
|
}
|
|
|
|
void measure(void) {
|
|
|
|
static int16_t temp;
|
|
static uint32_t vtemp;
|
|
|
|
// Regulator Voltage has a Voltage-Divider R1 = 56k, R2 = 27k
|
|
// U2 = U * ( R2 / (R1+R2) )
|
|
// U = U2 / ( R2 / (R1+R2) )
|
|
// U = 5V / ( 27k / 83k ) = 15.37V -> Umax
|
|
// 27k / 83k = 0.3253
|
|
// ADC = (Ur * 0.325 * 1024) / 5V
|
|
// ADC = Ur * 66,56
|
|
// ADC = ( Ur * 10 * 1000 ) / 665 -> Ur in mV
|
|
|
|
vtemp = adc_read_avg(AD_V_REG, 20);
|
|
vtemp = vtemp * 10 * 1000;
|
|
u_r = vtemp / (665 - 1); // -1 to calibrate the resistors
|
|
u_r = u_r + 143; // 143 resistor offset
|
|
|
|
|
|
// Generator Voltage has a Voltage-Divider R1 = 68k, R2 = 10k
|
|
// U2 = U * ( R2 / (R1+R2) )
|
|
// U = U2 / ( R2 / (R1+R2) )
|
|
// U = 5V / ( 10k / 78k ) = 39V -> Umax
|
|
// 10k / 78k = 0.128
|
|
// ADC = (Ur * 0.128 * 1024) / 5V
|
|
// ADC = Ur * 131,1 / 5V
|
|
// ADC = Ur * 26,2
|
|
// ADC = ( Ur * 10 * 1000 ) / 262 -> Ur in mV
|
|
vtemp = adc_read_avg(AD_V_GEN, 20);
|
|
vtemp = vtemp * 10 * 1000;
|
|
u_g = vtemp / (262 - 3); // -3 to calibrate the resistors
|
|
u_g = u_g + 85; // 85 resistor offset
|
|
|
|
|
|
temp = adc_read_avg(AD_I_GEN, 20);
|
|
temp -= 511; // substract Sensor offset (2,5V)
|
|
if(temp < 0) temp = 0;
|
|
//i_g = (temp * 151510) / 2048;
|
|
i_g = temp * (74 - 2);
|
|
if(i_g > 210) {
|
|
i_g = i_g - 210;
|
|
} else {
|
|
i_g = 0;
|
|
}
|
|
|
|
mode = (PIN_TP & _BV(TP1)) ? QUICK : EXHAUST;
|
|
}
|
|
|
|
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("u_r: ");
|
|
uart_print_uint16(u_r);
|
|
uart_puts_P("mV\r\n");
|
|
|
|
uart_puts_P("u_g: ");
|
|
uart_print_uint16(u_g);
|
|
uart_puts_P("mV\r\n");
|
|
|
|
uart_puts_P("i_g: ");
|
|
uart_print_uint16(i_g);
|
|
uart_puts_P("mA ");
|
|
uart_print_uint16(get_power(u_g, i_g));
|
|
uart_puts_P("W\r\n");
|
|
|
|
uart_puts_P("l,g,b: ");
|
|
uart_putc(48 + IS_LOAD_ON);
|
|
uart_putc(',');
|
|
uart_putc(48 + IS_GEN_ON);
|
|
uart_putc(',');
|
|
uart_putc(48 + IS_BAT_ON);
|
|
uart_puts_P("\r\n");
|
|
}
|
|
|
|
|
|
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_print_uint16(get_power(u_g, i_g));
|
|
uart_putc('\n');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
ports_init();
|
|
adc_init();
|
|
timer_init();
|
|
uart_init(UART_BAUD_SELECT(38400,F_CPU));
|
|
|
|
|
|
while(1) {
|
|
|
|
work_uart();
|
|
|
|
if(syscounter >= 100) {
|
|
syscounter = 0;
|
|
|
|
measure();
|
|
|
|
//pretty_print_all_values();
|
|
|
|
statemachine_k1();
|
|
statemachine_k2_k3();
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
// system timer
|
|
SIGNAL(TIMER1_COMPA_vect) {
|
|
syscounter++;
|
|
//syscounter %= 60000;
|
|
}
|
|
|
|
|