ATT7022CU和ATT7022EU三相电力测量芯片使用心得


前言

        机缘巧合之下接触了这两款三相电力计量芯片,在使用之初并没有太多的思考他们的后缀CU和EU,自以为和别的芯片一样只是后缀不同可以互相替代。在后来不断的查找资料翻阅数据手册才发现这两款芯片的引脚定义有差异,供电电压也有差异,网络上能够找到的与之相关的资料也是很少,故作此篇与众君共享。


一、两款芯片的异同

1.相同点

        两款芯片都可以用于三相三线或三相四线电能测量(包括电流、电压、功率、功率因数等),都使用SPI和外部MCU进行通讯,封装都是LQFP44。

2.不同点

        ATT7022EU的芯片供电电压是3.3V,ATT7022CU的芯片供电电压是5V,这会导致SPI通讯时需要注意到电平转换的问题,例如外部MCU的SPI电平是3.3V,那么他和ATT7022EU通讯是没有问题的,但是用他和ATT7022CU进行SPI通讯那么就会出现问题了,此时就需要用到一个电平转换装置将电平统一。

        其次EU需求的是5.5296MHz的晶振,SPI通讯速率最大为10Mbps,而CU需求的是24.576MHz的晶振,晶振使用不当也会导致SPI通讯失败。

        最后他们的引脚号也是有些不同的,主要集中在 11、21、22、30、31、32、33号引脚。

图1. ATT7022EU引脚封装图

图2. ATT7022CU引脚封装图

二、实际电路应用

1.参考设计

        这里主要用到了STM32F103C8T6最小系统板和ATT7022CU做的这个三相电能计量模块。

2.读程序设计

#include "ATT7022.h" 
#include "delay.h"
#include "stdio.h"
#include "stm32f10x_spi.h"
 

static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;


void ATT7022C_INIT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  , ENABLE);
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2  , ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  // PB12 推挽 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
 	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
	
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
	
	
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//设置为软件模式有什么作用?NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}






void ATT7022Reset_Hard(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_8);
	Delay_ms(20);
  GPIO_SetBits(GPIOA,GPIO_Pin_8);
	Delay_ms(20);
}



/*******************************************************************************************************
** 函数: SPI2_ReadWrite, SPI发送一个字节,同时接收一个字节
**------------------------------------------------------------------------------------------------------
** 参数: dat 发送数据 
** 返回: 接收数据
*******************************************************************************************************/


unsigned char SPI2_ReadWrite(const unsigned char  dat)
{
	SPITimeout = SPIT_FLAG_TIMEOUT;
    /* 等待发送缓冲区为空,TXE事件 */
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
    {
        if ((SPITimeout--) == 0)
            return 0;
    }
    SPI2->DR = dat;

    SPITimeout = SPIT_FLAG_TIMEOUT;
    /* 等待接收缓冲区非空,RXNE事件 */
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
    {
        if ((SPITimeout--) == 0)
            return 1;
    }

    return SPI2->DR;
}



/*------------------------------------ATT7022---------------------------------------*/
					

// ATT7022校准数据
static Energy_t	s_tEmt = {0};
struct ReviseTypeDef	RTS ={0}; 
// ATT7022校准数据
static Revise_t	s_tRts ={0xDC,{1.51,1.51,1.67},{33.5,34.3,34.3}};  


