SHT4X

Форк
0
/
adcmod.py 
295 строк · 19.4 Кб
1
# MicroPython
2
# mail: goctaprog@gmail.com
3
# MIT license
4

5
# from sensor_pack_2.bus_service import mpy_bl
6
from collections import namedtuple
7
from sensor_pack_2.base_sensor import check_value
8

9
# разностный вход (bool, differential_input)
10
# разрядность в битах (int, resolution)
11
# опорное напряжение в вольтах (float, rev_voltage)
12
# количество аналоговых входов (channels)
13
adc_base_props = namedtuple("adc_props", "ref_voltage resolution channels differential_channels")
14
# кортеж информации о канале АЦП: number(номер канала):int, is_differential(дифференциальный_режим):bool
15
adc_channel_info = namedtuple("adc_channel_info", "number is_differential")
16
# кортеж информации о количестве(!) каналов АЦП
17
# channels - количество обычных(single ended) каналов
18
# differential_channels - количество дифференциальных(differential) каналов
19
adc_channels = namedtuple("adc_channels", "channels differential_channels")
20
# основные свойства АЦП: опорное напряжение, Вольт; текущее кол-во значащих бит в отсчете,
21
# предельное кол-во значащих бит в отсчете, текущий номер канала, количество обычных накалов(Vxx..GND),
22
# предельное кол-во обычных каналов, предельное кол-во дифференциальных каналов,
23
# текущая частота отсчетов(current sample rate), Гц
24
adc_general_props = namedtuple("adc_general_props",
25
                               "ref_voltage resolution max_resolution current_channel channels diff_channels")
26
# основные 'сырые' настройки, характерные для всех(!) АЦП
27
adc_general_raw_props = namedtuple("adc_general_raw_props", "sample_rate gain_amplifier single_shot_mode")
28

29
# параметры для инициализации АЦП
30
# reference_voltage - опорное напряжение, Вольт
31
# max_resolution - предельное кол-во значащих бит в отсчете. Разрешение часто, параметр динамический(!).
32
# Зависит от частоты преобразования _data_rate (Гц) аналогового сигнала в цифровой.
33
# channels - количество обычных(single ended) каналов
34
# differential_channels - количество дифференциальных(differential) каналов
35
# differential_mode - Если истина, то это дифференциальный АЦП. для метода get_lsb.
36
adc_init_props = namedtuple("adc_init_props",
37
                            "reference_voltage max_resolution channels differential_channels differential_mode")
38
# для метода get_raw_value_ex
39
# value - значение АЦП, сырое(!)
40
# если low_limit в Истина, то "стрелка" АЦП на нижнем крае шкалы (underflow)
41
# если hi_limit в Истина, то "стрелка" АЦП верхнем крае шкалы (overflow)
42
raw_value_ex = namedtuple("raw_value_ex", "value low_limit hi_limit")
43

44
# Типовое содержимое регистра конфигурации (все значения сырые/raw):
45
# gain; коэффициент усиления для PGA-programmable gain amplifier (усилитель с программируемым усилением)
46
# channel;      измеряющий канал
47
# data_rate;    частота отсчетов
48
# resolution;   количество бит в отсчете    (для некоторых АЦП)
49
# meas_mode;    режим измерения (single shot or automatic)
50
# raw_config_reg = namedtuple("raw_config_reg", "gain channel data_rate resolution meas_mode")
51

52

53
# вычисляет 'сырые' предельные значения, считываемые из регистра АЦП
54
def _get_reg_raw_limits(adc_resolution: int, differential: bool) -> raw_value_ex:
55
    if differential:
56
        # для дифференциальных АЦП
57
        _base = 2 ** (adc_resolution - 1)
58
        return raw_value_ex(value=0, low_limit=_base, hi_limit=_base - 1)
59
    # для обычных АЦП
60
    return raw_value_ex(value=0, low_limit=0, hi_limit=2 ** adc_resolution - 1)
61

62

63
class ADC:
64
    def __init__(self, init_props: adc_init_props, model: str = None):
