⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ddcp.c

📁 设计一个数字电源
💻 C
字号:
/*********************************************
* vim: set sw=8 ts=8 si :
* Author: Guido Socher, Copyright: GPL 
* This is the main program for the digital dc power supply
* 
* See http://www.tuxgraphics.org/electronics/
* 
* Chip type           : ATMEGA8
* Clock frequency     : Internal clock 4 Mhz 
*********************************************/
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include "lcd.h"
#include "dac.h"
#include "kbd.h"
#include "analog.h"
#include "avr_compat.h"
#include "hardware_settings.h"
#include <stdlib.h> // atoi
#include <string.h> 
#include <avr/eeprom.h> 

static int set_val[2];
// the set values but converted to ADC steps
static int set_val_adcUnits[2]; 

void delay_ms(unsigned char ms)
/* delay for a minimum of <ms> */
/* with a 4Mhz clock */
{
	uint8_t inner,inner1;

    	while (ms) {
		inner = 200;
		while (inner) {
			inner--;
			inner1 = 70;
			while (inner1) {
				inner1--;
			}
		}
		ms--;
	}
}

// Convert a integer which is representing a float into a string.
// decimalpoint_pos sets the decimal point after 2 pos: e.g 74 becomes "0.74"
// The integer may not be larger than 10000.
// The integer must be a positive number.
// spacepadd can be used to add a leading speace if number is less than 10
static void int_to_ascii(int inum,char *outbuf,signed char decimalpoint_pos,signed char spacepadd){
	signed char i,j;
	char chbuf[8];
	j=0;
	while(inum>9 && j<7){
		// zero is ascii 48:
		chbuf[j]=(char)48+ inum-((inum/10)*10);
		inum=inum/10;
		j++;
		if(decimalpoint_pos==j){
			chbuf[j]='.';
			j++;
		}
	}
	chbuf[j]=(char)48+inum; // most significant digit
	decimalpoint_pos--;
	while(j<decimalpoint_pos){
		j++;
		chbuf[j]='0';
	}
	if (spacepadd && j > (decimalpoint_pos+2)){
		// no leading space padding needed
		spacepadd=0;
	}
	if(decimalpoint_pos==j){
		j++;
		chbuf[j]='.';
		j++;
		chbuf[j]='0'; // leading zero
	}
	if (spacepadd){
		j++;
		chbuf[j]=' '; // leading space padding: "9.50" becomes " 9.50"
	}
	// now reverse the order 
	i=0;
	while(j>=0){
		outbuf[i]=chbuf[j];
		j--;
		i++;
	}
	outbuf[i]='\0';
}

// convert voltage values to adc values, disp=10 is 1.0V
static int disp_u_to_adc(int disp){
	return((int)(disp * 102.3) / (ADC_REF * U_DIVIDER));
}
// calculate the needed adc offset for voltage drop on the
// current measurement shunt
static int disp_i_to_u_adc_offset(int disp){
	return(disp_u_to_adc(disp/20));
}
// 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
static int adc_u_to_disp(int adcunits,int disp_i_val){
	int adcdrop;
	adcdrop=disp_i_to_u_adc_offset(disp_i_val);
	if (adcunits < adcdrop){
		return(0);
	}
	adcunits=adcunits-adcdrop;
	return((int)(((adcunits /102.3)* ADC_REF * U_DIVIDER)+0.6));
}
// convert adc values to current values, disp=10 needed to be printed
// by the printing function as 0.10 A
static int disp_i_to_adc(int disp){
	return((int) (((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
static int adc_i_to_disp(int adcunits){
	return((int) (((adcunits* ADC_REF)/(10.23 * I_RESISTOR))+0.6));
}


// check the keyboard
static signed char check_buttons(void){
	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()){
		lcd_clrscr();
		lcd_puts_P("store not");
		lcd_gotoxy(0,1);
		lcd_puts_P("implemented yet");
		delay_ms(200);
		return(1);
	};
	return(0);
}

void main(void)
{
	char out_buf[20+1];
	int measured_val[2];
	measured_val[0]=0;
	measured_val[1]=0;
	init_dac();
	lcd_init(LCD_DISP_ON);
	init_kbd();
	set_val[0]=15;set_val[1]=50; // 150mA and 5V
	if (eeprom_read_byte((uint8_t *)0x0) == 19){
		// ok magic number matches accept values
		set_val[1]=eeprom_read_word((uint16_t *)0x04);
		set_val[0]=eeprom_read_word((uint16_t *)0x02);
	}
	sei();
	init_analog();
	while (1) {

		// current
		measured_val[0]=adc_i_to_disp(getanalogresult(0));
		set_val_adcUnits[0]=disp_i_to_adc(set_val[0]);
		set_target_adc_val(0,set_val_adcUnits[0]);
		// voltage
		measured_val[1]=adc_u_to_disp(getanalogresult(1),measured_val[0]);
		set_val_adcUnits[1]=disp_u_to_adc(set_val[1])+disp_i_to_u_adc_offset(measured_val[0]);
		set_target_adc_val(1,set_val_adcUnits[1]);

		// voltage
		lcd_clrscr();
		int_to_ascii(measured_val[1],out_buf,1,1);
		lcd_puts(out_buf);
		lcd_puts("V ");
		int_to_ascii(set_val[1],out_buf,1,1);
		lcd_putc('[');
		lcd_puts(out_buf);
		lcd_putc(']');
		if (!is_current_limit()){
			// put a marker to show which value is currenlty limiting
			lcd_puts("<-");
		}

		// current
		lcd_gotoxy(0,1);
		int_to_ascii(measured_val[0],out_buf,2,0);
		lcd_puts(out_buf);
		lcd_puts("A ");
		int_to_ascii(set_val[0],out_buf,2,0);
		lcd_putc('[');
		lcd_puts(out_buf);
		lcd_putc(']');
		if (is_current_limit()){
			// put a marker to show which value is currenlty limiting
			lcd_puts("<-");
		}
		//dbg
		//int_to_ascii(is_dacval(),out_buf,0,0);
		//lcd_puts(out_buf);

		// the buttons must be responsive but they must not 
		// scroll too fast if pressed permanently
		if (!check_buttons()){
			// no buttons pressed
			delay_ms(100);
			check_buttons();
			delay_ms(100);
		}else{
			delay_ms(200);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -