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

📄 ade7758_1.c

📁 ADE7758的相关程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************************************************** 
文件和函数说明 
本文件包含对ADE7758芯片进行操作的所有函数,利用单片机的I/O口模拟标准的SPI对ADE7758进行操作。 
使用单片机型号:p89v51rd2,护展1K处部RAM 
晶振频率:11.0592MHz 
功能模块: 
1、ADE7758底层操作函数: 
	write7753(unsigned char type,unsigned int wdata,unsigned char databit) 向ADE758写数据 
	read7753(unsigned char type,unsigned char databit) 从ADE758读出一个寄存器的数据 
2、ADE7758应用层操作函数: 
	write7753a(unsigned char type,unsigned int wdata,unsigned char databit) 
	read7753a(unsigned char type,unsigned char databit) 
	get_data_from7758() 从ADE7758中读出所需的电参量 
		硬件要求 
BIT 0022H.2 0000H.2 UNIT ?BI?ADE7758 
DATA 005DH 0007H UNIT ?DT?ADE7758 
XDATA 0000H 01AEH UNIT ?XD?ADE7758 
******************************************************************************************************************/ 

#include "reg52.h" 
#include "intrins.h" 
#include "surge.h" 
#include "rs232.h" 
#include "25045.h" 
#include "r_wIAP.h" 

#define PARAMETER 17 //将电能寄存器中的值转换成实际电能值的计参数 

#define uchar unsigned char 
#define uint unsigned int 
#define ulong unsigned long 
//key value table 
#define KeyUp 0xfd 
#define KeyDown 0xfb 
#define KeyEnter 0xf7 
#define KeyCancel 0xef 
//eerom address define 
#define EEROM_ADD_TAE 10 //5bytes first:flag,second to five:data 
#define EEROM_ADD_TVAE 16 // 5bytes first:flag,second to five:data 
#define EEROM_ADD_DATE 22 //存放开始计电能 的日期时间地址,连续6个字节 
//eerom address of saveing parameter 
#define EEROM_ADD_FLA 29 
#define EEROM_ADD_PAR 30 //存放参数的起始地址,第间二个字节存放一个12BIT参数 
#define EEROM_ADD_CRC 90 //存放参数的校验和 
//save ok define 
#define SAVE_OK 0XAA //接下来四个字节的数据有效标志 



//register name address length 

//read only register 
#define ADD_AWATTHR 0X01 //16 Phase A Watt-Hour accumulation 
#define ADD_BWATTHR 0X02 //16 Phase B Watt-Hour accumulation 
#define ADD_CWATTHR 0X03 //16 Phase C Watt-Hour accumulation 

#define ADD_AVARHR 0X04 //16 Var-Hour accumulation register for phase A 
#define ADD_BVARHR 0X05 //16 Var-Hour accumulation register for phase b 
#define ADD_CVARHR 0X06 //16 Var-Hour accumulation register for phase c 

#define ADD_AVAHR 0X07 //16 
#define ADD_BVAHR 0X08 //16 
#define ADD_CVAHR 0X09 //16 


#define ADD_AIRMS 0X0A //24 Current register 
#define ADD_BIRMS 0X0B //24 
#define ADD_CIRMS 0X0C //24 

#define ADD_AVRMS 0X0D //24 Voltage register 
#define ADD_BVRMS 0X0E //24 
#define ADD_CVRMS 0X0F //24 
//end of read only register 
#define ADD_COMPMODE 0x16 //8 R/W DEFAULT VALUE 0x1C 

#define ADD_MASK 0X18 //24 R/W IRQ Mask register,determines if an interrup event will generate an active-low output at IRQ pin 

#define ADD_RSTATUS 0X1A //24 READ ONLY,CLEANED ZERO after a read operation 


#define ADD_GAIN 0X23 //8 R/W 0~1bit used to select the Gain of the current channels inputs 

#define ADD_WDIV 0X42 //8 R/W Active Energy register divider 
#define ADD_VARDIV 0X43 //8 R/W Apparent Energy register divider 
#define ADD_VADIV 0X44 //8 R/W Apparent Energy register divider 