65
        """reference_voltage - опорное напряжение в Вольтах;
66
        max_resolution - предельное разрешение АЦП в битах;
67
        channels - кол-во(!) входных аналоговых каналов;
68
        differential_channels - кол-во(!) входных аналоговых дифференциальных каналов;
69
        model - модель АЦП в виде строки"""
70
        self.init_props = init_props
71
        adc_ip = self.init_props
72
        if adc_ip.reference_voltage <= 0 or adc_ip.channels < 0 or adc_ip.differential_channels < 0:
73
            raise ValueError(f"Неверный параметр! Опорное напряжение, В: {adc_ip.reference_voltage}; Кол-во каналов: {adc_ip.channels}/{adc_ip.differential_channels}")
74
        # текущее количество выполняемых преобразований аналогового сигнала в цифровой! RAW, сырое значение!
75
        # для записи в регистр
76
        self._curr_raw_data_rate = None
77
        # текущее разрешение АЦП в битах
78
        self._curr_resolution = None
79
        # текущий номер канала. Диапазон 0..self._channels/self._diff_channels. Проверка на правильность в методе
80
        # check_channel_number
81
        self._curr_channel = None
82
        # если Истина, то self._curr_channel это дифференциальный(!) канал, иначе канал не дифференциальный(!)
83
        self._is_diff_channel = None
84
        # текущий коэффициент усиления (raw). Для записи в регистр АЦП
85
        self._curr_raw_gain = None  # RAW!
86
        # действительный текущий коэффициент усиления.
87
        # присвойте его в классе - наследнике путем пересчета из self._curr_gain. Смотри метод Ads1115.get_correct_gain
88
        self._real_gain = None
89
        # режим преобразования. если истина, то АЦП выполняет преобразование по запросу,
90
        # иначе АЦП выполняет преобразования автоматически с определенной частотой (_curr_data_rate)
91
        self._single_shot_mode = None
92
        # режим пониженного энергопотребления
93
        self._low_pwr_mode = None
94
        # строковое имя модели АЦП
95
        self._model_name = model
96

97
    @property
98
    def model(self) -> str:
99
        """Строковое имя модели АЦП"""
100
        return self._model_name
101

102
    def get_general_props(self) -> adc_general_props:
103
        """Возвращает основные свойства АЦП"""
104
        ipr = self.init_props
105
        return adc_general_props(ipr.reference_voltage, self.current_resolution, ipr.max_resolution, self._curr_channel,
106
                                 ipr.channels, ipr.differential_channels)
107

108
    def get_general_raw_props(self) -> adc_general_raw_props:
109
        """Возвращает основные 'сырые' свойства АЦП, которые считываются из регистра"""
110
        return adc_general_raw_props(sample_rate=self._curr_raw_data_rate, gain_amplifier=self._curr_raw_gain,
111
                                     single_shot_mode=self._single_shot_mode)
112

113
    def get_specific_props(self):
114
        """Возвращает характерные для АЦП свойства, желательно в виде именованного кортежа.
115
        Для переопределения в классе-наследнике"""
116
        raise NotImplemented
117

118
    def check_channel_number(self, value: int, diff: bool) -> int:
119
        """Проверяет номер входного аналогового канала(value) АЦП на правильность.
120
        Если diff в Истина, то канал дифференциальный(!).
121
        value должно быть в диапазоне 0..self._channels/self._diff_channels"""
122
        ipr = self.init_props
123
        _max = ipr.differential_channels if diff else ipr.channels
124
        check_value(value, range(_max),
125
                    f"Неверный номер канала АЦП: {value}; дифф: {diff}. Допустимый диапазон: 0..{_max - 1}")
126
        return value
127

128
    def check_gain_raw(self, gain_raw: int) -> int:
129
        """Проверяет сырое усиление на правильность. В случае ошибки выброси исключение!
130
        Возвращает значение gain_raw в случае успеха! Для переопределения в классе-наследнике."""
131
        raise NotImplemented
132

133
    def check_data_rate_raw(self, data_rate_raw: int) -> int:
134
        """Проверяет сырое data_rate на правильность. В случае ошибки выброси исключение!
135
        Возвращает data_rate_raw в случае успеха! Для переопределения в классе-наследнике."""
