一、HT7017的简介:
HT7017是钜泉推出的新一代计量IC,其与钜泉推出的前几代计量IC没有实质区别。HT7017主要用于单相电表、多路电表、各种控制器、智能家居等。使用它设计的计量产品最多可满足0.5S级的计量认证。HT7017具有一路电压测量,两路电流测量(有一路是用来防窃电的),串口通讯。可以输出电压、电流、有功功率、无功功率、视在功率、有功电能、无功电能、频率等参数。芯片支持宽电压, 工作电压范围是 3.0 ~5.5V。工作晶振为 6MHz。
二、HT7017的原理图设计:
2.1、电压、电流采样电路:如下图,电流采用5A/5mA电流互感器,在5A输入时将两个16欧姆的电阻取样,采样电压为160mV(注意额定电流下采样电压一般不要超过300mV)。电压采用6个330K的电阻与两个1K的分压,取样值为220mV,注意330K电阻最好用1206封装的,电压耐压值低会被击穿。

2.2、IC外围电路:如图晶振为6MHZ,AVCC与VCC之间用10欧普电阻。注意该芯片的模拟地与数字地之间不要分地,否则抗干扰性能会变差。

2.3、光耦隔离电路:出于安规需要,我们设计的时候将计量部分与单片机用光耦隔开的,由于该芯片通信波特率较低,仅为4800 E81,所以用一般的817光耦足矣

三、寄存器介绍:
3.1、EMU寄存器:寄存器的配置值为:0x3400;Energy配置为读后清零,方便在单片机RAM中进行电能累加。有功、无功电能均配置为绝对值和型,防止用户把设备穿心反向接反。


3.2、GP1寄存器:GP1寄存器是第1通道功率增益校准寄存器,配置了这个寄存器有功功率、无功功率、视在功率的值即被校准。按照表下的公式计算校准参数即可,校准时需要用标准源加标准信号与从寄存器的值进行运算,用标准源加额定电压、电流信号,相角为0°。

3.3、I1EMSOFFSET寄存器,该寄存器为电流零点校准寄存器,在不加负载电流时读出寄存器的值进行校准。一般情况下该寄存器不许校准。


3.4、GPhs1:相角校正寄存器,该寄存器的校正需要标准源加60度的电压、电流标准信号时进行。该寄存器需要在GP1校准完后进行。

3.5、SumChecksum:配置参数校验和寄存器,该寄存器是实时自动更新的。用于配置参数的校验和计算,初始化时读取该校验和放到RAM中,后面在运行时经常读取该值与RAM中的值比较以判断是否配置参数出现错乱。计量芯片在遇到强干扰或电压不稳等情况时内部的校准参数或错乱造成计量不准确,所以要经常读取该校验和与单片机RAM中的校验和做对比。

3.6、电压、电流增益:由于这个计量芯片没有专门的电压电流校准增益寄存器,所以需要将标准的电压电流与从寄存器中读出测量的电压电流进行对比计算出一个系数并保存起来。将从寄存器中读出的电压电流乘以该系数既得到实际的电压电流。
四、读写操作
4.1、写操作:如下图所示,写操作的格式后面要等待一个ACK信号。

4.2、读操作:读操作的命令比较“操蛋”,要先发HEAD与CMD这两个字节,然后等待计量芯片恢复数据及校验和。这就要求单片机串口通讯阻塞式的等待,而通讯波特率只有4800这么慢,很浪费时间呀,尤其是由需要实时响应的产品。这么做很影响响应的及时性。


