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

📄 hvda.c

📁 含20个经典例程
💻 C
字号:
//////////HVDA高差压差动输入,定时启动,由T2定时////////////////
/////////选择4,5通道为ADC0差动转化通道//////////////
/////////仪表为某速度仪,输出Vout:0-10V,且带有参考电压输出Vref:5V////
/////////仪表特性:Vout-Vref与速度成线性关系,量程为-1m/s至1m/s///////
/////////对于电压超过3.6V的AD转化,只能采用HVDA通道////////////////
/////////仪表输出端与HVAIN+相连,仪表参考电平输出与HVAIN-相连////
/////////HVREF端与1V相连(可由DAC输出产生)//////////////////////////
///////////HVCAP连接30pf,滤波转折频率在1KHZ左右//////////////////
/////////程序中对速度积分求取位移//////////////////////////////////////
//////HVDA.c///////////////////////////////////
#include "mylcd.h"
#include "math.h"
#include "stdio.h"
extern bit isline0;
#define ADC0START temppage=SFRPAGE;SFRPAGE=0x00;AD0BUSY=1;SFRPAGE=temppage
#define RATE_P 680L
#define RATE_N 680L
#define VEL_RATE 119L
#define ADJRATEDIF 593L
#define STATIC_ERROR 8
#define NOISE_LIM 10

/*
REAL_RATE为物理量转化系数,由具体对象而定
ADJRATEDIF为差动模式下,增益为0.5时ADC0转化值与真实电压的转换系数
ADJRATESE为单端输入模式下,增益为0.5时ADC0转化值与真实电压的转换系数
STATIC_ERROR为HVDA运方静态误差,由实际使用标定,标定方法将HVAIN+与HVAIN-接在一起观察转化值
NOISE_LIM为噪声门限,由于测量噪声的存在,速度为0时,检测值不一定为0
当检测值大于噪声门限后,才认为速度不为0,对其积分,否则认为速度为0,这样能一定程度克服静态漂移
*/