136
        raise NotImplemented
137

138
    def get_lsb(self) -> float:
139
        """Возвращает цену младшего разряда в Вольтах в зависимости от текущих настроек АЦП.
140
        gain - коэффициент усиления/ослабления входного делителя АЦП, должен быть больше нуля!"""
141
        ipr = self.init_props
142
        _k = 2 if ipr.differential_mode else 1
143
        return _k * ipr.reference_voltage / (self.gain * 2 ** self.current_resolution)
144

145
    def get_conversion_cycle_time(self) -> int:
146
        """возвращает время преобразования в [мкc/мс] аналогового значения в цифровое в зависимости от
147
        текущих настроек АЦП. Переопредели для каждого АЦП!"""
148
        raise NotImplemented
149

150
    @property
151
    def general_properties(self) -> adc_general_props:
152
        return self.get_general_props()
153

154
    @property
155
    def value(self) -> float:
156
        """Возвращает значение текущего канала в Вольтах"""
157
        return self.get_value(raw=False)
158

159
    def get_raw_value(self) -> int:
160
        """Возвращает 'сырое' значение отсчета АЦП.
161
        Переопределяется в классах - наследниках!"""
162
        raise NotImplemented
163

164
    def get_raw_value_ex(self, delta: int = 5) -> raw_value_ex:
165
        """Возвращает 'сырое' значение отсчета АЦП и флаги переполнения.
166
        Переопределяется в классах - наследниках!
167
        delta - 'зазор'"""
168
        raw = self.get_raw_value()
169
        limits = _get_reg_raw_limits(self.current_resolution, self.init_props.differential_mode)
170
        return raw_value_ex(value=raw, low_limit=raw in range(limits.low_limit, 1 + delta + limits.low_limit),
171
                            hi_limit=raw in range(limits.hi_limit - delta, 1 + limits.hi_limit))
172

173
    def raw_value_to_real(self, raw_val: int) -> float:
174
        """Преобразует 'сырое' значение из регистра АЦП в значение в Вольтах"""
175
        return raw_val * self.get_lsb()
176

177
    def gain_raw_to_real(self, raw_gain: int) -> float:
178
        """Преобразует 'сырое' значение усиления в 'настоящее'.
179
        Переопределить в классе - наследнике!"""
180
        raise NotImplemented
181

182
    def get_value(self, raw: bool = True) -> float:
183
        """Возвращает значение текущего канала в Вольтах, если raw в Ложь, в коде, если raw в Истина"""
184
        val = self.get_raw_value()
185
        if raw:
186
            return val
187
        return self.raw_value_to_real(val)
188

189
    def get_resolution(self, raw_data_rate: int) -> int:
190
        """Возвращает кол-во бит в отсчете АЦП в зависимости от частоты взятия отсчетов (сырое значение!).
191
        Переопределить в классе - наследнике!"""
192
        raise NotImplemented
193

194
    def get_current_channel(self) -> adc_channel_info:
195
        """Возвращает информацию о текущем активном канале АЦП"""
196
        return adc_channel_info(number=self._curr_channel, is_differential=self._is_diff_channel)
197

198
    @property
199
    def channel(self) -> adc_channel_info:
200
        """Возвращает информацию о текущем канале"""
201
        return self.get_current_channel()
202

203
    def __len__(self) -> int:
204
        """Возвращает количество аналоговых каналов АЦП в зависимости от типа текущего канала.
205
        Если текущий канал дифференциальный, то возвращается кол-во дифференциальных каналов, иначе
206
        возвращается кол-во обычных(single ended) каналов"""
207
        ipr = self.init_props
208
        return ipr.differential_channels if self._is_diff_channel else ipr.channels
209

210
    def start_measurement(self, single_shot: bool, data_rate_raw: int, gain_raw: int, channel: int,
211
                          differential_channel: bool):
