【STM32】INA3221三通道电压电流采集模块,HAL库

一、简单介绍

芯片的datasheet地址:

INA3221 三通道、高侧测量、分流和总线电压监视器,具有兼容 I2C 和 SMBUS 的接口 datasheet (Rev. B)

笔者所使用的INA3221是淘宝买的模块

原理图

模块的三个通道的电压都是一样,都是POWER。这个芯片采用的是高侧测量:每个通道有两个引脚,一个连接负载去给负载供电,另一个回来,回到GND

经过笔者测量和观察,采样电阻的阻值应该是100mΩ

二、模块与接线

INA3221使用IIC通信协议进行读写,笔者使用的是STM32G030F6P6单片机来操作,读者按实际情况类推即可,cubeMX配置,基本都大差不差。

POWER连接外部电源的正极

GND连接外部电源的负极

将模块的GND与单片机的GND连接起来,注意这里地接在一起,如果单片机连着电脑,请务必小心操作,不要接反也不要短路

三、cubemx配置

设置时钟

用内部的RC震荡就可以了,也可以使用外部晶振,但如果用外部晶振的话,这颗晶振必须是有源的,之前看一些G030的板子焊了一个无源晶振,有点匪夷所思。

设置IIC

打算把电压和电流显示在0.96寸的oled上,因此就开了两个IIC,当然了,只开一个也可以,把INA3221和OLED都接在一个IIC总线上就行了,但为了方便,笔者开了两个。

这里的频率可以开到1Mhz,如果是103C8T6,应该是到不了的😋

数据量很小,DMA就不开了

设置GPIO

由于模块上自带了LED灯,所以就没必要开输入IO口给模块,可以开一个监控单片机程序运行的LED

至此,cubeMX配置完毕

四、keil配置

五、驱动编写

打开手册关于编程的章节

支持快速IIC传输,且高位在前

不管是读还是写,一开始要发一个寄存器指针过去,定位一下寄存器

寄存器读写函数

static void INA3221_ReadReg(INA3221_regType *reg)
{HAL_I2C_Mem_Read(INA3321_I2C, INA3221_I2C_ADDRESS, reg->address, 1, &reg->data, 2, 0xFFFF);DataReverse(reg->data, &reg->data);
}static void INA3221_WriteReg(INA3221_regType *reg)
{DataReverse(reg->data, &reg->data);HAL_I2C_Mem_Write(INA3321_I2C, INA3221_I2C_ADDRESS, reg->address, 1, &reg->data, 2, 0xFFFF);
}

寄存器表

先简单读一下芯片的ID,看看是否能正常通信

读芯片的id号,值是0x2032,但波形是3220,因此要翻转一下高低字节

代码如下

static void DataReverse(uint16_t raw, uint16_t* cook)
{*cook = ((uint8_t)(raw) << 8) | (raw >> 8);
}

读channel的bus电压值

一个位代表8mV,但寄存器里面的左移三位又刚好弥补了这一点,因此直接读到的就是电压值。

代码如下

static void INA3221_Sample_Volt()
{INA3221_ReadReg(&volt1);INA3221_ReadReg(&volt2);INA3221_ReadReg(&volt3);
}

读channel的shunt电压值

一个位代表40uV,满量程是163.8mV,因此这个用的100mΩ的模块最大采集电流为1638mA

shunt可以是负数,代表反向电流,但模块设计成IN-接PWR了,笔者就只实验了正向电流

代码如下

static void INA3221_Calculate_Current(uint32_t* current)
{current[0] = shunt1.data >> 3;/* 40uV per LSB */current[0] *= 4;current[0] = current[0] * 10 / SHUNT_RESISTOR;current[1] = shunt2.data >> 3;/* 40uV per LSB */current[1] *= 4;current[1] = current[1] * 10 / SHUNT_RESISTOR;current[2] = shunt3.data >> 3;/* 40uV per LSB */current[2] *= 4;current[2] = current[2] * 10 / SHUNT_RESISTOR;
}

主函数编写

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_I2C2_Init();MX_I2C1_Init();/* USER CODE BEGIN 2 */
INA3221_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"C1",16);
OLED_ShowString(0,2,"C2",16);
OLED_ShowString(0,4,"C3",16);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){INA3221_GetVolt();INA3221_GetCurrent();sprintf(info[0], "%.2fV ", voltage[0]/1000.0f);sprintf(info[1], "%.2fV ", voltage[1]/1000.0f);sprintf(info[2], "%.2fV ", voltage[2]/1000.0f);OLED_ShowString(20,0,info[0],16);OLED_ShowString(20,2,info[1],16);OLED_ShowString(20,4,info[2],16);sprintf(info[3], "%.3fA", current[0]/1000.0f);sprintf(info[4], "%.3fA", current[1]/1000.0f);sprintf(info[5], "%.3fA", current[2]/1000.0f);OLED_ShowString(80,0,info[3],16);OLED_ShowString(80,2,info[4],16);OLED_ShowString(80,4,info[5],16);HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);HAL_Delay(100);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

