【驱动】ina3221 德州仪器3通道电流采样芯片驱动

说明

基于stm32f103的ina3221电流采样芯片驱动,使用LL库进行开发。已经过验证。
INA3221 是一款三通道、高侧电流和总线电压监视器,具有一个兼容I2C 和SMBUS 的接口。INA3221不仅能够监视分流压降和总线电源电压,还针对这些信号提供有可编程的转换时间和平均值计算模式。INA3221 提供关键报警和警告报警,用于检测每条通道上可编程的多种超范围情况。
INA3221 感测总线(电压在0V 至+26V 范围内变化)上的电流。此器件由2.7V 至5.5V 单电源供电,电源电流消耗为350μA(典型值)。INA3221 的额定运行温度范围为-40°C 至+125°C。兼容I2C 和SMBUS 的接口具有四个可编程地址。

代码

INA3221.h

/*
 * @Author: xmprocat
 * @Date: 2022-07-31 15:36:14
 * @LastEditors: xmprocat
 * @LastEditTime: 2022-08-06 21:24:03
 * @Description: 
 */
#ifndef __INA3221_H
#define __INA3221_H
#include "stdint.h"

#define INA3221_ADDR1 0x80  // A0=GND
#define INA3221_ADDR2 0x82  // A0=VS
#define INA3221_ADDR3 0x84  // A0=SDA
#define INA3221_ADDR4 0x86  // A0=SCL

void INA3221_Init(uint8_t addr);
uint16_t INA3221_GetVoltage(uint8_t addr, uint8_t channel);
uint16_t INA3221_GetShuntVoltage(uint8_t addr, uint8_t channel);

#endif

INA3221.c

/*
 * @Author: xmprocat
 * @Date: 2022-07-31 15:35:40
 * @LastEditors: xmprocat
 * @LastEditTime: 2022-08-06 21:23:35
 * @Description: ina3221 模拟IIC驱动
 */

#include "INA3221.h"
#include "stm32f1xx_ll_utils.h"
#include "stm32f1xx_ll_gpio.h"

/*****************硬件连接定义*********************/
#define INA3221_SCL_PORT GPIOB
#define INA3221_SCL_PIN LL_GPIO_PIN_6

#define INA3221_SDA_PORT GPIOB
#define INA3221_SDA_PIN LL_GPIO_PIN_7

/************************延时接口****************************/
#define delay_nms_3221 LL_mDelay       //毫秒延时
// #define delay_nns_3221 delay_nus_3221       //毫秒延时

#define INA3221_CFG_REG         0x00    //配置寄存器
#define INA3221_CH1SHUNT_REG    0x01    //通道 1 分流电压
#define INA3221_CH1BUS_REG      0x02    //通道 1 总线电压
#define INA3221_CH2SHUNT_REG    0x03    //通道 2 分流电压
#define INA3221_CH2BUS_REG      0x04    //通道 2 总线电压
#define INA3221_CH3SHUNT_REG    0x05    //通道 3 分流电压
#define INA3221_CH3BUS_REG      0x06    //通道 3 总线电压
#define INA3221_CH1CAL_REG      0x07    //通道 1 严重警报限制
#define INA3221_CH1WAL_REG      0x08    //通道 1 警告警报限制
#define INA3221_CH2CAL_REG      0x09    //通道 2 严重警报限制
#define INA3221_CH2WAL_REG      0x0A    //通道 2 警告警报限制
#define INA3221_CH3CAL_REG      0x0B    //通道 3 严重警报限制
#define INA3221_CH3WAL_REG      0x0C    //通道 3 警告警报限制
#define INA3221_SVS_REG         0x0D    //分流电压和
#define INA3221_SVSLIMIT_REG    0x0E    //分流电压和限制
#define INA3221_ME_REG          0x0F    //屏蔽/启用 警报
#define INA3221_PVUPPER_REG     0x10    //功率有效上限
#define INA3221_PVLOW_REG       0x11    //功率有效下限
#define INA3221_MANUID_REG      0xFE    //制造商标识号
#define INA3221_DIEID_REG       0xFF    //模具标识号

#define INA3221_MANU_ID     0x5449  //唯一制造商标识号
#define INA3221_DIE_ID      0x3220  //唯一模具标识号


#define IIC_SCL_L_3221 LL_GPIO_ResetOutputPin(INA3221_SCL_PORT, INA3221_SCL_PIN)
#define IIC_SCL_H_3221 LL_GPIO_SetOutputPin(INA3221_SCL_PORT, INA3221_SCL_PIN)

