21 KiB
DS18B20: справочник API
Назначение
Публичный API ядра объявлен только в Inc/ds18b20.h. Приложение компилирует
Src/ds18b20.c, но не включает этот файл. Библиотека выполняет Search ROM,
проверяет Dallas CRC8, запускает Convert T, читает scratchpad, декодирует
температуру, меняет разрешение и TH/TL.
Константы и состояние
DS18B20_ROM_SIZE— 8 байт полного 64-битного ROM.DS18B20_SCRATCHPAD_SIZE— 9 байт scratchpad вместе с CRC.DS18B20_DEFAULT_TIMEOUT_MS— 750 мс, значение конфигурации по умолчанию.DS18B20_FAMILY_CODE—0x28.ds18b20_t— состояние одной шины. После инициализации его поля напрямую не изменяют; список датчиков читают черезds18b20_count()иds18b20_rom().
Platform callbacks
ds18b20_onewire_ops_t связывает переносимое ядро с аппаратурой:
| Callback | Обязателен | Контракт |
|---|---|---|
drive_low(context) |
да | Активно притянуть open-drain линию к 0 |
release(context) |
да | Отпустить линию; внешний/внутренний pull-up поднимает её |
read(context) |
да | Вернуть текущий логический уровень 0 или 1 |
delay_us(context, us) |
да | Синхронная задержка с микросекундной точностью |
tick_ms(context) |
для ds18b20_wait |
Монотонный, допускающий uint32 wrap tick |
critical_enter(context) |
нет | Начать защиту одного временного слота |
| critical_exit(context) | нет | Восстановить состояние после защиты слота |
| strong_pullup(context, enable) | для parasite Copy | Активно удерживать high и безопасно вернуть open-drain |
Обе функции critical section задаются парой либо обе оставляются NULL.
Коды возврата
| Код | Значение | Значение для приложения |
|---|---|---|
DS18B20_OK |
0 | Успех или преобразование готово |
DS18B20_E_ARGUMENT |
-1 | Неверный указатель, callback, размер или параметр |
DS18B20_E_IO |
-2 | Некорректная конфигурация scratchpad |
DS18B20_E_NO_DEVICE |
-3 | Нет presence pulse / подходящих устройств |
DS18B20_E_CRC |
-4 | CRC ROM или scratchpad не совпал |
DS18B20_E_TIMEOUT |
-5 | Истёк timeout блокирующего ожидания |
DS18B20_E_BUSY |
-6 | Преобразование ещё не готово |
DS18B20_E_CAPACITY |
-7 | Найдено больше ROM, чем помещается в storage |
| DS18B20_E_ROM | -8 | ROM имеет неверный family code либо отклонён адресной операцией |
| DS18B20_E_POWER | -9 | Parasite Copy запрошен без strong-pull-up callback |
Инициализация и поиск
ds18b20_init
ds18b20_status_t ds18b20_init(
ds18b20_t *instance,
const ds18b20_onewire_ops_t *ops,
void *platform_context,
uint8_t (*rom_storage)[DS18B20_ROM_SIZE],
size_t rom_capacity);
Обнуляет состояние, сохраняет callback/context/storage и отпускает линию.
rom_storage — массив приложения, rom_capacity — число ROM, не число байт.
Core не выделяет и не освобождает память.
ds18b20_search
ds18b20_status_t ds18b20_search(ds18b20_t *instance);
Заново выполняет Search ROM и заменяет прежний список. Сохраняются только ROM с
family 0x28 и корректным CRC. Результаты поиска:
DS18B20_OK— найден минимум один корректный DS18B20;DS18B20_E_NO_DEVICE— корректные DS18B20 не найдены;DS18B20_E_CAPACITY— storage заполнен; уже записанные ROM остаются доступны.
ds18b20_count и ds18b20_rom
size_t ds18b20_count(const ds18b20_t *instance);
const uint8_t *ds18b20_rom(const ds18b20_t *instance, size_t index);
count возвращает число сохранённых ROM либо 0 для неверного экземпляра.
rom возвращает указатель на 8 байт либо NULL для неверного индекса.
Указатель становится логически устаревшим после следующего поиска.
Преобразование и чтение
ds18b20_start_all
ds18b20_status_t ds18b20_start_all(ds18b20_t *instance);
Посылает Skip ROM + Convert T всем устройствам шины. Возвращает
DS18B20_E_NO_DEVICE, если нет presence pulse.
ds18b20_start
ds18b20_status_t ds18b20_start(
ds18b20_t *instance,
const uint8_t rom[DS18B20_ROM_SIZE]);
Проверяет ROM и посылает Match ROM + Convert T одному датчику.
ds18b20_conversion_ready
ds18b20_status_t ds18b20_conversion_ready(ds18b20_t *instance);
Один раз читает 1-Wire ready bit: DS18B20_OK означает готовность,
DS18B20_E_BUSY — преобразование продолжается. Это предпочтительная
неблокирующая проверка для main loop/RTOS.
ds18b20_wait
ds18b20_status_t ds18b20_wait(
ds18b20_t *instance, uint32_t timeout_ms);
Блокирующе опрашивает ready bit до готовности или DS18B20_E_TIMEOUT. Требует
tick_ms. Функция не делает sleep/yield и не рекомендуется в основном цикле.
ds18b20_read_scratchpad
ds18b20_status_t ds18b20_read_scratchpad(
ds18b20_t *instance,
const uint8_t rom[DS18B20_ROM_SIZE],
uint8_t scratchpad[DS18B20_SCRATCHPAD_SIZE]);
Проверяет ROM, посылает Match ROM + Read Scratchpad, читает 9 байт и
проверяет CRC. Функция не запускает Convert T и не проверяет, что преобразование
ранее завершилось.
ds18b20_decode_temperature
ds18b20_status_t ds18b20_decode_temperature(
const uint8_t scratchpad[DS18B20_SCRATCHPAD_SIZE],
float *temperature_c);
Проверяет CRC, маскирует неопределённые младшие биты согласно разрешению 9–12
бит и возвращает градусы Цельсия. Неизвестная комбинация configuration bits
даёт DS18B20_E_IO.
Конфигурация и User Bytes
ds18b20_set_resolution
ds18b20_status_t ds18b20_set_resolution(
ds18b20_t *instance,
const uint8_t rom[DS18B20_ROM_SIZE],
uint8_t bits);
bits принимает только 9, 10, 11 или 12. Функция читает
scratchpad, сохраняет TH/TL, записывает новый configuration byte и посылает
Copy Scratchpad.
ds18b20_write_user_bytes
ds18b20_status_t ds18b20_write_user_bytes(
ds18b20_t *instance,
const uint8_t rom[DS18B20_ROM_SIZE],
int16_t bytes12,
int16_t bytes34,
uint8_t mask);
Текущий контракт отражает физические writable bytes DS18B20:
mask & 0x01записывает младшие 8 битbytes12в TH, scratchpad[2];mask & 0x02записывает старшие 8 битbytes12в TL, scratchpad[3];bytes34зарезервирован и не используется: scratchpad[6]/[7] read-only;- остальные биты
maskигнорируются.
Перед записью функция читает scratchpad, поэтому невыбранный TH/TL и
configuration byte сохраняются. Затем выполняются Write Scratchpad и
Copy Scratchpad. Функция не выполняет no-op detection, Recall E2 и readback.
Application adapter обязан добавить эти шаги, если операция используется как
подтверждённая пользовательская запись.
CRC и ROM
uint8_t ds18b20_crc8(const void *data, size_t length);
ds18b20_status_t ds18b20_validate_rom(
const uint8_t rom[DS18B20_ROM_SIZE]);
crc8 вычисляет Dallas/Maxim CRC-8. validate_rom отдельно проверяет family
0x28 и CRC первых семи байтов против восьмого.
Неблокирующий пример опроса
enum poll_state { POLL_START, POLL_WAIT };
static enum poll_state state = POLL_START;
static uint8_t scratchpad[DS18B20_SCRATCHPAD_SIZE];
void poll_ds18b20(void)
{
if (state == POLL_START) {
if (ds18b20_start_all(&bus) == DS18B20_OK) {
state = POLL_WAIT;
}
return;
}
if (ds18b20_conversion_ready(&bus) != DS18B20_OK) {
return;
}
for (size_t i = 0; i < ds18b20_count(&bus); ++i) {
const uint8_t *rom = ds18b20_rom(&bus, i);
float temperature_c;
if (ds18b20_read_scratchpad(&bus, rom, scratchpad) == DS18B20_OK &&
ds18b20_decode_temperature(scratchpad, &temperature_c) ==
DS18B20_OK) {
publish_temperature(rom, temperature_c);
}
}
state = POLL_START;
}
Production adapter должен дополнительно иметь deadline: постоянный
DS18B20_E_BUSY не должен навсегда удерживать state machine.
Диагностика
| Симптом | Проверка |
|---|---|
DS18B20_E_NO_DEVICE |
Питание, общий GND, pull-up, pin, presence pulse |
Постоянный DS18B20_E_BUSY |
Deadline, питание датчика, конфликт операций |
DS18B20_E_CRC |
Длина/топология шины, помехи, timing, pull-up |
DS18B20_E_CAPACITY |
Увеличить ROM storage или ограничить число устройств |
| Неверная температура | Не читать до ready; проверить CRC и resolution bits |
| Зависание в delay | Таймер должен быть запущен и считать непрерывно |
Ограничения
- Вызовы одной шины не reentrant и не ISR-safe.
- Микросекундные 1-Wire-слоты синхронные; длительное преобразование должно быть вынесено в state machine.
- Callback
strong_pullupиспользуется модулем UserByte для parasite-poweredCopy Scratchpad; аппаратная схема и timing должны быть проверены на плате. - Low-level
Copy Scratchpadнамеренно разделён наstart/finish; выдержку 10 ms, Recall E2, CRC/readback и освобождение шины обеспечивает state machineModules/UserByte, а не одиночный low-level вызов. - Поиск синхронный и не имеет cancel callback; для большой шины или жёстких realtime-требований нужен пошаговый автомат поиска.
Тесты
Из корня репозитория:
python -m unittest Libraries.PortableTests.test_portable_models
Модель проверяет CRC, независимость экземпляров и неблокирующую интеграцию.
Libraries/PortableTests/test_portable_libraries.c дополнительно проверяет C
API CRC, декодирование температуры и независимость двух шин. Для полной задачи
также обязательны git diff --check и целевая Keil-сборка 0/0.
User Byte и EEPROM
Для новой логики приложения используйте внутренний модуль Modules/UserByte
с явным selector TH/TL, а не legacy ds18b20_write_user_bytes. Low-level API write_scratchpad, copy_*,
recall_e2, recall_ready и recover_bus предназначен для его state machine.
strong_pullup обязателен только для parasite-powered Copy Scratchpad.
ds18b20_search_retry_due помогает приложению повторять поиск при count=0,
не вмешиваясь в активную температурную конверсию; период и tick задаёт adapter.
Версия Modbus-контракта User Byte
Явный неблокирующий поиск
ds18b20_status_t status = ds18b20_search_begin(&bus);
while (status == DS18B20_E_BUSY ||
status == DS18B20_E_CRC ||
status == DS18B20_E_ROM) {
status = ds18b20_search_step(&bus);
/* Между шагами основной цикл продолжает обслуживать Modbus/RTC/SD. */
}
Не вызывайте ds18b20_search_retry_due() для GUI-команды: reconnect и polling
не должны автоматически менять таблицу ROM. В проектном адаптере команда
захватывается только по apply=1, а sequence защищает от старого ответа.
Legacy API ds18b20_user_byte_submit() остаётся TH-only. Для явного TL
используется selector DS18B20_USER_BYTE_TL; STM32 adapter принимает его только
с contractVersion=2, записанным атомарно с selector до APPLY. Это защищает GUI
от старого bridge/firmware, которое всегда маршрутизировало запрос как TH.
Известные ROM и ошибка поиска detail 2
В F407 сохранённые SensorBindings восстанавливаются в список опроса после AppStorage_Init. Если список непустой, стартовый SEARCH ROM не запускается. Температура читается адресно через MATCH ROM; запуск преобразования общий. Даже при отсутствии датчика во время старта его адрес остаётся доступен для повторного чтения. Подключение подтверждается успешным чтением температуры.
Явный поиск добавляет новые ID. При успехе, ошибке, тайм-ауте и отмене Dallas_FinishSearch объединяет результат с прежними ID, включая ещё не сохранённые во Flash. Ёмкость списка — 32 ID; найденные ID занимают места первыми. Сохранение использует существующий SensorBindings_SyncFound и повтор при BUSY. Отключать питание следует после завершения сохранения.
MCU detail 2 = DS18B20_E_IO: поиск ROM получил недопустимую комбинацию битов либо неполный ROM. Это не доказательство конкретной причины на кабеле. Ошибка поиска остаётся видна, но известные ID продолжают опрашиваться. Число в каталоге включает известные адреса; наличие определяется connected.
API ds18b20_add_known_rom проверяет family/CRC, возвращает E_ARGUMENT, E_ROM, E_CRC или E_CAPACITY; дубликат возвращает OK. Функция не делает I/O и не подтверждает наличие датчика. Вызывать вне поиска и конверсии.
Проверки: Libraries/DS18B20/Tests/run_host_tests.ps1 и
python -m unittest discover -s tests -p test_known_rom_host.py.
Для аппаратной проверки: найти датчики по одному, дождаться сохранения,
подключить все на 20 м, перезапустить МК без команды поиска и проверить
обновление температур; затем повторить при ошибке/отмене поиска.
Поиск с восстановлением после ошибок
Настройки в Inc/ds18b20_config.h: три прохода дерева, четыре дополнительных
повтора каждой неудачной ветки (пять попыток суммарно). Один вызов step делает
не более одной попытки ROM: Modbus и остальные сервисы работают между ними.
Перед попыткой сохраняются ROM-путь и discrepancy; после IO, отсутствия presence
или CRC они восстанавливаются. После пяти ошибок начинается следующий проход.
Результаты всех проходов объединяются; дубликаты не занимают ёмкость. CRC
проверяется до принятия пути. Чужое семейство с корректным CRC пропускается.
Успех означает, что хотя бы один проход полностью обошёл дерево и найден хотя бы один DS18B20. Ранее восстановленные ошибки сохраняются в диагностике, но не превращают успешный поиск в CRC_ERROR. Это не гарантия обнаружения каждого физического датчика на нестабильной линии. Если ни один проход не завершён, возвращается последняя ошибка; проверенные частичные результаты сохраняются. Пустая линия ограничена 15 попытками reset. Общий предел 512 попыток защищает и блокирующий API; приложение дополнительно ограничивает поиск 12000 мс.
Во время поиска после каждого слота добавляется 20 мкс высокого уровня: после записи нуля получается минимум 30 мкс вместо 10 мкс. Импульсы 6/60 мкс, read-init 3 мкс и выборка через дополнительные 10 мкс остаются прежними. Добавочная пауза выполняется с разрешёнными прерываниями. Обычное чтение, конверсия и Copy Scratchpad не получают эту добавку. Подбор паузы для кабеля требует измерений; программная модель не подтверждает аналоговый фронт.
bus.search_diagnostics содержит attempts, retries, crc_errors, io_errors,
passes_finished, complete_passes и последнее место ошибки. Номер бита 1..64;
0 означает reset/общий лимит, pair=0xFF — пары нет. Диагностика сохраняется
после последующего успеха и обнуляется новым search_begin.
FC04: 1210–1217 совместимы, 1218 и 1219 используют прежний резерв:
- 1218: биты 0..6 — номер ROM-бита, бит 8 — complement, бит 9 — id, биты 12..15 — положительный код последней ошибки; 0 — ошибок не было.
- 1219: биты 0..7 — число повторов с насыщением 255, биты 8..15 — число законченных проходов, включая прерванные после исчерпания повторов.
Bridge читает 10 регистров и возвращает diagnostics в ответе поиска.
Для ошибки шины сообщение дополнено битом, id/complement, повторами и проходами.
Старые восемь полей сохранены. При bit=0 пара не интерпретируется.
Проверки: run_host_tests.ps1, test_known_rom_host.py,
test_sensor_search_diagnostics_host.py, test_remote_ds18b20_host.py.
На плате проверить 20 последовательных поисков трёх датчиков на 20 м,
отключение/подключение датчика при поиске, отмену и восстановление опроса.