#define ADD_FREQ 0X10 //12 Read only,frequency of the line input estimated by zero-crossing processing 


#define ADD_LCYCMODE 0X17 //8 R/W bit7 
#define ADD_MMODE 0X14 //8 R/W bit01 
/////////////////////////////////////////////////////////////////////////////////////////// 
#define BaseAdd 41 

extern bit bit_1s; //1s钟标志,在时钟中断函数中置位 

void clean_energy(void); 
void check_ade7758(void); 
/////////////////////////////////////////////////////////////////////////////////////////// 
// MCU与ADE7758的接口函数 // 
/////////////////////////////////////////////////////////////////////////////////////////// 

//接口信号线 
sbit CSADE7753_A = P1^5;//ADE7758的片选信号 
sbit SSDO = P1^7; 
sbit SSCK = P1^3; 
sbit SSDI = P1^4; 
//接口信号线 

/***************************************************************************************** 
延时函数 
时间:40uS 
******************************************************************************************/ 
void delay10us() 
{ 
	uchar loop; 
	for(loop = 0;loop < 10;loop ++) 
	{ 
		_nop_(); 
	} 
} 

/****************************************************************************************** 
7758写数据函数 
入口参数:type:目标寄存器的地址 
wdata:写进寄存器的内容 
databit:目标寄存器的宽度 
出口参数:NULL 
返回值:NULL 
******************************************************************************************/ 
void write7753(unsigned char type,unsigned int wdata,unsigned char databit) 
{ 
		unsigned char loop = 0; 

		type = type &amt; //0x7F; 
		type = type | 0x80; 
		for(loop = 0; loop < 8; loop++) 
		{ 
			SSCK = 1; 
			_nop_(); 
			SSDI = type &amt; //0X80;  下降沿写入
			_nop_(); 
			SSCK = 0; 
			_nop_(); 
			type = (type << 1); 
		}//end of for() 

		delay10us(); 

		for(loop = 0; loop < databit; loop++) 
		{ 
			SSCK = 1; 
			_nop_(); 
			SSDI = wdata &amt; 0X8000; 
			_nop_(); 
			SSCK = 0; 
			_nop_(); 
			wdata = (wdata << 1); 
		}//end of for() 

}//end of write7753() 

/******************************************************************************************* 
7758写寄存器函数 
入口参数:type:目标寄存器的地址 
databit:目标寄存器的宽度 
出口参数:指定寄存器的内容 
返回值:指定寄存器的内容 
********************************************************************************************/ 
unsigned long read7753(unsigned char type,unsigned char databit) 
{ 
	unsigned char loop = 0; 
		unsigned long rtdata = 0; 
	//ade7758 7 bits address 
	//ade7754 6 bits address 
	type = type &amt; 0x7F; 
	type = type | 0x00; 
	for(loop = 0;loop < 8;loop ++) 
	{ 
		SSCK = 1; 
		_nop_(); 
			SSDI = type &amt; 0X80; 
		_nop_(); 
		SSCK = 0; 
		_nop_(); 
		type = (type << 1); 
	} 
	delay10us(); 
	for(loop = 0;loop < databit;loop ++) 
	{ 
		SSCK = 1; 
		_nop_(); 
		rtdata = (rtdata << 1); //上升沿读出数据
		if(SSDO) rtdata += 1; 
		_nop_(); 
		SSCK = 0; 
		_nop_(); 
	} 
	return(rtdata); 
}//end of read7753() 

/***************************************************************** 
7758写数据函数 
入口参数:type:目标寄存器的地址 
wdata:写进寄存器的内容 
databit:目标寄存器的宽度 
出口参数:NULL 
返回值:NULL 

注意写入数据的数据类型对写入数据的影响,参数:wdata 
wdata数据类型为整型,2个字节当形参的实参为字符型,1个字节时要先将 
它强制转换为整型再左移8位,databit为8。当wdata字长为12位时,必须先 
将它扩展为16位,并且第一字节的高半字节无任何意义. 
******************************************************************/ 
void write7753a(unsigned char type,unsigned int wdata,unsigned char databit) 
{ 
//EA = 0;//disable interrupt 
	CSADE7753_A = 1; 
	SSCK = 0; 
	SSDI = 0; 
	SSDO = 0; 
	CSADE7753_A = 0; 
	write7753(type,wdata,databit); 
	CSADE7753_A = 1; 
//EA = 1;//enable interrupt 
}//end of write7753a() 

