#include #include #include #include #include "main.h" #include "1wire.h" #include "gtext.h" #include "sed1335.h" #include "ds18b20.h" #include "dac8571.h" #include "ads1224.h" #include "display.h" volatile struct timers timers; volatile unsigned char tick; // incremented every 100ms unsigned char getkey(void){ static unsigned char old; unsigned char key; DDRA = 0; PORTA = 0xff; DDRC |= _BV(PC7); _delay_ms(2); key = ~PINA; DDRC &= ~_BV(PC7); PORTA = 0; DDRA = 0xff; if(key == old) return 0; old = key; return key; } struct settings { float coeff_generator_volt_A; float coeff_generator_volt_B; float coeff_generator_curr_A; float coeff_generator_curr_B; float coeff_disch_curr_A; float coeff_disch_curr_B; float coeff_volt_A; float coeff_volt_B; float coeff_curr_A; float coeff_curr_B; }; struct settings settings; EEMEM struct settings eep_settings = { .coeff_generator_volt_A = 1597.035901, .coeff_generator_volt_B = 1317.235211, .coeff_generator_curr_A = 65535.0/20, .coeff_generator_curr_B = 1310, .coeff_disch_curr_A = 65535.0/20, .coeff_disch_curr_B = 1000, .coeff_volt_A = 1.55337778893448E-07, .coeff_volt_B = -0.092784032021951, .coeff_curr_A = -9.03353481586364E-08, .coeff_curr_B = 0.124868806047484, // .coeff_curr_A = .001, // .coeff_curr_B = 0, }; unsigned int vdac = 0; unsigned int cdac = 0; void dac_update(void){ dac8571_set(cdac, CURR_DAC); dac8571_set(vdac, VOLT_DAC); } void set_voltage(float u){ vdac = u * settings.coeff_generator_volt_A + settings.coeff_generator_volt_B; dac_update(); } void set_charge_curr(float i){ cdac = i * settings.coeff_generator_curr_A + settings.coeff_generator_curr_B; dac_update(); } void set_discharge_curr(float i){ cdac = i * settings.coeff_disch_curr_A + settings.coeff_disch_curr_B; dac_update(); } #define CONV_ENABLE _BV(PD5) #define DISCH_ENABLE _BV(PD1) #define REL_K1 _BV(PD6) #define REL_K2 _BV(PD7) #define K1_ON() {PORTD |= REL_K1;} #define K1_OFF() {PORTD &= ~REL_K1;} #define K2_ON() {PORTD |= REL_K2;} #define K2_OFF() {PORTD &= ~REL_K2;} #define POWER_OFF() {PORTD &= ~(CONV_ENABLE | DISCH_ENABLE);} #define CONV_ON() {PORTD |= CONV_ENABLE;} #define DISCH_ON() {PORTD |= DISCH_ENABLE;} void output_off(void){ cdac = 0; vdac = 0; POWER_OFF(); dac_update(); K1_OFF(); K2_OFF(); } void charge_on(void){ output_off(); K1_ON(); CONV_ON(); } void discharge_on(void){ output_off(); K2_ON(); DISCH_ON(); } #define MEAS_VOLT 0 #define MEAS_CURR 1 float meas[2]; signed long int adc_results[2]; unsigned char adc_process_data(void){ static unsigned char adc_channel = AIN1; static signed long int adc; if(adc_data_ready){ atomic_set_slint(&adc, adc_val); switch(adc_channel){ case AIN1: adc_results[MEAS_VOLT] = adc; meas[MEAS_VOLT] = adc * settings.coeff_volt_A + settings.coeff_volt_B; adc_channel = AIN2; ads1224_mux(AIN2); break; case AIN2: default: adc_results[MEAS_CURR] = adc; meas[MEAS_CURR] = adc * settings.coeff_curr_A + settings.coeff_curr_B; adc_channel = AIN1; ads1224_mux(AIN1); break; } adc_data_ready = 0; return 1; } return 0; } __flash const char text0[] = "stop"; __flash const char text1[] = "\x80""aduj"; __flash const char text2[] = "roz\x80""aduj"; __flash const char text3[] = "reset"; __flash const char text4[] = "Uset = "; __flash const char text5[] = "Iset = "; __flash const char *main_menu_texts[] = { text0, text1, text2, text3, text4, text5, }; #define MENU_MAX 5 #define MODE_STOP 0 #define MODE_CHARGE 1 #define MODE_DISCHARGE 2 void main(void){ unsigned char i=0; unsigned char pos=0; unsigned char k; unsigned char mode = MODE_STOP; unsigned int volt_set = 126, curr_set = 8; // *0,1V/A signed long long int charge_counter = 0, energy_counter = 0; // *0,1µC, *10µJ unsigned long int time_counter = 0; // *0,1s /* unsigned char state = STATE_DEFAULT; unsigned char oldstate = state;*/ eeprom_read_block(&settings, &eep_settings, sizeof(struct settings)); OCR2A = 100; // 100µs TCCR2A = _BV(WGM21); TCCR2B = _BV(CS21); TIMSK2 = _BV(OCIE2A); sei(); PORTC &= _BV(PC7); // KEY DDRB |= _BV(PB2); // TESTPOINT DDRD |= REL_K1 | REL_K2 | DISCH_ENABLE | CONV_ENABLE; GLCD_Initialize(); GLCD_Clear(); ads1224_init(); ads1224_mux(AIN1); /* charge_on(); set_voltage(volt_set); set_charge_curr(curr_set);*/ for(;;){ /* if((i = getkey())){ cursor(0,0); disp_num(i, 0); clearline(); }*/ dac_update(); adc_process_data(); /*if(adc_process_data()){ cursor(0,1); disp_num(meas[MEAS_VOLT] * 1000, 3); putchar('V'); clearline(); cursor(0,2); disp_num(meas[MEAS_CURR] * 1000, 3); // disp_num(adc_results[MEAS_CURR], 0); putchar('A'); clearline(); }*/ for(i=0; i<=MENU_MAX; i++){ cursor(0, i); if(pos == i) putchar('*'); else putchar(' '); putchar(' '); puttext_P(main_menu_texts[i]); putchar(' '); switch(i){ default: break; case 1: if(mode == MODE_CHARGE) puttext_P(PSTR("w\x80.")); break; case 2: if(mode == MODE_DISCHARGE) puttext_P(PSTR("w\x80.")); break; case 4: disp_num(volt_set, 1); putchar('V'); break; case 5: disp_num(curr_set, 1); putchar('A'); break; } clearline(); } k = getkey(); switch(k){ default: break; case KEY_UP: if(pos>0) pos--; break; case KEY_DOWN: if(pos 0) volt_set -= 1; break; case 5: if(mode != MODE_STOP) break; if(curr_set > 0) curr_set -= 1; break; } break; case KEY_RIGHT: switch(pos){ case 4: if(mode != MODE_STOP) break; if(volt_set < 200) // 20V volt_set += 1; break; case 5: if(mode != MODE_STOP) break; if(curr_set < 100) curr_set += 1; // 10A break; } break; case KEY_OK: switch(pos){ case 0: mode = MODE_STOP; output_off(); break; case 1: if(mode != MODE_STOP) break; mode = MODE_CHARGE; charge_on(); set_voltage((float)volt_set/10.0); set_charge_curr((float)curr_set/10.0); break; case 2: break; case 3: if(mode != MODE_STOP) break; charge_counter = 0; energy_counter = 0; time_counter = 0; break; } break; } if(tick){ cli(); if(mode != MODE_STOP){ charge_counter += meas[MEAS_CURR] * (float)tick / 10.0 / 0.1e-6; energy_counter += meas[MEAS_CURR] * meas[MEAS_VOLT] * (float)tick / 10.0 / 10e-6; time_counter += tick; } tick = 0; sei(); cursor(0,6); disp_num(meas[MEAS_VOLT] * 1000, 3); putchar('V'); putchar(' '); disp_num(meas[MEAS_CURR] * 1000, 3); putchar('A'); clearline(); cursor(0,7); disp_num(charge_counter * 0.1e-6 * 10000 / 3600.0, 4); puttext_P(PSTR("Ah ")); disp_num(energy_counter * 10e-6 * 10000 / 3600.0, 4); puttext_P(PSTR("Wh ")); disp_num(time_counter, 1); puttext_P(PSTR("s")); clearline(); } } } ISR(TIMER2_COMPA_vect){ // 100µs static unsigned char pre; if(++pre < 10) return; pre = 0; // 1ms unsigned int *volatile ctimer; unsigned char i; for(i=0; i