sfr16 RCAP2=0xca;
sfr16 RCAP3=0xca;
sfr16 RCAP4=0xca;
sfr16 TMR4=0xcc;
sfr16 TMR3=0xcc;
sfr16 TMR2=0xcc;
sfr16 PCA0CP0=0xfb;
sfr16 PCA0CP1=0xfd;
sfr16 PCA0CP2=0xe9;
sfr16 PCA0CP3=0xeb;
sfr16 PCA0CP4=0xed;
sfr16 PCA0CP5=0xe1;
sfr16 ADC0VAL=0xbe;//将ADC0H-ADC0L通过sfr16实现
sfr16 ADC0GT=0xc4;
sfr16 ADC0LT=0xc6;
uchar temppage;
bit isnewdata;
int kk;
xdata long vel_val;//速度值
xdata long vol_val;//电压值
xdata long dis_val;//小位移值
xdata long vel_rate_p;
xdata long vel_rate_n;
xdata long dis;//大位移值
xdata long tempk;
void adc0_mux(uchar type,uchar source);
void adc0_source(uchar source);
void p3anolog_ini(uchar port);
void HVDA_ini(uchar gaind);
void adc0_ini();
void config();
void t2_ini();
void t2_baud(uint t2reload);
void dispini(){	//lcd显示初始化
	delay1ms(100);
	SFRPAGE=0xf;
	lcdcs=0;         
	lcdrs=1;
	lcdrw=1;
	delay1ms(30);
	sendc(0x38);//8位,2行,5*7字体
	delay1ms(100);
	sendc(0x0c);//显示开,光标关;不闪
	delay1ms(100);
	sendc(0x06);//增量方式,现不移动
	delay1ms(100);
	sendc(0x01);//清屏
	delay1ms(100);
}
void t2_ini(){
	SFRPAGE = 0x00;
	TMR2CF = 0x08;  // T2时钟为系统时钟,计数方向为增值计数
	TMR2CN = 0x04;  // T2为16bit定时器模式,并启动定时器运行
}
void t2_baud(uint t2reload){//每隔t2reload个T2时钟,产生一次定时溢出
	SFRPAGE = 0x00;
	RCAP2=~t2reload+1;//相当于65536-t2reload
	TMR2=RCAP2;
	vel_rate_n=RATE_N*(long)t2reload;
	vel_rate_p=RATE_P*(long)t2reload;
}
void adc0_mux(uchar type,uchar source){//type 配置测量方式为差动还是单端输入
//source 为ADC0通道选择(共有9个通道)
	SFRPAGE=0x00;
	AMX0CF=type;
	AMX0SL=source;
}
void adc0_source(uchar source){//ADC0通道选择,为adc0_mux()的简化函数
	SFRPAGE=0x00;
	AMX0SL=source;
}
void p3anolog_ini(uchar port){//配置p3口模拟输入管脚
	SFRPAGE=0x00;
	AMX0PRT=port;
	SFRPAGE=0x0f;
	P3MDIN&=~port;//将相应管脚配置成模拟输入口
}
void HVDA_ini(uchar gaind){
/*高压差动放大器配置,调的只是第二级的增益,整体增益还需再乘以0.05;*/
//HVDA禁止时,HCAP+上检测到的是HVAIN+的电压
	SFRPAGE=0x00;
	HVA0CN=gaind;
}
void adc0_ini(){
	SFRPAGE=0x00;
	ADC0CF=0x18;//ADC0时钟为系统时钟4分频,PGA增益为1
	ADC0CN=0x8c;//AD0TM=0,ADC0为连续跟踪模式,由T2溢出率启动ADC0
	//AD0LJST=0,数据存储格式右对齐,即ADC0H存放12bit高四位
	REF0CN&=0x0f;//AD0VRS=0,ADC0参考电压为VREFA
	REF0CN|=0x07;//TEMPE=1,内部温度传感器工作
	//BIASE=1,偏移产生器工作
	
	/*REFBE=1,内部参考电平工作,电路部分须将VREF参考输出(C8051F40的第12管脚)与	VREF0(C8051F040的16管脚相连,并最好并联一个4.7uF和0.1uF的旁路电容以电平滤波*/

	HVDA_ini(0x83);//启用HVDA高压差动放大器,增益为0.2
	adc0_mux(0x0c,4);//PORT3IC=1,ADC0 6、7通道为差动模式
	//HVDA2C=1,4、5通道为差动输入模式
	//AIN0.0-AIN0.3均为单端模式
	//选择4,5通道为ADC0差动转化通道
	/*
	进入ADC转化的电压为:
	HVDA(out)-HVREF=[(HVAIN+)-(HVAIN-)]*Gain+HVREF-HVREF=[(HVAIN+)-(HVAIN-)]*Gain
	其中整体增益Gain=Gain_HVDA*Gain_PGA=0.2*0.1=0.2
	所以进入ADC0转化的HVDA差动电压为:
	[(HVAIN+)-(HVAIN-)]*0.2,其值范围为-1V至1V
	引入HVREF的目的是在[(HVAIN+)-(HVAIN-)]*Gain为负电平时,通过HVREF抬升,使其落在ADNG-AV+范围内
	*/
	
	EIE2 |= 0x02;        //开ADC0中断
	t2_ini();
	t2_baud(30000);//每隔3000个T2时钟产生一次ADC0采样,约1ms采样一次
	SFRPAGE=0x00;
	TR2=1;
}
void config (void) {
//看门狗禁止
    WDTCN = 0x07;	
    WDTCN = 0xDE;   
    WDTCN = 0xAD;
    SFRPAGE = 0x0F;
    XBR0 = 0x00;	
    XBR1 = 0x00;	
    XBR2 = 0x40;	//交叉开关使能,使得P0-P3口能输出
    XBR3 = 0x00;    
    SFRPAGE = 0x0F;
    P0MDOUT = 0x00; //端口配置,P0-P3,P6-P7口为开漏输出
    P1MDOUT = 0x00; 
    P2MDOUT = 0x00; 
    P3MDOUT = 0x00; 
    P4MDOUT = 0x00; //P4口为开漏,也可推挽
    P5MDOUT = 0x07; 
    P6MDOUT = 0x00; 
    P7MDOUT = 0x00; 
    P1MDIN = 0xFF;  //所有端口为数字输入,没有模拟输入端口
    P2MDIN = 0xFF;  
    P3MDIN = 0xFF; 
    SFRPAGE = 0x0F;
    CLKSEL = 0x00;  
    OSCXCN = 0x00;	
    OSCICN = 0x84;	
    //采用内部晶振,为24.5MHZ8分频
}   

