1 /*********************************************
2 * vim: set sw=8 ts=8 si :
3 * Author: Guido Socher, Copyright: GPL v3
4 * This is the main program for the digital dc power supply
6 * See http://www.tuxgraphics.org/electronics/
9 * Clock frequency : Internal clock 8 Mhz
10 *********************************************/
13 #include <avr/interrupt.h>
14 #define F_CPU 8000000UL // 8 MHz
15 #include <util/delay.h>
18 #include <avr/eeprom.h>
23 #include "hardware_settings.h"
25 #define SWVERSION "ver: ddcp-0.6.0"
29 // set output to VCC, red LED off
30 #define LEDOFF PORTD|=(1<<PORTD0)
31 // set output to GND, red LED on
32 #define LEDON PORTD&=~(1<<PORTD0)
33 // to test the state of the LED
34 #define LEDISOFF PORTD&(1<<PORTD0)
36 // the units are display units and work as follows: 100mA=10 5V=50
37 // The function int_to_ascii is used to convert the intenal values
38 // into strings for the display
39 static int16_t measured_val[2]={0,0};
40 static int16_t set_val[2];
41 // the set values but converted to ADC steps
42 static int16_t set_val_adcUnits[2];
43 static uint8_t bpress=0;
45 void delay_ms(uint8_t ms)
46 // delay for a minimum of <ms>
54 // Convert an integer which is representing a float into a string.
55 // decimalpoint_pos sets the decimal point after 2 pos from the right: e.g 74 becomes "0.74"
56 // The integer may not be larger than 999.
57 // The integer must be a positive number.
58 // spacepadd can be used to add a leading speace if number is less than 10
59 //static void int_to_ascii(uint16_t inum,char *outbuf,int8_t decimalpoint_pos){
61 // itoa(inum,chbuf,10); // convert integer to string
62 static void int_to_ascii(int16_t inum,char *outbuf,int8_t decimalpoint_pos,uint8_t spacepadd){
68 chbuf[j]=(char)48+ inum-((inum/10)*10);
71 if(decimalpoint_pos==j){
76 chbuf[j]=(char)48+inum; // most significant digit
78 while(j<decimalpoint_pos){
82 if (spacepadd && j > (decimalpoint_pos+2)){
83 // no leading space padding needed
86 if(decimalpoint_pos==j){
90 chbuf[j]='0'; // leading zero
94 chbuf[j]=' '; // leading space padding: "9.50" becomes " 9.50"
96 // now reverse the order
106 // convert voltage values to adc values, disp=10 is 1.0V
107 // ADC for voltage is 11bit:
108 static int16_t disp_u_to_adc(int16_t disp){
109 return((int16_t)(((float)disp * 204.7) / (ADC_REF * U_DIVIDER )));
111 // calculate the needed adc offset for voltage drop on the
112 // current measurement shunt (the shunt has about 0.75 Ohm =1/1.33 Ohm)
113 // use 1/1.2 instead of 1/1.3 because cables and connectors have as well
115 static int16_t disp_i_to_u_adc_offset(int16_t disp){
116 return(disp_u_to_adc(disp/12));
118 // convert adc values to voltage values, disp=10 is 1.0V
119 // disp_i_val is needed to calculate the offset for the voltage drop over
120 // the current measurement shunt, voltage measurement is 11bit
121 static int16_t adc_u_to_disp(int16_t adcunits,int16_t disp_i_val){
123 adcdrop=disp_i_to_u_adc_offset(disp_i_val);
124 if (adcunits < adcdrop){
127 adcunits=adcunits-adcdrop;
128 return((int16_t)((((float)adcunits /204.7)* ADC_REF * U_DIVIDER)+0.5));
130 // convert adc values to current values, disp=10 needed to be printed
131 // by the printing function as 0.10 A, current measurement is 10bit
132 static int16_t disp_i_to_adc(int16_t disp){
133 return((int16_t) (((disp * 10.23)* I_RESISTOR) / ADC_REF));
135 // convert adc values to current values, disp=10 needed to be printed
136 // by the printing function as 0.10 A, current measurement is 10bit
137 static int16_t adc_i_to_disp(int16_t adcunits){
138 return((int16_t) (((float)adcunits* ADC_REF)/(10.23 * I_RESISTOR)+0.5));
141 static void store_permanent(void){
143 uint8_t changeflag=1;
145 if (eeprom_read_byte((uint8_t *)0x0) == 19){
147 // ok magic number matches accept values
148 tmp=eeprom_read_word((uint16_t *)0x04);
149 if (tmp != set_val[1]){
152 tmp=eeprom_read_word((uint16_t *)0x02);
153 if (tmp != set_val[0]){
158 lcd_puts_P("setting stored");
159 eeprom_write_byte((uint8_t *)0x0,19); // magic number
160 eeprom_write_word((uint16_t *)0x02,set_val[0]);
161 eeprom_write_word((uint16_t *)0x04,set_val[1]);
164 // display software version after long press
165 lcd_puts_P(SWVERSION);
167 lcd_puts_P("tuxgraphics.org");
169 lcd_puts_P("already stored");
175 // check the keyboard
176 static uint8_t check_buttons(void){
177 if (check_u_button(&(set_val[1]))){
178 if(set_val[1]>U_MAX){
183 if (check_i_button(&(set_val[0]))){
184 if(set_val[0]>I_MAX){
189 if (check_store_button()){
202 DDRD|= (1<<DDD0); // LED, enable PD0, LED as output
208 set_val[0]=15;set_val[1]=50; // 150mA and 5V
209 if (eeprom_read_byte((uint8_t *)0x0) == 19){
210 // ok magic number matches accept values
211 set_val[1]=eeprom_read_word((uint16_t *)0x04);
212 set_val[0]=eeprom_read_word((uint16_t *)0x02);
218 // due to electrical interference we can get some
219 // garbage onto the display especially if the power supply
220 // source is not stable enough. We can remedy it a bit in
221 // software with an ocasional reset:
222 if (i==50){ // not every round to avoid flicker
228 measured_val[0]=adc_i_to_disp(getanalogresult(0));
229 set_val_adcUnits[0]=disp_i_to_adc(set_val[0]);
230 set_target_adc_val(0,set_val_adcUnits[0]);
232 measured_val[1]=adc_u_to_disp(getanalogresult(1),measured_val[0]);
233 set_val_adcUnits[1]=disp_u_to_adc(set_val[1])+disp_i_to_u_adc_offset(measured_val[0]);
234 set_target_adc_val(1,set_val_adcUnits[1]);
235 ilimit=is_current_limit();
240 itoa(getanalogresult(1),out_buf,10);
242 int_to_ascii(measured_val[1],out_buf,1,1);
247 itoa(set_val_adcUnits[1],out_buf,10);
249 int_to_ascii(set_val[1],out_buf,1,1);
254 // put a marker to show which value is currenlty limiting
263 itoa(getanalogresult(0),out_buf,10);
265 int_to_ascii(measured_val[0],out_buf,2,0);
270 itoa(set_val_adcUnits[0],out_buf,10);
272 int_to_ascii(set_val[0],out_buf,2,0);
277 // put a marker to show which value is currenlty limiting
283 // the buttons must be responsive but they must not
284 // scroll too fast if pressed permanently
285 if (check_buttons()==0){
286 // no buttons pressed
289 if (check_buttons()==0){
290 // no buttons pressed
299 // somebody pressed permanetly the button=>scroll fast