六、效果展示

七、驱动附录

ina3221.h

#ifndef INA3221_H
#define INA3221_H#include"i2c.h"
#include "stdint.h"
#include "main.h"typedef struct
{uint8_t address;uint16_t data;
}INA3221_regType;typedef enum
{CH1,CH2,CH3,
}INA3221_SHUNTChannelType;/*** prepare for mask enable register*/
typedef struct
{uint8_t CF1;uint8_t CF2;uint8_t CF3;uint8_t WF1;uint8_t WF2;uint8_t WF3;
}INA3221_FlagType;extern INA3221_regType dieID;
extern INA3221_regType mask_enable;extern INA3221_regType volt1;
extern INA3221_regType shunt1;
extern INA3221_regType volt2;
extern INA3221_regType shunt2;
extern INA3221_regType volt3;
extern INA3221_regType shunt3;extern uint32_t current[3];
extern uint16_t voltage[3];extern INA3221_FlagType INA3221_flag;void INA3221_Config();
void INA3221_Init();
void INA3221_Reset();
void INA3221_ReadDieID();
void INA3221_ReadmanufactID();
void INA3221_GetVolt();
void INA3221_GetCurrent();#endif

ina3221.c

#include "INA3221.h"#define INA3321_I2C &hi2c1
#define INA3221_I2C_ADDRESS 0x80/*shunt resistor mohm*/
#define SHUNT_RESISTOR 			100#define POWER_VALID_UPPER 		10000#define POWER_VALID_LOWER 		9000/*** register address table*/
typedef enum
{SHUNT_CH1 = 0x01,VOLT_CH1,SHUNT_CH2,VOLT_CH2,SHUNT_CH3,VOLT_CH3,CRITICAL_CH1,WARNING_CH1,CRITICAL_CH2,WARNING_CH2,CRITICAL_CH3,WARNING_CH3,SHUNT_VOLT_SUM,SHUNT_VOLT_SUM_LIMIT,MASK_ENABLE,POWER_VALID_HIGH = 0x10,POWER_VALID_LOW,
}INA3221_RegAddressType;/*** average samples*/
typedef enum
{AVG_1,AVG_4,AVG_16,AVG_64,AVG_128,AVG_256,AVG_512,AVG_1024,
}INA3221_AVGType;/*** average samples*/
typedef enum
{CONV_TIME_140US,CONV_TIME_204US,CONV_TIME_332US,CONV_TIME_588US,CONV_TIME_1_1MS,CONV_TIME_2_116MS,CONV_TIME_4_156MS,CONV_TIME_8_244MS,
}INA3221_CTType;/*** average samples*/
typedef enum
{POWER_DOWN,SHUNT_SINGLE,BUS_SINGLE,SHUNT_BUS_SINGLE,POWER_DN,SHUNT_CONTINUOUS,BUS_CONTINUOUS,SHUNT_BUS_CONTINUOUS,
}INA3221_ModeType;INA3221_regType cfg = {.address = 0};INA3221_regType volt1 = {.address = VOLT_CH1};
INA3221_regType shunt1 = {.address = SHUNT_CH1};
INA3221_regType volt2 = {.address = VOLT_CH2};
INA3221_regType shunt2 = {.address = SHUNT_CH2};
INA3221_regType volt3 = {.address = VOLT_CH3};
INA3221_regType shunt3 = {.address = SHUNT_CH3};INA3221_regType critical_ch1 = {.address = CRITICAL_CH1};
INA3221_regType critical_ch2 = {.address = CRITICAL_CH2};
INA3221_regType critical_ch3 = {.address = CRITICAL_CH3};
INA3221_regType warning_ch1 = {.address = WARNING_CH1};
INA3221_regType warning_ch2 = {.address = WARNING_CH2};
INA3221_regType warning_ch3 = {.address = WARNING_CH3};INA3221_regType mask_enable = {.address = MASK_ENABLE};INA3221_regType power_valid_upper = {.address = POWER_VALID_HIGH};
INA3221_regType power_valid_lower = {.address = POWER_VALID_LOW};INA3221_regType manufactID = {.address = 0xFE};
INA3221_regType dieID = {.address = 0xFF};/* store power voltage */
uint32_t current[3];
/* store power current */
uint16_t voltage[3];INA3221_FlagType INA3221_flag;
/*** exchange data high and low byte for word variable*/
static void DataReverse(uint16_t raw, uint16_t* cook);/*** read register value*/
static void INA3221_ReadReg(INA3221_regType *reg);/*** write register value*/
static void INA3221_WriteReg(INA3221_regType *reg);/*** cacluate voltages from volt register value*/
static void INA3221_Calculate_Volt(uint16_t* volt);/*** cacluate currents from shunt register value*/
static void INA3221_Calculate_Current(uint32_t* current);/*** set limite value for current alert*/
static void INA3221_SetLimit(INA3221_regType *reg, uint16_t volt);/*** just read volt registers*/
static void INA3221_Sample_Volt();/*** just read shunt registers*/
static void INA3221_Sample_Shunt();static void DataReverse(uint16_t raw, uint16_t* cook)
{*cook = ((uint8_t)(raw) << 8) | (raw >> 8);
}static void INA3221_ReadReg(INA3221_regType *reg)
{HAL_I2C_Mem_Read(INA3321_I2C, INA3221_I2C_ADDRESS, reg->address, 1, &reg->data, 2, 0xFFFF);DataReverse(reg->data, &reg->data);
}static void INA3221_WriteReg(INA3221_regType *reg)
{DataReverse(reg->data, &reg->data);HAL_I2C_Mem_Write(INA3321_I2C, INA3221_I2C_ADDRESS, reg->address, 1, &reg->data, 2, 0xFFFF);
}static void INA3221_Calculate_Volt(uint16_t* volt)
{*volt = volt1.data;*(volt + 1) = volt2.data;*(volt + 2) = volt3.data;
}static void INA3221_Calculate_Current(uint32_t* current)
{current[0] = shunt1.data >> 3;/* 40uV per LSB */current[0] *= 4;current[0] = current[0] * 10 / SHUNT_RESISTOR;current[1] = shunt2.data >> 3;/* 40uV per LSB */current[1] *= 4;current[1] = current[1] * 10 / SHUNT_RESISTOR;current[2] = shunt3.data >> 3;/* 40uV per LSB */current[2] *= 4;current[2] = current[2] * 10 / SHUNT_RESISTOR;
}static void INA3221_SetLimit(INA3221_regType *reg, uint16_t volt)
{reg->data = volt;INA3221_WriteReg(reg);
}static void INA3221_Sample_Volt()
{INA3221_ReadReg(&volt1);INA3221_ReadReg(&volt2);INA3221_ReadReg(&volt3);
}static void INA3221_Sample_Shunt()
{INA3221_ReadReg(&shunt1);INA3221_ReadReg(&shunt2);INA3221_ReadReg(&shunt3);
}void INA3221_ReadDieID()
{INA3221_ReadReg(&dieID);
}void INA3221_ReadmanufactID()
{INA3221_ReadReg(&manufactID);
}void INA3221_GetVolt()
{INA3221_Sample_Volt();INA3221_Calculate_Volt(voltage);
}void INA3221_GetCurrent()
{INA3221_Sample_Shunt();INA3221_Calculate_Current(current);
}void INA3221_Config()
{/* read default register value from chip*/INA3221_ReadReg(&cfg);/* store it in config variable */cfg.data |= (cfg.data & !0x0E00) | (AVG_4 << 9);/*bus*/cfg.data |= (cfg.data & !0x01C0) | (CONV_TIME_2_116MS << 6);/*shunt*/cfg.data |= (cfg.data & !0x38) | (CONV_TIME_2_116MS << 3);/* wirte to register value */INA3221_WriteReg(&cfg);INA3221_ReadReg(&cfg);
}void INA3221_Set_Critical(INA3221_SHUNTChannelType channel, uint16_t current)
{switch (channel){case CH1:{/* 40uV per LSB */INA3221_SetLimit(&critical_ch1, (current * SHUNT_RESISTOR / 40) << 3);break;}case CH2:{INA3221_SetLimit(&critical_ch2, (current * SHUNT_RESISTOR / 40) << 3);break;}case CH3:{INA3221_SetLimit(&critical_ch3, (current * SHUNT_RESISTOR / 40) << 3);break;}default:break;}
}void INA3221_Set_Warning(INA3221_SHUNTChannelType channel, uint16_t current)
{switch (channel){case CH1:{INA3221_SetLimit(&warning_ch1, (current * SHUNT_RESISTOR / 40) << 3);break;}case CH2:{INA3221_SetLimit(&warning_ch2, (current * SHUNT_RESISTOR / 40) << 3);break;}case CH3:{INA3221_SetLimit(&warning_ch3, (current * SHUNT_RESISTOR / 40) << 3);break;}default:break;}
}void INA3221_Reset()
{cfg.data = 0x8000;INA3221_WriteReg(&cfg);
}void INA3221_Init()
{INA3221_ReadDieID();/* reset all registers */INA3221_Reset();INA3221_Config();
}

