MicroPython(ESP8266)を使用して、I2Cで接続できるADS1115を使用して、電圧の測定を行ってみました。
使用するADS1115は、16BitA/Dコンバータで、4つのシングルエンド入力または2つの差動入力、およびプログラムブルコンパレータを使用できます。
今回は、シングルエンド入力または2つの差動入力を使用して、電圧の測定に挑戦したいと思います。
ADS1115は、基板に実装されたものを使用しました。
KKHMF ADS1115(amazon 他)
ESP8266とADS1115との回路図は下記のとおりです。
A0~A3までのアナログ入力は、1KΩの抵抗を並列および直列に接続して、500Ω、1KΩ、2KΩ、3KΩで抵抗分割しています。電源電圧は 3.3Vです。
thonnyとシリアル通信するためには、回路図には図示していませんが、IO15(6pin)を10KΩでGnd(プルダウン)に接続する必要があります。
および、IO2(7pin)、IO0(8pin)は内部でプルアップされていますが、必要であれば10KΩでVCC(3.3V)に接続してください。
MicroPythonのプログラムは下記のようになりました。
開発環境は前回の「MicroPython(ESP8266)に萌えたい。ESP-WROOM-02でLちか。」を参照してください
まずは、I2Cのpinを決めます。ESP8266ではソフトウェアI2Cになっているので、任意のpinを指定できます。
ここでは、SCL=IO14(3pin)、SDA=IO12(4pin)に設定しました。
必要な、ライブラリーとI2Cの初期を行います。
# MicroPython ADS1115 readding
#
# SCL = IO14(3pin)
# SDA = IO12(4pin)
# I2C address =0x48 (addr open)
from machine import Pin, I2C
import utime
i2c=I2C(scl=Pin(14),sda=Pin(12),freq=400000)
I2CのADS1115のアドレスは、0x48(ADDR(5pin)は無接続)
極性表示のpolarityを設定します。polarity_data = 0で+表示、polarity_data = でー表示になります。
必要なバッファーを設定します。
configレジスター用に3バイト、conversion_addr用に1バイト、conversionレジスタ用に2バイト用意します。
また、configレジスターの定義をします。
最後にlsbサイズの定義をします。
polarity=['+','-']
polarity_data = 0
config_buff=bytearray(3)
conversion_addr_buff=bytearray(1)
conversion_buff=bytearray(2)
#Address Pointer Register
conversion_reg = 0x00
config_reg = 0x01
#config Register
# input(Differential)
ain0_ain1 = 0b0000_0000
ain0_ain3 = 0b0001_0000
ain1_ain3 = 0b0010_0000
ain2_ain3 = 0b0011_0000
# input(Single-ended)
ain0_gnd = 0b0100_0000
ain1_gnd = 0b0101_0000
ain2_gnd = 0b0110_0000
ain3_gnd = 0b0111_0000
# gain amplifier
v6144 = 0b0000_0000
v4064 = 0b0000_0010
v2048 = 0b0000_0100
v1024 = 0b0000_0110
v0512 = 0b0000_1000
v0256 = 0b0000_1010
v0256 = 0b0000_1100
v0256 = 0b0000_1110
# data rate
sps8 = 0b0000_0000
sps16 = 0b0010_0000
sps32 = 0b0100_0000
sps64 = 0b0110_0000
sps128 = 0b1000_0000
sps250 = 0b1010_0000
sps475 = 0b1100_0000
sps860 = 0b1110_0000
lsb_size=[187.5,125.0,62.5,31.25,15.625,7.8125,7.8125,7.8125]
今回は、ユーザー定義関数を作成しました。
関数名は、ads1115_readで引数として、入力端子、入力電圧範囲、レートです。
戻り値として、極性と測定した値を返します。
print文で、極性、測定したデータをmVで表示します。
polarity_data,data= ads1115_read(ain0_gnd ,v4064,sps128)
print("ain0_gnd=",polarity[polarity_data],data /1000,"mV")
作成したユーザー定義関数ads1115_readは下記のとおりです。
一部コメント文がありますが、確認用に残してあります。
config_buffを設定します。
config_buff[0]はconfigレジスターを指定します。0x01になります。
config_buff[1]は初期設定値0x81と入力端子、入力電圧範囲のorを取ります。
config_buff[2]は初期設定値0x03とレートのorを取ります。
i2c.writeto関数で、I2Cアドレスおよびconfigバッファーを指定して、書き込みします。
conversionレジスターから測定値を読み出す準備をします
conversion_addr_buff[0]にconversion_reg(0x00)を指定します。
20ms後にi2c.writeto関数でI2Cアドレスとconversion_buff[0]つまり0x00を指定して、書き込みします。
i2c.readfrom_into関数でI2Cアドレスおよびconversionバッファーを読み込みます。
読みこまれたconversion_buff[0]のbit7は極性となっていますので、IF文で0x80でandを取って検査します。
マイナスの場合は、polarity_data=1をセットした後、conversion_buff[0]を左8ビットシフトし、conversion_buff[1]とorをとり、0xffffでandを取ったのちbit反転します。
プラスの場合は、polarity_data=0をセットした後、conversion_buff[0]を左8ビットシフトし、conversion_buff[1]とorをとり、0x7fffでandを取ります。
16bit生データに、LSBの係数をかけます。
戻り値として、極性と測定データ(μV)を返します。
def ads1115_read(input_ads,gain,rate):
# utime.sleep_ms(10)
config_buff[0] = config_reg
config_buff[1] = 0x81 | input_ads | gain
config_buff[2] = 0x03 | rate
# print(config_buff[0])
# print(config_buff[1])
# print(config_buff[2])
conversion_addr_buff[0] = conversion_reg
i2c.writeto(i2c_addr,config_buff)
utime.sleep_ms(20)
# i2c.readfrom_into(i2c_addr,conversion_buff)
# print("buff0=",conversion_buff[0])
# print("buff1=",conversion_buff[1])
i2c.writeto(i2c_addr,conversion_addr_buff)
# conversion_buff=i2c.readfrom(i2c_addr,2)
i2c.readfrom_into(i2c_addr,conversion_buff)
# print("buff0=",conversion_buff[0])
# print("buff1=",conversion_buff[1])
if (conversion_buff[0] & 0x80):
polarity_data=1
data16bit = ~(((conversion_buff[0] << 8) | conversion_buff[1])) & 0xffff
# print("-data16bit=",bin(data16bit))
# print("-data16bit=",hex(data16bit))
# print("-data16bit=",data16bit)
else:
polarity_data=0
data16bit=(((conversion_buff[0] << 8) | conversion_buff[1])) & 0x7fff
# print("+data16bit=",data16bit)
# print(polarity[polarity_data])
# print("data16bit=",data16bit)
# print(lsb_size[gain >> 1])
data = data16bit * (lsb_size[gain >> 1])
return polarity_data,data
実際に測定した結果は下記のとおりです。(内はテスタで測定した結果です)
MicroPython v1.20.0 on 2023-04-26; ESP module with ESP8266
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
ain0_gnd= + 252.25 mV
ain1_gnd= + 754.5 mV
ain2_gnd= + 1763.75 mV
ain3_gnd= + 3278.88 mV
ain0_ain1= - 502.125 mV
ain0_ain3= - 3026.38 mV
ain1_ain3= - 2524.13 mV
ain2_ain3= - 1514.5 mV
>>>
ain0_gnd= + 252.25 mV (0.252V)
ain1_gnd= + 754.5 mV (0.753V)
ain2_gnd= + 1763.75 mV (1.760V)
ain3_gnd= + 3278.88 mV (3.279V)
ain0_ain1= - 502.125 mV (-0.503V)
ain0_ain3= - 3026.38 mV (-3.026V)
ain1_ain3= - 2524.13 mV (-2.523V)
ain2_ain3= - 1514.5 mV (-1.514V)
全体のブログラムは下記のとおりです。
# MicroPython ADS1115 readding
#
# SCL = IO14(4pin)
# SDA = IO12(3pin)
# I2C address =0x48 (addr open)
from machine import Pin, I2C
import utime
i2c=I2C(scl=Pin(14),sda=Pin(12),freq=400000)
i2c_addr= 0x48
polarity=['+','-']
polarity_data = 0
config_buff=bytearray(3)
conversion_addr_buff=bytearray(1)
conversion_buff=bytearray(2)
#Address Pointer Register
conversion_reg = 0x00
config_reg = 0x01
#config Register
# input(Differential)
ain0_ain1 = 0b0000_0000
ain0_ain3 = 0b0001_0000
ain1_ain3 = 0b0010_0000
ain2_ain3 = 0b0011_0000
# input(Single-ended)
ain0_gnd = 0b0100_0000
ain1_gnd = 0b0101_0000
ain2_gnd = 0b0110_0000
ain3_gnd = 0b0111_0000
# gain amplifier
v6144 = 0b0000_0000
v4064 = 0b0000_0010
v2048 = 0b0000_0100
v1024 = 0b0000_0110
v0512 = 0b0000_1000
v0256 = 0b0000_1010
v0256 = 0b0000_1100
v0256 = 0b0000_1110
# data rate
sps8 = 0b0000_0000
sps16 = 0b0010_0000
sps32 = 0b0100_0000
sps64 = 0b0110_0000
sps128 = 0b1000_0000
sps250 = 0b1010_0000
sps475 = 0b1100_0000
sps860 = 0b1110_0000
lsb_size=[187.5,125.0,62.5,31.25,15.625,7.8125,7.8125,7.8125]
def ads1115_read(input_ads,gain,rate):
# utime.sleep_ms(10)
config_buff[0] = config_reg
config_buff[1] = 0x81 | input_ads | gain
config_buff[2] = 0x03 | rate
# print(config_buff[0])
# print(config_buff[1])
# print(config_buff[2])
conversion_addr_buff[0] = conversion_reg
i2c.writeto(i2c_addr,config_buff)
utime.sleep_ms(20)
# i2c.readfrom_into(i2c_addr,conversion_buff)
# print("buff0=",conversion_buff[0])
# print("buff1=",conversion_buff[1])
i2c.writeto(i2c_addr,conversion_addr_buff)
# conversion_buff=i2c.readfrom(i2c_addr,2)
i2c.readfrom_into(i2c_addr,conversion_buff)
# print("buff0=",conversion_buff[0])
# print("buff1=",conversion_buff[1])
if (conversion_buff[0] & 0x80):
polarity_data=1
data16bit = ~(((conversion_buff[0] << 8) | conversion_buff[1])) & 0xffff
# print("-data16bit=",bin(data16bit))
# print("-data16bit=",hex(data16bit))
# print("-data16bit=",data16bit)
else:
polarity_data=0
data16bit=(((conversion_buff[0] << 8) | conversion_buff[1])) & 0x7fff
# print("+data16bit=",data16bit)
# print(polarity[polarity_data])
# print("data16bit=",data16bit)
# print(lsb_size[gain >> 1])
data = data16bit * (lsb_size[gain >> 1])
return polarity_data,data
polarity_data,data= ads1115_read(ain0_gnd ,v4064,sps128)
print("ain0_gnd=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain1_gnd ,v4064,sps128)
print("ain1_gnd=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain2_gnd ,v4064,sps128)
print("ain2_gnd=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain3_gnd ,v4064,sps128)
print("ain3_gnd=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain0_ain1,v4064,sps128)
print("ain0_ain1=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain0_ain3,v4064,sps128)
print("ain0_ain3=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain1_ain3,v4064,sps128)
print("ain1_ain3=",polarity[polarity_data],data /1000,"mV")
polarity_data,data= ads1115_read(ain2_ain3,v4064,sps128)
print("ain2_ain3=",polarity[polarity_data],data /1000,"mV")