五、编程
5.1、读操作驱动程序:采用了阻塞式读取的方式,包含了校验和计算
/* 功能描述: 从HT7017内读计量参数 输入参数: addr: 寄存器地址 *para: 读取数据 返回参数: 返回从寄存器中读取的值,入股该值为0xf,则表示读取错误 函数说明: */ //uint8_t Read_Reg(uint8_t addr, uint32_t *para) uint32_t Read_Reg_blocking(uint8_t addr) { uint8_t comBuf[10]; //通讯帧数据缓冲区 uint8_t i, sum; uint8_t result; uint32_t para; comBuf[0] = 0x6A; comBuf[1] = addr & 0x7F; for (i=0; i<3; i++) { if(HAL_OK == HAL_UART_Transmit(&huart2, comBuf, 2, 100)) { result = HAL_UART_Receive(&huart2, comBuf+2, 4, 200); if (HAL_OK==result) //UART接收处理 { sum = comBuf[0] +comBuf[1] +comBuf[2] +comBuf[3] +comBuf[4]; sum = ~sum; if (sum == comBuf[5]) { para = comBuf[2]<<16 | comBuf[3]<<8 | comBuf[4]; return para; } } } } return 0xf; }
讯享网
5.2、写操作驱动程序:包含了等待返回的ACK确认,为0x54表示计量IC正确的收到了校准参数,否则未正确收到。
讯享网/* 功能描述: 写校表参数 输入参数: addr: 寄存器地址 para: 寄存器数据 返回参数:FALSE/TRUE 函数说明: */ uint8_t Write_Reg_blocking(uint8_t addr, uint16_t para) { uint8_t comBuf[10]; //通讯帧数据缓冲区 uint8_t i, sum; comBuf[0] = 0x6A; comBuf[1] = addr | 0x80; comBuf[2] = para>>8; comBuf[3] = para; sum = comBuf[0] +comBuf[1] +comBuf[2] +comBuf[3]; comBuf[4] = ~sum; comBuf[5] = 0x00; for (i=0; i<3; i++) { if(HAL_OK == HAL_UART_Transmit(&huart2, comBuf, 5, 100)) { if (HAL_OK==HAL_UART_Receive(&huart2, comBuf+5, 1, 100))//UART接收处理 { if (comBuf[5] == 0x54) { return 1; } } } } return 0; }
5.3、写函数程序:改程序包含了打开写保护及关闭写保护的操作,向计量IC写参数时都需要包含这些操作的
/* 功能描述: 写校表参数 输入参数: addr: 寄存器地址 para: 寄存器数据 返回参数: 函数说明: */ uint8_t Uart_Write_Reg(uint8_t addr, uint16_t para) { uint8_t temp=0; if((addr<=0x45)&&(addr>=0x40)) { Write_Reg_blocking(0x32,0xBC);//关闭计量芯片写保护 } else if((addr<=0x7c)&&(addr>=0x50)) { Write_Reg_blocking(0x32,0xA6);//关闭计量芯片写保护 } temp=Write_Reg_blocking(addr,para); Write_Reg_blocking(0x32,0x00);//开启计量芯片写保护 return temp; }
5.4、读写寄存器的地址列表及默认值
讯享网//ATT7017 计量寄存器 Register Max 32bit // 地址 寄存器名 复位值 static const struct { uint8_t addr; char* const name; uint32_t rst; }EP_RegData[] = { {0x00, "r_SPlI1", 0x000000}, {0x01, "r_SPlI2", 0x000000}, {0x02, "r_SPlU", 0x000000}, {0x03, "r_Idc", 0x000000}, {0x04, "r_Udc", 0x000000}, {0x06, "r_RmsI1", 0x000000}, {0x07, "r_RmsI2", 0x000000}, {0x08, "r_RmsU", 0x000000}, {0x09, "r_FreqU", 0x000000}, {0x0A, "r_PowerP1", 0x000000}, {0x0B, "r_PowerQ1", 0x000000}, {0x0C, "r_PowerS", 0x000000}, {0x0D, "r_EnergyP0", 0x000000}, {0x0E, "r_EnergyQ0", 0x000000}, {0x0F, "r_PeakTimer", 0x000000}, {0x10, "r_PowerP2", 0x000000}, {0x11, "r_PowerQ2", 0x000000}, {0x12, "r_MaxWave", 0x000000}, {0x15, "r_CRCChkSum", 0x000000}, {0x16, "r_BackupData", 0x000000}, {0x17, "r_ComChkSum", 0x000000}, {0x18, "r_SumChkSum", 0x000000}, {0x19, "r_EMUSR", 0x000000}, {0x1A, "r_SYSSTA", 0x000002}, {0x1B, "r_ChipID", 0x7053B0}, {0x1C, "r_DeviceID", 0x} };
//ATT7017 校表寄存器 16bit // 地址 寄存器名 复位值 置1 清0 static const struct { uint8_t addr; char *name; uint16_t rst; uint16_t set; uint16_t clr; }EC_RegData[] = { {0x30, "w_EMUIE", 0x0000, 0xFFFF, 0x0000}, {0x31, "w_EMUIF", 0x8000, 0xFFFF, 0x0000}, {0x32, "w_WPREG", 0x0000, 0xFFFF, 0x0000}, {0x33, "w_SRSTREG", 0x0000, 0xFFFF, 0x0000}, {0x40, "w_EMUCFG", 0x0000, 0xFFFF, 0x0000}, {0x41, "w_FreqCFG", 0x0088, 0xFFFF, 0x0000}, {0x42, "w_ModuleEn", 0x007E, 0xFFFF, 0x0000}, {0x43, "w_ANAEN", 0x0003, 0xFFFF, 0x0000}, {0x45, "w_IOCFG", 0x0000, 0xFFFF, 0x0000}, {0x50, "w_GP1", 0x0000, 0xFFFF, 0x0000}, {0x51, "w_GQ1", 0x0000, 0xFFFF, 0x0000}, {0x52, "w_GS1", 0x0000, 0xFFFF, 0x0000}, {0x54, "w_GP2", 0x0000, 0xFFFF, 0x0000}, {0x55, "w_GQ2", 0x0000, 0xFFFF, 0x0000}, {0x56, "w_GS2", 0x0000, 0xFFFF, 0x0000}, {0x58, "w_QPhsCal", 0xFF00, 0xFFFF, 0x0000}, {0x59, "w_ADCCON", 0x0000, 0xFFFF, 0x0000}, {0x5B, "w_I2Gain", 0x0000, 0xFFFF, 0x0000}, {0x5C, "w_I1Off", 0x0000, 0xFFFF, 0x0000}, {0x5D, "w_I2Off", 0x0000, 0xFFFF, 0x0000}, {0x5E, "w_UOff", 0x0000, 0xFFFF, 0x0000}, {0x5F, "w_PQStart", 0x0040, 0xFFFF, 0x0000}, {0x61, "w_HFConst", 0x003E, 0xFFFF, 0x0000},//0X40 {0x62, "w_CHK", 0x0010, 0xFFFF, 0x0000}, {0x63, "w_IPTEMP", 0x0020, 0xFFFF, 0x0000}, {0x64, "w_DecShift", 0x0000, 0xFFFF, 0x0000}, {0x65, "w_P1Offset", 0x0000, 0xFFFF, 0x0000}, {0x66, "w_P2Offset", 0x0000, 0xFFFF, 0x0000}, {0x67, "w_Q1Offset", 0x0000, 0xFFFF, 0x0000}, {0x68, "w_Q2Offset", 0x0000, 0xFFFF, 0x0000}, {0x69, "w_I1RMSOff", 0x0000, 0xFFFF, 0x0000}, {0x6A, "w_I2RMSOff", 0x0000, 0xFFFF, 0x0000}, {0x6B, "w_URMSOff", 0x0000, 0xFFFF, 0x0000}, {0x6C, "w_ZCrossCur", 0x0004, 0xFFFF, 0x0000}, {0x6D, "w_GPhs1", 0x0000, 0xFFFF, 0x0000}, {0x6E, "w_GPhs2", 0x0000, 0xFFFF, 0x0000}, {0x6F, "w_PFCnt", 0x0000, 0xFFFF, 0x0000}, {0x70, "w_QFCnt", 0x0000, 0xFFFF, 0x0000}, {0x71, "w_SFCnt", 0x0000, 0xFFFF, 0x0000}, {0x72, "w_ANACON", 0x0031, 0xFFFF, 0x0000}, {0x73, "w_SumChkL", 0x0000, 0xFFFF, 0x0000}, {0x74, "w_SumChkH", 0x0000, 0xFFFF, 0x0000}, {0x75, "w_MODECFG", 0x0000, 0xFFFF, 0x0000}, {0x76, "w_P1OffsetL", 0x0000, 0xFFFF, 0x0000}, {0x77, "w_P2OffsetL", 0x0000, 0xFFFF, 0x0000}, {0x78, "w_Q1OffsetL", 0x0000, 0xFFFF, 0x0000}, {0x79, "w_Q2OffsetL", 0x0000, 0xFFFF, 0x0000}, {0x7A, "w_UPeakLvl", 0x0000, 0xFFFF, 0x0000}, {0x7B, "w_USagLvl", 0x0000, 0xFFFF, 0x0000}, {0x7C, "w_UCycLen", 0x0000, 0xFFFF, 0x0000} };
5.5、计量芯片初始化函数、读取电参数函数、读写函数的中间层封装(用于程序分层)
讯享网/* 函数名称:Init_MeterIC_Reg() 功能描述:初始化计量芯片 入口参数:INT8U ad_lu:计量芯片的编号,只有一个计量芯片时此值为0; INT16U locktmp:初始化锁,防止程序跑飞误入该函数; 出口参数:MeterIC_ERROR,失败,MeterIC_OK,成功 作 者:宋Neo 2021-03-15 */ MeterIC_StatusTypeDef Init_MeterIC_Reg(INT8U ad_lu,INT16U locktmp) { INT8U i,j,numbCali; INT32U mid32u,mid32u1; if((locktmp!=Meter_int_mark)&&(ad_lu>=METERnum)) return MeterIC_ERROR; mid32u = sizeof(EC_RegData); mid32u1 = sizeof(EC_RegData[0]); mid32u /= mid32u1;//得到数组里有多少个结构体元素 j=ad_lu; numbCali = mid32u; MeterCaliPara[j].CheckSum = 0; for (i=0; i<numbCali; i++) { if(strstr(EC_RegData[i].name,"EMUCFG"))//初始化EMUCFG,电能为读后清零型,有功、无功为绝对值和 { mid32u = 0x3400; } else if(strstr(EC_RegData[i].name,"GP1"))//初始化功率增益 { mid32u = MeterCaliPara[j].P1gain; } else if(strstr(EC_RegData[i].name,"I1RMSOff"))//初始化电流零点 { mid32u = MeterCaliPara[j].I1offset; } else if(strstr(EC_RegData[i].name,"GPhs1"))//初始化移相角 { mid32u = MeterCaliPara[j].UI1COS; } else { mid32u = EC_RegData[i].rst; //非这个参数初始化入默认值 } if(Write_MeterIC_block(EC_RegData[i].addr,mid32u)==MeterIC_ERROR) return MeterIC_ERROR; if(((EC_RegData[i].addr>=0x40)&&(EC_RegData[i].addr<0x6f))||((EC_RegData[i].addr>0x74)&&(EC_RegData[i].addr<=0x7c)))//校验和区间0X40~0X7C,不包括0X6F~0X74 MeterCaliPara[j].CheckSum += mid32u; //计算24位校验和,用于实时判断校准参数是否错乱 } return MeterIC_OK; } /* 函数名称:Read_MeterIC_block() 功能描述:读取计量芯片内的寄存器值 入口参数:INT8U meter_addr:计量芯片寄存器的地址号; INT32U *meter_value:读取的值放置的指针; 出口参数:读取成功否?MeterIC_ERROR,失败,MeterIC_OK,成功 作 者:宋Neo 2021-03-15 */ MeterIC_StatusTypeDef Read_MeterIC_block(INT8U meter_addr,INT32U *meter_value) { *meter_value = Read_Reg_blocking(meter_addr); if(*meter_value == 0xf)//特殊标记字符,读上来是这个值则表示读取错误 { *meter_value = 0; return MeterIC_ERROR; } else { return MeterIC_OK; } } /* 函数名称:Write_MeterIC_block() 功能描述:写入计量芯片内的寄存器值 入口参数:INT8U meter_addr:计量芯片寄存器的地址号; INT32U meter_value:写入计量芯片的值; 出口参数:读取成功否?MeterIC_ERROR,失败,MeterIC_OK,成功 作 者:宋Neo 2021-03-15 */ MeterIC_StatusTypeDef Write_MeterIC_block(INT8U meter_addr,INT16U meter_value) { if (Uart_Write_Reg(meter_addr, meter_value) == 1) { return MeterIC_OK; } else { return MeterIC_ERROR; } }
其他详细的程序见我的下载资源,里面还包含电参数读取函数、电能累加函数、校准函数等。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/12939.html