ads1115

Форк
0
/
ads1115mod.py 
372 строки · 25.0 Кб
1
# micropython
2
# mail: goctaprog@gmail.com
3
# MIT license
4
# import struct
5

6
from sensor_pack_2 import bus_service
7
from sensor_pack_2.base_sensor import DeviceEx, Iterator, check_value, get_error_str   # all_none
8
from sensor_pack_2.adcmod import ADC, adc_init_props    # , raw_value_ex
9
import micropython
10
from micropython import const
11
from collections import namedtuple
12
from sensor_pack_2.bitfield import bit_field_info
13
from sensor_pack_2.bitfield import BitFields
14
from sensor_pack_2.regmod import RegistryRW
15

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
# параметры компаратора АЦП
33
comparator_props = namedtuple("comparator_props", "mode polarity latch queue")
34
# основные параметры АЦП
35
common_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
#
53
specific_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-6
57
# действительные коэффициенты усиления в зависимости от поля PGA[2:0] регистра CONFIG
58
_natural_gains = 3.0, 2.0, 1.0, 1/2, 1/4, 1/8
59

60

61
def _get_lsb(gain_amp: int) -> float:
62
    """Возвращает цену младшего разряда в зависимости от настройки входного делителя напряжения.
63
    gain_amp = 0..5"""
64
    print(f"DBG: lsb: {_lsb[gain_amp]}; {gain_amp}")
65
    return _lsb[gain_amp]
66

67

68
def _get_correct_gain(gain: int) -> int:
69
    """Проверяет усиление на правильность и возвращает правильное значение в диапазоне 0..5 включительно.
70
    gain - сырое/raw значение для записи в регистр"""
71
    check_value(gain, range(8), f"Неверное значение усиления: {gain}")
72
    # print(f"DBG:_get_correct_gain: {gain}")
73
    if gain > 5:
74
        return 5
75
    return gain
76

77

78
_model_1115 = 'ads1115'
79

80

81
def get_init_props(model: str) -> adc_init_props:
82
    """Возвращает параметры для инициализации АЦП в виде именованного кортежа по имени модели АЦП."""
83
    if _model_1115 == model.lower():
84
        return adc_init_props(reference_voltage=2.048, max_resolution=16, channels=4,
85
                              differential_channels=4, differential_mode=True)
86
    raise ValueError(f"Неизвестная модель АЦП!")
87

88

89
class Ads1115(DeviceEx, ADC, Iterator):
90
    """АЦП на шине I2C от TI.
91
    Low-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 start
94
                           bit_field_info(name='MUX', position=range(12, 15), valid_values=None),   # Input multiplexer configuration
95
                           bit_field_info(name='PGA', position=range(9, 12), valid_values=range(6)),    # Programmable gain amplifier configuration
96
                           bit_field_info(name='MODE', position=range(8, 9), valid_values=None),        # Device operating mode
97
                           bit_field_info(name='DR', position=range(5, 8), valid_values=None),          # Data rate
98
                           bit_field_info(name='COMP_MODE', position=range(4, 5), valid_values=None),   # Comparator mode
99
                           bit_field_info(name='COMP_POL', position=range(3, 4), valid_values=None),    # Comparator polarity
100
                           bit_field_info(name='COMP_LAT', position=range(2, 3), valid_values=None),    # Latching comparator
101
                           bit_field_info(name='COMP_QUE', position=range(0, 2), valid_values=None)     # Comparator queue and disable
102
                           )
103

104
    def __init__(self, adapter: bus_service.BusAdapter, address=0x48):
105
        check_value(address, range(0x48, 0x4C), f"Неверное значение адреса I2C устройства: 0x{address:x}")
106
        DeviceEx.__init__(self, adapter, address, True)
107
        ADC.__init__(self, get_init_props(_model_1115), model=_model_1115)
108
        # регистр настройки
109
        self._config_reg = RegistryRW(device=self, address=0x01,
110
                                      fields=BitFields(Ads1115._config_reg_ads1115), byte_len=None)
111
        self._differential_mode = True      # дифференциальный АЦП. для get_lsb
112
        # буфер на 4 байта
113
        self._buf_4 = bytearray((0 for _ in range(4)))
114
        # При записи: 0: Нет эффекта; 1: Запустить одиночное преобразование (в состоянии пониж. энергопотребл)
115
        # При чтении: 0: устройство выполняет преобразование; 1: устройство НЕ выполняет преобразование.
116
        self._operational_status = None
117
        # настройки компаратора
118
        self._comparator_mode = None
119
        self._comparator_polarity = None
120
        self._comparator_latch = None
121
        self._comparator_queue = None
122
        # Внимание, важный вызов(!)
123
        # читаю config АЦП и обновляю поля класса
124
        _raw_cfg = self.get_raw_config()
125
        # print(f"DBG: get_raw_config(): 0x{_raw_cfg:x}")
126
        self.raw_config_to_adc_properties(_raw_cfg)
127

128
    @staticmethod
129
    def get_raw_mux_cfg(ch: int, df: bool) -> int:
130
        """Возвращает сырое значение для мультиплексора входов (MUX)"""
131
        # _ch = self.check_channel_number(ch, df)
132
        if df:
133
            return ch      # каналы 0..3 дифференциальные
134
        return 4 + ch      # каналы 4..7 обычные
135

136
    @micropython.native
137
    def get_conversion_cycle_time(self) -> int:
138
        """возвращает время преобразования в [мкc] аналогового значения в цифровое"""
139
        return 1 + int(1_000_000 / self.sample_rate)
140

141
    def gain_raw_to_real(self, gain_raw: int) -> float:
142
        """Преобразует 'сырое' значение усиления в 'настоящее'"""
143
        # self._natural_gain = _natural_gains[raw_gain]
144
        return 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

158
    def check_gain_raw(self, gain_raw: int) -> int:
159
        """Проверяет сырое усиление на правильность. В случае ошибки выброси исключение!
