HT7038核心板原理图
电压互感器接口板原理图
按上述原理图,我分别制作了HT7038模块板和互感器接口板。
原有51的程序可以正常读出HT7038电压数据,此次我把KEIL C51的程序移植到arduino WEMOS D1平台,
开始wemos D1可以读取 rDeviceID和rChipID数据,我就以为大功告成。可是当我读电压数据时没有任何返回数据。几经周折发现是往HT7038写命令时没有给命令最高位置1.
实际SPI写寄存器命令
现在回想调试HT7038大概步骤应该是:
1实现读取rDeviceID和rChipID数据,如果能读取到,则表明SPI通讯正常。
2向w_ModeCfg写入数据,然后再读取该寄存器的数据,看是否和写入的数据一致,如果返回的是默认值0x89AA,则表明写入不成功。
写入前应开启校表寄存器写入,
ht7038.Write7038(0xC9,0x00005A); //设置可以写入校表寄存器的参数
然后写入数据
ht7038.Write7038(w_ModeCfg,0xF954);//开启电压通道ADC ,更新速率为慢速0xF9FE
禁止校表寄存器写入
ht7038.Write7038(0xC9,0x0000FF); //关闭写校表寄存器
开启读取校表寄存器
ht7038.Write7038(0xC6,0x00005A); //设置可以读校表寄存器的参数
读取校表寄存器
Serial.println(ht7038.Read7038(w_ModeCfg),HEX);//读取校表w_ModeCfg寄存器,并返回给串口输出
具体解释见官方表格
如果写入校表寄存器成功,则读取电压电流功率等数据不成问题。
下面是arduino代码:
//2ma/2ma互感器按220V 2ma设置
#include <SPI.h>
#include "HT7038.h"
#include <BlynkSimpleEsp8266.h>
HT7038 ht7038;
BlynkTimer timer;
//#define _DEBUG;
typedef union
{
unsigned long Long_Data;
byte da[4];
}DWord;
DWord rData;
union UN_RMS{
// unsigned char volChar[4]; //电压字节数组
unsigned long volFloat; //电压浮点数
};
union UN_RMS U_rms;
float Uab;
float Ubc;
float Uac;
void SPIsendData()
{
#ifdef _DEBUG
Serial.print("rDeviceID=0x");
Serial.println(ht7038.Read7038(rDeviceID),HEX);
Serial.print(" rChipID=0x");
Serial.println(ht7038.Read7038(rChipID),HEX);
#endif
rData.Long_Data = ht7038.Read7038(rUaRms); //读取Uab电压
U_rms.volFloat=rData.Long_Data ;
Uab=(float)U_rms.volFloat/8192;
rData.Long_Data = ht7038.Read7038(rUbRms); //读取Uac电压 内部计算得出
U_rms.volFloat=rData.Long_Data ;
Uac=(float)U_rms.volFloat/8192; //长整型强制转换成浮点型,否者液晶显示数据为0
rData.Long_Data = ht7038.Read7038(rUcRms); //读取Ubc电压
U_rms.volFloat=rData.Long_Data ;
Ubc=(float)U_rms.volFloat/8192;
Serial.print("Uab=");
Serial.print(Uab);
Serial.println("V");
Serial.print("Ubc=");
Serial.print(Ubc);
Serial.println("V");
Serial.print("Uac=");
Serial.print(Uac);
Serial.println("V");
Serial.println("-------------------");
}
void setup()
{
Serial.begin(230400);
ht7038.HT7038_begin();
ht7038.HT7038_init();
delay(20);
ht7038.Write7038(0xC9,0x00005A); //设置可以写入校表寄存器的参数
ht7038.Write7038(w_ModeCfg,0xF954);//开启电压通道ADC ,更新速率为慢速0xF9FE
ht7038.Write7038(w_EMCfg,0x0003);//设置三相三线模式0x0111
ht7038.Write7038(w_EMUIE,0xFFFF);
ht7038.Write7038(w_ModuleCFG,0x3404);//0x3404
ht7038.Write7038(w_PGACtrl,0x0000); //ADC增益配置为三相电压通道ADC增益放大2倍 bit09和bit08为设置电压通道增益位
ht7038.Write7038(w_EMUCfg,0x0201); //EMU模块配置寄存器0x0201
ht7038.Write7038(w_UgainA,0x022E);//Uab电压增益
ht7038.Write7038(w_UgainC,0x022E);//Ubc电压增益
ht7038.Write7038(w_UgainB,0x022E);//Uac相电压增益需单独计算,不与A相C相相同
ht7038.Write7038(0xC9,0x0000FF); //关闭写校表寄存器
ht7038.Write7038(0xC6,0x000000); //设置可以读计量寄存器的参数
timer.setInterval(1000L, SPIsendData);
}
void loop() {
timer.run();
}
头文件代码:
#ifndef __HT7038_H__
#define __HT7038_H__
//导入Arduino核心头文件
#include"Arduino.h"
#include <SPI.h>
#define HT7038_CS D8 //针对自制的HT7038接口板
//===================================================
// 定义HT7038的数据寄存器
//===================================================
#define rDeviceID 0x00 //7038 Device ID
#define rPa 0x01 //A相有功功率
#define rPb 0x02 //B相有功功率
#define rPc 0x03 //C相有功功率
#define rPt 0x04 //合相有功功率
#define rQa 0x05 //A相无功功率
#define rQb 0x06 //B相无功功率
#define rQc 0x07 //C相无功功率
#define rQt 0x08 //合相无功功率
#define rSa 0x09 //A相视在功率
#define rSb 0x0A //B相视在功率
#define rSc 0x0B //C相视在功率
#define rSt 0x0C //合相视在功率
#define rUaRms 0x0D //A相电压有效值
#define rUbRms 0x0E //B相电压有效值
#define rUcRms 0x0F //C相电压有效值
#define rIaRms 0x10 //A相电流有效值
#define rIbRms 0x11 //B相电流有效值
#define rIcRms 0x12 //C相电流有效值
#define rItRms 0x13 //ABC相电流矢量和的有效值
#define rPfa 0x14 //A相功率因数
#define rPfb 0x15 //B相功率因数
#define rPfc 0x16 //C相功率因数
#define rPft 0x17 //合相功率因数
#define rPga 0x18 //A相电流与电压相角
#define rPgb 0x19 //B相电流与电压相角功率因数
#define rPgc 0x1a //C相电流与电压相角
#define rINTFlag 0x1b //中断标志,读后清零 ☆
#define rFreq 0x1C //线频率
#define rEFlag 0x1d //电能寄存器的工作状态,读后清零☆
#define rEpa 0x1e //A相有功电能
#define rEpb 0x1f //B相有功电能
#define rEpc 0x20 //C相有功电能
#define rEpt 0x21 //合相有功电能
#define rEqa 0x22 //A相无功电能
#define rEqb 0x23 //B相无功电能
#define rEqc 0x24 //C相无功电能
#define rEqt 0x25 //合相无功电能
#define rYUaUb 0x26 //Ua与Ub的电压夹角 ☆
#define rYUaUc 0x27 //Ua与Uc的电压夹角 ☆
#define rYUbUc 0x28 //Ub与Uc的电压夹角 ☆
#define rTPSD 0x2a //温度传感器的输出
#define rURmst 0x2b //ABC电压矢量和的有效值
#define rS_Flag 0x2c //存放断相、相序、SIG信号的有效值
#define rBackReg 0x2d //通讯数据备份寄存器☆
#define rComChksum 0x2e //通讯校验和寄存器☆
#define rSampleIA 0x2f //A相电流通道ADC采样数据☆
#define rSampleIB 0x30 //B相电流通道ADC采样数据☆
#define rSampleIC 0x31 //C相电流通道ADC采样数据☆
#define rSampleUA 0x32 //A相电压通道ADC采样数据☆
#define rSampleUB 0x33 //B相电压通道ADC采样数据☆
#define rSampleUC 0x34 //C相电压通道ADC采样数据☆
#define rEsa 0x35 //A相视在电能☆
#define rEsb 0x36 //B相视在电能☆
#define rEsc 0x37 //C相视在电能☆
#define rEst 0x38 //合相视在电能☆
#define rFstCntA 0x39 //A相快速脉冲计数☆
#define rFstCntB 0x40 //B相快速脉冲计数☆
#define rFstCntC 0x40 //C相快速脉冲计数☆
#define rFstCntT 0x41 //合相快速脉冲计数☆
#define rPFlag 0x3d //有功和无功功率方向,正向为0,负向为1
#define rChkSum 0x3e //校表数据校验寄存器(三相四线模式下是0x01D4CD;三相三线模式下是0x01E0CD;)
#define rVrefgain 0x5c //Vref自动补偿系数
#define rChipID 0x5d //芯片版本指示器0X7026E0
#define rChkSum1 0x5e //新增校表寄存器校验和
//==================================================================
// HT7038校表寄存器定义
//==================================================================
#define w_ModeCfg 0X01 //模式相关控制
#define w_PGACtrl 0X02 //ADC增益选择
#define w_EMUCfg 0X03 //EMU模块配置寄存器
#define w_PgainA 0X04 //A相有功功率增益
#define w_PgainB 0X05 //B相有功功率增益
#define w_PgainC 0X06 //C相有功功率增益
#define w_QgainA 0X07 //A相无功功率增益
#define w_QgainB 0X08 //B相无功功率增益
#define w_QgainC 0X09 //C相无功功率增益
#define w_SgainA 0X0A //A相视在功率增益
#define w_SgainB 0X0B //B相视在功率增益
#define w_SgainC 0X0C //C相视在功率增益
#define w_PhSregApq0 0X0D //A相相位校正0
#define w_PhSregBpq0 0X0E //B相相位校正0
#define w_PhSregCpq0 0X0F //C相相位校正0
#define w_PhSregApq1 0X10 //A相相位校正1
#define w_PhSregBpq1 0X11 //B相相位校正1
#define w_PhSregCpq1 0X12 //C相相位校正1
#define w_PoffsetA 0X13 //A相有功功率offset校正
#define w_PoffsetB 0X14 //B相有功功率offset校正
#define w_PoffsetC 0X15 //C相有功功率offset校正
#define w_QPhscal 0X16 //无功相位校正
#define w_UgainA 0X17 //A相电压增益
#define w_UgainB 0X18 //B相电压增益
#define w_UgainC 0X19 //C相电压增益
#define w_IgainA 0X1A //A相电流增益
#define w_IgainB 0X1B //B相电流增益
#define w_IgainC 0X1C //C相电流增益
#define w_Istarup 0X1D //起动电流阈值设置
#define w_Hfconst 0X1E //高频脉冲输出设置
#define w_FailVoltage 0X1F //失压阈值设置
#define w_QoffsetA 0X21 //A相无功功率offset校正
#define w_QoffsetB 0X22 //B相无功功率offset校正
#define w_QoffsetC 0X23 //C相无功功率offset校正
#define w_UaRmsoffse 0X24 //A相电压有效值offset校正
#define w_UbRmsoffse 0X25 //B相电压有效值offset校正
#define w_UcRmsoffse 0X26 //C相电压有效值offset校正
#define w_IaRmsoffse 0X27 //A相电流有效值offset校正
#define w_IbRmsoffse 0X28 //B相电流有效值offset校正
#define w_IcRmsoffse 0X29 //C相电流有效值offset校正
#define w_UoffsetA 0X2A //A相电压通道ADC offset校正
#define w_UoffsetB 0X2B //B相电压通道ADC offset校正
#define w_UoffsetC 0X2C //C相电压通道ADC offset校正
#define w_IoffsetA 0X2D //A相电流通道ADC offset校正
#define w_IoffsetB 0X2E //B相电流通道ADC offset校正
#define w_IoffsetC 0X2F //C相电流通道ADC offset校正
#define w_EMUIE 0X30 //中断使能
#define w_ModuleCFG 0X31 //电路模块配置寄存器
#define w_AllGain 0X32 //全通道增益,用于校正ref自校正
#define w_HFDouble 0X33 //脉冲常数加倍选择
#define w_LineGain 0X34 //基波增益校正
#define w_PinCtrl 0X35 //数字pin上下拉电阻选择控制
#define w_Pstartup 0X36 //起动功率阈值设置
#define w_Iregion0 0X37 //相位补偿区域设置寄存器
#define w_Iregion1 0X60 //相位补偿区域设置寄存器1
#define w_PhSregApq2 0X61 //A相相位校正2
#define w_PhSregBpq2 0X62 //B相相位校正2
#define w_PhSregCpq2 0X63 //C相相位校正2
#define w_PoffsetAL 0X64 //A相有功功率offset校正低字节
#define w_PoffsetBL 0X65 //B相有功功率offset校正低字节
#define w_PoffsetCL 0X66 //C相有功功率offset校正低字节
#define w_QoffsetAL 0X67 //A相无功功率offset校正低字节
#define w_QoffsetBL 0X68 //B相无功功率offset校正低字节
#define w_QoffsetCL 0X69 //C相无功功率offset校正低字节
#define w_ItRmsoffset 0X6A //电流矢量和offset校正寄存器
#define w_TPSoffset 0X6B //TPS初值校正寄存器
#define w_TPSgain 0X6C //TPS斜率校正寄存器
#define w_TCcoffA 0X6D //Vrefgain的二次系数
#define w_TCcoffB 0X6E //Vrefgain的一次系数
#define w_TCcoffC 0X6F //Vrefgain的常数项
#define w_EMCfg 0X70 //新增算法控制寄存器
//===================================================================================
class HT7038
{
private:
byte pin; //CS引脚
public:
HT7038(byte p=HT7038_CS,bool state=HIGH );
~HT7038();
void HT7038_begin();
void HT7038_init();
void disattach();
unsigned long Read7038(unsigned char rCmd);
void Write7038(unsigned char wCmd,unsigned long Dat);
};
//====================================================================================
#endif
CPP实现文件:
#include "HT7038.h"
HT7038::HT7038(byte p,bool state):pin(p)
{
pinMode(pin,OUTPUT);
digitalWrite(pin, HIGH);
}
HT7038::~HT7038()
{
disattach();
}
void HT7038::HT7038_begin()
{
SPI.begin();
digitalWrite(pin, HIGH);
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV32);
SPI.setBitOrder(MSBFIRST);
}
void HT7038::HT7038_init()
{
Write7038(0xD3,0X000000);//软件复位
}
unsigned long HT7038:: Read7038(unsigned char rCmd)
{
unsigned long buffer=0;
unsigned char dataLength=3;
unsigned char byteIndex=0 ;
unsigned char receiveBuffer = 0;
digitalWrite(pin, LOW);
SPI.transfer(rCmd); //发送命令
//接收从站返回数据,SPI.transfer(0)一次带回1个byte数据
while(byteIndex < dataLength)
{
receiveBuffer = SPI.transfer(0);
buffer = (buffer << 8) + receiveBuffer;
byteIndex++;
}
digitalWrite(pin, HIGH);
return buffer;
}
void HT7038::Write7038(unsigned char wCmd,unsigned long Dat)
{
long send;
unsigned char data[3];
typedef union
{
unsigned long Long_Data;
unsigned char da[4];
}DWord;
DWord rData;
wCmd = wCmd | 0x80; //最高位置位,表示为写操作 这句很重要
//32大端转小端原理
send = ((Dat>>24)&0xff) | // move byte 3 to byte 0
((Dat<<8)&0xff0000) | // move byte 1 to byte 2
((Dat>>8)&0xff00) | // move byte 2 to byte 1
((Dat<<24)&0xff000000); // byte 0 to byte 3
rData.Long_Data=send;
data[0]=rData.da[1];
data[1]=rData.da[2];
data[2]=rData.da[3];
digitalWrite(pin, LOW);
SPI.transfer(wCmd);
SPI.transfer(&data,3);
digitalWrite(pin, HIGH);
}
void HT7038::disattach() //引脚回收,恢复到上电状态
{
digitalWrite(pin,LOW);
pinMode(pin,INPUT);
}
C51工程文件,比较乱,但功能正常基于STC15的,其它STC单片机注意延时。
链接:https://pan.baidu.com/s/1csUBAD3v5Go8YPSeVRpK3w
提取码:vb3h