212
        """Запуск однократного(single_shot в Истина) или многократного(single_shot в Ложь) измерения.
213
        data_rate_raw - частота получения выборок АЦП, отсчетов в сек., RAW-параметр, смотри в datasheet битовое поле!
214
        gain_raw - коэффициент усиления входного аналогового напряжения, RAW-параметр, смотри в datasheet битовое поле!
215
        channel - номер аналогового входа. От 0 до self._channels/self._diff_channels - 1
216
        differential_channel - если Истина, то канал с номером channel дифференциальный(!)
217
        Внимание! Последней строкой этого метода всегда вызывайте метод raw_config_to_adc_properties для
218
        записи значений в соответствующие поля класса!
219
        Скорее всего этот метод не потребуется переопределять, в крайнем случае и это можно сделать."""
220
        self.check_gain_raw(gain_raw=gain_raw)   # проверка на правильность
221
        self.check_data_rate_raw(data_rate_raw=data_rate_raw)   # проверка на правильность
222
        self.check_channel_number(channel, differential_channel)  # проверка на правильность
223
        #
224
        self._single_shot_mode = single_shot
225
        self._curr_raw_data_rate = data_rate_raw
226
        self._curr_raw_gain = gain_raw
227
        self._curr_channel = channel
228
        self._curr_resolution = self.get_resolution(data_rate_raw)
229
        self._is_diff_channel = differential_channel
230
        # переопределяемые для каждого АЦП, методы
231
        _raw_cfg = self.adc_properties_to_raw_config()
232
        self.set_raw_config(_raw_cfg)
233
        # читаю config АЦП и обновляю поля класса
234
        _raw_cfg = self.get_raw_config()    # читаю настройки АЦП
235
        self.raw_config_to_adc_properties(_raw_cfg)     # обновляю поля экземпляра класса
236
        # пересчет в реальное усиление
237
        self._real_gain = self.gain_raw_to_real(self._curr_raw_gain)
238

239
    def raw_config_to_adc_properties(self, raw_config: int):
240
        """Возвращает текущие настройки датчика из числа, возвращенного get_raw_config(!), в поля(!) класса.
241
        raw_config -> adc_properties.
242
        Переопределить в классе - наследнике!"""
243
        raise NotImplemented
244

245
    def adc_properties_to_raw_config(self) -> int:
246
        """Преобразует свойства АЦП из полей класса в 'сырую' конфигурацию АЦП.
247
        adc_properties -> raw_config.
248
        Переопределить в классе - наследнике!"""
249
        raise NotImplemented
250

251
    def get_raw_config(self) -> int:
252
        """Возвращает(считывает) текущие настройки датчика из регистров(конфигурации) в виде числа.
253
        Переопределить в классе - наследнике!"""
254
        raise NotImplemented
255

256
    def set_raw_config(self, value: int):
257
        """Записывает настройки(value) во внутреннюю память/регистр датчика.
258
        Переопределить в классе - наследнике!"""
259
        raise NotImplemented
260

261
    def raw_sample_rate_to_real(self, raw_sample_rate: int) -> float:
262
        """Преобразует сырое значение частоты преобразования в [Гц].
263
        Переопределить в классе - наследнике!"""
264
        raise NotImplemented
265

266
    @property
267
    def sample_rate(self) -> float:
268
        """Возвращает текущее число отсчетов в секунду"""
269
        return self.raw_sample_rate_to_real(self.current_sample_rate)
270

271
    @property
272
    def current_sample_rate(self) -> int:
273
        """Возвращает текущее сырое(!) количество отсчетов АЦП"""
274
        return self._curr_raw_data_rate
275

276
    @property
277
    def current_raw_gain(self) -> int:
278
        """Возвращает текущий сырой(!) коэффициент усиления АЦП"""
279
        return self._curr_raw_gain
280

281
    @property
282
    def gain(self) -> float:
283
        """Возвращает текущий реальный коэффициент усиления АЦП"""
284
        return self._real_gain
285

286
    @property
287
    def current_resolution(self) -> int:
288
        """Возвращает текущее(!) кол-во бит в отсчете АЦП"""
289
        return self._curr_resolution
290

291
    @property
292
    def single_shot_mode(self) -> bool:
293
        """Возвращает Истина, Если АЦП настроен на однократный(single shot conversion) режим работы,
294
        иначе на непрерывный (continuous conversion mode)"""
295
        return self._single_shot_mode
296

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

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

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

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