八、补充功能

INA3221还带可编程报警和警告输出

一、关键提示

会去比较每个通道的shunt电压值和相应的预设的值,用来判断是否发生过流

二、警告提示

会去比较每个通道的平均shunt电压值和相应的预设的值,用来判断是否发生过流

三、电源有效提示

芯片默认的PV上限是10V,下限是9V,都是可以改写的

意思是在外部高压输入的时候,如果三个通道的电压均高于10V,那么电源OK

如果电压降低,低于9V,电源不OK,模块的灯就会亮起来,因为这几个提示引脚都是开漏输出的

在外部高压输入的时候,如果有任意通道电压<10V,电源不OK,模块的灯就会亮起来,因为这几个提示引脚都是开漏输出的

如果电压升高,高于10V就可以了

有点像施密特触发器

可以把PV上拉到VPU去,这样电压就抬起来了,也可以在PV引脚和地直接串电阻来降压

模块的输入端子里有VPU,根据实际情况使用即可

四、时序控制提示

九、工程链接

STM32INA3221电压电流实时显示OLED工程资源-CSDN文库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/462738.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML 标签属性——id、class、style 等全局属性详解

文章目录 1. id属性2. class属性3. style属性4. title属性5. lang属性6. dir属性7. accesskey属性8. tabindex属性小结HTML全局属性是一组可以应用于几乎所有HTML元素的特殊属性。这些属性提供了额外的功能和信息,使得网页开发者能够更好地控制元素的行为、样式和可访问性。 …

