Introduction
Test de i2c
Clase ina3221 en voltmètre
Classe ina3221 complete
#
from machine import SoftI2C,Pin
from micropython import const
import time
from time import sleep
# Définir les broches SCL et SDA pour le bus I2C
scl = Pin(22)
sda = Pin(21)
# Créer un objet I2C
i2c = SoftI2C(scl=scl, sda=sda, freq=400000)
"""
# Scanner le bus I2C et afficher les adresses trouvées
adresses_trouvees = i2c.scan()
print("Adresses I2C trouvées :")
for adresse in adresses_trouvees:
print(f" - Adresse décimale : {adresse}")
print(f" - Adresse hexadécimale : {hex(adresse)}")
#
"""
# Adresse I2C du INA3221
INA3221_ADDR = 0x40
# Registres
CONFIG_REG = 0x00
BUS_VOLTAGE_CH = (None, const(0x02), const(0x04), const(0x06))
BUS_ADC_LSB = 0.008 # VBus ADC LSB is 8mV
class INA3221:
def __init__(self,
scl=22,
sda=21,
CHen="111"):
# Définir les broches SCL et SDA pour le bus I2C
pscl = Pin(scl)
psda = Pin(sda)
self.i2c = SoftI2C(scl=pscl, sda=psda, freq=400000)
self.config(CHen[0],CHen[1],CHen[2])
def scan(self):
# Scanner le bus I2C et afficher les adresses trouvées
adresses_trouvees = self.i2c.scan()
print("Adresses I2C trouvées :")
for adresse in adresses_trouvees:
print(f" - Adresse décimale : {adresse}")
print(f" - Adresse hexadécimale : {hex(adresse)}")
def config(self,cH1en=1,cH2en=1,cH3en=1,):
RST = "0" #15
CH1en = str(cH1en) #14
CH2en = str(cH2en) #13
CH3en = str(cH3en) #12
AVG = "000" #11-9 Average
VBUSCT= "001" #8-6 Conv. Time
VSHCT = "000" #5-3 Conv. Time
MODE = "110" #2-0
config_value = RST+CH1en+CH2en+CH3en+AVG+VBUSCT+VSHCT+MODE
#print(config_value)
config_value = self.bin_to_int(config_value)
self.i2c.writeto_mem(INA3221_ADDR, CONFIG_REG, config_value.to_bytes(2, 'big'))
def read_config(self):
reg = self.i2c.readfrom_mem(INA3221_ADDR,CONFIG_REG , 2)
reg = int.from_bytes(reg, 'big')
reg = hex(reg)
print("conf: ",reg)
def bin_to_int(self,strbin):
sum = 0
puis = len(strbin)-1
for i,c in enumerate(strbin):
#print(i,c)
sum+= 2**(puis-i)*int(c)
#a=hex(sum)
#print(a)
return sum
def voltmeter(self, channel=1):
"""Returns the channel's bus voltage in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value_reg = self.i2c.readfrom_mem(INA3221_ADDR, BUS_VOLTAGE_CH[channel] , 2)
bus_voltage = int.from_bytes(value_reg, 'big') >> 3 # Conversion en 13 bits
#print(bus_voltage)
# convert to volts - LSB = 8mV
return bus_voltage * BUS_ADC_LSB
ina = INA3221(CHen="101")
#ina.scan()
#ina.read_config()
while True:
v1 = ina.voltmeter(3)
print(v1)
sleep(1)
break
# imports
from micropython import const
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/neaxi/MicroPython_INA3221"
# pylint: disable=bad-whitespace
_DEFAULT_ADDRESS = const(0x40)
#
# Registers and bits definitions
#
# Config register
C_REG_CONFIG = const(0x00)
C_RESET = const(0x8000)
C_ENABLE_CH = (None,const(0x4000),const(0x2000),const(0x1000)) # default set
C_AVERAGING_MASK = const(0x0E00)
C_AVERAGING_NONE = const(0x0000) # 1 sample, default
C_AVERAGING_4_SAMPLES = const(0x0200)
C_AVERAGING_16_SAMPLES = const(0x0400)
C_AVERAGING_64_SAMPLES = const(0x0600)
C_AVERAGING_128_SAMPLES = const(0x0800)
C_AVERAGING_256_SAMPLES = const(0x0A00)
C_AVERAGING_512_SAMPLES = const(0x0C00)
C_AVERAGING_1024_SAMPLES = const(0x0E00)
C_VBUS_CONV_TIME_MASK = const(0x01C0)
C_VBUS_CONV_TIME_140US = const(0x0000)
C_VBUS_CONV_TIME_204US = const(0x0040)
C_VBUS_CONV_TIME_332US = const(0x0080)
C_VBUS_CONV_TIME_588US = const(0x00C0)
C_VBUS_CONV_TIME_1MS = const(0x0100) # 1.1ms, default
C_VBUS_CONV_TIME_2MS = const(0x0140) # 2.116ms
C_VBUS_CONV_TIME_4MS = const(0x0180) # 4.156ms
C_VBUS_CONV_TIME_8MS = const(0x01C0) # 8.244ms
C_SHUNT_CONV_TIME_MASK = const(0x0038)
C_SHUNT_CONV_TIME_140US = const(0x0000)
C_SHUNT_CONV_TIME_204US = const(0x0008)
C_SHUNT_CONV_TIME_332US = const(0x0010)
C_SHUNT_CONV_TIME_588US = const(0x0018)
C_SHUNT_CONV_TIME_1MS = const(0x0020) # 1.1ms, default
C_SHUNT_CONV_TIME_2MS = const(0x0028) # 2.116ms
C_SHUNT_CONV_TIME_4MS = const(0x0030) # 4.156ms
C_SHUNT_CONV_TIME_8MS = const(0x0038) # 8.244ms
C_MODE_MASK = const(0x0007)
C_MODE_POWER_DOWN = const(0x0000) # Power-down
C_MODE_SHUNT_VOLTAGE_TRIGGERED = const(0x0001) # Shunt voltage, single-shot (triggered)
C_MODE_BUS_VOLTAGE_TRIGGERED = const(0x0002) # Bus voltage, single-shot (triggered)
C_MODE_SHUNT_AND_BUS_TRIGGERED = const(0x0003) # Shunt and bus, single-shot (triggered)
C_MODE_POWER_DOWN2 = const(0x0004) # Power-down
C_MODE_SHUNT_VOLTAGE_CONTINUOUS = const(0x0005) # Shunt voltage, continous
C_MODE_BUS_VOLTAGE_CONTINUOUS = const(0x0006) # Bus voltage, continuous
C_MODE_SHUNT_AND_BUS_CONTINOUS = const(0x0007) # Shunt and bus, continuous (default)
# Other registers
C_REG_SHUNT_VOLTAGE_CH = (None, const(0x01), const(0x03), const(0x05))
C_REG_BUS_VOLTAGE_CH = (None, const(0x02), const(0x04), const(0x06))
C_REG_CRITICAL_ALERT_LIMIT_CH = (None, const(0x07), const(0x09), const(0x0B))
C_REG_WARNING_ALERT_LIMIT_CH = (None, const(0x08), const(0x0A), const(0x0C))
C_REG_SHUNT_VOLTAGE_SUM = const(0x0D)
C_REG_SHUNT_VOLTAGE_SUM_LIMIT = const(0x0E)
# Mask/enable register
C_REG_MASK_ENABLE = const(0x0F)
C_SUM_CONTROL_CH = (None,const(0x4000),const(0x2000),const(0x1000)) # def. not set
C_WARNING_LATCH_ENABLE = const(0x0800) # default not set
C_CRITICAL_LATCH_ENABLE = const(0x0400) # default not set
C_CRITICAL_FLAG_CH = (None,const(0x0200),const(0x0100),const(0x0080))
C_SUM_ALERT_FLAG = const(0x0040)
C_WARNING_FLAG_CH = (None,const(0x0020),const(0x0010),const(0x0008))
C_POWER_ALERT_FLAG = const(0x0004)
C_TIMING_ALERT_FLAG = const(0x0002)
C_CONV_READY_FLAG = const(0x0001)
# Other registers
C_REG_POWER_VALID_UPPER_LIMIT = const(0x10)
C_REG_POWER_VALID_LOWER_LIMIT = const(0x11)
C_REG_MANUFACTURER_ID = const(0xFE)
C_REG_DIE_ID = const(0xFF)
# Constants for manufacturer and device ID
C_MANUFACTURER_ID = const(0x5449) # "TI"
C_DIE_ID = const(0x3220)
# General constants
C_BUS_ADC_LSB = 0.008 # VBus ADC LSB is 8mV
C_SHUNT_ADC_LSB = 0.00004 # VShunt ADC LSB is 40µV
class INA3221:
"""Driver class for Texas Instruments INA3221 3 channel current sensor device"""
IS_FULL_API = True
@staticmethod
def _to_signed(val):
if val > 32767:
return val - 65536
return val
@staticmethod
def _to_unsigned(val):
if val < 0:
return val + 65536
return val
def write(self, reg, value):
"""Write value in device register"""
seq = bytearray([reg, (value >> 8) & 0xFF, value & 0xFF])
print(reg,value,seq)
self.i2c_device.write(seq)
def read(self, reg):
"""Return value from device register"""
buf = bytearray(3)
buf[0] = reg
self.write_then_readinto(buf, buf, out_end=1, in_start=1)
value = (buf[1] << 8) | (buf[2])
return value
def update(self, reg, mask, value):
"""Read-modify-write value in register"""
regvalue = self.read(reg)
regvalue &= ~mask
value &= mask
self.write(reg, regvalue | value)
def writeto_then_readfrom(
self,
address,
buffer_out,
buffer_in,
*,
out_start=0,
out_end=None,
in_start=0,
in_end=None,
stop=False
):
"""Write data from buffer_out to an address and then
read data from an address and into buffer_in
"""
if out_end:
self.i2c_device.writeto(address, buffer_out[out_start:out_end], stop)
else:
self.i2c_device.writeto(address, buffer_out[out_start:], stop)
if not in_end:
in_end = len(buffer_in)
read_buffer = memoryview(buffer_in)[in_start:in_end]
self.i2c_device.readfrom_into(address, read_buffer, stop)
def write_then_readinto(
self,
out_buffer,
in_buffer,
*,
out_start=0,
out_end=None,
in_start=0,
in_end=None
):
"""
Write the bytes from ``out_buffer`` to the device, then immediately
reads into ``in_buffer`` from the device. The number of bytes read
will be the length of ``in_buffer``.
If ``out_start`` or ``out_end`` is provided, then the output buffer
will be sliced as if ``out_buffer[out_start:out_end]``. This will
not cause an allocation like ``buffer[out_start:out_end]`` will so
it saves memory.
If ``in_start`` or ``in_end`` is provided, then the input buffer
will be sliced as if ``in_buffer[in_start:in_end]``. This will not
cause an allocation like ``in_buffer[in_start:in_end]`` will so
it saves memory.
:param bytearray out_buffer: buffer containing the bytes to write
:param bytearray in_buffer: buffer containing the bytes to read into
:param int out_start: Index to start writing from
:param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)``
:param int in_start: Index to start writing at
:param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)``
"""
if out_end is None:
out_end = len(out_buffer)
if in_end is None:
in_end = len(in_buffer)
self.writeto_then_readfrom(
self.i2c_addr,
out_buffer,
in_buffer,
out_start=out_start,
out_end=out_end,
in_start=in_start,
in_end=in_end,
)
def __init__(self, i2c_instance, i2c_addr = _DEFAULT_ADDRESS, shunt_resistor = (0.1, 0.1, 0.1)):
self.i2c_device = i2c_instance
self.i2c_addr = i2c_addr
self.shunt_resistor = shunt_resistor
#self.write(C_REG_CONFIG, C_AVERAGING_NONE | \
# C_VBUS_CONV_TIME_1MS | \
# C_MODE_BUS_VOLTAGE_CONTINUOUS )
self.write(C_REG_CONFIG, C_MODE_BUS_VOLTAGE_CONTINUOUS )
def is_channel_enabled(self, channel=1):
"""Returns if a given channel is enabled or not"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
bit = C_ENABLE_CH[channel]
return self.read(C_REG_CONFIG) & bit != 0
def enable_channel(self, channel=1, enable=True):
"""Enables or disable a given channel"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
bit = C_ENABLE_CH[channel]
value = 0
if enable:
value = bit
self.update(C_REG_CONFIG, bit, value)
def shunt_voltage(self, channel=1):
"""Returns the channel's shunt voltage in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_signed(self.read(C_REG_SHUNT_VOLTAGE_CH[channel])) / 8.0
# convert to volts - LSB = 40uV
return value * C_SHUNT_ADC_LSB
def current(self, channel=1):
"""Return's the channel current in Amps"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
return self.shunt_voltage(channel) / self.shunt_resistor[channel-1]
def bus_voltage(self, channel=1):
"""Returns the channel's bus voltage in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_signed(self.read(C_REG_BUS_VOLTAGE_CH[channel])) / 8
# convert to volts - LSB = 8mV
return value * C_BUS_ADC_LSB
def shunt_critical_alert_limit(self, channel=1):
"""Returns the channel's shunt voltage critical alert limit in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_signed(self.read(C_REG_CRITICAL_ALERT_LIMIT_CH[channel])) / 8
# convert to volts - LSB = 40uV
return value * C_SHUNT_ADC_LSB
def set_shunt_critical_alert_limit(self, channel, voltage):
"""Sets the channel's shunt voltage critical alert limit in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_unsigned(round(voltage * C_SHUNT_ADC_LSB) * 8)
self.write(C_REG_CRITICAL_ALERT_LIMIT_CH[channel], value)
def shunt_warning_alert_limit(self, channel=1):
"""Returns the channel's shunt voltage warning alert limit in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_signed(self.read(C_REG_WARNING_ALERT_LIMIT_CH[channel])) / 8
# convert to volts - LSB = 40uV
return value * C_SHUNT_ADC_LSB
def set_shunt_warning_alert_limit(self, channel, voltage):
"""Sets the channel's shunt voltage warning alert limit in Volts"""
assert 1 <= channel <= 3, "channel argument must be 1, 2, or 3"
value = self._to_unsigned(round(voltage * C_SHUNT_ADC_LSB) * 8)
self.write(C_REG_WARNING_ALERT_LIMIT_CH[channel], value)
@property
def is_ready(self):
"""Returns the CVRF (ConVersion Ready Flag) from the mask/enable register """
regvalue = self.read(C_REG_MASK_ENABLE)
print(regvalue)
test = (regvalue & C_CONV_READY_FLAG) != 0x0
print(test)
return test
import sys
from machine import Pin, SoftI2C
#from ina3221 import *
ina = INA3221(i2c)
ina.enable_channel(3)
volt = ina.bus_voltage(3)
print(volt)
from machine import I2C, Pin
# Initialisation de l'I2C
i2c = I2C(1, scl=Pin(22), sda=Pin(21), freq=100000)
# Adresse I2C du INA3221
INA3221_ADDR = 0x40
def int_to_binary(num):
if num == 0:
return "0"
binary_string = ""
while num > 0:
remainder = num % 2
binary_string = str(remainder) + binary_string
num //= 2
return binary_string
def bin_to_int(strbin):
sum = 0
puis = len(strbin)-1
for i,c in enumerate(strbin):
#print(i,c)
sum+= 2**(puis-i)*int(c)
a=hex(sum)
print(a)
return sum
RST = "0" #15
CH1en = "1" #14
CH2en = "0" #13
CH3en = "1" #12
AVG = "000" #11-9
VBUSCT= "001" #8-6
VSHCT = "000" #5-3
MODE = "110" #2-0
config_value = RST+CH1en+CH2en+CH3en+AVG+VBUSCT+VSHCT+MODE
#print(config_value)
#config_value = bin_to_int(config_value)
# Registres
CONFIG_REG = 0x00
BUS_VOLTAGE_REG_CH1 = 0x06
"""
# Configuration du registre de configuration
#config_value = 0x5006 # Exemple de valeur de configuration
#print(config_value)
#config_value = C_RESET
#print(len(config_value))
i2c.writeto_mem(INA3221_ADDR, CONFIG_REG, config_value.to_bytes(2, 'big'))
reg = i2c.readfrom_mem(INA3221_ADDR,CONFIG_REG , 2)
#reg = int.from_bytes(reg, 'big') >> 3 # Conversion en 13 bits
reg = int.from_bytes(reg, 'big')
reg = hex(reg)
print("a",reg)
while True:
# Lecture de la tension de bus du canal 1
bus_voltage_raw = i2c.readfrom_mem(INA3221_ADDR, BUS_VOLTAGE_REG_CH1, 2)
reg = int.from_bytes(bus_voltage_raw, 'big')
print(reg)
binary = int_to_binary(reg)
print(binary)
binary = binary[:-3]
print(binary)
volt = bin_to_int(binary)
print(volt)
print(volt*0.008)
bus_voltage = int.from_bytes(bus_voltage_raw, 'big') >> 3 # Conversion en 13 bits
print(bus_voltage)
bus_voltage *= 0.008 # Conversion en volts (1 LSB = 8 mV)
print("Tension de bus du canal 1 : {:.3f} V".format(bus_voltage))
time.sleep(2)
break
"""