2019年TI杯 简易电路特性测试仪 制作过程(5)——测量任务分析(UCQ、Ri、Ro) 20/04/26

       上一篇简要的分析了一下测量任务,但是没有展开来对其进行具体的分析,接下来就对其进行具体的分析,分析各个参数的采集测量方法。
一、触发测量

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:程序源码和硬件电路图都在之前发的这个系列博文第一篇中,大家可以在那篇博文的最下面,点击网盘链接进行下载。

  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
前言: 今天的主角其实是好多朋友都应该已经熟悉的8位米字VFD显示屏,由YLEEE老板一年前“隆重”推出,期间很多朋友都做过,各种各样的实现和驱动方法都有,这里我就不做评价。我的主要思路是:简单、可靠,有专门驱动就用专门驱动,当然最重要的是要时间精准:1、和我之前的同步母钟同步(推荐)2、使用GPS模块校时。 八位米字VFD显示屏实物截图: 这个屏从图片上可以看出,做时钟屏是非常合适的,唯一的缺点就是稍微小点,不过瑕不掩瑜,量多价优呀! 尺寸图: 先说说规划的功能和特点: 1、从上面数据手册可以知道,这个屏是8位16段,使用PT6311可以了,专用芯片稳定、可靠、驱动效果好,这是我的一贯的原则,大家也可以使用几十个三极管做动态扫描驱动,反正是折腾,咋么搞亮都行; 2、还是使用绕制的高频变压器做灯丝、负压、隔离电源,优点:简单、稳定、可靠,灯丝交流、负压一次产生,不需要再利用系统其它资源。缺点:变压器虽然是EE13,可也不能能做的超薄; 3、3组硬件自动开关机,这个我之前的很多时钟上面都有。就是可以设置几组自动开 关时间,控制VFD 的灯丝、负压电源,做到节能,延长屏寿命; 4、3组闹钟,每组可单独设置开启、关闭,闹铃响铃长度1-99秒,周末闹铃是否开启; 5、星期是程序根据年月日自动计算的,不需要设置; 6、12小时/24小时时间显示模式选择;(遥控器上F1快捷功能有效) 7、温度显示;(遥控器上TEMP快捷功能有效) 8、日期 星期显示;(遥控器上DATE快捷功能有效) 9、固定显示时间/或者循序显示:时间1分钟-星期、日期显示5秒、温度显示5秒,2种显示模式可选。(遥控器上F2快捷功能有效) 10、光控自动调节或手动亮度调节,1-8级,设置00就是光控自动调节。自动开关机时段,也能手动或自动亮度控制; 11、红外遥控功能,也带红外学习功能,可以使用你自己的遥控器学习、控制; 12、有DS1302实时时钟芯片(正宗的能弄到只有拆机的了),外接正品日本KDS 5ppm晶振(这个好不容易找工厂朋友弄到,厂家仪表进行过筛选) 13、母钟的同步子钟/GPS同步时钟/普通时钟,大家可以根据自己的需要,选择不同的功能应用; 子母钟同步时,可以使用我之前介绍的2种,具体可参考之前的文章: https://www.yeyudo.cn/article.asp?id=254 https://www.yeyudo.cn/article.asp?id=259 https://www.yeyudo.cn/article.asp?id=260 8位米字VFD屏制作的同步子钟/GPS时钟电路设计包括MCU控制板+驱动板2部分。 见PCB实物截图: 实物购买链接:https://item.taobao.com/item.htm?spm=2013.1.0.0.lJN4W6&id=15071361340

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落叶凋凌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值