Python数据分析案例62——基于MAGU-LSTM的时间序列预测(记忆增强门控单元)

案例背景 时间序列lstm系列预测在学术界发论文都被做烂了&#xff0c;现在有一个新的MAGU-LSTM层的代码&#xff0c;并且效果还可以&#xff0c;非常少见我觉得还比较创新&#xff0c;然后我就分享一下它的代码演示一下&#xff0c;并且结合模态分解等方法做一次全面的深度学习…

C++泛型编程

一、什么是泛型编程 泛型编程 是一种编程范式&#xff0c;它通过编写可以处理多种数据类型的代码来实现代码的灵活复用。泛型编程主要通过模板来实现。 比如我们日常使用的容器类型vector就应用了模板来实现其通用性&#xff0c;我们在使用时可以通过传入型别创建对应的动态数…

ServletContext,Cookie,HttpSession的使用

ServletContext对象 ServletContext对象官方也称servlet上下文。服务器会为每一个Web应用创建一个ServletContext对象&#xff0c;这个对象全局唯一&#xff0c;而且Web应用中所有的Servlet都共享这个对象。 ServletContext对象的作用 相对路径转绝对路径 servletContext.g…

如何封装一个可取消的 HTTP 请求?

前言 你可能会好奇什么样的场景会需要取消 HTTP 请求呢&#xff1f; 确实在实际的项目开发中&#xff0c;可能会很少有这样的需求&#xff0c;但是不代表没有&#xff0c;比如&#xff1a; 假如要实现上述这个公告栏&#xff0c;每点击一个 tab 按钮就会切换展示容器容器中…

前端笔试新问题总结

记录总结下最近遇到的前端笔试新问题 目录 一、操作数组方法 1.Array.isArray(arr) 2.Object.prototype.toString.call(arr) "[object Array]" 3.arr instanceof Array 1&#xff09;跨帧问题 2&#xff09;修改Array.prototype 3&#xff09;模拟数组的对象…

玩转Hugging Face/魔搭社区/魔乐社区”教程

2.1 HF 平台 2.1.1 注册Hugging Face 平台 &#xff08;需要魔法上网&#xff09; Hugging Face 最初专注于开发聊天机器人服务。尽管他们的聊天机器人项目并未取得预期的成功&#xff0c;但他们在GitHub上开源的Transformers库却意外地在机器学习领域引起了巨大轰动。如今&…

Chrome与夸克谁更节省系统资源

在当今数字化时代&#xff0c;浏览器已经成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;我们都依赖于浏览器来访问互联网。然而&#xff0c;不同的浏览器在性能和资源消耗方面存在差异。本文将探讨Chrome和夸克两款浏览器在系统资源消耗方面的表现…

