一、引言

在许多电子系统中,对电压和电流的精确采集至关重要。INA3221 是一款集成了三个独立的电压和电流监测通道的芯片,非常适合用于需要同时监测多个电源或电路的应用场景。结合 STM32 微控制器,我们可以方便地实现对 INA3221 的控制和数据采集。本文将详细介绍如何使用 STM32 与 INA3221 三通道电压电流采集模块进行通信和数据采集,并给出相应的代码示例。

二、INA3221 模块概述

2.1 主要特性

  • 三通道监测:可以同时监测三个不同的电源或电路的电压和电流。
  • 高精度测量:具有较高的测量精度,能够满足大多数应用的需求。
  • I²C 接口:通过 I²C 总线与微控制器进行通信,方便连接和控制。

2.2 工作原理

INA3221 通过测量分流电阻上的电压降来计算电流,同时可以直接测量电源的电压。测量数据可以通过 I²C 接口读取,用户可以根据需要配置不同的测量参数。

三、硬件连接

3.1 STM32 与 INA3221 的连接

假设使用 STM32F103 系列微控制器,将 INA3221 与 STM32 进行如下连接:

  • SCL(I²C 时钟线):连接到 STM32 的 I²C 时钟引脚,例如 PB6。
  • SDA(I²C 数据线):连接到 STM32 的 I²C 数据引脚,例如 PB7。
  • VCC:连接到 3.3V 电源。
  • GND:连接到地。

3.2 分流电阻连接

在每个通道上,需要连接一个合适的分流电阻,用于测量电流。分流电阻的阻值根据需要测量的电流范围进行选择。

四、代码实现

4.1 I²C 初始化代码

#include "stm32f10x.h"

// I2C 初始化函数
void I2C1_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;

    // 使能 GPIOB 和 I2C1 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    // 配置 SCL 和 SDA 引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 初始化 I2C1
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;
    I2C_Init(I2C1, &I2C_InitStructure);

    // 使能 I2C1
    I2C_Cmd(I2C1, ENABLE);
}

4.2 INA3221 读写函数

// 向 INA3221 写入一个字节数据
void INA3221_WriteByte(uint8_t reg, uint8_t data) {
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, 0x80, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, reg);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, data);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2C1, ENABLE);
}

// 从 INA3221 读取一个字节数据
uint8_t INA3221_ReadByte(uint8_t reg) {
    uint8_t data;

    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, 0x80, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, reg);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, 0x81, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    I2C_AcknowledgeConfig(I2C1, DISABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

    data = I2C_ReceiveData(I2C1);

    I2C_GenerateSTOP(I2C1, ENABLE);

    return data;
}

4.3 读取通道电压和电流

// 读取指定通道的电压(单位:mV)
float INA3221_ReadChannelVoltage(uint8_t channel) {
    uint8_t reg;
    if (channel == 1) reg = 0x02;
    else if (channel == 2) reg = 0x04;
    else if (channel == 3) reg = 0x06;
    else return 0;

    uint16_t raw_data = (INA3221_ReadByte(reg) << 8) | INA3221_ReadByte(reg + 1);
    return (float)raw_data * 1.25;
}

// 读取指定通道的电流(单位:mA)
float INA3221_ReadChannelCurrent(uint8_t channel, float shunt_resistor) {
    uint8_t reg;
    if (channel == 1) reg = 0x01;
    else if (channel == 2) reg = 0x03;
    else if (channel == 3) reg = 0x05;
    else return 0;

    uint16_t raw_data = (INA3221_ReadByte(reg) << 8) | INA3221_ReadByte(reg + 1);
    return (float)raw_data * 0.005 / shunt_resistor;
}

4.4 主函数

#include <stdio.h>

#define SHUNT_RESISTOR 0.1  // 分流电阻阻值,单位:欧姆

int main(void) {
    I2C1_Init();

    while (1) {
        for (int i = 1; i <= 3; i++) {
            float voltage = INA3221_ReadChannelVoltage(i);
            float current = INA3221_ReadChannelCurrent(i, SHUNT_RESISTOR);

            printf("Channel %d: Voltage = %.2f mV, Current = %.2f mA\n", i, voltage, current);
        }

        for (int j = 0; j < 1000000; j++);  // 简单延时
    }
}

五、代码解释

5.1 I²C 初始化

I2C1_Init 函数用于初始化 STM32 的 I²C1 接口,配置相关的 GPIO 引脚和 I²C 参数,并使能 I²C 模块。

5.2 INA3221 读写操作

  • INA3221_WriteByte 函数用于向 INA3221 的指定寄存器写入一个字节的数据。
  • INA3221_ReadByte 函数用于从 INA3221 的指定寄存器读取一个字节的数据。

5.3 读取电压和电流

  • INA3221_ReadChannelVoltage 函数根据指定的通道号读取该通道的电压值,并将原始数据转换为以 mV 为单位的电压值。
  • INA3221_ReadChannelCurrent 函数根据指定的通道号和分流电阻阻值读取该通道的电流值,并将原始数据转换为以 mA 为单位的电流值。

5.4 主函数

在主函数中,首先初始化 I²C 接口,然后进入一个无限循环,循环中依次读取三个通道的电压和电流值,并打印输出。每次读取完所有通道后,进行一个简单的延时。

六、总结

通过以上代码和解释,我们可以看到如何使用 STM32 与 INA3221 三通道电压电流采集模块进行通信和数据采集。在实际应用中,还可以根据需要对代码进行优化和扩展,例如添加错误处理、提高数据采集的精度等。同时,要注意分流电阻的选择,以确保能够准确测量所需的电流范围。

✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