mcp3421
295 строк · 19.4 Кб
1# MicroPython
2# mail: goctaprog@gmail.com
3# MIT license
4
5# from sensor_pack_2.bus_service import mpy_bl
6from collections import namedtuple7from sensor_pack_2.base_sensor import check_value8
9# разностный вход (bool, differential_input)
10# разрядность в битах (int, resolution)
11# опорное напряжение в вольтах (float, rev_voltage)
12# количество аналоговых входов (channels)
13adc_base_props = namedtuple("adc_props", "ref_voltage resolution channels differential_channels")14# кортеж информации о канале АЦП: number(номер канала):int, is_differential(дифференциальный_режим):bool
15adc_channel_info = namedtuple("adc_channel_info", "number is_differential")16# кортеж информации о количестве(!) каналов АЦП
17# channels - количество обычных(single ended) каналов
18# differential_channels - количество дифференциальных(differential) каналов
19adc_channels = namedtuple("adc_channels", "channels differential_channels")20# основные свойства АЦП: опорное напряжение, Вольт; текущее кол-во значащих бит в отсчете,
21# предельное кол-во значащих бит в отсчете, текущий номер канала, количество обычных накалов(Vxx..GND),
22# предельное кол-во обычных каналов, предельное кол-во дифференциальных каналов,
23# текущая частота отсчетов(current sample rate), Гц
24adc_general_props = namedtuple("adc_general_props",25"ref_voltage resolution max_resolution current_channel channels diff_channels")26# основные 'сырые' настройки, характерные для всех(!) АЦП
27adc_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.
36adc_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)
42raw_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# вычисляет 'сырые' предельные значения, считываемые из регистра АЦП
54def _get_reg_raw_limits(adc_resolution: int, differential: bool) -> raw_value_ex:55if differential:56# для дифференциальных АЦП57_base = 2 ** (adc_resolution - 1)58return raw_value_ex(value=0, low_limit=_base, hi_limit=_base - 1)59# для обычных АЦП60return raw_value_ex(value=0, low_limit=0, hi_limit=2 ** adc_resolution - 1)61
62
63class ADC:64def __init__(self, init_props: adc_init_props, model: str = None):65"""reference_voltage - опорное напряжение в Вольтах;66max_resolution - предельное разрешение АЦП в битах;
67channels - кол-во(!) входных аналоговых каналов;
68differential_channels - кол-во(!) входных аналоговых дифференциальных каналов;
69model - модель АЦП в виде строки"""
70self.init_props = init_props71adc_ip = self.init_props72if adc_ip.reference_voltage <= 0 or adc_ip.channels < 0 or adc_ip.differential_channels < 0:73raise ValueError(f"Неверный параметр! Опорное напряжение, В: {adc_ip.reference_voltage}; Кол-во каналов: {adc_ip.channels}/{adc_ip.differential_channels}")74# текущее количество выполняемых преобразований аналогового сигнала в цифровой! RAW, сырое значение!75# для записи в регистр76self._curr_raw_data_rate = None77# текущее разрешение АЦП в битах78self._curr_resolution = None79# текущий номер канала. Диапазон 0..self._channels/self._diff_channels. Проверка на правильность в методе80# check_channel_number81self._curr_channel = None82# если Истина, то self._curr_channel это дифференциальный(!) канал, иначе канал не дифференциальный(!)83self._is_diff_channel = None84# текущий коэффициент усиления (raw). Для записи в регистр АЦП85self._curr_raw_gain = None # RAW!86# действительный текущий коэффициент усиления.87# присвойте его в классе - наследнике путем пересчета из self._curr_gain. Смотри метод Ads1115.get_correct_gain88self._real_gain = None89# режим преобразования. если истина, то АЦП выполняет преобразование по запросу,90# иначе АЦП выполняет преобразования автоматически с определенной частотой (_curr_data_rate)91self._single_shot_mode = None92# режим пониженного энергопотребления93self._low_pwr_mode = None94# строковое имя модели АЦП95self._model_name = model96
97@property98def model(self) -> str:99"""Строковое имя модели АЦП"""100return self._model_name101
102def get_general_props(self) -> adc_general_props:103"""Возвращает основные свойства АЦП"""104ipr = self.init_props105return adc_general_props(ipr.reference_voltage, self.current_resolution, ipr.max_resolution, self._curr_channel,106ipr.channels, ipr.differential_channels)107
108def get_general_raw_props(self) -> adc_general_raw_props:109"""Возвращает основные 'сырые' свойства АЦП, которые считываются из регистра"""110return adc_general_raw_props(sample_rate=self._curr_raw_data_rate, gain_amplifier=self._curr_raw_gain,111single_shot_mode=self._single_shot_mode)112
113def get_specific_props(self):114"""Возвращает характерные для АЦП свойства, желательно в виде именованного кортежа.115Для переопределения в классе-наследнике"""
116raise NotImplemented117
118def check_channel_number(self, value: int, diff: bool) -> int:119"""Проверяет номер входного аналогового канала(value) АЦП на правильность.120Если diff в Истина, то канал дифференциальный(!).
121value должно быть в диапазоне 0..self._channels/self._diff_channels"""
122ipr = self.init_props123_max = ipr.differential_channels if diff else ipr.channels124check_value(value, range(_max),125f"Неверный номер канала АЦП: {value}; дифф: {diff}. Допустимый диапазон: 0..{_max - 1}")126return value127
128def check_gain_raw(self, gain_raw: int) -> int:129"""Проверяет сырое усиление на правильность. В случае ошибки выброси исключение!130Возвращает значение gain_raw в случае успеха! Для переопределения в классе-наследнике."""
131raise NotImplemented132
133def check_data_rate_raw(self, data_rate_raw: int) -> int:134"""Проверяет сырое data_rate на правильность. В случае ошибки выброси исключение!135Возвращает data_rate_raw в случае успеха! Для переопределения в классе-наследнике."""
136raise NotImplemented137
138def get_lsb(self) -> float:139"""Возвращает цену младшего разряда в Вольтах в зависимости от текущих настроек АЦП.140gain - коэффициент усиления/ослабления входного делителя АЦП, должен быть больше нуля!"""
141ipr = self.init_props142_k = 2 if ipr.differential_mode else 1143return _k * ipr.reference_voltage / (self.gain * 2 ** self.current_resolution)144
145def get_conversion_cycle_time(self) -> int:146"""возвращает время преобразования в [мкc/мс] аналогового значения в цифровое в зависимости от147текущих настроек АЦП. Переопредели для каждого АЦП!"""
148raise NotImplemented149
150@property151def general_properties(self) -> adc_general_props:152return self.get_general_props()153
154@property155def value(self) -> float:156"""Возвращает значение текущего канала в Вольтах"""157return self.get_value(raw=False)158
159def get_raw_value(self) -> int:160"""Возвращает 'сырое' значение отсчета АЦП.161Переопределяется в классах - наследниках!"""
162raise NotImplemented163
164def get_raw_value_ex(self, delta: int = 5) -> raw_value_ex:165"""Возвращает 'сырое' значение отсчета АЦП и флаги переполнения.166Переопределяется в классах - наследниках!
167delta - 'зазор'"""
168raw = self.get_raw_value()169limits = _get_reg_raw_limits(self.current_resolution, self.init_props.differential_mode)170return raw_value_ex(value=raw, low_limit=raw in range(limits.low_limit, 1 + delta + limits.low_limit),171hi_limit=raw in range(limits.hi_limit - delta, 1 + limits.hi_limit))172
173def raw_value_to_real(self, raw_val: int) -> float:174"""Преобразует 'сырое' значение из регистра АЦП в значение в Вольтах"""175return raw_val * self.get_lsb()176
177def gain_raw_to_real(self, raw_gain: int) -> float:178"""Преобразует 'сырое' значение усиления в 'настоящее'.179Переопределить в классе - наследнике!"""
180raise NotImplemented181
182def get_value(self, raw: bool = True) -> float:183"""Возвращает значение текущего канала в Вольтах, если raw в Ложь, в коде, если raw в Истина"""184val = self.get_raw_value()185if raw:186return val187return self.raw_value_to_real(val)188
189def get_resolution(self, raw_data_rate: int) -> int:190"""Возвращает кол-во бит в отсчете АЦП в зависимости от частоты взятия отсчетов (сырое значение!).191Переопределить в классе - наследнике!"""
192raise NotImplemented193
194def get_current_channel(self) -> adc_channel_info:195"""Возвращает информацию о текущем активном канале АЦП"""196return adc_channel_info(number=self._curr_channel, is_differential=self._is_diff_channel)197
198@property199def channel(self) -> adc_channel_info:200"""Возвращает информацию о текущем канале"""201return self.get_current_channel()202
203def __len__(self) -> int:204"""Возвращает количество аналоговых каналов АЦП в зависимости от типа текущего канала.205Если текущий канал дифференциальный, то возвращается кол-во дифференциальных каналов, иначе
206возвращается кол-во обычных(single ended) каналов"""
207ipr = self.init_props208return ipr.differential_channels if self._is_diff_channel else ipr.channels209
210def start_measurement(self, single_shot: bool, data_rate_raw: int, gain_raw: int, channel: int,211differential_channel: bool):212"""Запуск однократного(single_shot в Истина) или многократного(single_shot в Ложь) измерения.213data_rate_raw - частота получения выборок АЦП, отсчетов в сек., RAW-параметр, смотри в datasheet битовое поле!
214gain_raw - коэффициент усиления входного аналогового напряжения, RAW-параметр, смотри в datasheet битовое поле!
215channel - номер аналогового входа. От 0 до self._channels/self._diff_channels - 1
216differential_channel - если Истина, то канал с номером channel дифференциальный(!)
217Внимание! Последней строкой этого метода всегда вызывайте метод raw_config_to_adc_properties для
218записи значений в соответствующие поля класса!
219Скорее всего этот метод не потребуется переопределять, в крайнем случае и это можно сделать."""
220self.check_gain_raw(gain_raw=gain_raw) # проверка на правильность221self.check_data_rate_raw(data_rate_raw=data_rate_raw) # проверка на правильность222self.check_channel_number(channel, differential_channel) # проверка на правильность223#224self._single_shot_mode = single_shot225self._curr_raw_data_rate = data_rate_raw226self._curr_raw_gain = gain_raw227self._curr_channel = channel228self._curr_resolution = self.get_resolution(data_rate_raw)229self._is_diff_channel = differential_channel230# переопределяемые для каждого АЦП, методы231_raw_cfg = self.adc_properties_to_raw_config()232self.set_raw_config(_raw_cfg)233# читаю config АЦП и обновляю поля класса234_raw_cfg = self.get_raw_config() # читаю настройки АЦП235self.raw_config_to_adc_properties(_raw_cfg) # обновляю поля экземпляра класса236# пересчет в реальное усиление237self._real_gain = self.gain_raw_to_real(self._curr_raw_gain)238
239def raw_config_to_adc_properties(self, raw_config: int):240"""Возвращает текущие настройки датчика из числа, возвращенного get_raw_config(!), в поля(!) класса.241raw_config -> adc_properties.
242Переопределить в классе - наследнике!"""
243raise NotImplemented244
245def adc_properties_to_raw_config(self) -> int:246"""Преобразует свойства АЦП из полей класса в 'сырую' конфигурацию АЦП.247adc_properties -> raw_config.
248Переопределить в классе - наследнике!"""
249raise NotImplemented250
251def get_raw_config(self) -> int:252"""Возвращает(считывает) текущие настройки датчика из регистров(конфигурации) в виде числа.253Переопределить в классе - наследнике!"""
254raise NotImplemented255
256def set_raw_config(self, value: int):257"""Записывает настройки(value) во внутреннюю память/регистр датчика.258Переопределить в классе - наследнике!"""
259raise NotImplemented260
261def raw_sample_rate_to_real(self, raw_sample_rate: int) -> float:262"""Преобразует сырое значение частоты преобразования в [Гц].263Переопределить в классе - наследнике!"""
264raise NotImplemented265
266@property267def sample_rate(self) -> float:268"""Возвращает текущее число отсчетов в секунду"""269return self.raw_sample_rate_to_real(self.current_sample_rate)270
271@property272def current_sample_rate(self) -> int:273"""Возвращает текущее сырое(!) количество отсчетов АЦП"""274return self._curr_raw_data_rate275
276@property277def current_raw_gain(self) -> int:278"""Возвращает текущий сырой(!) коэффициент усиления АЦП"""279return self._curr_raw_gain280
281@property282def gain(self) -> float:283"""Возвращает текущий реальный коэффициент усиления АЦП"""284return self._real_gain285
286@property287def current_resolution(self) -> int:288"""Возвращает текущее(!) кол-во бит в отсчете АЦП"""289return self._curr_resolution290
291@property292def single_shot_mode(self) -> bool:293"""Возвращает Истина, Если АЦП настроен на однократный(single shot conversion) режим работы,294иначе на непрерывный (continuous conversion mode)"""
295return self._single_shot_mode296