184 lines
5.0 KiB
C
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;
|
|
}
|