160
        Возвращает gain_raw в случае успеха! Для переопределения в классе-наследнике."""
161
        r6 = range(6)
162
        return check_value(gain_raw, r6, get_error_str("gain_raw", gain_raw, r6))
163

164
    def check_data_rate_raw(self, data_rate_raw: int) -> int:
165
        """Проверяет сырое data_rate на правильность. В случае ошибки выброси исключение!
166
        Возвращает data_rate_raw в случае успеха!"""
167
        r8 = range(8)
168
        return 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

176
    def _adc_props_to_raw(self,
177
                          # При записи: 0: Нет эффекта; 1: Запустить одиночное преобразование (в состоянии пониж. энергопотребл)
178
                          # При чтении: 0: устройство выполняет преобразование; 1: устройство НЕ выполняет преобразование.
179
                          operational_status: [bool, None] = None,  # bit 15, config register
180
                          # Эти биты настраивают входной мультиплексор. Эти биты не выполняют никакой функции в 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(-)
189
                          in_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 Вольта
200
                          gain_amplifier: [int, None] = None,  # bit 11..9, config register. усиление raw
201
                          # 0 - Режим непрерывного преобразования;
202
                          # 1 - Режим одиночного преобразования или состояние отключения питания (по умолчанию)
203
                          operating_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 ОВС
213
                          data_rate: [int, None] = None,    # bit 7..5, config register
214
                          # 0: Традиционный компаратор (по умолчанию).
215
                          # 1: Оконный компаратор.
216
                          comparator_mode: [bool, None] = None,  # bit 4, config register, режим сравнения, только для ADS1114 и ADS1115!
217
                          # bit 3, режим сравнения, только для ADS1114 и ADS1115!
218
                          # 0: активный сигнал "0" (по умолчанию).
219
                          # 1: активный сигнал "1".
220
                          comparator_polarity: [bool, None] = None,     # config register
221
                          # 0: Компаратор без фиксации. Вывод ALERT/RDY не фиксируется при подаче сигнала (по умолчанию).
222
                          # 1: Фиксирующийся компаратор. Вывод ALERT/RDY остается зафиксированным до тех пор, пока данные
223
                          # преобразования не будут прочитаны ведущим или соответствующий ответ на предупреждение SMBus не будет
224
                          # отправлен ведущим.
225
                          comparator_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 в высокое сопротивление (по умолчанию).
235
                          comparator_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]"""
239
        val = self.get_raw_config()  # читаю регистр CONF. Обязательная первая строка метода!!!
240
        reg = self._config_reg
241
        # изменяю настройки. Ниже пишете свой код!
242
        if operational_status is not None:
243
            reg['OS'] = operational_status
244
        if in_mux_config is not None:
245
            reg['MUX'] = in_mux_config
246
        if gain_amplifier is not None:
247
            reg['PGA'] = self.check_gain_raw(gain_amplifier)
248
        if operating_mode is not None:
249
            reg['MODE'] = operating_mode
250
        if data_rate is not None:
251
            reg['DR'] = data_rate
252
        if comparator_mode is not None:
253
            reg['COMP_MODE'] = comparator_mode
254
        if comparator_polarity is not None:
255
            reg['COMP_POL'] = comparator_polarity
256
        if comparator_latch is not None:
257
            reg['COMP_LAT'] = comparator_latch
258
        if comparator_queue is not None:
259
            reg['COMP_QUE'] = comparator_queue
260
        # возвращаю измененное, в соотв с входными параметрами, 'сырое' значение для записи в регистр CONF
261
        return reg.value
262

263
    def 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]
267
        return int(self._config_reg)    # неявный вызов метода RegistryRO.read()