#define IIC_SDA_L_3221 LL_GPIO_ResetOutputPin(INA3221_SDA_PORT, INA3221_SDA_PIN)
#define IIC_SDA_H_3221 LL_GPIO_SetOutputPin(INA3221_SDA_PORT, INA3221_SDA_PIN)
#define SDA_READ_3221 LL_GPIO_IsInputPinSet(INA3221_SDA_PORT, INA3221_SDA_PIN)
#define SDA_IN_3221                                                                \
    do                                                                             \
    {                                                                              \
        LL_GPIO_SetPinMode(INA3221_SDA_PORT, INA3221_SDA_PIN, LL_GPIO_MODE_INPUT); \
    } while (0)
#define SDA_OUT_3221                                                                \
    do                                                                              \
    {                                                                               \
        LL_GPIO_SetPinMode(INA3221_SDA_PORT, INA3221_SDA_PIN, LL_GPIO_MODE_OUTPUT); \
    } while (0)


static void delay_nns_3221(uint16_t D) // 30纳秒ns  根据手册要用到IIC的HS高速模式
{
    while (--D)
        ;
}

/**
 * @description: stm32f103c8t6 微秒延迟函数 72Mhz
 * @param {uint16_t} us
 * @return {*}
 */
void delay_nus_3221(uint16_t us)
{
    uint32_t temp;
    SysTick->LOAD = us * (72000000 / 8000000); //时间加载
    SysTick->VAL = 0x00;                       //清空计数器
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;  //开始倒数
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16))); //等待时间到达
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;      //关闭计数器
    SysTick->VAL = 0X00;                            //清空计数器
}

/************************模拟IIC接口****************************/
void INA3221_IIC_Init(void)
{
    // IO初始化设置由cubeMX完成 移植的话需要在此处实现IO初始化

    IIC_SDA_H_3221;
    IIC_SCL_H_3221;

    delay_nms_3221(5);
}
void INA3221_IIC_Start(void)
{
    IIC_SDA_H_3221;
    IIC_SCL_H_3221;
    delay_nns_3221(5);
    IIC_SDA_L_3221; // START:when CLK is high,DATA change form high to low
    delay_nns_3221(5);
    IIC_SCL_L_3221; //钳住I2C总线,准备发送或接收数据
    delay_nns_3221(5);
}

void INA3221_IIC_Stop(void)
{
    IIC_SDA_L_3221; // STOP:when CLK is high DATA change form low to high
    delay_nns_3221(5);
    IIC_SCL_H_3221;
    delay_nns_3221(5);
    IIC_SDA_H_3221; //发送I2C总线结束信号
    delay_nns_3221(5);
}

void INA3221_IIC_Ack(void)
{
    IIC_SDA_L_3221;
    delay_nns_3221(5);
    IIC_SCL_H_3221;
    delay_nns_3221(5);
    IIC_SCL_L_3221;
    delay_nns_3221(5);
    IIC_SDA_H_3221;
}

void INA3221_IIC_NAck(void)
{
    IIC_SDA_H_3221;
    delay_nns_3221(5);
    IIC_SCL_H_3221;
    delay_nns_3221(5);
    IIC_SCL_L_3221;
    delay_nns_3221(5);
    IIC_SDA_L_3221;
}

uint8_t INA3221_IIC_Wait_Ack(void)
{
    uint8_t ucErrTime = 0;
    IIC_SDA_H_3221;
    SDA_IN_3221; // SDA设置为输入
    delay_nns_3221(5);
    IIC_SCL_H_3221;
    delay_nns_3221(5);

    while (SDA_READ_3221)
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            INA3221_IIC_Stop();
            return 1;
        }
    }
    IIC_SCL_L_3221; //时钟输出0
    SDA_OUT_3221; // SDA设置为输入
    return 0;
}

void INA3221_IIC_Send_Byte(uint8_t txd)
{
    IIC_SCL_L_3221; //拉低时钟开始数据传输
    for (uint8_t i = 0; i < 8; i++)
    {
        if (txd & 0x80)
            IIC_SDA_H_3221;
        else
            IIC_SDA_L_3221;
        txd <<= 1;

        IIC_SCL_H_3221;
        delay_nns_3221(5);
        IIC_SCL_L_3221;
        delay_nns_3221(5);
    }
    //    IIC_SDA_H_3221;
    //    IIC_SCL_H_3221;            //当去掉wait_ack时的时候添加
    //    delay_nns_3221(5);
    // IIC_SCL_L_3221;
}

uint8_t INA3221_IIC_Read_Byte(unsigned char ack)
{
    uint8_t TData = 0, i;
    SDA_IN_3221; // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        IIC_SCL_H_3221;
        delay_nns_3221(5);
        TData = TData << 1;
        // if(GPIOB->IDR& GPIO_IDR_IDR7)        //判断SDA是否为高
        if (SDA_READ_3221)
        {
            TData |= 0x01;
        }
        IIC_SCL_L_3221;
        delay_nns_3221(5);
    }
    SDA_OUT_3221; // SDA设置为输出
    if (!ack)
        INA3221_IIC_NAck();
    else
        INA3221_IIC_Ack();

    return TData;
}