【OJ题解】C++实现反转字符串中的每个单词

&#x1f4b5;个人主页: 起名字真南 &#x1f4b5;个人专栏:【数据结构初阶】 【C语言】 【C】 【OJ题解】 题目要求&#xff1a;给定一个字符串 s &#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 题目链接: 反转字符串中的所…

Vue 学习随笔系列十三 -- ElementUI 表格合并单元格

ElementUI 表格合并单元格 文章目录 ElementUI 表格合并单元格[TOC](文章目录)一、表头合并二、单元格合并1、示例代码2、示例效果 一、表头合并 参考&#xff1a; https://www.jianshu.com/p/2befeb356a31 二、单元格合并 1、示例代码 <template><div><el-…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.3-4.4

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第四周 特殊应用&#xff1a;人脸识别和神经风格转换&#xff08;Special applications: Face recognition &Neural style transfer&#xff09;4.3 Siamese 网络&#xff08;Siamese net…

vue data变量之间相互赋值或进行数据联动

摘要&#xff1a; 使用vue时开发会用到data中是数据是相互驱动&#xff0c;经常会想到watch,computed&#xff0c;总结一下&#xff01; 直接赋值&#xff1a; 在 data 函数中定义的变量可以直接在方法中进行赋值。 export default {data() {return {a: 1,b: 2};},methods: {u…

安装Blender并使用

前言 该系列记录了如何用Blenderpro来构建自己的场景数据集&#xff0c;从环境搭建到后期构建数据集的整个流程 本文章是第一部分&#xff0c;BlenderPrc2的安装以及环境配置 部分参考https://blog.csdn.net/weixin_49521551/article/details/121573334 官方文档https://dlr…

百度SEO分析实用指南 提升网站搜索排名的有效策略

内容概要 在数字化时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已经成为提升网站曝光度的关键工具。本指南将带您了解SEO的基本知识&#xff0c;帮助您在复杂的网络环境中立足。我们将从关键词优化开始&#xff0c;重点讲解如何选择合适的关键词来提高搜索引擎排…

【蔬菜识别】Python+深度学习+CNN卷积神经网络算法+TensorFlow+人工智能+模型训练

一、介绍 蔬菜识别系统&#xff0c;本系统使用Python作为主要编程语言&#xff0c;通过收集了8种常见的蔬菜图像数据集&#xff08;‘土豆’, ‘大白菜’, ‘大葱’, ‘莲藕’, ‘菠菜’, ‘西红柿’, ‘韭菜’, ‘黄瓜’&#xff09;&#xff0c;然后基于TensorFlow搭建卷积神…

ESP8266 自定义固件烧录-Tcpsocket固件

一、固件介绍 固件为自定义开发的一个适配物联网项目的开源固件&#xff0c;支持网页配网、支持网页tcpsocket服务器配置、支持串口波特率设置。 方便、快捷、稳定&#xff01; 二、烧录说明 固件及工具打包下载地址&#xff1a; https://download.csdn.net/download/flyai…

探秘机器学习算法:智慧背后的代码逻辑

1、 线性回归 线性回归是预测连续变量的一种简单而有效的方法。其数学模型假设因变量 y 与自变量 x 之间存在线性关系&#xff0c;用公式表示为&#xff1a; ​ Python代码实现 import numpy as np from sklearn.linear_model import LinearRegression import matplotlib.…

【合肥工业大学】操作系统 习题解析 作业答案(仅作学习与交流/侵删)

第一章习题解析 1&#xff0e;设计现代OS的主要目标是什么&#xff1f; 答&#xff1a;&#xff08;1&#xff09;有效性 &#xff08; 2&#xff09;方便性 &#xff08; 3&#xff09;可扩充性 &#xff08; 4&#xff09;开放性 2&#xff0e; OS 的作用可表现在哪几个方…

要在微信小程序中让一个 `view` 元素内部的文字水平垂直居中,可以使用 Flexbox 布局

文章目录 主要特点&#xff1a;基本用法&#xff1a;常用属性&#xff1a; 要在微信小程序中让一个 view 元素内部的文字水平垂直居中&#xff0c;可以使用 Flexbox 布局。以下是如何设置样式的示例&#xff1a; .scan-button {display: flex; /* 启用 Flexbox 布局 */justify…

JSON交互处理

目录 一、什么是JSON 二、JSON和JavaScript对象互转 ​三、Controller返回JSON数据 3.1 使用Jackson 编写Controller 1. 一个对象 2. 多个对象 3. 输出时间对象 4. 优化&#xff1a;抽取为工具类 一、什么是JSON Json是JavaScript对象的字符串表示法&#xff0c;它用…