#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; static unsigned char counter; DDRA = 0; PORTA = 0xff; DDRC |= _BV(PC7); _delay_ms(2); key = ~PINA; DDRC &= ~_BV(PC7); PORTA = 0; DDRA = 0xff; if(key == 0) counter = 0; if(key == old){ switch(counter){ default: counter++; return 0; case 5: counter++; break; case 8: break; } } else { counter = 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 = 2996.00532623169, .coeff_disch_curr_B = 4298.2689747004, .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(charg) = "; __flash const char text5[] = "Uset(disch) = "; __flash const char text6[] = "Iset = "; __flash const char *main_menu_texts[] = { text0, text1, text2, text3, text4, text5, text6, }; #define MENU_MAX 6 #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 = 365, disch_volt_set = 210, curr_set = 30; // *0,01V, *0,01V, *0,1A 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)); // system timer OCR2A = (125-1); // 1ms TCCR2A = _BV(WGM21); TCCR2B = _BV(CS22); TIMSK2 = _BV(OCIE2A); // fan pwm timer ICR1 = (330-1); // 25kHz OCR1B = 40; TCCR1A = _BV(COM1B1) | _BV(WGM11); TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); TCCR1C = 0; DDRD |= _BV(PD4); 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(;;){ dac_update(); adc_process_data(); gettemp(); cursor(0, 7); puttext_P(PSTR("Temp: ")); if(temp_ok & _BV(0)){ disp_temp(temps[0]); if(temps[0] < 350){ atomic_set_uint(&OCR1B, 0); } else if(temps[0] < 900){ atomic_set_uint(&OCR1B, (unsigned long int)((temps[0] - 300)*(unsigned long int)(0.506*32.0))>>5); } else { atomic_set_uint(&OCR1B, 329); } } else { atomic_set_uint(&OCR1B, 329); puttext_P(PSTR("B\x80\x7e""d")); } 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, 2); putchar('V'); break; case 5: disp_num(disch_volt_set, 2); putchar('V'); break; case 6: 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 -= 5; break; case 5: if(mode != MODE_STOP) break; if(disch_volt_set > 0) disch_volt_set -= 5; break; case 6: 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 < 3000) // 30V volt_set += 5; break; case 5: if(mode != MODE_STOP) break; if(disch_volt_set < 3000) // 30V disch_volt_set += 5; break; case 6: if(mode != MODE_STOP) break; if(curr_set < 200) 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/100.0); set_charge_curr((float)curr_set/10.0); break; case 2: if(mode != MODE_STOP) break; mode = MODE_DISCHARGE; discharge_on(); set_discharge_curr((float)curr_set/10.0); 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 / (float)(10.0 * 0.1e-6); energy_counter += meas[MEAS_CURR] * meas[MEAS_VOLT] * (float)tick / (float)(10.0 * 10e-6); time_counter += tick; } tick = 0; sei(); if(mode == MODE_DISCHARGE && meas[MEAS_VOLT] < (float)disch_volt_set/100.0){ mode = MODE_STOP; output_off(); } cursor(0,8); disp_num(meas[MEAS_VOLT] * 1000, 3); putchar('V'); putchar(' '); disp_num(meas[MEAS_CURR] * 1000, 3); putchar('A'); putchar(' '); disp_num(meas[MEAS_CURR] * meas[MEAS_VOLT] * 10, 1); putchar('W'); clearline(); cursor(0,9); disp_num((float)charge_counter * (float)(0.1e-6 * 10000.0 / 3600.0), 4); puttext_P(PSTR("Ah ")); disp_num((float)energy_counter * (float)(10e-6 * 10000.0 / 3600.0), 4); puttext_P(PSTR("Wh ")); disp_num(time_counter, 1); puttext_P(PSTR("s")); clearline(); } } } ISR(TIMER2_COMPA_vect){ // 1ms unsigned int *volatile ctimer; unsigned char i; for(i=0; i