ads1115
/
ads1115mod.py
372 строки · 25.0 Кб
1# micropython
2# mail: goctaprog@gmail.com
3# MIT license
4# import struct
5
6from sensor_pack_2 import bus_service7from sensor_pack_2.base_sensor import DeviceEx, Iterator, check_value, get_error_str # all_none8from sensor_pack_2.adcmod import ADC, adc_init_props # , raw_value_ex9import micropython10from micropython import const11from collections import namedtuple12from sensor_pack_2.bitfield import bit_field_info13from sensor_pack_2.bitfield import BitFields14from sensor_pack_2.regmod import RegistryRW15
16# Register address pointer
17# 00: Conversion register
18# 01: Config register
19# 10: Lo threshold register
20# 11: Hi threshold register
21
22_mask_in_mux = const(0b111_0000_0000_0000)23_mask_gain_amp = const(0b1110_0000_0000)24_mask_data_rate = const(0b1110_0000)25_mask_comp_queue = const(0b11)26
27_2pwr15 = const(2 ** 15)28_low_val = const(_2pwr15)29_max_val = const(_2pwr15 - 1)30
31'''
32# параметры компаратора АЦП
33comparator_props = namedtuple("comparator_props", "mode polarity latch queue")
34# основные параметры АЦП
35common_props = namedtuple("common_props", "operational_status in_mux_config gain_amplifier operating_mode data_rate")
36'''
37
38# свойства компаратора: mode:bool, polarity:bool, latch:bool, queue:int 0..3,
39# lo_threshold:int 16 bit, hi_threshold:int 16 bit
40# mode: False - обычный компаратор (по умолчанию); True - оконный компаратор
41# polarity: False - активный низкий уровень (по умолчанию); True - активный высокий уровень
42# latch: False - Компаратор без фиксации. Вывод ALERT/RDY не фиксируется при его включении (по умолчанию); True -
43# Защелкивающийся компаратор. Вывод ALERT/RDY остается зафиксированным до тех пор, пока данные преобразования не будут
44# прочитаны ведущим.
45# queue: 00 Утвердить после одного преобразования
46# 01 Утвердить после двух преобразований
47# 10 Утвердить после четырех преобразований
48# 11 Отключить компаратор и установите вывод ALERT/RDY в состояние высокого импеданса (по умолчанию).
49# lo_threshold, hi_threshold: значения верхнего и нижнего порогов, используемые компаратором, сохраняются в двух
50# 16-битных регистрах в формате дополнения до двух. Компаратор реализован как цифровой компаратор; поэтому значения в
51# этих регистрах должны обновляться при каждом изменении настроек PGA.
52#
53specific_props = namedtuple("specific_props", "mode polarity latch queue lo_threshold hi_threshold")54# цена младшего разряда АЦП в зависимости от коэффициента усиления(gain_amp)
55# 0, 1, 2, 3, 4, 5
56_lsb = 187.5E-6, 125E-6, 62.5E-6, 31.25E-6, 15.625E-6, 7.8125E-657# действительные коэффициенты усиления в зависимости от поля PGA[2:0] регистра CONFIG
58_natural_gains = 3.0, 2.0, 1.0, 1/2, 1/4, 1/859
60
61def _get_lsb(gain_amp: int) -> float:62"""Возвращает цену младшего разряда в зависимости от настройки входного делителя напряжения.63gain_amp = 0..5"""
64print(f"DBG: lsb: {_lsb[gain_amp]}; {gain_amp}")65return _lsb[gain_amp]66
67
68def _get_correct_gain(gain: int) -> int:69"""Проверяет усиление на правильность и возвращает правильное значение в диапазоне 0..5 включительно.70gain - сырое/raw значение для записи в регистр"""
71check_value(gain, range(8), f"Неверное значение усиления: {gain}")72# print(f"DBG:_get_correct_gain: {gain}")73if gain > 5:74return 575return gain76
77
78_model_1115 = 'ads1115'79
80
81def get_init_props(model: str) -> adc_init_props:82"""Возвращает параметры для инициализации АЦП в виде именованного кортежа по имени модели АЦП."""83if _model_1115 == model.lower():84return adc_init_props(reference_voltage=2.048, max_resolution=16, channels=4,85differential_channels=4, differential_mode=True)86raise ValueError(f"Неизвестная модель АЦП!")87
88
89class Ads1115(DeviceEx, ADC, Iterator):90"""АЦП на шине I2C от TI.91Low-Power, I2C, 860-SPS, 16-Bit ADC with internal reference, oscillator, and programmable comparator"""
92
93_config_reg_ads1115 = (bit_field_info(name='OS', position=range(15, 16), valid_values=None), # Operational status or single-shot conversion start94bit_field_info(name='MUX', position=range(12, 15), valid_values=None), # Input multiplexer configuration95bit_field_info(name='PGA', position=range(9, 12), valid_values=range(6)), # Programmable gain amplifier configuration96bit_field_info(name='MODE', position=range(8, 9), valid_values=None), # Device operating mode97bit_field_info(name='DR', position=range(5, 8), valid_values=None), # Data rate98bit_field_info(name='COMP_MODE', position=range(4, 5), valid_values=None), # Comparator mode99bit_field_info(name='COMP_POL', position=range(3, 4), valid_values=None), # Comparator polarity100bit_field_info(name='COMP_LAT', position=range(2, 3), valid_values=None), # Latching comparator101bit_field_info(name='COMP_QUE', position=range(0, 2), valid_values=None) # Comparator queue and disable102)103
104def __init__(self, adapter: bus_service.BusAdapter, address=0x48):105check_value(address, range(0x48, 0x4C), f"Неверное значение адреса I2C устройства: 0x{address:x}")106DeviceEx.__init__(self, adapter, address, True)107ADC.__init__(self, get_init_props(_model_1115), model=_model_1115)108# регистр настройки109self._config_reg = RegistryRW(device=self, address=0x01,110fields=BitFields(Ads1115._config_reg_ads1115), byte_len=None)111self._differential_mode = True # дифференциальный АЦП. для get_lsb112# буфер на 4 байта113self._buf_4 = bytearray((0 for _ in range(4)))114# При записи: 0: Нет эффекта; 1: Запустить одиночное преобразование (в состоянии пониж. энергопотребл)115# При чтении: 0: устройство выполняет преобразование; 1: устройство НЕ выполняет преобразование.116self._operational_status = None117# настройки компаратора118self._comparator_mode = None119self._comparator_polarity = None120self._comparator_latch = None121self._comparator_queue = None122# Внимание, важный вызов(!)123# читаю config АЦП и обновляю поля класса124_raw_cfg = self.get_raw_config()125# print(f"DBG: get_raw_config(): 0x{_raw_cfg:x}")126self.raw_config_to_adc_properties(_raw_cfg)127
128@staticmethod129def get_raw_mux_cfg(ch: int, df: bool) -> int:130"""Возвращает сырое значение для мультиплексора входов (MUX)"""131# _ch = self.check_channel_number(ch, df)132if df:133return ch # каналы 0..3 дифференциальные134return 4 + ch # каналы 4..7 обычные135
136@micropython.native137def get_conversion_cycle_time(self) -> int:138"""возвращает время преобразования в [мкc] аналогового значения в цифровое"""139return 1 + int(1_000_000 / self.sample_rate)140
141def gain_raw_to_real(self, gain_raw: int) -> float:142"""Преобразует 'сырое' значение усиления в 'настоящее'"""143# self._natural_gain = _natural_gains[raw_gain]144return 1 / _natural_gains[gain_raw]145
146# @staticmethod
147# def get_correct_gain(self, gain_raw: int) -> int:
148# """Проверяет усиление на правильность и возвращает правильное значение в диапазоне 0..5 включительно.
149# Вычисляет действительный коэффициент усиления в self._natural_gain.
150# gain - сырое/raw значение для записи в регистр"""
151# check_value(gain_raw, range(8), f"Неверное значение усиления: {gain_raw}")
152# # присваиваю действительное значение усиления входного аналогового сигнала
153# # self._real_gain = self.gain_raw_to_real(gain) # qqq
154# if gain_raw in range(6):
155# return gain_raw
156# return 5
157
158def check_gain_raw(self, gain_raw: int) -> int:159"""Проверяет сырое усиление на правильность. В случае ошибки выброси исключение!160Возвращает gain_raw в случае успеха! Для переопределения в классе-наследнике."""
161r6 = range(6)162return check_value(gain_raw, r6, get_error_str("gain_raw", gain_raw, r6))163
164def check_data_rate_raw(self, data_rate_raw: int) -> int:165"""Проверяет сырое data_rate на правильность. В случае ошибки выброси исключение!166Возвращает data_rate_raw в случае успеха!"""
167r8 = range(8)168return check_value(data_rate_raw, r8, get_error_str("data_rate_raw", data_rate_raw, r8))169
170# def check_params(self, data_rate_raw: int, gain_raw: int):
171# r6, r8 = range(6), range(8)
172# # check_value(in_mux_conf, r8, get_error_str("in_mux_conf", in_mux_conf, r8))
173# check_value(gain_raw, r6, get_error_str("gain_raw", gain_raw, r6))
174# check_value(data_rate_raw, r8, get_error_str("data_rate_raw", data_rate_raw, r8))
175
176def _adc_props_to_raw(self,177# При записи: 0: Нет эффекта; 1: Запустить одиночное преобразование (в состоянии пониж. энергопотребл)178# При чтении: 0: устройство выполняет преобразование; 1: устройство НЕ выполняет преобразование.179operational_status: [bool, None] = None, # bit 15, config register180# Эти биты настраивают входной мультиплексор. Эти биты не выполняют никакой функции в ADS1113/ADS1114.181# 0 - измеряет напряжение между выводами Ain0(+) и Ain1(-) (по умолчанию, дифференциальный вход)182# 1 - измеряет напряжение между выводами Ain0(+) и Ain3(-) (дифференциальный вход)183# 2 - измеряет напряжение между выводами Ain1(+) и Ain3(-) (дифференциальный вход)184# 3 - измеряет напряжение между выводами Ain2(+) и Ain3(-) (дифференциальный вход)185# 4 - измеряет напряжение между выводами Ain0(+) и GND(-)186# 5 - измеряет напряжение между выводами Ain1(+) и GND(-)187# 6 - измеряет напряжение между выводами Ain2(+) и GND(-)188# 7 - измеряет напряжение между выводами Ain3(+) и GND(-)189in_mux_config: [int, None] = None, # bit 14..12, config register, только ADS1115;190# Конфигурация усилителя с программируемым усилением.191# Не подавайте на аналоговые входы устройства напряжение более VDD+0,3 В!!!192# Эти биты устанавливают 'полный диапазон шкалы' (FSR) усилителя с программируемым усилением.193# Эти биты не выполняют никакой функции в ADS1113.194# 0 - FSR = +/- 6.144 Вольта (полный диапазон масштабирования АЦП)195# 1 - FSR = +/- 4.096 Вольта (полный диапазон масштабирования АЦП)196# 2 - FSR = +/- 2.048 Вольта (по умолчанию)197# 3 - FSR = +/- 1.024 Вольта198# 4 - FSR = +/- 0.512 Вольта199# 5 - FSR = +/- 0.256 Вольта200gain_amplifier: [int, None] = None, # bit 11..9, config register. усиление raw201# 0 - Режим непрерывного преобразования;202# 1 - Режим одиночного преобразования или состояние отключения питания (по умолчанию)203operating_mode: [bool, None] = None, # bit 8, config register, текущий режим работы204# bit 7..5, кол-во отсчетов АЦП в секунду (ОВС/samples per second)205# 0 - 8 отчетов в секунду (ОВС)206# 1 - 16 ОВС207# 2 - 32 ОВС208# 3 - 64 ОВС209# 4 - 128 ОВС210# 5 - 250 ОВС211# 6 - 475 ОВС212# 7 - 860 ОВС213data_rate: [int, None] = None, # bit 7..5, config register214# 0: Традиционный компаратор (по умолчанию).215# 1: Оконный компаратор.216comparator_mode: [bool, None] = None, # bit 4, config register, режим сравнения, только для ADS1114 и ADS1115!217# bit 3, режим сравнения, только для ADS1114 и ADS1115!218# 0: активный сигнал "0" (по умолчанию).219# 1: активный сигнал "1".220comparator_polarity: [bool, None] = None, # config register221# 0: Компаратор без фиксации. Вывод ALERT/RDY не фиксируется при подаче сигнала (по умолчанию).222# 1: Фиксирующийся компаратор. Вывод ALERT/RDY остается зафиксированным до тех пор, пока данные223# преобразования не будут прочитаны ведущим или соответствующий ответ на предупреждение SMBus не будет224# отправлен ведущим.225comparator_latch: [bool, None] = None, # bit 2, config register, только для ADS1114 и ADS1115!226# Эти биты выполняют две функции. Если установлено значение 0b11, компаратор отключается, а вывод227# ALERT/RDY устанавливается в состояние с высоким импедансом. При установке любого другого значения228# вывод ALERT/RDY и функция компаратора активируются, а установленное значение определяет количество229# последовательных преобразований, превышающих верхний или нижний порог, необходимый для установки230# вывода ALERT/RDY.231# 0: установка после одного преобразования.232# 1: установка после двух преобразований.233# 2: установка после четырех преобразований.234# 3: отключает компаратор и установит вывод ALERT/RDY в высокое сопротивление (по умолчанию).235comparator_queue: [int, None] = None, # bit 1..0, config register, только для ADS1114 и ADS1115!236) -> int:237"""Возвращает 'сырое' значение настроек АЦП/датчика для записи в регистр CONF/config register.238Регистр Config. (P[1:0] = 0x1) [reset value = 0x8583]"""
239val = self.get_raw_config() # читаю регистр CONF. Обязательная первая строка метода!!!240reg = self._config_reg241# изменяю настройки. Ниже пишете свой код!242if operational_status is not None:243reg['OS'] = operational_status244if in_mux_config is not None:245reg['MUX'] = in_mux_config246if gain_amplifier is not None:247reg['PGA'] = self.check_gain_raw(gain_amplifier)248if operating_mode is not None:249reg['MODE'] = operating_mode250if data_rate is not None:251reg['DR'] = data_rate252if comparator_mode is not None:253reg['COMP_MODE'] = comparator_mode254if comparator_polarity is not None:255reg['COMP_POL'] = comparator_polarity256if comparator_latch is not None:257reg['COMP_LAT'] = comparator_latch258if comparator_queue is not None:259reg['COMP_QUE'] = comparator_queue260# возвращаю измененное, в соотв с входными параметрами, 'сырое' значение для записи в регистр CONF261return reg.value262
263def get_raw_config(self) -> int:264"""Возвращает текущие настройки датчика из регистров(конфигурации) датчика в виде числа.265Чтение регистра CONF, адрес 0x01, 16 бит"""
266# return self.unpack(fmt_char="H", source=self.read_reg(reg_addr=0x01, bytes_count=2))[0]267return int(self._config_reg) # неявный вызов метода RegistryRO.read()268
269def set_raw_config(self, value: int):270self._config_reg.write(value)271# self.write_reg(reg_addr=0x01, value=value, bytes_count=2)272
273def raw_config_to_adc_properties(self, raw_config: int):274"""Возвращает текущие настройки датчика из числа в поля класса."""275def mux_raw_cfg_to_channel(mux_raw_cfg: int):276"""Преобразует сырою информацию о канале АЦП в обработанную. А именно, номер канала и является ли этот канал277дифференциальным"""
278check_value(mux_raw_cfg, range(8), f"Неверный значение MUX[2:0]: {mux_raw_cfg}")279self._is_diff_channel = mux_raw_cfg < 4 # У ADS1115 первые 4 канала дифференциальные!280if mux_raw_cfg in range(4): # 0..3281self._curr_channel = mux_raw_cfg282else: # >= 4..7283self._curr_channel = mux_raw_cfg - 4284# поехали285reg = self._config_reg286# это лишний вызов, поскольку метод get_raw_config вызывает метод RegistryRO.read(), но287# для ясности кода присваиваю явно288reg.value = raw_config289# обновление значений полей экземпляра класса290self._operational_status = reg['OS']291mux_raw_cfg_to_channel(reg['MUX'])292self._curr_raw_gain = _get_correct_gain(reg['PGA'])293self._single_shot_mode = reg['MODE']294self._curr_raw_data_rate = reg['DR']295self._curr_resolution = self.init_props.max_resolution # число бит в отсчете не изменяется у этого АЦП296# comparator297self._comparator_mode = reg['COMP_MODE']298self._comparator_polarity = reg['COMP_POL']299self._comparator_latch = reg['COMP_LAT']300self._comparator_queue = reg['COMP_QUE']301
302def adc_properties_to_raw_config(self) -> int:303"""Преобразует свойства АЦП из полей класса в 'сырую' конфигурацию АЦП.304adc_properties -> raw_config"""
305
306return self._adc_props_to_raw(307operational_status=self._single_shot_mode,308in_mux_config=Ads1115.get_raw_mux_cfg(self._curr_channel, self._is_diff_channel),309gain_amplifier=self.current_raw_gain,310operating_mode=self._single_shot_mode,311data_rate=self.current_sample_rate,312comparator_mode=None,313comparator_polarity=None,314comparator_latch=None,315comparator_queue=None316)317
318def get_raw_value(self) -> int:319"""Возвращает 'сырое' значение отсчета АЦП."""320return self.unpack(fmt_char="h", source=self.read_reg(reg_addr=0x00, bytes_count=2))[0]321
322def _get_thresholds(self) -> tuple:323"""Возвращает пороговые значения компаратора в виде кортежа: (высокий порог, низкий порог)"""324buf = self.read_buf_from_mem(0x02, self._buf_4)325# print(f"DBG: {buf}")326return self.unpack(fmt_char="hh", source=buf)327
328# def _set_thresholds(self, hi_val: int, lo_val: int):329# rng = range(-32768, 32768)330# str_error = "Входной параметр вне диапазона!"331# check_value(hi_val, rng, str_error)332# check_value(lo_val, rng, str_error)333# # в буфере пара значений334# buf = self.pack("hh", lo_val, hi_val)335# self.write_buf_to_mem(0x02, buf)336
337# @property338# def thresholds(self) -> tuple:339# return self._get_thresholds()340
341# @thresholds.setter342# def thresholds(self, value: tuple[int, int]):343# self._set_thresholds(value[0], value[1])344
345def get_specific_props(self):346"""Возвращает свойства компаратора"""347thr = self._get_thresholds()348return specific_props(mode=self._comparator_mode, polarity=self._comparator_polarity,349latch=self._comparator_latch, queue=self._comparator_queue,350lo_threshold=thr[0], hi_threshold=thr[1])351
352def get_resolution(self, raw_data_rate: int) -> int:353"""Возвращает кол-во бит в отсчете АЦП в зависимости от частоты взятия отсчетов (сырое значение!).354Переопределить в классе - наследнике!"""
355# у данного АЦП разрешение не изменяется!356return 16357
358def raw_sample_rate_to_real(self, raw_sample_rate: int) -> float:359"""Преобразует сырое значение частоты преобразования в [Гц].360Переопределить в классе - наследнике!"""
361sps = 8, 16, 32, 64, 128, 250, 475, 860362return sps[raw_sample_rate]363
364# Iterator365def __iter__(self):366return self367
368def __next__(self) -> [int, None]:369if not self._single_shot_mode:370# режим непрерывного преобразования!371return self.value372return None373