void main(){
	xdata float showfloat;
	xdata uint i;
	bit isfirst1=1,isfirst2=1,isfirst3=1;
	config();
	dispini();//LCD初始化,具体见LCD章节部分
	adc0_ini();//ADC0初始化
	EA=1;
	i=0;
	dis_val=0;
	dis=0;
	isline0=1;
	printf("\nhello");
	printf("\ntesting");
	while(1){
		if(isnewdata){//轮流显示三组数据
			i++;
			if(i>80&&i<160){
				if(isfirst1){
					showfloat=vol_val/100000.0;
					printf("\nvol=%.2f",showfloat);
					isfirst1=0;
				}
				isfirst2=1;
				isfirst3=1;
			}
			if(i>160&&i<240){
				if(isfirst2){
					showfloat=vel_val/100000.0;
					printf("\nvel=%.5f",showfloat);
					isfirst2=0;

			}
			isfirst1=1;
			isfirst3=1;
			}
			if(i>240&&i<300){
				if(isfirst3){
					showfloat=dis/1000.0;
					printf("\ndis=%.3f",showfloat);
					i=0;
					isfirst3=0;
				}
				isfirst1=1;
				isfirst2=1;
			}
			isnewdata=0;
		}
	}
}
void ADC0_ISR() interrupt 15{
	SFRPAGE=0x00;
	AD0INT=0;
	kk=ADC0VAL;
	kk+=STATIC_ERROR;//转化值加上静态误差,进行测量修正
	vel_val=(long)kk*VEL_RATE;
	vol_val=(long)kk*ADJRATEDIF;
	/*
	ADC0转化值乘以速度转化系数,其结果为速度真实值乘以100000
	例如ADC0VAL=65136时,即kk=-400,则vel_val=-400*119=-47600,即表示真实速度值为-0.476m/s 
	*/

	if(abs(kk)>NOISE_LIM){//与噪声门限比较,决定是否积分
		tempk=kk;
		if(tempk>0)
			tempk*=vel_rate_p;//正向系数
		else
			tempk*=vel_rate_n;//反向系数
		dis_val+=tempk;
		if(labs(dis_val)>=1.0e9L){//当小位移绝对值大于1.0e9L时,将其值与1.0e9L的比值赋给大位移
		//这是long运算位数不够的一种处理方法
			tempk=dis_val/1.0e9L;
			dis+=tempk;//dis*10e-3为物理量值(单位为米)
			dis_val-=tempk*1.0e9L;
		}
		
	}
	isnewdata=1;
	
	/*
	对速度等进行数字积分,由于测量噪声的存在,往往需要考虑滤波问题
	本程序以调试为目的,实际使用中,要结合具体测量对象,可能要考虑卡尔曼滤波等算法提高测量精度
	vel_rate_p与检测周期和RATE_P有关,在t2_baud()中赋值,用户只需改变RATE_P便可进行标定调整
	vel_rate_n与检测周期和RATE_N有关,实际当中测量对象正向增益与反向增益可能不同
	通过调整RATE_P和RATE_N能一定程度克服回差
	RATE_P理论计算值如下推导:
	采样时间:tf=1/[24.5MHZ/(8*t2_baud)],t2_baud为T2定时周期
	速度值:(2.43/2048)*Val_AD,  Val_AD为ADC转化值
	采样时间*速度值=采样周期内的位移=Val_AD*vel_rate_p=Val_AD*t2_baud*RATE_P
	从而得:RATE_P=(2.43*8)/(2048*24.5M)=3.874e-10
	若不采用浮点运算,取RATE_P=387L,则运算结果相当于放大1.0e12倍
	分析运算溢出可能性:
	long型数据为32位,由于是带符号,则绝对值为31位,即最大数据为2^31约为2.1e9>1.0e9,所以小位移采用1.0e9为程序控制溢出值合理
	当速度为1m/s时,ADC转化值为842,则采样周期内位移计算为:842*387*T2_baud<1.0e9,则有T2_baud<3068
	大位移值为10e-3m,将大位移与小位移数据合并,大位移相当于整个数据的10进制高于1.0e9部分
	而整个数据与真实物理值为1.0e12倍关系,所以大位移数据与真实物理值为1.0e-3关系
	若要使得定时周期可调范围更大,则通过改变vel_rate_p和vel_rate_n的计算公式即可
	比如不是乘以t2reload,而是乘以t2reload的1/100,则定时时间可增长100倍
		
	*/
	
}

⌨️ 快捷键说明

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