feat(ds18b20): термометры DS18B20 поверх программной 1-Wire
Перенесён из репозитория ds18b20, который подключался сабмодулем в KONOR_ds18b20. История библиотеки осталась там; сюда пришло состояние на момент переезда. Ядро на C99 без stm32f10x.h и динамической памяти. Порт — пять функций (Init, DelayUs, Reset, WriteBit, ReadBit); реализация для STM32F1 идёт в комплекте в ports/stm32f1. Хостовые тесты на модели шины с виртуальными датчиками проходят: tests/test_ds18b20.c.
This commit is contained in:
127
c/ds18b20/README.md
Normal file
127
c/ds18b20/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# ds18b20
|
||||
|
||||
Драйвер термометров **DS18B20** поверх программной шины **1-Wire**.
|
||||
Вынесен из проекта `KONOR_ds18b20` и подключается в него сабмодулем.
|
||||
|
||||
Ядро на C99: ни динамической памяти, ни ОС, ни `stm32f10x.h`. Всё
|
||||
аппаратно-зависимое собрано в порте — на новую платформу переносятся
|
||||
пять функций, остальное собирается как есть.
|
||||
|
||||
```
|
||||
приложение
|
||||
│
|
||||
ds18b20.c поиск датчиков, чтение и запись scratchpad
|
||||
│
|
||||
onewire.c побайтовый обмен, CRC8, SEARCH ROM, MATCH/SKIP ROM
|
||||
│
|
||||
ports/<платформа> Init, DelayUs, Reset, WriteBit, ReadBit
|
||||
```
|
||||
|
||||
## Состав
|
||||
|
||||
| Файл | Что делает | Зависимости |
|
||||
|---|---|---|
|
||||
| `include/ds18b20.h`, `src/ds18b20.c` | перечень датчиков, измерения, запись TH/TL/разрешения | `onewire.h`, `stdint.h` |
|
||||
| `include/onewire.h`, `src/onewire.c` | байты и блоки, CRC8 Dallas/Maxim, обход SEARCH ROM | `stdint.h` |
|
||||
| `ports/stm32f1/` | тайминги Maxim, вывод с открытым стоком, задержки по DWT | CMSIS `stm32f10x.h` |
|
||||
| `tests/` | симулятор шины с виртуальными датчиками и host-тесты | — |
|
||||
|
||||
## Порт: что нужно от платформы
|
||||
|
||||
```c
|
||||
void OneWire_Init(void); /* настроить вывод и источник задержек */
|
||||
void OneWire_DelayUs(uint32_t us);
|
||||
uint8_t OneWire_Reset(void); /* сброс и проверка presence */
|
||||
void OneWire_WriteBit(uint8_t bit);
|
||||
uint8_t OneWire_ReadBit(void);
|
||||
```
|
||||
|
||||
Всё остальное — `OneWire_WriteByte`, `OneWire_ReadByte`, `OneWire_Crc8`,
|
||||
`OneWire_SearchNext`, `OneWire_SelectRom`, `OneWire_SkipRom` и весь
|
||||
`ds18b20.c` — уже написано и от платформы не зависит.
|
||||
|
||||
### Готовый порт STM32F1
|
||||
|
||||
Вывод настроен как выход с открытым стоком; чтение идёт через `IDR`,
|
||||
поэтому режим не переключается. Прерывания запрещаются только на
|
||||
длительность одного тайм-слота, чтобы не терять байты USART. Источник
|
||||
микросекундных задержек — счётчик тактов ядра `DWT->CYCCNT`.
|
||||
|
||||
Привязку вывода порт берёт из `onewire_config.h`, который предоставляет
|
||||
приложение — шаблон лежит рядом:
|
||||
|
||||
```c
|
||||
#include "stm32f10x.h"
|
||||
|
||||
#define ONEWIRE_GPIO GPIOA
|
||||
#define ONEWIRE_PIN 1U
|
||||
#define ONEWIRE_GPIO_CLOCK RCC_APB2ENR_IOPAEN
|
||||
```
|
||||
|
||||
Требуется внешняя подтяжка 4.7 кОм к питанию.
|
||||
|
||||
## Использование
|
||||
|
||||
```c
|
||||
DS18B20_Bus bus;
|
||||
|
||||
OneWire_Init();
|
||||
DS18B20_Scan(&bus); /* найти датчики на шине */
|
||||
|
||||
DS18B20_StartConversion(); /* SKIP ROM + CONVERT T */
|
||||
/* выдержать DS18B20_ConversionTimeMs(config) */
|
||||
DS18B20_ReadAll(&bus); /* обновить измерения */
|
||||
|
||||
for (uint8_t i = 0; i < bus.count; i++) {
|
||||
if (bus.sensors[i].status & DS18B20_STATUS_VALID) {
|
||||
float celsius = bus.sensors[i].raw / 16.0f;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ошибка одного датчика не прерывает опрос остальных — она видна в поле
|
||||
`status` соответствующей записи.
|
||||
|
||||
## Тесты
|
||||
|
||||
Симулятор шины реализует те же пять функций, что и настоящий порт, но
|
||||
работает не с выводом, а с моделью: виртуальные датчики отвечают побитно,
|
||||
включая полный алгоритм `SEARCH ROM`. Так на хосте проверяется именно то,
|
||||
что иначе проверялось бы только осциллографом.
|
||||
|
||||
```bash
|
||||
cmake -B build && cmake --build build && ctest --test-dir build
|
||||
```
|
||||
|
||||
```bash
|
||||
clang -std=c99 -Wall -Wextra -Iinclude -Itests \
|
||||
tests/test_ds18b20.c tests/fake_onewire.c src/onewire.c src/ds18b20.c -o test && ./test
|
||||
```
|
||||
|
||||
Покрыто: CRC8, обход шины с несколькими датчиками и пустой шины, отсев
|
||||
чужих семейств по коду ROM, паразитное питание, битый scratchpad,
|
||||
пропажа датчика, подтверждение и отказ записи, сохранение в EEPROM
|
||||
датчика, пределы разрешения 9..12 бит.
|
||||
|
||||
## Особенности, которые стоит знать
|
||||
|
||||
* **Порядок датчиков задаёт шина, а не код.** `SEARCH ROM` обходит их в
|
||||
порядке битов идентификатора, поэтому индекс в `bus.sensors[]` не
|
||||
совпадает с порядком подключения. Искать датчик нужно по ROM через
|
||||
`DS18B20_Find()`.
|
||||
* **Пропажу датчика на живой шине не видно по presence.** Импульс
|
||||
подтверждают соседи, и `MATCH ROM` к снятому датчику проходит без
|
||||
признаков ошибки — она проявится как `DS18B20_STATUS_CRC_ERROR`.
|
||||
`DS18B20_STATUS_NO_PRESENCE` означает, что молчит вся шина.
|
||||
* **`DS18B20_MAX_SENSORS` равен 8** — столько датчиков помещается в один
|
||||
кадр `SENSOR_DATA` протокола SETGUI. Для другого применения значение
|
||||
можно поднять.
|
||||
* **Обратное чтение после записи обязательно.** Датчик может ответить и
|
||||
оставить регистры прежними; такой случай отличается от ошибки шины
|
||||
кодом `DS18B20_WRITE_REJECTED`.
|
||||
|
||||
## Лицензия и происхождение
|
||||
|
||||
Код вынесен из `KONOR_ds18b20` (модуль термометрии на STM32F103C8T6)
|
||||
без изменения поведения: разделение на ядро и порт сделано переносом
|
||||
функций, тела не правились.
|
||||
Reference in New Issue
Block a user