main.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include <avr/io.h>
  2. #include <util/delay.h>
  3. #include <avr/pgmspace.h>
  4. #include <avr/eeprom.h>
  5. #include "main.h"
  6. #include "1wire.h"
  7. #include "gtext.h"
  8. #include "sed1335.h"
  9. #include "ds18b20.h"
  10. #include "dac8571.h"
  11. #include "ads1224.h"
  12. #include "display.h"
  13. volatile struct timers timers;
  14. volatile unsigned char tick; // incremented every 100ms
  15. unsigned char getkey(void){
  16. static unsigned char old;
  17. unsigned char key;
  18. DDRA = 0;
  19. PORTA = 0xff;
  20. DDRC |= _BV(PC7);
  21. _delay_ms(2);
  22. key = ~PINA;
  23. DDRC &= ~_BV(PC7);
  24. PORTA = 0;
  25. DDRA = 0xff;
  26. if(key == old) return 0;
  27. old = key;
  28. return key;
  29. }
  30. struct settings {
  31. float coeff_generator_volt_A;
  32. float coeff_generator_volt_B;
  33. float coeff_generator_curr_A;
  34. float coeff_generator_curr_B;
  35. float coeff_disch_curr_A;
  36. float coeff_disch_curr_B;
  37. float coeff_volt_A;
  38. float coeff_volt_B;
  39. float coeff_curr_A;
  40. float coeff_curr_B;
  41. };
  42. struct settings settings;
  43. EEMEM struct settings eep_settings = {
  44. .coeff_generator_volt_A = 1597.035901,
  45. .coeff_generator_volt_B = 1317.235211,
  46. .coeff_generator_curr_A = 65535.0/20,
  47. .coeff_generator_curr_B = 1310,
  48. .coeff_disch_curr_A = 2996.00532623169,
  49. .coeff_disch_curr_B = 4298.2689747004,
  50. .coeff_volt_A = 1.55337778893448E-07,
  51. .coeff_volt_B = -0.092784032021951,
  52. .coeff_curr_A = -9.03353481586364E-08,
  53. .coeff_curr_B = 0.124868806047484,
  54. // .coeff_curr_A = .001,
  55. // .coeff_curr_B = 0,
  56. };
  57. unsigned int vdac = 0;
  58. unsigned int cdac = 0;
  59. void dac_update(void){
  60. dac8571_set(cdac, CURR_DAC);
  61. dac8571_set(vdac, VOLT_DAC);
  62. }
  63. void set_voltage(float u){
  64. vdac = u * settings.coeff_generator_volt_A + settings.coeff_generator_volt_B;
  65. dac_update();
  66. }
  67. void set_charge_curr(float i){
  68. cdac = i * settings.coeff_generator_curr_A + settings.coeff_generator_curr_B;
  69. dac_update();
  70. }
  71. void set_discharge_curr(float i){
  72. cdac = i * settings.coeff_disch_curr_A + settings.coeff_disch_curr_B;
  73. dac_update();
  74. }
  75. #define CONV_ENABLE _BV(PD5)
  76. #define DISCH_ENABLE _BV(PD1)
  77. #define REL_K1 _BV(PD6)
  78. #define REL_K2 _BV(PD7)
  79. #define K1_ON() {PORTD |= REL_K1;}
  80. #define K1_OFF() {PORTD &= ~REL_K1;}
  81. #define K2_ON() {PORTD |= REL_K2;}
  82. #define K2_OFF() {PORTD &= ~REL_K2;}
  83. #define POWER_OFF() {PORTD &= ~(CONV_ENABLE | DISCH_ENABLE);}
  84. #define CONV_ON() {PORTD |= CONV_ENABLE;}
  85. #define DISCH_ON() {PORTD |= DISCH_ENABLE;}
  86. void output_off(void){
  87. cdac = 0;
  88. vdac = 0;
  89. POWER_OFF();
  90. dac_update();
  91. K1_OFF();
  92. K2_OFF();
  93. }
  94. void charge_on(void){
  95. output_off();
  96. K1_ON();
  97. CONV_ON();
  98. }
  99. void discharge_on(void){
  100. output_off();
  101. K2_ON();
  102. DISCH_ON();
  103. }
  104. #define MEAS_VOLT 0
  105. #define MEAS_CURR 1
  106. float meas[2];
  107. signed long int adc_results[2];
  108. unsigned char adc_process_data(void){
  109. static unsigned char adc_channel = AIN1;
  110. static signed long int adc;
  111. if(adc_data_ready){
  112. atomic_set_slint(&adc, adc_val);
  113. switch(adc_channel){
  114. case AIN1:
  115. adc_results[MEAS_VOLT] = adc;
  116. meas[MEAS_VOLT] = adc * settings.coeff_volt_A + settings.coeff_volt_B;
  117. adc_channel = AIN2;
  118. ads1224_mux(AIN2);
  119. break;
  120. case AIN2: default:
  121. adc_results[MEAS_CURR] = adc;
  122. meas[MEAS_CURR] = adc * settings.coeff_curr_A + settings.coeff_curr_B;
  123. adc_channel = AIN1;
  124. ads1224_mux(AIN1);
  125. break;
  126. }
  127. adc_data_ready = 0;
  128. return 1;
  129. }
  130. return 0;
  131. }
  132. __flash const char text0[] = "stop";
  133. __flash const char text1[] = "\x80""aduj";
  134. __flash const char text2[] = "roz\x80""aduj";
  135. __flash const char text3[] = "reset";
  136. __flash const char text4[] = "Uset(charg) = ";
  137. __flash const char text5[] = "Uset(disch) = ";
  138. __flash const char text6[] = "Iset = ";
  139. __flash const char *main_menu_texts[] = {
  140. text0,
  141. text1,
  142. text2,
  143. text3,
  144. text4,
  145. text5,
  146. text6,
  147. };
  148. #define MENU_MAX 6
  149. #define MODE_STOP 0
  150. #define MODE_CHARGE 1
  151. #define MODE_DISCHARGE 2
  152. void main(void){
  153. unsigned char i=0;
  154. unsigned char pos=0;
  155. unsigned char k;
  156. unsigned char mode = MODE_STOP;
  157. unsigned int volt_set = 365, disch_volt_set = 210, curr_set = 30; // *0,01V, *0,01V, *0,1A
  158. signed long long int charge_counter = 0, energy_counter = 0; // *0,1µC, *10µJ
  159. unsigned long int time_counter = 0; // *0,1s
  160. /* unsigned char state = STATE_DEFAULT;
  161. unsigned char oldstate = state;*/
  162. eeprom_read_block(&settings, &eep_settings, sizeof(struct settings));
  163. OCR2A = 100; // 100µs
  164. TCCR2A = _BV(WGM21);
  165. TCCR2B = _BV(CS21);
  166. TIMSK2 = _BV(OCIE2A);
  167. sei();
  168. PORTC &= _BV(PC7); // KEY
  169. DDRB |= _BV(PB2); // TESTPOINT
  170. DDRD |= REL_K1 | REL_K2 | DISCH_ENABLE | CONV_ENABLE;
  171. GLCD_Initialize();
  172. GLCD_Clear();
  173. ads1224_init();
  174. ads1224_mux(AIN1);
  175. /* charge_on();
  176. set_voltage(volt_set);
  177. set_charge_curr(curr_set);*/
  178. for(;;){
  179. /* if((i = getkey())){
  180. cursor(0,0);
  181. disp_num(i, 0);
  182. clearline();
  183. }*/
  184. dac_update();
  185. adc_process_data();
  186. /*if(adc_process_data()){
  187. cursor(0,1);
  188. disp_num(meas[MEAS_VOLT] * 1000, 3);
  189. putchar('V');
  190. clearline();
  191. cursor(0,2);
  192. disp_num(meas[MEAS_CURR] * 1000, 3);
  193. // disp_num(adc_results[MEAS_CURR], 0);
  194. putchar('A');
  195. clearline();
  196. }*/
  197. for(i=0; i<=MENU_MAX; i++){
  198. cursor(0, i);
  199. if(pos == i)
  200. putchar('*');
  201. else
  202. putchar(' ');
  203. putchar(' ');
  204. puttext_P(main_menu_texts[i]);
  205. putchar(' ');
  206. switch(i){
  207. default: break;
  208. case 1: if(mode == MODE_CHARGE) puttext_P(PSTR("w\x80.")); break;
  209. case 2: if(mode == MODE_DISCHARGE) puttext_P(PSTR("w\x80.")); break;
  210. case 4: disp_num(volt_set, 2); putchar('V'); break;
  211. case 5: disp_num(disch_volt_set, 2); putchar('V'); break;
  212. case 6: disp_num(curr_set, 1); putchar('A'); break;
  213. }
  214. clearline();
  215. }
  216. k = getkey();
  217. switch(k){
  218. default: break;
  219. case KEY_UP: if(pos>0) pos--; break;
  220. case KEY_DOWN: if(pos<MENU_MAX) pos++; break;
  221. case KEY_LEFT:
  222. switch(pos){
  223. case 4:
  224. if(mode != MODE_STOP)
  225. break;
  226. if(volt_set > 0)
  227. volt_set -= 1;
  228. break;
  229. case 5:
  230. if(mode != MODE_STOP)
  231. break;
  232. if(disch_volt_set > 0)
  233. disch_volt_set -= 1;
  234. break;
  235. case 6:
  236. if(mode != MODE_STOP)
  237. break;
  238. if(curr_set > 0)
  239. curr_set -= 1;
  240. break;
  241. }
  242. break;
  243. case KEY_RIGHT:
  244. switch(pos){
  245. case 4:
  246. if(mode != MODE_STOP)
  247. break;
  248. if(volt_set < 2000) // 20V
  249. volt_set += 1;
  250. break;
  251. case 5:
  252. if(mode != MODE_STOP)
  253. break;
  254. if(disch_volt_set < 2000) // 20V
  255. disch_volt_set += 1;
  256. break;
  257. case 6:
  258. if(mode != MODE_STOP)
  259. break;
  260. if(curr_set < 100)
  261. curr_set += 1; // 10A
  262. break;
  263. }
  264. break;
  265. case KEY_OK:
  266. switch(pos){
  267. case 0:
  268. mode = MODE_STOP;
  269. output_off();
  270. break;
  271. case 1:
  272. if(mode != MODE_STOP)
  273. break;
  274. mode = MODE_CHARGE;
  275. charge_on();
  276. set_voltage((float)volt_set/100.0);
  277. set_charge_curr((float)curr_set/10.0);
  278. break;
  279. case 2:
  280. if(mode != MODE_STOP)
  281. break;
  282. mode = MODE_DISCHARGE;
  283. discharge_on();
  284. set_discharge_curr((float)curr_set/10.0);
  285. break;
  286. case 3:
  287. if(mode != MODE_STOP)
  288. break;
  289. charge_counter = 0;
  290. energy_counter = 0;
  291. time_counter = 0;
  292. break;
  293. }
  294. break;
  295. }
  296. if(tick){
  297. cli();
  298. if(mode != MODE_STOP){
  299. charge_counter += meas[MEAS_CURR] * (float)tick / 10.0 / 0.1e-6;
  300. energy_counter += meas[MEAS_CURR] * meas[MEAS_VOLT] * (float)tick / 10.0 / 10e-6;
  301. time_counter += tick;
  302. }
  303. tick = 0;
  304. sei();
  305. if(mode == MODE_DISCHARGE && meas[MEAS_VOLT] < (float)disch_volt_set/100.0){
  306. mode = MODE_STOP;
  307. output_off();
  308. }
  309. cursor(0,8);
  310. disp_num(meas[MEAS_VOLT] * 1000, 3);
  311. putchar('V');
  312. putchar(' ');
  313. disp_num(meas[MEAS_CURR] * 1000, 3);
  314. putchar('A');
  315. putchar(' ');
  316. disp_num(meas[MEAS_CURR] * meas[MEAS_VOLT] * 10, 1);
  317. putchar('W');
  318. clearline();
  319. cursor(0,9);
  320. disp_num(charge_counter * 0.1e-6 * 10000 / 3600.0, 4);
  321. puttext_P(PSTR("Ah "));
  322. disp_num(energy_counter * 10e-6 * 10000 / 3600.0, 4);
  323. puttext_P(PSTR("Wh "));
  324. disp_num(time_counter, 1);
  325. puttext_P(PSTR("s"));
  326. clearline();
  327. }
  328. }
  329. }
  330. ISR(TIMER2_COMPA_vect){ // 100µs
  331. static unsigned char pre;
  332. if(++pre < 10)
  333. return;
  334. pre = 0;
  335. // 1ms
  336. unsigned int *volatile ctimer;
  337. unsigned char i;
  338. for(i=0; i<sizeof(timers)/sizeof(unsigned int); i++){
  339. ctimer = ((unsigned int *)&timers) + i;
  340. if(*ctimer)
  341. (*ctimer)--;
  342. }
  343. if(timers.tick == 0){
  344. tick++; // 100ms
  345. timers.tick = 100;
  346. }
  347. }