/******************************************************************************************* 
7758写寄存器函数 
入口参数:type:目标寄存器的地址 
databit:目标寄存器的宽度 
出口参数:指定寄存器的内容 
返回值:指定寄存器的内容 

该函数与 read7753(unsigned char type,unsigned char databit)的区别在于操作ADE7758之前先确定一下 
SPI接口的各个状态,所以当需要从ADE7758中读出一个数据时不要直接调用 
read7753a(unsigned char type,unsigned char databit)而是直接调用本函数。 
********************************************************************************************/ 
unsigned long read7753a(unsigned char type,unsigned char databit) 
{ 
	unsigned long rtdata = 0; 
	//EA = 0;//disable interrupt 
	CSADE7753_A = 1; 
	SSCK = 0; 
	SSDI = 0; 
	SSDO = 0; 
	CSADE7753_A = 0; 
	rtdata = read7753(type,databit); 
	CSADE7753_A = 1; 
	//EA = 1;//enable interrupt 
	return(rtdata); 
}	//end of read7753a() 



/*************************************************************************************************************** 
从ADE7758中读出所有的电参量,并做相应的处理 
因为本模块起始是用P89C51RC2HBP芯片,由于没有扩展数据存储器,资源有限,为了充分利用有限的资源,设计了以下的共用体 
数据结构。 
功能: 
1、在校准模式下:从ADE7758中读取电压电流和功率值,并发给上位机,上位机运算后再校准参数发回来(通讯方面请参考RS232模块) 
2、在正常工作模式下:读取电压电流电能值等电参量,并等待上位机发指令读取。电参量就存放于以下共用体中。 

注:在MCS51单片机中,共用体数据的存放与386机器有点区别,MCS51的一个共用体中高位地址存放高位数据,低位地址存放低位数据 
386机器刚好相反。所以在使用共用体与上位机通讯时要注意这个问题。 
****************************************************************************************************************/ 
#define DIVI_VALUE 30000 //30千瓦以上时,将分频器重新设值 
#define ERR_VOLTAGE 250 //当ADE7758受干扰导校准参数混乱而检测不准 

//整型数和字符型数的共用体 
union int_char 
{ 
	uint data16; 
	uchar data8[2]; 
}; 

//长整型数和字符型数的共用体 
union long_char 
{ 
	ulong data32; 
	uchar data8[4]; 
}; 

//通讯时的信息头结构(MODBUS协议头) 
struct com 
{ 
	uchar local_add;//本机地址 

	uchar funtion_code;//功能码 

	uchar reg_num;//寄存器个数 
}; 

//保存所有处理过的从7758中来的电参量,也是一个在正常模式下的通讯发送缓冲区 
struct all_data 
{ 
	struct com com_head;//通讯时的响应帧的开头 3bytes 

	union int_char voltage[4];//三相电压值 + 平均值 8bytes 

	union int_char voltageLL[4];//三相线电压压值 + 平均值 8bytes 

	union int_char current[4];//三相电流值 + 平均值 8bytes 

	union int_char watt[4];//三相有功功率,最后一个是三相总和 8bytes 

	union int_char var[4];//三相无功功率,最后一个是三相总和 8bytes 

	union int_char va[4];//三相视在功率,最后一个是三相总和 8bytes 

	union long_char watt_hour[4];//三相有功电能值,最后一个是三相总和,初始化时应该将E2PROM中的数据读出来。16bytes 

	union long_char var_hour[4];//三相无功电能值,最后一个是三相总和 16bytes 

	union long_char va_hour[4];//三相视在电能值,最后一个是三相总和 16bytes 

	union int_char sys_hz;//系统频率 2bytes 

	union long_char surge;//浪涌个数 4bytes 

	union int_char com_crc;//通讯时存放校验和 2bytes 

//整个结构体的长度为95字节 //+12bytes 
}; 