268

269
    def set_raw_config(self, value: int):
270
        self._config_reg.write(value)
271
        # self.write_reg(reg_addr=0x01, value=value, bytes_count=2)
272

273
    def raw_config_to_adc_properties(self, raw_config: int):
274
        """Возвращает текущие настройки датчика из числа в поля класса."""
275
        def mux_raw_cfg_to_channel(mux_raw_cfg: int):
276
            """Преобразует сырою информацию о канале АЦП в обработанную. А именно, номер канала и является ли этот канал
277
            дифференциальным"""
278
            check_value(mux_raw_cfg, range(8), f"Неверный значение MUX[2:0]: {mux_raw_cfg}")
279
            self._is_diff_channel = mux_raw_cfg < 4   # У ADS1115 первые 4 канала дифференциальные!
280
            if mux_raw_cfg in range(4):     # 0..3
281
                self._curr_channel = mux_raw_cfg
282
            else:   # >= 4..7
283
                self._curr_channel = mux_raw_cfg - 4
284
        # поехали
285
        reg = self._config_reg
286
        # это лишний вызов, поскольку метод get_raw_config вызывает метод RegistryRO.read(), но
287
        # для ясности кода присваиваю явно
288
        reg.value = raw_config
289
        # обновление значений полей экземпляра класса
290
        self._operational_status = reg['OS']
291
        mux_raw_cfg_to_channel(reg['MUX'])
292
        self._curr_raw_gain = _get_correct_gain(reg['PGA'])
293
        self._single_shot_mode = reg['MODE']
294
        self._curr_raw_data_rate = reg['DR']
295
        self._curr_resolution = self.init_props.max_resolution        # число бит в отсчете не изменяется у этого АЦП
296
        # comparator
297
        self._comparator_mode = reg['COMP_MODE']
298
        self._comparator_polarity = reg['COMP_POL']
299
        self._comparator_latch = reg['COMP_LAT']
300
        self._comparator_queue = reg['COMP_QUE']
301

302
    def adc_properties_to_raw_config(self) -> int:
303
        """Преобразует свойства АЦП из полей класса в 'сырую' конфигурацию АЦП.
304
        adc_properties -> raw_config"""
305

306
        return self._adc_props_to_raw(
307
            operational_status=self._single_shot_mode,
308
            in_mux_config=Ads1115.get_raw_mux_cfg(self._curr_channel, self._is_diff_channel),
309
            gain_amplifier=self.current_raw_gain,
310
            operating_mode=self._single_shot_mode,
311
            data_rate=self.current_sample_rate,
312
            comparator_mode=None,
313
            comparator_polarity=None,
314
            comparator_latch=None,
315
            comparator_queue=None
316
        )
317

318
    def get_raw_value(self) -> int:
319
        """Возвращает 'сырое' значение отсчета АЦП."""
320
        return self.unpack(fmt_char="h", source=self.read_reg(reg_addr=0x00, bytes_count=2))[0]
321

322
    def _get_thresholds(self) -> tuple:
323
        """Возвращает пороговые значения компаратора в виде кортежа: (высокий порог, низкий порог)"""
324
        buf = self.read_buf_from_mem(0x02, self._buf_4)
325
        # print(f"DBG: {buf}")
326
        return 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
    # @property
338
    # def thresholds(self) -> tuple:
339
    #    return self._get_thresholds()
340

341
    # @thresholds.setter
342
    # def thresholds(self, value: tuple[int, int]):
343
    #    self._set_thresholds(value[0], value[1])
344

345
    def get_specific_props(self):
346
        """Возвращает свойства компаратора"""
347
        thr = self._get_thresholds()
348
        return specific_props(mode=self._comparator_mode, polarity=self._comparator_polarity,
349
                              latch=self._comparator_latch, queue=self._comparator_queue,
350
                              lo_threshold=thr[0], hi_threshold=thr[1])
351

352
    def get_resolution(self, raw_data_rate: int) -> int:
353
        """Возвращает кол-во бит в отсчете АЦП в зависимости от частоты взятия отсчетов (сырое значение!).
354
        Переопределить в классе - наследнике!"""
355
        # у данного АЦП разрешение не изменяется!
356
        return 16
357

358
    def raw_sample_rate_to_real(self, raw_sample_rate: int) -> float:
359
        """Преобразует сырое значение частоты преобразования в [Гц].
360
        Переопределить в классе - наследнике!"""
361
        sps = 8, 16, 32, 64, 128, 250, 475, 860
362
        return sps[raw_sample_rate]
363

364
    # Iterator
365
    def __iter__(self):
366
        return self
367

368
    def __next__(self) -> [int, None]:
369
        if not self._single_shot_mode:
370
            # режим непрерывного преобразования!
371
            return self.value
372
        return None
373

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.