/***********************************************************************
***********************************************************************/
#include "numicro_8051.h"
#include "debug_log.h"
#define RAVG_BUFCNT 20
typedef struct
{
unsigned int buffer[RAVG_BUFCNT];
unsigned char index;
unsigned long sum;
} RAVG;
static float adc_vdd;
static RAVG ravg_voltage;
static RAVG ravg_current;
#define OFFSET_VOLTAGE 0.016
#define SCALE_VOLTAGE 39.96
#define OFFSET_CURRENT 0.100
#define SCALE_CURRENT 7.032
static const float real_table_v[] =
{
0.3,
0.4,
0.5,
1.0,
2.0,
3.0,
5.0,
10.0,
20.0,
40.0,
80.0,
100.0,
};
static const float adc_table_v[] =
{
0.011,
0.02,
0.05,
0.274,
1.188,
2.214,
4.235,
9.11,
19.14,
39.31,
79.83,
100.14,
};
static const float real_table_i[] =
{
0.05,
0.1,
0.2,
0.3,
0.5,
1.0,
1.5,
2.0,
4.0,
8.0,
10.0,
};
static const float adc_table_i[] =
{
0.057,
0.106,
0.207,
0.311,
0.527,
1.054,
1.55,
2.046,
4.01,
8.03,
10.1,
};
/***********************************************************************
***********************************************************************/
float interpolate(const float* real_table,
const float* adc_table,
unsigned int size,
float adc_value)
{
unsigned int i;
for (i = 0; i < (size - 1); i++)
{
if ((adc_table[i] <= adc_value) &&
adc_value < adc_table[i + 1])
{
break;
}
}
float adc_low = adc_table[i];
float adc_high = adc_table[i + 1];
float real_low = real_table[i];
float real_high = real_table[i + 1];
float real_value = real_low + ((adc_value - adc_low) / (adc_high - adc_low)) * (real_high - real_low);
return real_value;
}
/***********************************************************************
***********************************************************************/
static void ravg_run(RAVG* ravg, unsigned int data)
{
ravg->sum -= ravg->buffer[ravg->index];
ravg->sum += data;
ravg->buffer[ravg->index] = data;
ravg->index = (ravg->index + 1) % RAVG_BUFCNT;
}
/***********************************************************************
***********************************************************************/
static float ravg_average(RAVG* ravg)
{
return (float)ravg->sum / RAVG_BUFCNT;
}
/***********************************************************************
***********************************************************************/
static unsigned int adc_read_raw(void)
{
clr_ADCCON0_ADCF;
set_ADCCON0_ADCS;
while ((ADCCON0 & SET_BIT7) == 0)
{
;
}
unsigned int data = (ADCRH << 4) | (ADCRL & 0x0f);
return data;
}
/***********************************************************************
***********************************************************************/
unsigned int adc_read_voltage_raw(void)
{
ENABLE_ADC_AIN6;
return adc_read_raw();
}
/***********************************************************************
***********************************************************************/
unsigned int adc_read_current_raw(void)
{
ENABLE_ADC_AIN5;
return adc_read_raw();
}
/***********************************************************************
***********************************************************************/
static unsigned int adc_bandgap_stored(void)
{
unsigned int data;
set_IAPEN;
IAPAL = 0x0C;
IAPAH = 0x00;
IAPCN = 0x04;
set_IAPGO;
data = IAPFD;
IAPAL = 0x0d;
IAPAH = 0x00;
IAPCN = 0x04;
set_IAPGO;
data = (data << 4) | (IAPFD & 0x0f);
clr_IAPEN;
debug_log(1, "data = %u\n", data);
return data;
}
/***********************************************************************
***********************************************************************/
static unsigned int adc_bandgap_actual(void)
{
ENABLE_ADC_BANDGAP;
adc_read_raw();
adc_read_raw();
adc_read_raw();
unsigned int data = adc_read_raw();
debug_log(1, "data = %u\n", data);
return data;
}
/***********************************************************************
***********************************************************************/
void adc_task(void)
{
ravg_run(&ravg_voltage, adc_read_voltage_raw());
ravg_run(&ravg_current, adc_read_current_raw());
}
/* #define _CALIBRATE_ */
/***********************************************************************
***********************************************************************/
float adc_read_voltage(void)
{
float value = ravg_average(&ravg_voltage) * adc_vdd / 4095.0;
value = (value - OFFSET_VOLTAGE) * SCALE_VOLTAGE;
#ifndef _CALIBRATE_
value = interpolate(real_table_v,
adc_table_v,
sizeof(real_table_v) / sizeof(real_table_v[0]),
value);
#endif
return value;
}
/***********************************************************************
***********************************************************************/
float adc_read_current(void)
{
float value = ravg_average(&ravg_current) * adc_vdd / 4095.0;
value = (value - OFFSET_CURRENT) * SCALE_CURRENT;
#ifndef _CALIBRATE_
value = interpolate(real_table_i,
adc_table_i,
sizeof(real_table_i) / sizeof(real_table_i[0]),
value);
#endif
return value;
}
/***********************************************************************
***********************************************************************/
void adc_init(void)
{
unsigned int bg_stored = adc_bandgap_stored();
unsigned int bg_actual = adc_bandgap_actual();
float vbg = 3072.0 * bg_stored / 4096.0;
adc_vdd = 4095.0 / bg_actual * vbg / 1000.0;
debug_log(1, "bgs = %u, bga = %u, vbg = %f, vdd = %f\n",
bg_stored, bg_actual, vbg, adc_vdd);
}