基于STM32的ATT7022E电能计量芯片完整程序实现

基于STM32的ATT7022E电能计量芯片程序实现,包含硬件初始化、数据采集、校准算法及通信模块。代码基于HAL库开发,支持SPI接口通信,适用于三相电能计量场景。


一、硬件连接与配置

1. 硬件连接表

STM32引脚 ATT7022E引脚 功能说明
PA4 CS 片选信号
PA5 SCK SPI时钟
PA6 MISO 主设备输入/从设备输出
PA7 MOSI 主设备输出/从设备输入
PB0 RST 硬件复位
PB1 INT 中断信号

2. 系统时钟配置(STM32F103)

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    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_PLL_MUL9;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    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_APB1_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

二、核心驱动代码

1. SPI通信模块

SPI_HandleTypeDef hspi1;

void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 7;
    HAL_SPI_Init(&hspi1);
}

// SPI读写函数
uint8_t SPI_WriteRead(uint8_t data)
{
    HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&hspi1, &data, &data, 1, 1000);
    return (status == HAL_OK) ? data : 0xFF;
}

2. ATT7022E驱动模块

#define ATT7022E_CS_PIN   GPIO_PIN_4
#define ATT7022E_CS_PORT  GPIOA

// 寄存器地址定义
#define REG_SYS_CTRL      0x00
#define REG_VOLTAGE_GAIN  0x0D
#define REG_CURRENT_GAIN  0x00
#define REG_ACTIVE_POWER  0x13

// 复位芯片
void ATT7022E_Reset(void)
{
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_RESET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_SET);
    HAL_Delay(100);
}

// 写入寄存器
HAL_StatusTypeDef ATT7022E_WriteReg(uint16_t regAddr, uint8_t *data, uint16_t size)
{
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_RESET);
    SPI_WriteRead((regAddr >> 8) & 0xFF);
    SPI_WriteRead(regAddr & 0xFF);
    
    for(uint16_t i=0; i<size; i++) {
        SPI_WriteRead(data[i]);
    }
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_SET);
    return HAL_OK;
}

// 读取寄存器
HAL_StatusTypeDef ATT7022E_ReadReg(uint16_t regAddr, uint8_t *data, uint16_t size)
{
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_RESET);
    SPI_WriteRead((regAddr >> 8) & 0xFF | 0x80); // 设置读模式
    SPI_WriteRead(regAddr & 0xFF);
    
    for(uint16_t i=0; i<size; i++) {
        data[i] = SPI_WriteRead(0x00);
    }
    HAL_GPIO_WritePin(ATT7022E_CS_PORT, ATT7022E_CS_PIN, GPIO_PIN_SET);
    return HAL_OK;
}

三、关键算法实现

1. 校准算法(零点校准)

void ATT7022E_Calibration(void)
{
    uint8_t calData[4] = {0};
    
    // 进入校准模式
    ATT7022E_WriteReg(0x06, (uint8_t[]){0xA5, 0x5A}, 2);
    HAL_Delay(100);
    
    // 读取校准参数
    ATT7022E_ReadReg(0x0600, calData, 4);
    
    // 计算校准系数(示例)
    float V_gain = (calData[0] << 8 | calData[1]) / 4096.0f;
    float I_gain = (calData[2] << 8 | calData[3]) / 4096.0f;
    
    // 更新校准参数
    ATT7022E_WriteReg(0x0D, (uint8_t*)&V_gain, 4);
    ATT7022E_WriteReg(0x10, (uint8_t*)&I_gain, 4);
}

2. 数据采集与转换

typedef struct {
    float voltage;    // 电压有效值 (V)
    float current;    // 电流有效值 (A)
    float power;      // 有功功率 (W)
} EnergyData;

EnergyData ATT7022E_GetData(void)
{
    EnergyData data = {0};
    uint8_t buffer[8] = {0};
    
    // 读取电压电流数据
    ATT7022E_ReadReg(0x0D, buffer, 8);
    
    // 数据转换(32位补码格式)
    int32_t V_raw = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
    int32_t I_raw = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
    
    // 转换为实际物理量
    data.voltage = (V_raw * 0.001f) * 220.0f;  // 假设额定电压220V
    data.current = (I_raw * 0.0001f) * 5.0f;   // 假设额定电流5A
    data.power = data.voltage * data.current * 0.95f; // 功率因数0.95
    
    return data;
}

四、完整应用示例

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_SPI1_Init();
    
    // 硬件初始化
    ATT7022E_Reset();
    HAL_Delay(100);
    
    // 校准流程
    ATT7022E_Calibration();
    
    while(1)
    {
        EnergyData data = ATT7022E_GetData();
        
        // 显示数据(示例)
        printf("Voltage: %.2f V\n", data.voltage);
        printf("Current: %.2f A\n", data.current);
        printf("Power: %.2f W\n", data.power);
        
        HAL_Delay(1000);
    }
}

五、调试与优化建议

  1. 通信调试

    • 使用逻辑分析仪验证SPI时序(时钟频率建议≤1MHz)
    • 检查片选信号是否稳定(低电平有效)
  2. 校准优化

    • 校准前需等待芯片稳定(建议>30秒)
    • 多点校准法:0%、50%、100%负载下分别校准
  3. 抗干扰措施

    // 添加数字滤波
    #define FILTER_DEPTH 5
    static float voltageBuffer[FILTER_DEPTH] = {0};
    
    float MovingAverageFilter(float newValue)
    {
        for(int i=0; i<FILTER_DEPTH-1; i++) {
            voltageBuffer[i] = voltageBuffer[i+1];
        }
        voltageBuffer[FILTER_DEPTH-1] = newValue;
        return (voltageBuffer[0] + voltageBuffer[1] + voltageBuffer[2] +
                voltageBuffer[3] + voltageBuffer[4]) / FILTER_DEPTH;
    }
    

参考代码 基于STM32的电量计量芯片ATT7022E的程序 www.youwenfan.com/contentcnr/56439.html

六、扩展功能实现

1. RS485通信模块

void RS485_SendData(uint8_t *data, uint16_t len)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 使能发送
    HAL_UART_Transmit(&huart1, data, len, 1000);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 切换回接收
}

2. Modbus协议封装

typedef struct {
    uint8_t addr;
    uint8_t func;
    uint16_t regAddr;
    uint16_t data;
} ModbusFrame;

void Modbus_BuildFrame(ModbusFrame *frame, uint8_t *buffer)
{
    buffer[0] = frame->addr;
    buffer[1] = frame->func;
    buffer[2] = (frame->regAddr >> 8) & 0xFF;
    buffer[3] = frame->regAddr & 0xFF;
    buffer[4] = (frame->data >> 8) & 0xFF;
    buffer[5] = frame->data & 0xFF;
    buffer[6] = CalculateCRC(buffer, 7);
}

七、参考资料

  1. ATT7022E数据手册(重点章节:寄存器映射、校准流程)
  2. STM32F103参考手册(SPI章节)
  3. 《三相电能计量技术及应用》(王兆安著)

 

专注于matlab/simulink,电子电路,编程