mcp3421

Форк
0
/
mcp3421mod.py 
201 строка · 12.5 Кб
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

15
_model_3421 = 'mcp3421'
16
_model_3422 = 'mcp3422'
17
_model_3424 = 'mcp3424'
18

19

20
def get_init_props(model: str) -> adc_init_props:
21
    """Возвращает параметры для инициализации АЦП в виде именованного кортежа по имени модели АЦП."""
22
    if _model_3421 == model.lower():
23
        return adc_init_props(reference_voltage=2.048, max_resolution=18, channels=0,
24
                              differential_channels=1, differential_mode=True)
25
    if _model_3422 == model.lower():
26
        return adc_init_props(reference_voltage=2.048, max_resolution=18, channels=0,
27
                              differential_channels=2, differential_mode=True)
28
    if _model_3424 == model.lower():
29
        return adc_init_props(reference_voltage=2.048, max_resolution=18, channels=0,
30
                              differential_channels=4, differential_mode=True)
31
    raise ValueError(f"Неизвестная модель АЦП!")
32

33

34
class Mcp342X(DeviceEx, ADC, Iterator):
35
    """18-битный аналого-цифровой преобразователь с интерфейсом I2C и встроенным ИОН.
36
    18-Bit Analog-to-Digital Converter with I2C Interface and On-Board Reference"""
37

38
    _config_reg_mcp3421 = (bit_field_info(name='RDY', position=range(7, 8), valid_values=None),    # Этот бит является флагом готовности данных. В режиме чтения этот бит указывает, был ли выходной регистр обновлен новым преобразованием. В режиме однократного преобразования запись этого бита в «1» инициирует новое преобразование.
39
                           bit_field_info(name='CH', position=range(5, 7), valid_values=None),   # (channel) Это биты выбора канала, но они не используются в MCP3421.
40
                           bit_field_info(name='CCM', position=range(4, 5), valid_values=range(6)),    # (continue conversion mode) Бит режима преобразования. 1 - режим непрерывного преобразования. 0 - режим однократного преобразования.
41
                           bit_field_info(name='SampleRate', position=range(2, 4), valid_values=None),  # Бит выбора частоты дискретизации. 0 - 240 SPS (12 bit); 1 - 60 SPS (14 bit); 2 - 15 SPS (16 bit); 3 - 3.75 SPS (18 bit)
42
                           bit_field_info(name='PGA', position=range(2), valid_values=None),            # Биты выбора усиления PGA. 0 - 1; 1 - 1/2; 2 - 1/4; 3 - 1/8
43
                           )
44
    # ответ от АЦП
45
    _mcp3421_raw_data = namedtuple("_mcp3421_raw_data", "b0 b1 b2 config")
46

47
    def get_resolution(self, raw_data_rate: int) -> int:
48
        """Преобразует сырое значение частоты обновления данных в кол-во бит в отсчете АЦП.
49
        У многих АЦП кол-во бит в отсчете зависит(!) от частоты преобразования."""
50
        return 12 + 2 * raw_data_rate
51

52
    def __init__(self, adapter: bus_service.BusAdapter, model: str = 'mcp3421', address=0x68):
53
        # MCP3421 имеет фиксированный адрес 0x68, но АЦП MCP342Х имеют адреса в диапазоне 0x68..0x6F
54
        check_value(address, range(0x68, 0x70), f"Неверное значение адреса I2C устройства: 0x{address:x}")
55
        DeviceEx.__init__(self, adapter, address, True)
56
        ADC.__init__(self, get_init_props(model), model=model)
57
        # print("DBG:__init__")
58
        # для удобства работы с настройками АЦП
59
        self._bit_fields = BitFields(fields_info=Mcp342X._config_reg_mcp3421)
60
        # буфер на 4 байта
61
        self._buf_4 = bytearray((0 for _ in range(4)))
62
        # последнее считанное из АЦП значение
63
        self._last_raw_value = None
64
        self._differential_mode = True      # дифференциальный АЦП. для get_lsb
65
        # Этот бит является флагом готовности данных. В режиме чтения этот бит указывает, был ли выходной регистр
66
        # обновлен новым преобразованием (0).
67
        # В режиме однократного преобразования запись этого бита в «1» инициирует новое преобразование.
68
        self._data_ready = None
69
        # Внимание, важный вызов(!)
70
        # читаю config АЦП и обновляю поля класса
71
        _raw_cfg = self.get_raw_config()
72
        self.raw_config_to_adc_properties(_raw_cfg)
73

74
#    def _read_raw_data(self) -> _mcp3421_raw_data:
75
#        """Считывает из АЦП информацию о результате преобразования и текущие 'сырые' настройки"""
76
#        buf = self._buf_4
77
#        self.read_to_buf(buf)
78
#        b0, b1, b2, cfg = self.unpack(fmt_char=len(buf)*"B", source=buf)
79
#        return Mcp3421._mcp3421_raw_data(b0=b0, b1=b1, b2=b2, config=cfg)
80

81
    def get_raw_config(self) -> int:
82
        """Возвращает(считывает) текущие настройки датчика из регистров(конфигурации) в виде числа."""
83
        # raw = self._read_raw_data()
84
        buf = self._buf_4
85
        self.read_to_buf(buf)
86
        # print(f"DBG:get_raw_config: 0x{buf[-1]:x}")
87
        return buf[-1]
88

89
    def set_raw_config(self, value: int):
90
        """Записывает настройки(value) во внутреннюю память/регистр датчика."""
91
        self.write(value.to_bytes(1, 'big'))
92

93
    def raw_config_to_adc_properties(self, raw_config: int):
94
        """Возвращает текущие настройки датчика из числа, возвращенного get_raw_config(!), в поля(!) класса.
95
        raw_config -> adc_properties"""
