/** test * @file ds18b20.c * @brief Реализация драйвера DS18B20: поиск, чтение и запись scratchpad. */ #include "ds18b20.h" #define DS_CMD_CONVERT_T 0x44U #define DS_CMD_WRITE_SCRATCHPAD 0x4EU #define DS_CMD_READ_SCRATCHPAD 0xBEU #define DS_CMD_COPY_SCRATCHPAD 0x48U #define DS_CMD_READ_POWER 0xB4U /** Задержка записи EEPROM датчика по datasheet, мкс. */ #define DS_EEPROM_WRITE_US 12000U /** * @brief Считывает scratchpad адресованного датчика с проверкой CRC8. * * @param rom Идентификатор датчика. * @param scratchpad Буфер на DS18B20_SCRATCHPAD_SIZE байт. * @return Битовая маска ошибок DS18B20_STATUS_* без бита VALID. */ static uint8_t ds_read_scratchpad(const uint8_t *rom, uint8_t *scratchpad) { if (OneWire_SelectRom(rom) == 0U) { return DS18B20_STATUS_NO_PRESENCE; } OneWire_WriteByte(DS_CMD_READ_SCRATCHPAD); OneWire_ReadBytes(scratchpad, DS18B20_SCRATCHPAD_SIZE); if (OneWire_Crc8(scratchpad, DS18B20_SCRATCHPAD_SIZE) != 0U) { return DS18B20_STATUS_CRC_ERROR; } return 0U; } /** * @brief Опрашивает тип питания датчика командой READ POWER SUPPLY. * * @param rom Идентификатор датчика. * @return 1 для паразитного питания, иначе 0. */ static uint8_t ds_read_parasite(const uint8_t *rom) { if (OneWire_SelectRom(rom) == 0U) { return 0U; } OneWire_WriteByte(DS_CMD_READ_POWER); /* Датчик с паразитным питанием прижимает шину к нулю. */ return (uint8_t)(OneWire_ReadBit() == 0U); } uint8_t DS18B20_ConfigFromResolution(uint8_t bits) { if (bits < 9U) { bits = 9U; } else if (bits > 12U) { bits = 12U; } return (uint8_t)(0x1FU | ((bits - 9U) << 5U)); } uint16_t DS18B20_ConversionTimeMs(uint8_t config) { switch ((config >> 5U) & 0x03U) { case 0U: return 94U; case 1U: return 188U; case 2U: return 375U; default: return 750U; } } uint8_t DS18B20_Scan(DS18B20_Bus *bus) { OneWire_Search search; uint8_t index; bus->count = 0U; bus->parasite = 0U; OneWire_SearchInit(&search); while ((bus->count < DS18B20_MAX_SENSORS) && (OneWire_SearchNext(&search) != 0U)) { if (search.rom[0] != DS18B20_FAMILY_CODE) { continue; } DS18B20_Sensor *sensor = &bus->sensors[bus->count]; for (index = 0U; index < ONEWIRE_ROM_SIZE; index++) { sensor->rom[index] = search.rom[index]; } sensor->raw = 0; sensor->user_byte1 = 0U; sensor->user_byte2 = 0U; sensor->config = DS18B20_ConfigFromResolution(12U); sensor->status = 0U; if (ds_read_parasite(sensor->rom) != 0U) { sensor->status |= DS18B20_STATUS_PARASITE; bus->parasite = 1U; } bus->count++; } return bus->count; } uint8_t DS18B20_StartConversion(void) { if (OneWire_SkipRom() == 0U) { return 0U; } OneWire_WriteByte(DS_CMD_CONVERT_T); return 1U; } uint8_t DS18B20_ReadAll(DS18B20_Bus *bus) { uint8_t scratchpad[DS18B20_SCRATCHPAD_SIZE]; uint8_t valid = 0U; uint8_t index; for (index = 0U; index < bus->count; index++) { DS18B20_Sensor *sensor = &bus->sensors[index]; const uint8_t parasite = (uint8_t)(sensor->status & DS18B20_STATUS_PARASITE); const uint8_t error = ds_read_scratchpad(sensor->rom, scratchpad); if (error != 0U) { sensor->status = (uint8_t)(parasite | error); continue; } sensor->raw = (int16_t)((uint16_t)scratchpad[0] | ((uint16_t)scratchpad[1] << 8U)); sensor->user_byte1 = scratchpad[2]; sensor->user_byte2 = scratchpad[3]; sensor->config = scratchpad[4]; sensor->status = (uint8_t)(parasite | DS18B20_STATUS_VALID); valid++; } return valid; } DS18B20_Sensor *DS18B20_Find(DS18B20_Bus *bus, const uint8_t *rom) { uint8_t index; uint8_t byte; for (index = 0U; index < bus->count; index++) { for (byte = 0U; byte < ONEWIRE_ROM_SIZE; byte++) { if (bus->sensors[index].rom[byte] != rom[byte]) { break; } } if (byte == ONEWIRE_ROM_SIZE) { return &bus->sensors[index]; } } return 0; } uint8_t DS18B20_WriteScratchpad(DS18B20_Sensor *sensor, uint8_t user_byte1, uint8_t user_byte2, uint8_t config, uint8_t save_to_eeprom) { uint8_t scratchpad[DS18B20_SCRATCHPAD_SIZE]; if (OneWire_SelectRom(sensor->rom) == 0U) { sensor->status = (uint8_t)((sensor->status & DS18B20_STATUS_PARASITE) | DS18B20_STATUS_NO_PRESENCE); return DS18B20_WRITE_BUS_ERROR; } OneWire_WriteByte(DS_CMD_WRITE_SCRATCHPAD); OneWire_WriteByte(user_byte1); OneWire_WriteByte(user_byte2); OneWire_WriteByte(config); /* Обратное чтение подтверждает, что датчик принял все три байта. */ if (ds_read_scratchpad(sensor->rom, scratchpad) != 0U) { return DS18B20_WRITE_BUS_ERROR; } if ((scratchpad[2] != user_byte1) || (scratchpad[3] != user_byte2) || (scratchpad[4] != config)) { /* Обмен состоялся, но регистры остались прежними: значение отвергнуто. */ sensor->user_byte1 = scratchpad[2]; sensor->user_byte2 = scratchpad[3]; sensor->config = scratchpad[4]; return DS18B20_WRITE_REJECTED; } sensor->user_byte1 = scratchpad[2]; sensor->user_byte2 = scratchpad[3]; sensor->config = scratchpad[4]; if (save_to_eeprom != 0U) { if (OneWire_SelectRom(sensor->rom) == 0U) { return DS18B20_WRITE_BUS_ERROR; } OneWire_WriteByte(DS_CMD_COPY_SCRATCHPAD); /* Датчик с внешним питанием тоже допускает выдержку по времени. */ OneWire_DelayUs(DS_EEPROM_WRITE_US); } return DS18B20_WRITE_OK; }