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

273 lines
6.2 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 digit_translate[10] = {
63, 6, 91, 79, 102, 109, 125, 7, 127, 111
};
const uint8_t leddigit_translate[9] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
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) {
for(uint8_t i = 0; i< 3; i++) {
digitbuffer[i] = digit_translate[d[i]];
}
} else {
for(uint8_t i = 0; i< 3; i++) {
digitbuffer[i+3] = digit_translate[d[i]];
}
}
}
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);
if(x > 8) x = 8;
switch(display) {
case LEDS_LOAD:
leddigitbuffer[2] = leddigit_translate[x];
break;
case LEDS_GEN:
leddigitbuffer[3] = leddigit_translate[x];
break;
}
}
static void print_bar_bottom(uint16_t curin, uint16_t curout) {
}
#ifdef DEBUG
void pretty_print_all_values(void) {
uart_puts_P("Voltage: ");
uart_print_uint16(voltage);
uart_puts_P("mV\r\n");
uart_puts_P("Load: ");
uart_print_uint16(current_out);
uart_puts_P("mA ");
uart_print_uint16( power_load);
uart_puts_P("W\r\n");
uart_puts_P("Generator: ");
uart_print_uint16(current_in);
uart_puts_P("mA ");
uart_print_uint16( power_gen);
uart_puts_P("W\r\n");
uart_puts_P("switches (load, dump, gen): ");
uart_putc(48 + loadsw);
uart_putc(',');
uart_putc(48 + dumpsw);
uart_putc(',');
uart_putc(48 + gensw);
uart_puts_P("\r\n");
}
#endif
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++;
#ifdef DEBUG
uart_puts_P("from start: ");
uart_puts(start);
uart_puts_P("\r\n");
#endif
token = strtok(start, ",");
while( token ) {
#ifdef DEBUG
uart_puts_P("token= ");
uart_puts(token);
uart_puts_P("\r\n");
#endif
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, ",");
}
#ifdef DEBUG
pretty_print_all_values();
#endif
}
}
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++;
}
}
}
int main(void) {
ports_init();
timer_init();
uart_init(UART_BAUD_SELECT(19200,F_CPU));
memset(data_in, 0, BUFSIZE);
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);
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);
}