上一篇简要的分析了一下测量任务,但是没有展开来对其进行具体的分析,接下来就对其进行具体的分析,分析各个参数的采集测量方法。
一、触发测量
if((key == KEY0_PRES) && (device_mode == DEVICE_MODE_MEASURE)) //测量模式 向上键
{
Measure_data.data_reg.Measure = 1;//开始测量
DC_OFFSET_MEASURE();//测直流偏置
vTaskDelay(100);
measure_sta = MEASURE_DC_STA; //测量直流偏置
}
#define DC_OFFSET_MEASURE() {J1_OFF;J2_OFF;J3_OFF;J4_OFF;J5_ON;J6_OFF;J7_OFF;} //直流
程序中通过外部按键触发测量,在测量模式下按下KEY0按键触发一次测量,设置标志位和继电器状态,只有J5是闭合的其他所有继电器全部断开,放大电路没有输入信号,输出为纯直流分量。
一、直流偏置UCQ测量
1.直流电压采样
void TIM2_IRQHandler(void)
{
uint8_t res = 0;
BaseType_t xHigherPriorityTaskWoken;
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)//定时器溢出中断
{
res |= ADC_Sample();//读取ADC每个通道的数值到数据缓存区
res |= Check_Sample_Data();
if(res) //有数据采集完成
{
xSemaphoreGiveFromISR(Measure_SemaphoreHandle ,&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
}
}
ADC1的采样由TIM2触发,在中断中进行采样保证采样的时间间隔,中断频率为32k,其中ADC_Sample()函数即是ADC采样函数。根据这个函数的返回值判断是否完成了一组数据的采样,返回值为1则表示完成了一组数据的采样,释放一次Measure_SemaphoreHandle 信号量,在measure_task任务中会进行一次数据计算。
uint8_t DC_Sample_Handle(void)
{
if(Measure_Dc.dc_sample_count < MEASURE_BUF_SIZE) //采样还没有完成
{
Sample_data_buf[Sample_count] = ADC1_BUFF[1];
Sample_count++;
if(Sample_count == 4) //均值缓存满了
{
Sample_count = 0;
Measure_Dc.dc_buf[Measure_Dc.dc_sample_count] = (Sample_data_buf[0] + Sample_data_buf[1] + Sample_data_buf[2] + Sample_data_buf[3])/4;//求均值
Measure_Dc.dc_sample_count++;
}
}
if(Measure_Dc.dc_sample_count >= MEASURE_BUF_SIZE) //采样结束完成
{
Sample_data_buf[0] = 0;
Sample_data_buf[1] = 0;
Sample_data_buf[2] = 0;
Sample_data_buf[3] = 0;
Sample_count = 0;
return 1;//返回1准备计算
}
return 0;
}
#define MEASURE_BUF_SIZE 256 //用于保存采集的数据的缓存区的大小
//测量直流偏置电压的数据描述结构体
struct Measure_Dc_obj
{
uint16_t dc_gain; //ADC的电压值和实际偏置的关系 几倍 30代表AD的信号要放大3.0倍
uint16_t dc_sample_count; //指示dc采集缓存区指针
uint16_t dc_value; //指示最近一次测量的DC直流偏置的值 单位mV
uint16_t dc_buf[MEASURE_BUF_SIZE];//直流偏置测量时的缓存区
};
采样函数和直流电压测量结构体如上所示。放入缓存中的采样值由四个采样值取平均得到,dc_buf[]缓存装满之后一共256个值,然后返回1开始进行计算。
2.直流电压计算
case(MEASURE_DC_STA): //测量直流偏置电压
cal_res = DC_Cal_Handle();
if(cal_res == 1) //直流偏置电压计算完成
{
Measure_data.data_reg.Dc_sta = 1; //DC测量完毕
Measure_data.Dc = Measure_Dc.dc_value;
measure_sta = MEASURE_NONE_STA;//停止采样
/***************** 测量输入电阻 ******************/
R6_MEASURE_UI2_IN();//切继电器 接入R6
Measure_Rs.Rs_Ri_sta = 0;//R6
DDS_reg.fre_num = 1000;
ad9850_wr_serial(0x00,DDS_reg.fre_num);//1K 默认输出
vTaskDelay(200);//延时 等待继电器切换
memset(&Measure_Ri_Jun,0,sizeof(Measure_Ri_Jun));//清空缓存
Measure_Dc.dc_sample_count = 0;
measure_sta = MEASURE_RI_STA; //测量输入电阻
Measure_Dc.dc_sample_count = 0;
}
break;
uint8_t DC_Cal_Handle(void)
{
uint16_t i;
uint32_t cal = 0;
if(Measure_Dc.dc_sample_count >= MEASURE_BUF_SIZE) //采样满了
{
for(i = 0;i<MEASURE_BUF_SIZE;i++)
{
cal += Measure_Dc.dc_buf[i]; //求和
}
cal = cal/16;//得到16位的分辨 256倍过采样 提高精度
cal = cal*1000/65536*3300; //得到进入ADC的电压值 单位uV
cal = cal * Measure_Dc.dc_gain/10000;//直流偏置电压值 单位mV
Measure_Dc.dc_value = cal;
Measure_Dc.dc_sample_count = 0;
return 1;
}
return 0;
}
//最终测量得到的数据结构体
struct data_reg_bit
{
uint8_t Measure : 1; //正在进行数据测试
uint8_t Dc_sta : 1; //dc测量完毕
uint8_t Ri_sta : 1; //输入电阻测量完毕
uint8_t Ro_sta : 1; //输出电阻测量完毕
uint8_t Av_sta : 1; //增益测量完毕
uint8_t Fptx_sta : 1; //幅频特性测试完毕
uint8_t res : 2; //保留
};
struct Measure_data_obj
{
struct data_reg_bit data_reg;
uint16_t Ri; //输入电阻
uint16_t Ro; //输出电阻
uint16_t Av; //1K时的增益
uint32_t fre_stop; //上限截止频率
uint16_t Dc;
};
#define R6_MEASURE_UI2_IN() {J1_OFF;J2_ON;J3_OFF;J4_OFF;J5_OFF;J6_OFF;J7_OFF;} //测量串入电阻R6后的U_OUT
measure_task任务中接收到Measure_SemaphoreHandle 信号量之后就会开始进行一次计算,根据状态标志进入对应的计算函数。有关直流电压的计算,其中主要是调用了 DC_Cal_Handle()函数完成。
DC_Cal_Handle()函数中首先判断采样缓存是否满了,然后对其进行求和,然后采用过采样(直接求平均应该影响也不大)的方法提高测量的分辨率,得到16位的分辨率,然后计算得到实际的电压值,计算完成之后返回1表示直流电压测量完成。
直流电压测量完成之后,将直流电压的测量结果存放到Measure_data结构体中,将对应的测量完成标志位设置为1。切换继电器、清空缓存、改变测量状态标志开始测量输入电阻Ri。可以看出测量输入电阻时默认接入的是R6电阻,根据电路图可以发现R6电阻时3k电阻,也就是先接入小电阻进行测量。
二、输入电阻测量
1.输入电阻测量——采样部分
uint8_t RI_Sample_1KHz_Handle(void)
{
uint8_t res = 0;
if(Measure_Ri_Jun.Ui2_ave_count < 32)//串入电阻之后的Ui
{
if(Measure_Ri_Jun.Ui2_jun_buf_sta == 0) //缓存一
{
Measure_Ri_Jun.Ui2_jun_buf1[Measure_Ri_Jun.Ui2_jun_count1] = ADC1_BUFF[0];
Measure_Ri_Jun.Ui2_jun_count1++;
if(Measure_Ri_Jun.Ui2_jun_count1 == 32) //满了
{
Measure_Ri_Jun.Ui2_jun_buf_sta = 1;
res = 1;
}
}
else
{
Measure_Ri_Jun.Ui2_jun_buf2[Measure_Ri_Jun.Ui2_jun_count2] = ADC1_BUFF[0];
Measure_Ri_Jun.Ui2_jun_count2++;
if(Measure_Ri_Jun.Ui2_jun_count2 == 32) //满了
{
Measure_Ri_Jun.Ui2_jun_buf_sta = 0;
res = 1;
}
}
}
return res;
}
//测量输入电阻的数据描述结构体 1KHz时使用均方根
struct Measure_Ri_Jun_obj
{
int32_t Ui1_jun_buf1[32]; //双缓存 Ui1没有进行测量
int32_t Ui1_jun_buf2[32]; //后续更新的程序可能会对Ui1的相关变量进行删除
int32_t Ui1_jun_count1;
int32_t Ui1_jun_count2;
int32_t Ui1_jun_buf_sta; //0使用缓存1
int32_t Ui2_jun_buf1[32]; //双缓存
int32_t Ui2_jun_buf2[32];
int32_t Ui2_jun_count1;
int32_t Ui2_jun_count2;
int32_t Ui2_jun_buf_sta; //0使用缓存1
int32_t Ui1_ave_buf[32]; //最终均值缓存
int32_t Ui1_ave_count;
int32_t Ui2_ave_buf[32]; //最终均值缓存
int32_t Ui2_ave_count;
int32_t measure_ri_sta; //0测量Ui1 1测量Ui2
int32_t Ui1_value;
int32_t Ui2_value;
};
虽然结构体中有Ui1相关的变量(我忘删了。。[捂脸]),但是实际上程序中并没有测量Ui1的大小,而是直接在实际电路中使用示波器测量得到。程序中只是测量的Ui2的大小,Ui2即为串联电阻之后的Ui值。程序中采用均方根算法计算Ui2的值,由于中断的频率很快为了进行不间断的采样,采用了双缓存的方法进行采样,通过Ui2_jun_buf_sta标志判断当前使用的是哪个缓存区,缓存区满了之后就发送信号量进行数据计算并切换缓存区。
2.输入电阻测量——计算
case(MEASURE_RI_STA): //测量输入电阻
if(DDS_reg.fre_num == 1000) //1K
cal_res = Ri_Cal_1KHz_Handle();
if(cal_res == 1) //直流输入电阻计算完成
{
Measure_data.data_reg.Ri_sta = 1; //输入电阻测量完毕
measure_sta = MEASURE_NONE_STA;//停止采样
/***************** 测量输出电阻 ******************/
MEASURE_UO1_OUT();//Uo1
Measure_Rs.Rs_Ro_sta = 1;//R42
DDS_reg.fre_num = 1000;
ad9850_wr_serial(0x00,DDS_reg.fre_num);//1K 默认输出
vTaskDelay(200);//延时 等待继电器切换
if(DDS_reg.fre_num == 1000) //1K
memset(&Measure_Ri_Jun,0,sizeof(Measure_Ri_Jun));//清缓存
measure_sta = MEASURE_RO_STA; //测量输出电阻
}
break;
uint8_t Ri_Cal_1KHz_Handle(void)
{
static uint8_t err_count = 0;//电阻测量错误计数
uint16_t i,Rs;
int32_t cal = 0;
uint32_t average;
int32_t *data_buf = NULL;
Measure_Ri_Jun.Ui1_value = 9636; //Ui1峰峰值 96.36mV
if((Measure_Ri_Jun.Ui2_jun_count1 == 32) || (Measure_Ri_Jun.Ui2_jun_count2 == 32))
{
if(Measure_Ri_Jun.Ui2_ave_count < 32) //32个周波求平均
{
if(Measure_Ri_Jun.Ui2_jun_buf_sta == 1) //之前是用的缓存1
{
data_buf = Measure_Ri_Jun.Ui2_jun_buf1;
Measure_Ri_Jun.Ui2_jun_count1 = 0;
}
else
{
Measure_Ri_Jun.Ui2_jun_count2 = 0;
data_buf = Measure_Ri_Jun.Ui2_jun_buf2;
}
for(i = 0;i<32;i++)
{
data_buf[i] = data_buf[i]*3300/4096; //得到电压值单位1mv
}
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i];
average = cal/32; //均值
for(i = 0;i<32;i++)
{
cal = data_buf[i] - average;
data_buf[i] = cal;
}
/****************** 计算电流的有效值 均方根 *************************/
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i]*data_buf[i]; //平方相加
cal /= 32;
cal = (int)mysqrt((uint32_t)cal); // 开平方根
Measure_Ri_Jun.Ui2_ave_buf[Measure_Ri_Jun.Ui2_ave_count] = cal;//单位mv
Measure_Ri_Jun.Ui2_ave_count++;
if(Measure_Ri_Jun.Ui2_ave_count == 32) //满了
{
cal = 0;
for(i = 0;i<32;i++)
cal += Measure_Ri_Jun.Ui2_ave_buf[i];
cal /= 32;
Measure_Ri_Jun.Ui2_value = cal*1414*2/Ui_gain; //0.01mV 峰峰值
if(Measure_Rs.Rs_Ri_sta == 0) //接入的R6
Rs = Measure_Rs.R6_value;
else //接入的是R8
Rs = Measure_Rs.R8_value;
if(Measure_Ri_Jun.Ui1_value > (Measure_Ri_Jun.Ui2_value + 2500)) //Ui1>Ui2+25mV 这样的话会测量准确性高
{
cal_Ri_1K:
cal = Measure_Ri_Jun.Ui1_value - Measure_Ri_Jun.Ui2_value;
cal *= 1000;
cal /= Rs;
cal = Measure_Ri_Jun.Ui2_value*1000/cal; //得到输入电阻值 单位欧姆
Measure_data.Ri = cal; //输入阻抗值
if(Measure_data.Ri < 500) //输入电阻有时测量不到 还在找问题。
{
err_count++;
if(err_count == 3)//连续三次那就是真的这样 故障判断模式时出现
{
err_count = 0;
return 1;
}
else
{
memset(&Measure_Ri_Jun,0,sizeof(Measure_Ri_Jun));//清空缓存 继续测量
Measure_data.Ri = 0;
}
}
else
return 1;//计算完成
}
else //换电阻采样
{
if(Measure_Rs.Rs_Ri_sta == 0) //接入的R6小电阻 还可以接入大电阻试一下
{
R8_MEASURE_UI2_IN();//切换继电器接入R8
Measure_Rs.Rs_Ri_sta = 1;
delay_ms(100);
memset(&Measure_Ri_Jun,0,sizeof(Measure_Ri_Jun));//清空缓存
}
else //已经接入的是R8了
goto cal_Ri_1K;//直接算一下
}
}
}
}
return 0;
}
在函数Ri_Cal_1KHz_Handle()中对采集得到的数据进行算,可以看到函数一开始执行Measure_Ri_Jun.Ui1_value = 9636; //Ui1峰峰值 96.36mV
对Ui1_value进行赋值,这个值需要各位填入自己实际的电路中测量的到的值,我的电路中测量得到的值为96.36mV。
之后就是根据采样得到值计算Ui2的峰峰值,先判断当前的缓存区是哪个,然后求得平均值,然后缓存中的所有值与平均值求差,得到正弦波的交流分量,然后根据均方根公式计算。mysqrt()函数是一个整型数快速开平方根算法函数,采用迭代的思想计算(有兴趣的可以看一下源码,数越大需要迭代的次数越多。)。需要采样计算32次,得到32个计算值,然后再对这32个值求平均得到最终的Ui2的值。
根据标志位得到当前串联电阻是哪个,然后判断(Ui1 ~= Ui2)?,我这里的判断依据就是(Ui1 > Ui2 + 25mv)?,这个25mv可以各位根据自己电路进行试验调整。两个值比较接近的话就表明Ri >>R6,需要切换电阻再次测量。切换继电器,然后等待信号建立稳定,再清空缓存等待采样缓存满,然后再次计算。
我在测试过程中偶尔会出现Ri测量为0或者很小的情况,所以程序中会有if(Measure_data.Ri < 500) 这个判断,出现这个问题的话也会重新进行测量。(各位可以试一下会不会出现这个问题,不知道是程序中的bug还是硬件电路的问题。有待测试mark)
Ri测量完成之后,函数返回1,设置Ri测量完成标志为1,切换继电器,切换测量状态标志,开始测量输出电阻Ro。
三、输出电阻测量
1.输出电阻测量——采样
uint8_t RO_Sample_1KHz_Handle(void)
{
uint8_t res = 0;
if(Measure_Ro_Jun.measure_ro_sta == 0) //测量Uo1
{
if(Measure_Ro_Jun.Uo1_ave_count < 32) //空载时
{
if(Measure_Ro_Jun.Uo1_jun_buf_sta == 0) //缓存一
{
Measure_Ro_Jun.Uo1_jun_buf1[Measure_Ro_Jun.Uo1_jun_count1] = ADC1_BUFF[3];
Measure_Ro_Jun.Uo1_jun_count1++;
if(Measure_Ro_Jun.Uo1_jun_count1 == 32) //满了
{
Measure_Ro_Jun.Uo1_jun_buf_sta = 1;
res = 1;
}
}
else
{
Measure_Ro_Jun.Uo1_jun_buf2[Measure_Ro_Jun.Uo1_jun_count2] = ADC1_BUFF[3];
Measure_Ro_Jun.Uo1_jun_count2++;
if(Measure_Ro_Jun.Uo1_jun_count2 == 32) //满了
{
Measure_Ro_Jun.Uo1_jun_buf_sta = 0;
res = 1;
}
}
}
}
else //测量Uo2
{
if(Measure_Ro_Jun.Uo2_ave_count < 32) //直接测量接入电阻的电压值
{
if(Measure_Ro_Jun.Uo2_jun_buf_sta == 0) //缓存一
{
Measure_Ro_Jun.Uo2_jun_buf1[Measure_Ro_Jun.Uo2_jun_count1] = ADC1_BUFF[3];
Measure_Ro_Jun.Uo2_jun_count1++;
if(Measure_Ro_Jun.Uo2_jun_count1 == 32) //满了
{
Measure_Ro_Jun.Uo2_jun_buf_sta = 1;
res = 1;
}
}
else
{
Measure_Ro_Jun.Uo2_jun_buf2[Measure_Ro_Jun.Uo2_jun_count2] = ADC1_BUFF[3];
Measure_Ro_Jun.Uo2_jun_count2++;
if(Measure_Ro_Jun.Uo2_jun_count2 == 32) //满了
{
Measure_Ro_Jun.Uo2_jun_buf_sta = 0;
res = 1;
}
}
}
}
return res;
}
//测量输出电阻的数据描述结构体 1KHz时使用均方根
struct Measure_Ro_Jun_obj
{
int32_t Uo1_jun_buf1[32]; //双缓存
int32_t Uo1_jun_buf2[32];
int32_t Uo1_jun_count1;
int32_t Uo1_jun_count2;
int32_t Uo1_jun_buf_sta; //0使用缓存1
int32_t Uo2_jun_buf1[32]; //双缓存
int32_t Uo2_jun_buf2[32];
int32_t Uo2_jun_count1;
int32_t Uo2_jun_count2;
int32_t Uo2_jun_buf_sta; //0使用缓存1
int32_t Uo1_ave_buf[32]; //最终均值缓存
int32_t Uo1_ave_count;
int32_t Uo2_ave_buf[32]; //最终均值缓存
int32_t Uo2_ave_count;
int32_t measure_ro_sta; //0测量Uo1 1测量Uo2
int32_t Uo1_value;
int32_t Uo2_value;
};
Ro的测量方式基本和Ri相同,信号的测量也是采用的均方根算法来计算,32k的中断采集32个的数据。Uo1为放大电路空载时的输出信号大小,Uo2为放大电路带载时在负载电阻上的信号大小。采样时由Measure_Ro_Jun.measure_ro_sta标志确定当前采集的信号是Uo1还是Uo2,同样采用了双缓存的方式进行采样,采样完成之后函数返回1,会在定时器中断函数中释放信号量进行任务同步,然后在measure_task任务中进行数据计算。
2.输出电阻测量——计算
case(MEASURE_RO_STA): //测量输出电阻
if(DDS_reg.fre_num == 1000) //1K
cal_res = Ro_Cal_1KHz_Handle();
if(cal_res == 1) //直流输出电阻计算完成
{
Measure_data.data_reg.Ro_sta = 1; //输出电阻测量完毕
measure_sta = MEASURE_NONE_STA;//停止采样
/***************** 测量增益 ******************/
AV_MEASURE_UO_IN() ;//切继电器 Ui
DDS_reg.fre_num = 1000;
ad9850_wr_serial(0x00,DDS_reg.fre_num);//1K 默认输出
vTaskDelay(200);//延时 等待继电器切换
if(DDS_reg.fre_num == 1000) //1K
memset(&Measure_Ro_Jun,0,sizeof(Measure_Ro_Jun));//清缓存
measure_sta = MEASURE_AV_STA; //测量增益
}
break;
uint8_t Ro_Cal_1KHz_Handle(void)
{
uint16_t i,Rs;
int32_t cal = 0;
uint32_t average;
int32_t *data_buf = NULL;
if(Measure_Ro_Jun.measure_ro_sta == 0) //测量Uo1
{
if((Measure_Ro_Jun.Uo1_jun_count1 == 32) || (Measure_Ro_Jun.Uo1_jun_count2 == 32))
{
if(Measure_Ro_Jun.Uo1_ave_count < 32) //32个周波求平均
{
if(Measure_Ro_Jun.Uo1_jun_buf_sta == 1) //之前是用的缓存1
{
Measure_Ro_Jun.Uo1_jun_count1 = 0;
data_buf = Measure_Ro_Jun.Uo1_jun_buf1;
}
else
{
Measure_Ro_Jun.Uo1_jun_count2 = 0;
data_buf = Measure_Ro_Jun.Uo1_jun_buf2;
}
for(i = 0;i<32;i++)
data_buf[i] = data_buf[i]*3300/4096; //得到电压值单位1mv
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i];
average = cal/32; //均值
for(i = 0;i<32;i++)
{
cal = data_buf[i] - average;
data_buf[i] = cal;
}
/****************** 计算电压的有效值 均方根 *************************/
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i]*data_buf[i]; //平方相加
cal /= 32;
cal = (int)mysqrt((uint32_t)cal); // 开平方根
Measure_Ro_Jun.Uo1_ave_buf[Measure_Ro_Jun.Uo1_ave_count] = cal;
Measure_Ro_Jun.Uo1_ave_count++;
if(Measure_Ro_Jun.Uo1_ave_count == 32) //满了
{
cal = 0;
for(i = 0;i<32;i++)
cal += Measure_Ro_Jun.Uo1_ave_buf[i];
cal /= 32;
Measure_Ro_Jun.Uo1_value = cal*Uo_gain*2*1414/10000; //Uo1峰峰值
if(Measure_Rs.Rs_Ro_sta == 0) //接入的R40
{
R40_MEASURE_UO2_OUT();
}
else //接入的是R42
{
R42_MEASURE_UO2_OUT();
}
delay_ms(50);
Measure_Ro_Jun.measure_ro_sta = 1;//测量UO2
}
}
}
}
else
{
if((Measure_Ro_Jun.Uo2_jun_count1 == 32) || (Measure_Ro_Jun.Uo2_jun_count2 == 32))
{
if(Measure_Ro_Jun.Uo2_ave_count < 32) //32个周波求平均
{
if(Measure_Ro_Jun.Uo2_jun_buf_sta == 1) //之前是用的缓存1
{
Measure_Ro_Jun.Uo2_jun_count1 = 0;
data_buf = Measure_Ro_Jun.Uo2_jun_buf1;
}
else
{
Measure_Ro_Jun.Uo2_jun_count2 = 0;
data_buf = Measure_Ro_Jun.Uo2_jun_buf2;
}
for(i = 0;i<32;i++)
data_buf[i] = data_buf[i]*3300/4096; //得到电压值单位1mv
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i];
average = cal/32; //均值
for(i = 0;i<32;i++)
{
cal = data_buf[i] - average;
data_buf[i] = cal;
}
/****************** 计算电压的有效值 均方根 *************************/
cal = 0;
for(i = 0;i<32;i++)
cal += data_buf[i]*data_buf[i]; //平方相加
cal /= 32;
cal = (int)mysqrt((uint32_t)cal); // 开平方根
Measure_Ro_Jun.Uo2_ave_buf[Measure_Ro_Jun.Uo2_ave_count] = cal;
Measure_Ro_Jun.Uo2_ave_count++;
if(Measure_Ro_Jun.Uo2_ave_count == 32) //满了
{
cal = 0;
for(i = 0;i<32;i++)
cal += Measure_Ro_Jun.Uo2_ave_buf[i];
cal /= 32;
Measure_Ro_Jun.Uo2_value = cal*Uo_gain*2*1414/10000; //Uo2峰峰值
if(Measure_Rs.Rs_Ro_sta == 0) //接入的R40
Rs = Measure_Rs.R40_value;
else //接入的是R42
Rs = Measure_Rs.R42_value;
if(Measure_Ro_Jun.Uo1_value > (Measure_Ro_Jun.Uo2_value + 400)) //Uo1>Uo2+400mV 这样的话会测量准确性高
{
cal_Ro_1K:
cal = Measure_Ro_Jun.Uo2_value*1000/Rs;//I 单位uA
if(Measure_Ro_Jun.Uo2_value >= Measure_Ro_Jun.Uo1_value)
Measure_data.Ro = 0;
else
{
cal = (Measure_Ro_Jun.Uo1_value - Measure_Ro_Jun.Uo2_value)*1000/cal;//得到Ro 单位欧姆
Measure_data.Ro = cal;
}
return 1;//计算完成
}
else //换电阻采样
{
if(Measure_Rs.Rs_Ro_sta == 0) //接入的R40小电阻
{
goto cal_Ro_1K;//直接算一下
}
else //接入的是R42了 大电阻 可以换小电阻试一下
{
MEASURE_UO1_OUT();//切换继电器
Measure_Ro_Jun.measure_ro_sta = 0;//Uo1
Measure_Rs.Rs_Ro_sta = 0;
delay_ms(100);
memset(&Measure_Ro_Jun,0,sizeof(Measure_Ro_Jun));//清空缓存
}
}
}
}
}
}
return 0;
}
与测量Ri时相同,数据的计算在Ro_Cal_1KHz_Handle()函数中完成,先判断当前测量的是Uo1还是Uo2,然后根据缓存中的数据计算得到一个计算值,等到采样计算得到了32个计算值之后求平均,基本和Ri的计算过程相同。采样计算完成Uo1之后,切换继电器再采样计算Uo2,过程基本相同,两个值都采样完成之后,开始计算Ro,一开始默认接入的是R42也就是大电阻(测量完Ri之后的切换代码可以看出),同样需要判断两个值的接近程度,
if(Measure_Ro_Jun.Uo1_value > (Measure_Ro_Jun.Uo2_value + 400))
两个值如果太过接近的话,表示这个负载阻值很大,远大于Ro,将电阻切换到R40小电阻,清空缓存再进行采样计算。这个判断门槛,我这里选择了400mv,各位需要根据自己实际的实验测量得到一个比较合适的值。
由于这篇博文的程序放的比较多,所以篇幅就比较长了,这里就先分析UCQ、Ri、Ro这三个量的采样计算程序部分,接下来还有Av和fH将在下篇博文进行分析。欢迎各位留言或私信讨论。
PS:程序源码和硬件电路图都在之前发的这个系列博文第一篇中,大家可以在那篇博文的最下面,点击网盘链接进行下载。