void INA3221_SendData(uint8_t addr, uint8_t reg, uint16_t data)
{
    uint8_t temp = 0;
    INA3221_IIC_Start();
    INA3221_IIC_Send_Byte(addr);
    INA3221_IIC_Wait_Ack();

    INA3221_IIC_Send_Byte(reg);
    INA3221_IIC_Wait_Ack();

    temp = (uint8_t)(data >> 8);
    INA3221_IIC_Send_Byte(temp);
    INA3221_IIC_Wait_Ack();

    temp = (uint8_t)(data & 0x00FF);
    INA3221_IIC_Send_Byte(temp);
    INA3221_IIC_Wait_Ack();

    INA3221_IIC_Stop();
}

void INA3221_SetRegPointer(uint8_t addr, uint8_t reg)
{
    INA3221_IIC_Start();

    INA3221_IIC_Send_Byte(addr);
    INA3221_IIC_Wait_Ack();

    INA3221_IIC_Send_Byte(reg);
    INA3221_IIC_Wait_Ack();

    INA3221_IIC_Stop();
}

uint16_t INA3221_ReadData(uint8_t addr)
{
    uint16_t temp = 0;
    INA3221_IIC_Start();

    INA3221_IIC_Send_Byte(addr + 1);
    INA3221_IIC_Wait_Ack();

    temp = INA3221_IIC_Read_Byte(1);
    temp <<= 8;
    temp |= INA3221_IIC_Read_Byte(0);

    INA3221_IIC_Stop();
    return temp;
}


/**
 * @description: INA3221自检
 * @param {uint8_t} addr
 * @return {*}
 */
void INA3221_SelfCheck(uint8_t addr)
{
    uint16_t id = 0;
    while (id != INA3221_DIE_ID)
    {
        delay_nms_3221(50);
        //卡这说明硬件连接异常或者是地址错误
        INA3221_SetRegPointer(addr, INA3221_DIEID_REG);
        id = INA3221_ReadData(addr);
    }
}

/********************************应用部分****************************************/

/**
 * @description: INA3221初始化
 * @return {*}
 */
void INA3221_Init(uint8_t addr)
{
    
    INA3221_IIC_Init();     //初始化IIC

    INA3221_SendData(addr, INA3221_CFG_REG, 0x8000); //软件复位
    LL_mDelay(10);

    // 配置寄存器设置控制三个输入通道的分流和总线电压测量的工作模式。 
    // 该寄存器控制分流和总线电压测量的转换时间设置以及使用的平均模式。 
    // 配置寄存器用于独立启用或禁用每个通道,以及选择控制选择要测量的信号的操作模式。
    // 详见数据手册P26
    INA3221_SendData(addr, INA3221_CFG_REG, 0x7127); // 7127为默认配置

    INA3221_SelfCheck(addr);
     
}

/**
 * @description: 获取电压
 * @param {uint8_t} addr
 * @param {uint8_t} channel 通道编号(1\2\3)
 * @return {uint16_t} 通道所对应的电压
 */
uint16_t INA3221_GetVoltage(uint8_t addr, uint8_t channel)
{
    uint32_t temp = 0;
    switch (channel)
    {
    case 1:
        INA3221_SetRegPointer(addr, INA3221_CH1BUS_REG);
        break;
    case 2:
        INA3221_SetRegPointer(addr, INA3221_CH2BUS_REG);
        break;
    case 3:
        INA3221_SetRegPointer(addr, INA3221_CH3BUS_REG);
        break;
    default:
        break;
    }
    temp = INA3221_ReadData(addr);
    if (temp & 0x8000)
        temp = ~(temp - 1);
    return (uint16_t)temp;
}


/**
 * @description: 获取分流电压
 * @param {uint8_t} addr    ina3221的IIC地址
 * @param {uint8_t} channel 通道编号(1\2\3)
 * @return {uint16_t} 通道的分流电压
 */
uint16_t INA3221_GetShuntVoltage(uint8_t addr, uint8_t channel)
{
    uint32_t temp = 0;
    switch (channel)
    {
    case 1:
        INA3221_SetRegPointer(addr, INA3221_CH1SHUNT_REG);
        break;
    case 2:
        INA3221_SetRegPointer(addr, INA3221_CH2SHUNT_REG);
        break;
    case 3:
        INA3221_SetRegPointer(addr, INA3221_CH3SHUNT_REG);
        break;
    default:
        break;
    }
    temp = INA3221_ReadData(addr);
    if (temp & 0x8000)
        temp = ~(temp - 1);
    return (uint16_t)temp;
}

硬件

image.png

结果

在这里插入图片描述

1bc74d11890cfe64b69c6af4bca7b53.jpg


版权声明:本文为u011493046原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。