319 lines
7.0 KiB
C
319 lines
7.0 KiB
C
#include <stdlib.h>
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <string.h>
|
|
#include "utils.h"
|
|
#include "main.h"
|
|
#include "uart.h"
|
|
|
|
#define BUFSIZE 40
|
|
#define CURRENT_MAX 30000 // 30 Ampere is max
|
|
|
|
volatile uint16_t syscounter = 0;
|
|
volatile uint8_t digitbuffer[6] = { 0,0,0,0,0,0 };
|
|
volatile uint8_t leddigitbuffer[4] = { 0,0,0,0 };
|
|
uint8_t digit = 0;
|
|
uint8_t leddigit = 0;
|
|
|
|
// values send over uart from powerboard
|
|
uint16_t voltage = 0;
|
|
int16_t current_in = 0;
|
|
int16_t current_out = 0;
|
|
uint8_t dumpsw = 0; //TODO: make bitfield
|
|
uint8_t loadsw = 0; //TODO: make bitfield
|
|
uint8_t gensw = 0; //TODO: make bitfield
|
|
|
|
uint16_t power_gen = 0;
|
|
uint16_t power_load = 0;
|
|
|
|
unsigned char data_count = 0;
|
|
unsigned char data_in[BUFSIZE];
|
|
char command_in[BUFSIZE];
|
|
|
|
const uint8_t segment_translate[10] = {
|
|
63, 6, 91, 79, 102, 109, 125, 7, 127, 111
|
|
};
|
|
|
|
const uint8_t smallbar_translate[9] = {
|
|
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
|
};
|
|
|
|
const uint8_t bigbar_translate[15][2] = {
|
|
{ 0x00, 0xc0},
|
|
{ 0x00, 0x60},
|
|
{ 0x00, 0x30},
|
|
{ 0x00, 0x18},
|
|
{ 0x00, 0x0c},
|
|
{ 0x00, 0x06},
|
|
{ 0x00, 0x03},
|
|
{ 0x01, 0x01},
|
|
{ 0x03, 0x00},
|
|
{ 0x06, 0x00},
|
|
{ 0x0c, 0x00},
|
|
{ 0x18, 0x00},
|
|
{ 0x30, 0x00},
|
|
{ 0x60, 0x00},
|
|
{ 0xc0, 0x00}
|
|
};
|
|
|
|
|
|
|
|
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 = 250; // 500Hz
|
|
TIMSK = _BV(OCIE1A);
|
|
sei(); // enable interrupts
|
|
}
|
|
|
|
static void ports_init(void) {
|
|
// make column / digit driver pins to output
|
|
LEDDIG_DDR |= _BV(LEDS_MID1) | _BV(LEDS_MID2) | _BV(LEDS_LOAD) | _BV(LEDS_GEN);
|
|
SEVENSEGDIG_DDR |= _BV(DIG0) | _BV(DIG1) | _BV(DIG2) | _BV(DIG3) | _BV(DIG4) | _BV(DIG5);
|
|
|
|
// make data ports to output
|
|
LED_DDR = 0xff;
|
|
SEVENSEG_DDR = 0xff;
|
|
|
|
SEVENSEGDIG_PORT = 0;
|
|
SEVENSEG_PORT = 0;
|
|
|
|
LEDDIG_PORT = 0;
|
|
LED_PORT = 0;
|
|
}
|
|
|
|
static void print_sevenseg(uint8_t display, uint16_t value) {
|
|
uint8_t d[3];
|
|
d[2] = (value % 1000 / 100 );
|
|
d[1] = (value % 100 / 10 );
|
|
d[0] = (value % 10);
|
|
|
|
if(display == 0) {
|
|
digitbuffer[0] = segment_translate[d[0]];
|
|
if(d[1] == 0 && d[2] == 0)
|
|
digitbuffer[1] = 0x00;
|
|
else
|
|
digitbuffer[1] = segment_translate[d[1]];
|
|
if(d[2] == 0)
|
|
digitbuffer[2] = 0x00;
|
|
else
|
|
digitbuffer[2] = segment_translate[d[2]];
|
|
} else {
|
|
digitbuffer[3] = segment_translate[d[0]];
|
|
if(d[1] == 0 && d[2] == 0)
|
|
digitbuffer[4] = 0x00;
|
|
else
|
|
digitbuffer[4] = segment_translate[d[1]];
|
|
if(d[2] == 0)
|
|
digitbuffer[5] = 0x00;
|
|
else
|
|
digitbuffer[5] = segment_translate[d[2]];
|
|
|
|
}
|
|
}
|
|
|
|
static void print_bar(uint8_t display, uint16_t value, uint16_t max) {
|
|
uint16_t x = 0;
|
|
float temp = max;
|
|
|
|
x = (uint16_t)( (value / temp) * 8.0);
|
|
|
|
x%=8;
|
|
|
|
switch(display) {
|
|
case LEDS_LOAD:
|
|
leddigitbuffer[2] = smallbar_translate[x];
|
|
break;
|
|
case LEDS_GEN:
|
|
leddigitbuffer[3] = smallbar_translate[x];
|
|
break;
|
|
}
|
|
|
|
}
|
|
static void print_bar_bottom(uint16_t in, uint16_t out, uint16_t max) {
|
|
uint16_t x;
|
|
float temp = max;
|
|
|
|
if(out == in) {
|
|
leddigitbuffer[0] = bigbar_translate[7][0];
|
|
leddigitbuffer[1] = bigbar_translate[7][1];
|
|
return;
|
|
} else if( out > in ) {
|
|
x = (uint16_t)( ((out - in) / temp) * 8.0);
|
|
x = x+8;
|
|
|
|
} else {
|
|
x = (uint16_t)( ((in - out) / temp) * 8.0);
|
|
x = 7-x;
|
|
}
|
|
|
|
if(x > 14) x = 14;
|
|
if(x < 0) x = 0;
|
|
|
|
leddigitbuffer[0] = bigbar_translate[x][0];
|
|
leddigitbuffer[1] = bigbar_translate[x][1];
|
|
|
|
}
|
|
|
|
void process_command() {
|
|
if(strstr(command_in,"A") != NULL) {
|
|
// we have an A and B (from check in work_uart()
|
|
// so our message should be complete and consist of:
|
|
// A$voltage,$current_in,$current_out,$power_in,$power_out,loadsw,dumpsw,gensw\n
|
|
|
|
//A12.5,65464,00000,00000,00000,1,0,1B
|
|
|
|
char *token;
|
|
uint8_t tokencounter = 0;
|
|
|
|
char *start = strrchr(command_in, 'A');
|
|
|
|
// remove first (B is ignored by atoi)
|
|
start++;
|
|
|
|
token = strtok(start, ",");
|
|
|
|
while( token ) {
|
|
switch(tokencounter) {
|
|
case 0:
|
|
voltage = atoi(token);
|
|
break;
|
|
case 1:
|
|
current_in = atoi(token);
|
|
break;
|
|
case 2:
|
|
current_out = atoi(token);
|
|
break;
|
|
case 3:
|
|
power_gen = atoi(token);
|
|
break;
|
|
case 4:
|
|
power_load = atoi(token);
|
|
break;
|
|
case 5:
|
|
if(atoi(token) == 1) loadsw = 1;
|
|
else loadsw = 0;
|
|
break;
|
|
case 6:
|
|
if(atoi(token) == 1) dumpsw = 1;
|
|
else dumpsw = 0;
|
|
break;
|
|
case 7:
|
|
if(atoi(token) == 1) gensw = 1;
|
|
else gensw = 0;
|
|
break;
|
|
}
|
|
|
|
tokencounter++;
|
|
token = strtok(NULL, ",");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void work_uart(){
|
|
unsigned int c = uart_getc();
|
|
|
|
if ( !(c & UART_NO_DATA) ) {
|
|
data_in[data_count] = c;
|
|
|
|
if (data_in[data_count] == 'B') {
|
|
data_count = 0;
|
|
|
|
memcpy(command_in, data_in, BUFSIZE);
|
|
memset(data_in, 0, BUFSIZE);
|
|
|
|
process_command();
|
|
} else {
|
|
data_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void demo_display(void) {
|
|
|
|
for(uint8_t i = 0; i< 16;i++) {
|
|
leddigitbuffer[0] = bigbar_translate[i][0];
|
|
leddigitbuffer[1] = bigbar_translate[i][1];
|
|
wait(5);
|
|
}
|
|
|
|
for(uint8_t i = 0; i< 9;i++) {
|
|
leddigitbuffer[2] = smallbar_translate[i];
|
|
wait(5);
|
|
}
|
|
|
|
for(uint8_t i = 0; i< 9;i++) {
|
|
leddigitbuffer[3] = smallbar_translate[i];
|
|
wait(5);
|
|
}
|
|
|
|
for(uint8_t j = 0; j< 3;j++) {
|
|
for(uint8_t i = 0; i< 6; i++) {
|
|
digitbuffer[i] = 0xff;
|
|
}
|
|
wait(20);
|
|
for(uint8_t i = 0; i< 6; i++) {
|
|
digitbuffer[i] = 0x00;
|
|
}
|
|
wait(20);
|
|
}
|
|
|
|
for(uint8_t i = 0; i< 3;i++) {
|
|
leddigitbuffer[i] = 0x00;
|
|
}
|
|
|
|
}
|
|
|
|
int main(void) {
|
|
ports_init();
|
|
timer_init();
|
|
uart_init(UART_BAUD_SELECT(19200,F_CPU));
|
|
memset(data_in, 0, BUFSIZE);
|
|
|
|
|
|
demo_display();
|
|
|
|
while(1) {
|
|
|
|
work_uart();
|
|
|
|
if(syscounter >= 100) {
|
|
uart_putc('a'); // send a to receive values
|
|
|
|
print_sevenseg(0, power_gen);
|
|
print_sevenseg(1, power_load);
|
|
|
|
print_bar(LEDS_GEN, current_in, CURRENT_MAX);
|
|
print_bar(LEDS_LOAD, current_out, CURRENT_MAX);
|
|
|
|
print_bar_bottom(current_in, current_out, 10000);
|
|
|
|
syscounter = 0;
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
// system timer
|
|
SIGNAL(TIMER1_COMPA_vect) {
|
|
syscounter++;
|
|
|
|
// output to sevensegment and leds
|
|
// make this here to reduce display flicker
|
|
digit++;
|
|
if(digit >5) digit = 0;
|
|
leddigit++;
|
|
if(leddigit >3) leddigit = 0;
|
|
|
|
SEVENSEG_PORT = digitbuffer[digit];
|
|
SEVENSEGDIG_PORT = _BV(digit+DIG0);
|
|
|
|
LED_PORT = leddigitbuffer[leddigit];
|
|
LEDDIG_PORT = _BV(leddigit);
|
|
}
|
|
|
|
|