/********************************************* * vim: set sw=8 ts=8 si et : * Author: Guido Socher, Copyright: GPL v3 * This is the main program for the digital dc power supply * * See http://www.tuxgraphics.org/electronics/ * * Chip type : ATMEGA8 * Clock frequency : Internal clock 8 Mhz *********************************************/ #include #include #include #define F_CPU 8000000UL // 8 MHz #include #include #include #include #include "lcd.h" #include "dac.h" #include "kbd.h" #include "uart.h" #include "analog.h" #include "hardware_settings.h" // change this version string when you compile: #define SWVERSION "ver: ddcp-0.6.3" //#define DEBUGDISP 1 //debug LED: // set output to VCC, red LED off #define LEDOFF PORTD|=(1< { uint8_t innerloop=1; while(ms){ #ifdef USE_UART if(uart_has_one_line==0 && uart_getchar_isr_noblock(&uartstr[uartstrpos])){ // ignore any white space: if (uartstr[uartstrpos]==' ' || uartstr[uartstrpos]=='\t'){ goto NEXTCHAR; } if (uartstr[uartstrpos]=='\r'){ uartstr[uartstrpos]='\0'; uart_sendchar('\r'); // the echo line end uart_sendchar('\n'); // the echo line end //uart_sendchar('|'); uart_sendstr(&uartstr[0]);uart_sendchar('|'); //debug uart_has_one_line=1; goto NEXTCHAR; } uart_sendchar(uartstr[uartstrpos]);// echo back /* // debug itoa(uartstr[uartstrpos],buf,10); uart_sendchar('\r'); // the echo line end uart_sendchar('\n'); // the echo line end uart_sendstr(buf); uart_sendchar('\r'); // the echo line end uart_sendchar('\n'); // the echo line end */ if (uartstr[uartstrpos]=='\b'){ if (uartstrpos>0){ uartstrpos--; uart_sendchar(' '); // clear char on screen uart_sendchar('\b'); } }else if (uartstr[uartstrpos]==0x7f){ // del if (uartstrpos>0){ uartstrpos--; } }else{ uartstrpos++; } if (uartstrpos>UARTSTRLEN){ uart_sendstr_P("\r\nERROR\r\n"); uartstrpos=0; // empty buffer uartstr[0]='\0'; // just print prompt uart_has_one_line=1; } } #endif NEXTCHAR: innerloop--; if (innerloop==0){ innerloop=45; ms--; } } } // Convert an integer which is representing a float into a string. // Our display is always 4 digits long (including one // decimal point position). decimalpoint_pos defines // after how many positions from the right we set the decimal point. // The resulting string is fixed width and padded with leading space. // // decimalpoint_pos=2 sets the decimal point after 2 pos from the right: // e.g 74 becomes "0.74" // The integer should not be larger than 999. // The integer must be a positive number. // decimalpoint_pos can be 0, 1 or 2 static void int_to_dispstr(uint16_t inum,char *outbuf,int8_t decimalpoint_pos){ int8_t i,j; char chbuf[8]; itoa(inum,chbuf,10); // convert integer to string i=strlen(chbuf); if (i>3) i=3; //overflow protection strcpy(outbuf," 0"); //decimalpoint_pos==0 if (decimalpoint_pos==1) strcpy(outbuf," 0.0"); if (decimalpoint_pos==2) strcpy(outbuf,"0.00"); j=4; while(i){ outbuf[j-1]=chbuf[i-1]; i--; j--; if (j==4-decimalpoint_pos){ // jump over the pre-set dot j--; } } } // convert voltage values to adc values, disp=10 is 1.0V // ADC for voltage is 11bit: static int16_t disp_u_to_adc(int16_t disp){ return((int16_t)(((float)disp * 204.7) / (ADC_REF * U_DIVIDER ))); } // calculate the needed adc offset for voltage drop on the // current measurement shunt (the shunt has about 0.75 Ohm =1/1.33 Ohm) // use 1/1.2 instead of 1/1.3 because cables and connectors have as well // a loss. static int16_t disp_i_to_u_adc_offset(int16_t disp){ return(disp_u_to_adc(disp/12)); } // convert adc values to voltage values, disp=10 is 1.0V // disp_i_val is needed to calculate the offset for the voltage drop over // the current measurement shunt, voltage measurement is 11bit static int16_t adc_u_to_disp(int16_t adcunits,int16_t disp_i_val){ int16_t adcdrop; adcdrop=disp_i_to_u_adc_offset(disp_i_val); if (adcunits < adcdrop){ return(0); } adcunits=adcunits-adcdrop; return((int16_t)((((float)adcunits /204.7)* ADC_REF * U_DIVIDER)+0.5)); } // convert adc values to current values, disp=10 needed to be printed // by the printing function as 0.10 A, current measurement is 10bit static int16_t disp_i_to_adc(int16_t disp){ return((int16_t) (((disp * 10.23)* I_RESISTOR) / ADC_REF)); } // convert adc values to current values, disp=10 needed to be printed // by the printing function as 0.10 A, current measurement is 10bit static int16_t adc_i_to_disp(int16_t adcunits){ return((int16_t) (((float)adcunits* ADC_REF)/(10.23 * I_RESISTOR)+0.5)); } static void store_permanent(void){ int16_t tmp; uint8_t changeflag=1; lcd_clrscr(); if (eeprom_read_byte((uint8_t *)0x0) == 19){ changeflag=0; // ok magic number matches accept values tmp=eeprom_read_word((uint16_t *)0x04); if (tmp != set_val[1]){ changeflag=1; } tmp=eeprom_read_word((uint16_t *)0x02); if (tmp != set_val[0]){ changeflag=1; } } delay_ms_uartcheck(1); // check for uart without delay if (changeflag){ lcd_puts_P("setting stored"); eeprom_write_byte((uint8_t *)0x0,19); // magic number eeprom_write_word((uint16_t *)0x02,set_val[0]); eeprom_write_word((uint16_t *)0x04,set_val[1]); }else{ if (bpress> 2){ // display software version after long press lcd_puts_P(SWVERSION); lcd_gotoxy(0,1); lcd_puts_P("tuxgraphics.org"); }else{ lcd_puts_P("already stored"); } } delay_ms_uartcheck(200); delay_ms_uartcheck(200); delay_ms_uartcheck(200); } // check the keyboard static uint8_t check_buttons(void){ uint8_t uartprint_ok=0; uint8_t cmdok=0; #ifdef USE_UART char buf[21]; #endif // #ifdef USE_UART if (uart_has_one_line){ if (uartstr[0]=='i' && uartstr[1]=='=' && uartstr[2]!='\0'){ set_val[0]=atoi(&uartstr[2]); if(set_val[0]>I_MAX){ set_val[0]=I_MAX; } if(set_val[0]<0){ set_val[0]=0; } uartprint_ok=1; } // version if (uartstr[0]=='v' && uartstr[1]=='e'){ uart_sendstr_p(P(" ")); uart_sendstr_p(P(SWVERSION)); uart_sendstr_p(P("\r\n")); cmdok=1; } // store if (uartstr[0]=='s' && uartstr[1]=='t'){ store_permanent(); uartprint_ok=1; } if (uartstr[0]=='u' && uartstr[1]=='=' && uartstr[2]!='\0'){ set_val[1]=atoi(&uartstr[2]); if(set_val[1]>U_MAX){ set_val[1]=U_MAX; } if(set_val[1]<0){ set_val[1]=0; } uartprint_ok=1; } // help if (uartstr[0]=='h' || uartstr[0]=='H'){ uart_sendstr_p(P(" Usage: u=V*10|i=mA/10|store|help|version\r\n")); uart_sendstr_p(P(" Examples:\r\n")); uart_sendstr_p(P(" set 6V: u=60\r\n")); uart_sendstr_p(P(" max 200mA: i=20\r\n")); cmdok=1; } if (uartprint_ok){ cmdok=1; uart_sendstr_p(P(" ok\r\n")); } if (uartstr[0]!='\0' && cmdok==0){ uart_sendstr_p(P(" command unknown\r\n")); } int_to_dispstr(measured_val[1],buf,1); uart_sendstr(buf); uart_sendchar('V'); uart_sendchar(' '); uart_sendchar('['); int_to_dispstr(set_val[1],buf,1); uart_sendstr(buf); uart_sendchar(']'); uart_sendchar(','); int_to_dispstr(measured_val[0],buf,2); uart_sendstr(buf); uart_sendchar('A'); uart_sendchar(' '); uart_sendchar('['); int_to_dispstr(set_val[0],buf,2); uart_sendstr(buf); uart_sendchar(']'); if (is_current_limit()){ uart_sendchar('I'); }else{ uart_sendchar('U'); } uart_sendchar('>'); uart_has_one_line=0; uartstrpos=0; } #endif if (check_u_button(&(set_val[1]))){ if(set_val[1]>U_MAX){ set_val[1]=U_MAX; } return(1); } if (check_i_button(&(set_val[0]))){ if(set_val[0]>I_MAX){ set_val[0]=I_MAX; } return(1); } if (check_store_button()){ store_permanent(); return(2); }; return(0); } int main(void) { char out_buf[21]; uint8_t i=0; uint8_t ilimit=0; #ifndef USE_UART // debug led, you can not have an LED if you use the uart DDRD|= (1< 10){ // somebody pressed permanetly the button=>scroll fast delay_ms_uartcheck(120); }else{ bpress++; delay_ms_uartcheck(180); delay_ms_uartcheck(180); delay_ms_uartcheck(180); delay_ms_uartcheck(180); } } } return(0); }