//在校准模式下的只读寄存器内容,与上面的结构体内存共用 
struct adjust_datar 
{ 
	struct com com_head;//通讯时的响应帧的开头 

	union long_char voltage[3]; 

	union long_char current[3]; 

	union int_char watt[3]; 

	union int_char var[3]; 

	union int_char va[3]; 

	union int_char com_crc;//通讯时存放校验和 
//以上部分不只作为只读数据缓冲,还作为校准模式下的通讯缓冲,总长度为:3+36+2+6 
}; 

//在校准模式下的只写寄存器内容,与上面的结构体内存共用 
struct adjust_dataw 
{ 
		union int_char voltage[3]; 

		union int_char current[3]; 

		union int_char watt[3]; 

		union int_char var[3]; 

		union int_char va[3]; 

		//总长度为:30字节 
}; 


//在校准模式下存放电参量的原始数据 
struct adjust_data 
{ 
		struct adjust_dataw write_data;//存放修正参数,最后将写入E2PROM 30 

		struct adjust_datar read_data;//存放原始数据 

}; 

//存放正常模块和校准模式下的数据,采用共用体以节省存储空间 
union all 
{ 
		struct all_data working;//正常工作模式下存放的电参量 95 

		struct adjust_data adjusting;//校准模式下存放的数据 65 

		uint serie_data16[47]; //连续的数据16位 94 
		
		uchar serie_data8[107]; //连续的数据8位 95 

		uchar serie1_data8[41]; //连续的数据8位,communication 41 

}xdata rwdata; 
//整个结构体的长度为107字节 

uchar data counter[3] = {0,0,0};//滤波计数器 
		union long_char xdata energy[9];//用于累加电能值 36 

		unsigned long xdata i_buffer[5][3]; //用于原始电压电流的积分虑波 
		unsigned long xdata v_buffer[5][3]; 

		union int_char xdata vo_buffer[5][3];//用于电压电流的积分虑波 36 
		union int_char xdata io_buffer[5][3];//用于电压电流的积分虑波 36 

		bit b_clean_en = 0;//能量清除标志 
		extern bit bWorkModel;//工作模式标志位 1:校准模式;0:正常工作模式;启动时检测键盘口状态,确定该位状态 
		extern bit bit_3s; 

		uchar sample_cycle = 0; //电压采样周期,5次取平均 
		uchar sample_cycle1 = 0; //电压采样周期,5次取平均 

		uchar data divider = 1;//电能分频器,默认值为零,视在功率超出一定值时,自动将该值提高 

/**************************************************************** 
从ADE7758中取出三相电压电流功率等电参量 
*****************************************************************/ 

