Files
templates/c/ds18b20/src/onewire.c
T

184 lines
5.0 KiB
C

/*
* Общие операции 1-Wire и обход дерева 64-битных ROM. Поиск разрешает коллизии побитно,
* поэтому обнаружение нескольких устройств не сводится к чтению одного адреса. Электрические
* уровни и длительности импульсов задаёт порт.
*/
/**
* @file onewire.c
* @brief Переносимая часть шины 1-Wire: побайтовый обмен, CRC8 и поиск ROM.
*
* Здесь нет ни регистров, ни задержек, ни запрета прерываний: всё это живёт
* в порте (ports/), а этот файл собирается любым C99-компилятором и
* проверяется host-тестами на симуляторе шины.
*
* От порта требуются пять функций: OneWire_Init, OneWire_DelayUs,
* OneWire_Reset, OneWire_WriteBit и OneWire_ReadBit.
*/
#include "onewire.h"
#define OW_CMD_SEARCH_ROM 0xF0U
#define OW_CMD_MATCH_ROM 0x55U
#define OW_CMD_SKIP_ROM 0xCCU
void OneWire_WriteByte(uint8_t value)
{
uint8_t index;
for (index = 0U; index < 8U; index++) {
OneWire_WriteBit((uint8_t)(value & 1U));
value = (uint8_t)(value >> 1U);
}
}
uint8_t OneWire_ReadByte(void)
{
uint8_t value = 0U;
uint8_t index;
for (index = 0U; index < 8U; index++) {
value = (uint8_t)(value >> 1U);
if (OneWire_ReadBit() != 0U) {
value |= 0x80U;
}
}
return value;
}
void OneWire_WriteBytes(const uint8_t *data, uint32_t size)
{
uint32_t index;
for (index = 0U; index < size; index++) {
OneWire_WriteByte(data[index]);
}
}
void OneWire_ReadBytes(uint8_t *data, uint32_t size)
{
uint32_t index;
for (index = 0U; index < size; index++) {
data[index] = OneWire_ReadByte();
}
}
uint8_t OneWire_Crc8(const uint8_t *data, uint32_t size)
{
uint8_t crc = 0U;
uint32_t index;
uint8_t bit;
for (index = 0U; index < size; index++) {
crc ^= data[index];
for (bit = 0U; bit < 8U; bit++) {
crc = (uint8_t)((crc & 1U) != 0U ? ((crc >> 1U) ^ 0x8CU) : (crc >> 1U));
}
}
return crc;
}
void OneWire_SearchInit(OneWire_Search *search)
{
uint32_t index;
for (index = 0U; index < ONEWIRE_ROM_SIZE; index++) {
search->rom[index] = 0U;
}
search->last_discrepancy = 0U;
search->last_family_discrepancy = 0U;
search->last_device = 0U;
}
uint8_t OneWire_SearchNext(OneWire_Search *search)
{
uint8_t id_bit_number = 1U;
uint8_t last_zero = 0U;
uint8_t rom_byte_number = 0U;
uint8_t rom_byte_mask = 1U;
uint8_t search_direction;
uint8_t id_bit;
uint8_t cmp_id_bit;
if (search->last_device != 0U) {
OneWire_SearchInit(search);
return 0U;
}
if (OneWire_Reset() == 0U) {
OneWire_SearchInit(search);
return 0U;
}
OneWire_WriteByte(OW_CMD_SEARCH_ROM);
do {
id_bit = OneWire_ReadBit();
cmp_id_bit = OneWire_ReadBit();
if ((id_bit != 0U) && (cmp_id_bit != 0U)) {
/* Ни одно устройство не ответило: обход прерван. */
OneWire_SearchInit(search);
return 0U;
}
if (id_bit != cmp_id_bit) {
search_direction = id_bit;
} else if (id_bit_number < search->last_discrepancy) {
search_direction =
(uint8_t)((search->rom[rom_byte_number] & rom_byte_mask) != 0U);
} else {
search_direction = (uint8_t)(id_bit_number == search->last_discrepancy);
}
if ((id_bit == cmp_id_bit) && (search_direction == 0U)) {
last_zero = id_bit_number;
if (last_zero < 9U) {
search->last_family_discrepancy = last_zero;
}
}
if (search_direction != 0U) {
search->rom[rom_byte_number] |= rom_byte_mask;
} else {
search->rom[rom_byte_number] &= (uint8_t)~rom_byte_mask;
}
OneWire_WriteBit(search_direction);
id_bit_number++;
rom_byte_mask = (uint8_t)(rom_byte_mask << 1U);
if (rom_byte_mask == 0U) {
rom_byte_number++;
rom_byte_mask = 1U;
}
} while (rom_byte_number < ONEWIRE_ROM_SIZE);
if (OneWire_Crc8(search->rom, ONEWIRE_ROM_SIZE) != 0U) {
OneWire_SearchInit(search);
return 0U;
}
search->last_discrepancy = last_zero;
if (search->last_discrepancy == 0U) {
search->last_device = 1U;
}
return 1U;
}
uint8_t OneWire_SelectRom(const uint8_t *rom)
{
if (OneWire_Reset() == 0U) {
return 0U;
}
OneWire_WriteByte(OW_CMD_MATCH_ROM);
OneWire_WriteBytes(rom, ONEWIRE_ROM_SIZE);
return 1U;
}
uint8_t OneWire_SkipRom(void)
{
if (OneWire_Reset() == 0U) {
return 0U;
}
OneWire_WriteByte(OW_CMD_SKIP_ROM);
return 1U;
}