/*******************************************************************************************************
** 函数: Att7022GpioInit,  ATT7022  GPIO初始化
**------------------------------------------------------------------------------------------------------
** 参数: NULL
** 返回: NULL
********************************************************************************************************/
void ATT7022GpioInit(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	//------------------------------------------------------------------------------------------------
	// 配置IO和时钟	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB , ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ;					// RESET复位
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 ;					// CS使能
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/*******************************************************************************************************
** 函数: ReadData_ATT7022,  读参数寄存器
**------------------------------------------------------------------------------------------------------
** 参数: addr:被读数据的地址(最高位为0)	
** 返回: temp:读出数据(24位) 
********************************************************************************************************/
unsigned long AttReadData(unsigned char addr)
{
	unsigned long temp=0;
	ATTCS=0;
	ATT_SPI_ReadWrite(addr&0x7f);
	Delay_us(20);						// SPI时钟频率过高,读数据时需要等待2us
	temp=(temp<<8)|ATT_SPI_ReadWrite(0);
	temp=(temp<<8)|ATT_SPI_ReadWrite(0);
	temp=(temp<<8)|ATT_SPI_ReadWrite(0);
	ATTCS=1;
	Delay_us(20);
	return temp;   							 		
}

/*******************************************************************************************************
** 函数: WriteData_ATT7022,  写入命令或校表数据
**------------------------------------------------------------------------------------------------------
** 参数: addr:被写数据的地址 dat 被写的数据
** 返回: void 
********************************************************************************************************/
void WriteData_ATT7022(unsigned char addr,unsigned long dat)
{	  
	ATTCS=0;
	ATT_SPI_ReadWrite(addr|0x80);
	ATT_SPI_ReadWrite(dat>>16);
	ATT_SPI_ReadWrite(dat>>8);
	ATT_SPI_ReadWrite(dat>>0);
	ATTCS=1;
}


/*******************************************************************************************************
** 函数: AttVarInit, ATT7022寄存器配置
**------------------------------------------------------------------------------------------------------
** 参数: NOLL
** 返回: NOLL
********************************************************************************************************/
void ATT7022VarInit(void)
{	
	WriteData_ATT7022( 0xC3,0x000000); 							// 清校表数据
	WriteData_ATT7022( 0xC9,0x00005A); 							// 打开校准数据写
	WriteData_ATT7022( 0x01,0xB97E);							// 模式配置寄存器
	WriteData_ATT7022( 0x03,0xF804);							// EMU 单元配置寄存器
	WriteData_ATT7022( 0x31,0x3427);							// 模拟模块使能寄存器
	WriteData_ATT7022( 0x6D,0xFF00); 							// Vrefgain 的补偿曲线系数
	WriteData_ATT7022( 0x6E,0x0DB8); 							// Vrefgain 的补偿曲线系数
	WriteData_ATT7022( 0x6F,0xD1DA); 							// Vrefgain 的补偿曲线系数
	WriteData_ATT7022( 0x16,0x0000);							// 无功相位校正寄存器
	WriteData_ATT7022( 0x1E,HFconst);							// HFConst高频脉冲参数校准
	WriteData_ATT7022( 0xC9,0x0001); 							// 关闭校准数据写
// 	printf("%x\n\n",(u32)AttReadData(0));						// 测试指令 打印 7122A0 芯片工作 SPI通信正常
}


void Att7022Init(void)
{
	ATT7022C_INIT();
	ATT7022GpioInit();
//	ATT7022VarInit();
}


/*******************************************************************************************************
** 函数: AttGetVolue 
**------------------------------------------------------------------------------------------------------
** 参数: addr 地址 
** 返回: 有符号数据
********************************************************************************************************/
long AttGetVolue( unsigned char Value)
{	
	long temp;
	temp=AttReadData(Value);
	if(AttReadData(0X2d)!=temp) return -1;
	if(temp&0x800000) temp = 0x1000000 - temp ;  
	return temp;
}

/*******************************************************************************************************
** 函数: AttGetUnVolue 
**------------------------------------------------------------------------------------------------------
** 参数: addr 地址 
** 返回: 无符号数据
********************************************************************************************************/
long AttGetUnVolue(  unsigned char Value)
{	
	long temp;
	temp=AttReadData(Value);
	if(AttReadData(0X2d)!=temp) return -1;
	return 	temp;
}



/*******************************************************************************************************
** 函数: AttGetAllVolue, 获取ATT7022UE内部电能计量值
**------------------------------------------------------------------------------------------------------
** 参数: Energy_t *dat
** 返回: NONE
********************************************************************************************************/
void AttGetAllVolue( void )
{	
	//----------------------------------------------------------------------------------------------- 
	// 单相用电器电能参数采集
	s_tEmt.dMU [ItemA]   = AttGetVolue(VOLTAGE+ItemA)/UKrmsA;				   		// A相电压
	s_tEmt.dMI [ItemA]   = AttGetVolue(CURRENT+ItemA)/IKrmsA;				  		// A相电流
	s_tEmt.dMP [ItemA]   = AttGetVolue(POWERS+ItemA)*KCoefficient;					// A相有功功率
	s_tEmt.dMQ [ItemA]   = AttGetVolue(QPOWERS+ItemA)*KCoefficient;		   			// A相无功功率
	s_tEmt.dMPF[ItemA]   = AttGetVolue(PF+ItemA)/8388608.0;				   			// A相功率因数
	s_tEmt.dwMPoEpt[ItemA] = AttGetUnVolue(EP+ItemA);								// A相有功电能
	s_tEmt.dwMQoEpt[ItemA] = AttGetUnVolue(EQ+ItemA);								// A相无功电能
	
	//----------------------------------------------------------------------------------------------- 
	// 总电能参数采集
	s_tEmt.dMF  = AttGetVolue(FREQUENCY)/8191.0;									// 总频率
	s_tEmt.dMP [ItemALL]   = AttGetVolue(POWERS+ItemALL)*KCoefficient*2;			// 总有功功率
	s_tEmt.dMQ [ItemALL]   = AttGetVolue(QPOWERS+ItemALL)*KCoefficient*2;			// 总无功功率
 	s_tEmt.dMPF[ItemALL] = AttGetVolue(PF+ItemALL)/8388608.0;						// 总功率因数
	s_tEmt.dwMPoEpt[ItemALL] = AttGetUnVolue(EP+ItemALL);							// 总有功电能
	s_tEmt.dwMQoEpt[ItemALL] = AttGetUnVolue(EQ+ItemALL);							// 总无功电能
}


void Appear_U_Data (void){	printf("电压:%0.1fV\n",s_tEmt.dMU[ItemA]);}
void Appear_I_Data (void){	printf("电流:%0.3fA\n",s_tEmt.dMI[ItemA]);}
void Appear_P_Data (void){	printf("有功功率:%0.1fW\n", s_tEmt.dMP[ItemA]-0.3);}
void Appear_Q_Data (void){	printf( "无功功率:%0.1fVar\n", s_tEmt.dMQ[ItemA]);}
void Appear_F_Data (void){	printf("频率:%0.1fHz\n",s_tEmt.dMF);}


void PutAllData(void)
{
	printf("-----------------电源线参数-----------------------\n");
	Appear_U_Data();		// 串口显示 电压数据
	Appear_I_Data();		// 串口显示 电流数据
	Appear_P_Data();		// 串口显示 有功功率数据
	Appear_Q_Data();		// 串口显示 无功功率数据
	Appear_F_Data();    	// 串口显示 频率
	
	printf("\n\n");
}

总结

        网络上的ATT7022EU资料相对多一些,不过在看懂了数据手册后,两者之间的异同也就了解了,使用起来也就大同小异。

含程序、硬件设计及开发使用手册。 计量  提供全波、基波有功电能,5000:1 动态范围内,非线性误差<0.1%,满足 0.5S 0.2S 级有功电能表精度要求  提供全波、基波无功电能,5000:1 动态范围内,非线性误差<0.1%  提供全波、基波视在电能  提供有功、无功功率方向,支持无功四象限判断  具有潜动启动功能,启动阈值可调  电表常数可调  提供有功、无功、视在的快速脉冲计数  提供全波、基波,有功、无功视在脉冲输出  测量  提供全波基波有功、无功、视在功率  提供全波、基波谐波三相电压电流有效值  提供全波、基波功率因数  提供电压线频率,测量误差<0.02%  提供各相电压电流相角,测量误差<0.02°  提供七路过零检测,过零阈值可设置  提供电压相序错检测  提供失压指示,失压阈值可设置  提供灵活的电压、电流波形缓存数据  提供电压暂降检测  提供过压、过流检测  防窃电  提供零线电流测量  提供一种低功耗模式 NVM2,用于电流比较预判,阈值 2 档可设置,功耗小于 150μA  提供一种低功耗模式 NVM1,实现低功耗电流有效值测量,功耗小于 2mA  提供全失压主动上报功能,典型应用平均功耗仅为 7μ A  软件校表  提供七路 ADC 通道增益校正  提供七路 ADC 通道相位校正,其中 A、B、C 三路电流通道支持分段相位校正  提供功率增益校正  提供有功、无功功率分段相位校正  提供有功、无功、有效值 Offset 校正  提供校验寄存器,对校表数据自动校验  适用于三相三线、三相四线制  单+3.3V 电源供电,具有电源监控功能  内置 1.25V ADC 基准电压,温度系数典型值 5ppm/℃,也可外接基准电压  具有高速 SPI 接口,传输速率可达 3.5Mbps,提供写保护功能  具有一个中断输出引脚  工作电压范围:3.0V-3.6V  工作温度范围:-40℃-85℃  采用 LQFP44 绿色封装  通过欧盟 RoHS 指令 2011/65EU 附录的修订指令(EU)2015/863 的测试需求
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

寻梦旅程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值