-
Notifications
You must be signed in to change notification settings - Fork 0
/
tmp117ti.py
201 lines (177 loc) · 10.7 KB
/
tmp117ti.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# micropython
# MIT license
# Copyright (c) 2022 Roman Shevchik goctaprog@gmail.com
import micropython
from sensor_pack import bus_service
from sensor_pack.base_sensor import BaseSensor, Iterator, check_value
# Please read this before use!: https://www.ti.com/product/TMP117
# About NIST: https://e2e.ti.com/support/sensors-group/sensors/f/sensors-forum/1000579/tmp117-tmp117-nist-byte-order-and-eeprom4-address
class TMP117(BaseSensor, Iterator):
__scale = 7.8125E-3
def __init__(self, adapter: bus_service.BusAdapter, address: int = 0x48,
conversion_mode: int = 2, conversion_cycle_time: int = 4,
average: int = 1):
"""conversion_mode:
00: Continuous conversion (CC)
01: Shutdown (SD)
10: Continuous conversion (CC), Same as 00
11: One-shot conversion (OS)
conversion_cycle_time 0..7:
время ожидания между преобразованиями.
See Table 7-7 for the standby time between conversions.
average (Conversion averaging modes):
00: No averaging
01: 8 Averaged conversions
10: 32 averaged conversions
11: 64 averaged conversions
"""
super().__init__(adapter, address, True)
self._buf_2 = bytearray((0 for _ in range(2))) # для _read_from_into
self.conversion_mode = check_value(conversion_mode, range(0, 4),
f"Invalid conversion_mode value: {conversion_mode}")
self.conversion_cycle_time = check_value(conversion_cycle_time, range(0, 8),
f"Invalid conversion_cycle_time value: {conversion_cycle_time}")
self.average = check_value(average, range(0, 4), f"Invalid conversion_mode value: {average}")
self.DR_Alert = self.POL = self.T_nA = False
self.data_ready = self.low_alert = self.high_alert = False
#
self.set_config()
def _read_buf_from_mem(self, address: int, buf):
"""Читает из устройства, начиная с адреса address в буфер.
Кол-во читаемых байт равно "длине" буфера в байтах!"""
return self.adapter.read_buf_from_mem(self.address, address, buf)
@micropython.native
def get_conversion_cycle_time(self) -> int:
"""возвращает время преобразования температуры датчиком
в зависимости от его настроек"""
_ = check_value(self.conversion_cycle_time, range(0, 8),
f"Invalid conversion cycle time value: {self.conversion_cycle_time}")
_ = check_value(self.average, range(0, 4),
f"Invalid conversion averaging mode value: {self.average}")
avg_0 = 16, 125, 250, 500, 1000, 4000, 8000, 16000 # in [ms]
if 0x03 == self.conversion_mode: # One-shot conversion mode
# Когда биты MOD[1:0] в регистре конфигурации установлены на 11, TMP117 будет выполнять преобразование
# температуры, называемое однократным преобразованием. После того, как устройство завершит однократное
# преобразование, оно переходит в режим отключения с низким энергопотреблением. Однократный цикл
# преобразования, в отличие от непрерывного режима преобразования, состоит только из активного времени
# преобразования и не имеет периода ожидания. Таким образом, продолжительность однократного преобразования
# зависит только от битовых настроек AVG. Биты CONV не влияют на продолжительность
# однократного преобразования.
s_shot = 16, 125, 500, 1000
return s_shot[self.average]
if self.average < 2:
if 0 == self.conversion_cycle_time and 1 == self.average:
return 125
return avg_0[self.conversion_cycle_time]
# average >= 2
if self.conversion_cycle_time < 4:
return 500 * (self.average - 2)
# conversion_cycle_time >= 4
return avg_0[self.conversion_cycle_time]
def __del__(self):
self.conversion_mode = 0x01 # Shutdown (SD)
self.set_config()
del self._buf_2 # возвращаю несколько байт управляющему памятью :-)
def _read_register(self, reg_addr, bytes_count=2) -> bytes:
"""считывает из регистра датчика значение.
bytes_count - размер значения в байтах"""
return self.adapter.read_register(self.address, reg_addr, bytes_count)
def _write_register(self, reg_addr, value: int, bytes_count=2) -> int:
"""записывает данные value в датчик, по адресу reg_addr.
bytes_count - кол-во записываемых данных"""
byte_order = self._get_byteorder_as_str()[0]
return self.adapter.write_register(self.address, reg_addr, value, bytes_count, byte_order)
def _get_config_reg(self) -> int:
"""read config from register (2 byte)"""
buf = self._buf_2
self._read_buf_from_mem(0x01, buf) # читаю из памяти устройства в буфер два байта
config = self.unpack("H", buf)[0]
return config
def _set_config_reg(self, cfg: int) -> int:
"""write config to register (2 byte)"""
return self._write_register(0x01, cfg)
@micropython.native
def get_config(self) -> int:
"""читает настройки датчика из регистра.
сохраняет их в полях экземпляра класса"""
config = self._get_config_reg()
self.DR_Alert = config & (0x01 << 2)
self.POL = config & (0x01 << 3)
self.T_nA = config & (0x01 << 4)
self.average = (config & (0b11 << 5)) >> 5
self.conversion_cycle_time = (config & (0b111 << 7)) >> 7
self.conversion_mode = (config & (0b11 << 10)) >> 10
self.data_ready = config & (0x01 << 13)
self.low_alert = config & (0x01 << 14)
self.high_alert = config & (0x01 << 15)
#
return config
@micropython.native
def set_config(self):
"""write current settings to sensor"""
tmp = 0
tmp |= int(self.DR_Alert) << 2
tmp |= int(self.POL) << 3
tmp |= int(self.T_nA) << 4
tmp |= int(self.average) << 5
tmp |= int(self.conversion_cycle_time) << 7
tmp |= int(self.conversion_mode) << 10
#
self._set_config_reg(tmp)
def set_temperature_offset(self, offset: float) -> int:
"""set temperature offset to sensor.
Большая просьба к читателям: значение смещения не должно превышать разумного значения.
Например +/- 10. Контролируйте это самостоятельно!
A big request to readers: the offset value should not exceed a reasonable value.
For example +/- 10.
Control it yourself!
"""
reg_val = int(offset // TMP117.__scale)
return self._write_register(0x07, reg_val)
def get_temperature_offset(self) -> float:
"""set temperature offset from sensor"""
buf = self._buf_2
self._read_buf_from_mem(0x07, buf) # читаю из памяти устройства в буфер два байта
return TMP117.__scale * self.unpack("h", buf)[0]
def get_id(self) -> int:
"""Возвращает идентификатор датчика. Правильное значение - 0х55.
Returns the ID of the sensor. The correct value is 0x55."""
buf = self._buf_2
self._read_buf_from_mem(0x0F, buf) # читаю из памяти устройства в буфер два байта
return self.unpack("H", buf)[0]
def _get_flags(self) -> tuple:
"""Return tuple: (EEPROM_Busy, Data_Ready, LOW_Alert) flags"""
config = self._get_config_reg()
# print(f"config_reg: {hex(config)}")
return tuple([0 != (config & (0x01 << i)) for i in range(12, 16)])
def is_data_ready(self) -> bool:
"""Флаг готовности данных. Этот флаг указывает, что преобразование завершено и регистр температуры
может быть прочитан. Каждый раз, когда считывается регистр температуры или регистр конфигурации,
этот бит сбрасывается!
Data ready flag.
This flag indicates that the conversion is complete and the
temperature register can be read. Every time the temperature
register or configuration register is read, this bit is cleared."""
return self._get_flags()[1]
@micropython.native
def get_temperature(self) -> float:
"""return temperature most recent conversion"""
buf = self._buf_2
self._read_buf_from_mem(0x00, buf) # читаю из памяти устройства в буфер два байта
return TMP117.__scale * self.unpack("h", buf)[0]
def soft_reset(self):
"""программный сброс датчика.
software reset of the sensor"""
config = self._get_config_reg()
self._set_config_reg(config | 0x01)
def __next__(self):
"""Удобное чтение температуры с помощью итератора"""
return self.get_temperature()
def get_nist(self) -> tuple:
"""Читает NIST, число необходимое для идентификации датчика. TI не сообщает о способе вычисления NIST.
Дискуссии на эту тему вы найдете на TI E2E форуме.
Reads NIST, the number needed to identify the sensor.
TI does not report how NIST calculates.
You can find discussions on this topic on the TI E2E forum."""
addresses = 0x05, 0x08
return tuple([self.unpack("H", self._read_register(adr, 2))[0] for adr in addresses])