96
        # вызывать только после вызова get_raw_config!!!
97
        bf = self._bit_fields
98
        bf.source = raw_config
99
        bf.field_name = 'RDY'   # инверсное значение, читай bit 7, RDY: Ready Bit
100
        # 0 - в бите DRY, означает, что данные были обновлены АЦП
101
        self._data_ready = not bf.get_field_value()
102
        bf.field_name = 'CH'
103
        self._curr_channel = bf.get_field_value()
104
        bf.field_name = 'CCM'
105
        self._single_shot_mode = not bf.get_field_value()
106
        bf.field_name = 'PGA'
107
        self._curr_raw_gain = bf.get_field_value()
108
        bf.field_name = 'SampleRate'
109
        self._curr_raw_data_rate = bf.get_field_value()
110

111
    def get_raw_value(self) -> int:
112
        """Возвращает 'сырое' значение отсчета АЦП. Переопределяется в классах - наследниках!"""
113
        # вызывать только после вызова get_raw_config и raw_config_to_adc_properties!!!
114
        # print("DBG:get_raw_value")
115
        cfg = self.get_raw_config()
116
        # print(f"DBG:get_raw_value. config: 0x{cfg:x}")
117
        self.raw_config_to_adc_properties(raw_config=cfg)
118
        if self.data_ready:
119
            if self._curr_raw_data_rate < 3:
120
                # два байта на отсчет, 12, 14, 16 бит
121
                return self.unpack(fmt_char='h', source=self._buf_4)[0]
122
            b0, b1, b2 = self.unpack(fmt_char='bBB', source=self._buf_4)    # 18 бит на отсчет
123
            return 65536*b0 + 256*b1 + b2
124
        # print(f"DBG:get_raw_value. data not ready! config: 0x{cfg:x}")
125

126
    def raw_sample_rate_to_real(self, raw_sample_rate: int) -> float:
127
        """Преобразует сырое значение частоты преобразования в частоту [Гц]."""
128
        sps = 240, 60, 15, 3.75
129
        return sps[raw_sample_rate]
130

131
    def gain_raw_to_real(self, raw_gain: int) -> float:
132
        """Преобразует 'сырое' значение усиления в 'настоящее'"""
133
        return 2 ** raw_gain
134

135
    def get_conversion_cycle_time(self) -> int:
136
        """возвращает время преобразования в [мкс] аналогового значения в цифровое в зависимости от
137
        текущих настроек АЦП. Переопредели для каждого АЦП!"""
138
        # вызывать только после вызова get_raw_config и raw_config_to_adc_properties!!!
139
        return 1 + int(1_000_000 / self.sample_rate)
140

141
    def check_gain_raw(self, gain_raw: int) -> int:
142
        """Проверяет сырое усиление на правильность. В случае ошибки выброси исключение!
143
        Возвращает значение gain_raw в случае успеха! Для переопределения в классе-наследнике."""
144
        r4 = range(4)
145
        return check_value(gain_raw, r4, get_error_str("gain_raw", gain_raw, r4))
146

147
    def check_data_rate_raw(self, data_rate_raw: int) -> int:
148
        """Проверяет сырое data_rate на правильность. В случае ошибки выброси исключение!
149
        Возвращает data_rate_raw в случае успеха! Для переопределения в классе-наследнике."""
150
        r4 = range(4)
151
        return check_value(data_rate_raw, r4, get_error_str("data_rate_raw", data_rate_raw, r4))
152

153
    def adc_properties_to_raw_config(self) -> int:
154
        """Преобразует свойства АЦП из полей класса в 'сырую' конфигурацию АЦП.
155
        adc_properties -> raw_config"""
156
        # print("DBG:adc_properties_to_raw_config")
157
        _cfg = self.get_raw_config()
158
        bf = self._bit_fields
159
        bf.source = _cfg
160
        #
161
        bf.field_name = 'CH'
162
        bf.set_field_value(value=not self._curr_channel)
163
        bf.field_name = 'CCM'
164
        bf.set_field_value(value=not self.single_shot_mode)
165
        bf.field_name = 'RDY'
166
        bf.set_field_value(value=self.single_shot_mode)
167
        bf.field_name = 'SampleRate'
168
        bf.set_field_value(value=self.current_sample_rate)
169
        bf.field_name = 'PGA'
170
        bf.set_field_value(value=self.current_raw_gain)
171
        #
172
        # print(f"DBG:adc_properties_to_raw_config: 0x{bf.source:x}")
173
        return bf.source
174

175
    @property
176
    def data_ready(self) -> bool:
177
        if self.single_shot_mode:
178
            return self._data_ready
179
        else:   # автоматический режим измерений
180
            if 3 == self.current_sample_rate:
181
                return self._data_ready
182
        # В автоматическом режиме измерений, при data_rate меньше трех, не выставлялся бит готовности данных.
183
        # Причину не нашел! Пришлось делать это!
184
        # Вот что сказано в документации:
185
        # The MCP3421 device performs a Continuous Conversion if the O/C bit is set to logic “high”. Once the
186
        # conversion is completed, the result is placed at the output data register. The device immediately begins
187
        # another conversion and overwrites the output data register with the most recent data.
188
        #
189
        # The device also clears the data ready flag (RDY bit = 0) when the conversion is completed. The device sets the
190
        # ready flag bit (RDY bit = 1), if the latest conversion result has been read by the Master.
191
        return True
192

193
    # Iterator
194
    def __iter__(self):
195
        return self
196

197
    def __next__(self) -> [int, None]:
198
        if not self.single_shot_mode:
199
            # режим непрерывного преобразования!
200
            return self.value
201
        return None
202

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

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

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

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