最近做了一个stm32与ht7038的数据采集项目
硬件包含太阳能充电电路
ht7038采集芯片电路
buck电路
stm32最小系统电路和lora模块电路
硬件PCB如下图所示
ht7038的程序如下所示ht7038.c
#include "ht7038.h"
#include "stm32l0xx_hal_spi.h"
typedef uint8_t u8;
typedef uint32_t u32;
//=================================================================
/*******************************************************************************
* Function Name : SPI1_ReadWriteByte
* Description : SPI1 read or write one byte.
* Input : TxData: write one byte data.
* Return : Read one byte data.
*******************************************************************************/
void HT7038_Write(uint8_t addr, uint32_t data)
{
uint8_t TxSend[3]; // 定义3个字节的数据 发完命令紧接着发3个数据
//列如data=0xA48CD5
TxSend[0]=(data>>16)&0xff; //先发高位 0xA4
TxSend[1]=(data>>8)&0xff; //再发中位 0x8C
TxSend[2]=(data>>0)&0xff; //先发低位 0xD5
addr=addr|0x80; //写特殊命令最高位为1 HT7036中有表明
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET);// CS=0;
HAL_SPI_Transmit(&hspi2, &addr, 1, 1000); // 发送命令
HAL_SPI_Transmit(&hspi2, TxSend, 3, 1000); // 发送3字节数据
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET); // CS=1;
}
uint32_t HT7038_Read(uint8_t addr) // 读 发1+收3
{
uint8_t ReadData[3];
uint32_t data;
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET);// CS=0;
HAL_SPI_Transmit(&hspi2, &addr, 1, 1000); // 发送读取命令
HAL_SPI_Receive(&hspi2, ReadData, 3, 1000); // 接收数据
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET); // CS=1;
data=ReadData[0]<<16 | ReadData[1]<<8 | ReadData[2];
return data;
}
void HT7038_init()
{
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET); // CS=1;
HAL_Delay(10);
HT7038_Write(0xd3,0x000000);//软件复位;
HAL_Delay(10);
HT7038_Write(0xC9,0x00005A);//允许校表
HAL_Delay(10);
HT7038_Write(0x01,0x00B97f);//慢速1.76Hz,主频172.8KHz,开启所有电压和电流转换0x00f97e
HAL_Delay(10);
HT7038_Write(0x31,0x003427);//开启电流电压滤波
HAL_Delay(10);
HT7038_Write(0xC9,0x00005f);
HAL_Delay(10);
HT7038_Write(0xC6,0x00005f);
HAL_Delay(10);
}
ht7038.h
#ifndef HT7038_H_
#define HT7038_H_
#include "stdint.h"
//#include "ch32v10x_spi.h"
#include "spi.h"
#define CS_PIN_PORT GPIOB
#define CS_PIN SPI2_CS_Pin
#define SPI_CS_Disable() HAL_GPIO_WritePin(GPIOB, SPI2_CS_Pin, GPIO_PIN_RESET)
#define SPI_CS_Enable() HAL_GPIO_WritePin(GPIOB, SPI2_CS_Pin, GPIO_PIN_SET)
//===================================================
// ??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 //新增算法控制寄存器
//===================================================================================
extern void HT7038_init(); //???HT7038
extern uint32_t HT7038_Read(uint8_t rCmd); //?HT703824????
extern void HT7038_Write(uint8_t pBuffer, uint32_t WriteAddr);
//====================================================================================
#endif /* USER_HT7038_H_ */
main.c
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include <stdbool.h>
#include "ht7038.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t rUaRms_v[4];
uint8_t rUbRms_v[4];
uint8_t rUcRms_v[4];
uint8_t rIaRms_v[4];
uint8_t rIbRms_v[4];
uint8_t rIcRms_v[4];
float temp_Ia;
float temp_Ib;
float temp_Ic;
float temp_Ua;
float temp_Ub;
float temp_Uc;
void float2u8Arry(uint8_t *u8Arry, float *floatdata, bool key)
{
uint8_t farray[4];
*(float *)farray = *floatdata;
if (key == true)
{
u8Arry[3] = farray[0];
u8Arry[2] = farray[1];
u8Arry[1] = farray[2];
u8Arry[0] = farray[3];
}
else
{
u8Arry[0] = farray[0];
u8Arry[1] = farray[1];
u8Arry[2] = farray[2];
u8Arry[3] = farray[3];
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI2_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
HT7038_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// result2[0]=HT7038_Read(rChipID)>>16;
// result2[1]=HT7038_Read(rChipID)>>8;
// result2[2]=HT7038_Read(rChipID);
//
// HAL_Delay(10);
// result1[0]=HT7038_Read(rDeviceID)>>16;
// result1[1]=HT7038_Read(rDeviceID)>>8;
// result1[2]=HT7038_Read(rDeviceID);
//
temp_Ia = (HT7038_Read(rIaRms)/8192.0f)/3;
float2u8Arry(rIaRms_v,&temp_Ia,true);
HAL_Delay(10);
temp_Ib = (HT7038_Read(rIbRms)/8192.0f)/3;
float2u8Arry(rIbRms_v,&temp_Ib,true);
HAL_Delay(10);
temp_Ic = (HT7038_Read(rIcRms)/8192.0f)/3;
float2u8Arry(rIcRms_v,&temp_Ic,true);
HAL_Delay(10);
temp_Ua = (HT7038_Read(rUaRms)/8192.0f)/3;
float2u8Arry(rUaRms_v,&temp_Ua,true);
HAL_Delay(10);
temp_Ub = (HT7038_Read(rUbRms)/8192.0f)/3;
float2u8Arry(rUbRms_v,&temp_Ub,true);
HAL_Delay(10);
temp_Uc = (HT7038_Read(rUcRms)/8192.0f)/3;
float2u8Arry(rUcRms_v,&temp_Uc,true);
HAL_Delay(10);
HAL_UART_Transmit(&huart2,(uint8_t*)rIaRms_v,4, 1000);
HAL_UART_Transmit(&huart2,(uint8_t*)rIbRms_v,4, 1000);
HAL_UART_Transmit(&huart2,(uint8_t*)rIcRms_v,4, 1000);
HAL_UART_Transmit(&huart2,(uint8_t*)rUaRms_v,4, 1000);
HAL_UART_Transmit(&huart2,(uint8_t*)rUbRms_v,4, 1000);
HAL_UART_Transmit(&huart2,(uint8_t*)rUcRms_v,4, 1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
HAL_Delay(60000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_3;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
这里记录下遇到的坑;
注意点:
1:lora模块是TTL的串口通信,遇到电压不足;lora模块电压需要5V;这样tx和rx上的通讯时候的电压为3.3V; lora模块的M0,M1模式为0,0;透传模式。
2:注意stm32的时钟;当选择外界时钟晶振时候,注意晶振不要选错;---选错后串口ttl也可以读到数据但是波特率不对,数据数量也不对。
3:注意stm32与ht7038的spi通讯----注意时钟不要设置错误;
4:注意ht7038的供电为3.3V;供电不足也带不起来芯片,数据通道读不到数据。