void get_data_from7758() 
{ 
	union long_char temp_data[9];//存放运算过程的中间变量 
	uchar i,j; 
	long idata temp_v,temp_i; 
	
	if( bSendingData ) 
	return; 

	if( !bWorkModel ) 
	{//正常工作模式 

	if( bit_1s ) 
	{ 
		bit_1s = 0; 
		//有功 
		temp_data[ADD_AWATTHR - 1 ].data32 = read7753a(ADD_AWATTHR,16); 
		temp_data[ADD_BWATTHR - 1 ].data32 = read7753a(ADD_BWATTHR,16); 
		temp_data[ADD_CWATTHR - 1 ].data32 = read7753a(ADD_CWATTHR,16); 
		//无功 
		temp_data[ADD_AVARHR - 1 ].data32 = read7753a(ADD_AVARHR,16); 
		temp_data[ADD_BVARHR - 1 ].data32 = read7753a(ADD_BVARHR,16); 
		temp_data[ADD_CVARHR - 1 ].data32 = read7753a(ADD_CVARHR,16); 
		//视在 
		temp_data[ADD_AVAHR - 1 ].data32 = read7753a(ADD_AVAHR,16); 
		temp_data[ADD_BVAHR - 1 ].data32 = read7753a(ADD_BVAHR,16); 
	temp_data[ADD_CVAHR - 1 ].data32 = read7753a(ADD_CVAHR,16); 
	
	for( i = 0; i < 9 ; i++) 
	{ 
	if( temp_data[ i ].data32 > 0x7fff ) 
	temp_data[ i ].data32 = 0xffff - temp_data[ i ].data32 + 1; 
	}//end of for( i = 0; i < 9 ; i++) 
	
	if( divider > 1) 
	{ 
	for( i = 0; i < 9; i++) 
	temp_data[ i ].data32 = temp_data[ i ].data32 * divider;//乘上分频器的值 
	
	}//end of if(divider != 0) 
	
	
	///////////////////////////////////////////////////////////////////////////////// 
	//能量的计算 
	for( i = 0; i < 9; i++) 
	energy[i].data32 += temp_data[i].data32;//累加电能值,单位为 WS(瓦秒) 
	
	//转换成千瓦时 
	for( i = 0; i < 3; i++) 
	{ 
	rwdata.working.watt_hour[i].data32 += (energy[i].data32 / 3600000);//转换成千瓦时 
	energy[i].data32 = energy[i].data32 > 3600000; 
	
	}//end of for(i) 
	rwdata.working.watt_hour[3].data32 = rwdata.working.watt_hour[0].data32 
	+ rwdata.working.watt_hour[1].data32 
	+ rwdata.working.watt_hour[2].data32;//总和 
	// 
	for( i = 0; i < 3; i++) 
	{ 
	rwdata.working.var_hour[i].data32 += (energy[ i+3 ].data32 / 3600000);//转换成千瓦时 
	energy[ i+3 ].data32 = energy[i+3].data32 > 3600000; 
	
	}//end of for(i) 
	rwdata.working.var_hour[3].data32 = rwdata.working.var_hour[0].data32 
	+ rwdata.working.var_hour[1].data32 
	+ rwdata.working.var_hour[2].data32;//总和 
	
	//转换成千伏安时 
	for( i = 0; i < 3; i++) 
	{ 
	rwdata.working.va_hour[i].data32 += (energy[ i+6 ].data32 / 3600000);//转换成千瓦时 
	energy[ i+6 ].data32 = energy[i+6].data32 > 3600000; 
	
	}//end of for(i) 
	rwdata.working.va_hour[3].data32 = rwdata.working.va_hour[0].data32 
	+ rwdata.working.va_hour[1].data32 
	+ rwdata.working.va_hour[2].data32;//总和 
	//能量的计算结束 
	///////////////////////////////////////////////////////////////////////////////// 
	
	
	///////////////////////////////////////////////////////////////////////////////// 
	//功率的计算 
	
	for( rwdata.working.watt[ 3 ].data16 = 0, i = 0; i < 3; i++ ) 
	{ 
	rwdata.working.watt[ i ].data16 = ( temp_data[ i ].data32 )/1000;//千瓦 
	rwdata.working.watt[ 3 ].data16 += rwdata.working.watt[ i ].data16; 
	}//end of for(i) 
	
	for( rwdata.working.var[ 3 ].data16 = 0, i = 0; i < 3; i++ ) 
	{ 
	rwdata.working.var[ i ].data16 = ( temp_data[ i +3 ].data32 )/1000;// 
	rwdata.working.var[ 3 ].data16 += rwdata.working.var[ i ].data16; 
	}//end of for(i) 
	
	for( rwdata.working.va[ 3 ].data16 = 0, i = 0; i < 3; i++ ) 
	{ 
	rwdata.working.va[ i ].data16 = ( temp_data[ i + 6 ].data32 )/1000;//千伏安 
	
	if(rwdata.working.va[ i ].data16 < rwdata.working.watt[ i ].data16) 
	{ 
	rwdata.working.va[ i ].data16 = rwdata.working.watt[ i ].data16; 
	}//end of if(rwdata.working.va[ i ].data16 < rwdata.working.watt[ i ].data16) 
	
	rwdata.working.va[ 3 ].data16 += rwdata.working.va[ i ].data16; 
	}//end of for(i) 
	
	//功率的计算结束 
	///////////////////////////////////////////////////////////////////////////////// 
	
	}//end of if(bit_1s) 
	
	
	
	for( j = 0; j < 3; j++) 

⌨️ 快捷键说明

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