/** ****************************************************************************** * @file dallas_tools.c * @brief Драйвер для работы с датчиками температуры DS18B20 ****************************************************************************** @details Библиотека предназначена для работы с цифровыми датчиками температуры DS18B20 по однопроводному интерфейсу 1-Wire. Реализована поддержка инициализации, поиска, добавления и работы с несколькими датчиками. @verbatim ============================================================================== ## Основные задачи библиотеки ## ============================================================================== Эта библиотека предоставляет следующие основные функции: (+) Инициализация шины 1-Wire и обнаружение подключённых датчиков (+) Инициализация структуры датчика по: - ROM-адресу - пользовательским байтам (TH, TL, UserByte3, UserByte4) - порядковому номеру в списке найденных устройств (+) Конфигурация разрешения измерения (+) Чтение температуры (+) Замена «потерянного» датчика (+) Деинициализация структуры датчика ============================================================================== ## Быстрый старт ## ============================================================================== Пример последовательности инициализации и использования: 1. Определение пина и таймера для OneWire в ow_port.h: #define OW_GPIO_Port GPIOB #define OW_Pin_Numb 0 #define OW_Pin (1<hdallas = hdallas; result = sensor->Init.init_func(hdallas, sensor); return result; } /** * @brief Функция для нахождения нового датчика на место потерянного * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_ReplaceLostedSensor(DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(sensor == NULL) return HAL_ERROR; result = Dallas_IsConnected(sensor); if(sensor->isLost) { if(DS18B20_Search(sensor->hdallas->ds_devices, sensor->hdallas->onewire) != HAL_OK) return HAL_ERROR; if(sensor->Init.init_func(sensor->hdallas, sensor) != HAL_OK) return HAL_ERROR; return HAL_OK; } else { return HAL_BUSY; // датчик не потерян } } /** * @brief Запускает измерение температуры на всех датчиках * @param hdallas Указатель на хендл для общения с датчиками * @param waitCondition Условие ожидания завершения преобразования * @param dallas_delay_ms Время ожидания окончания конверсии * @retval HAL Status */ HAL_StatusTypeDef Dallas_StartConvertTAll(DALLAS_HandleTypeDef *hdallas, DALLAS_WaitConvertionTypeDef waitCondition, uint8_t dallas_delay_ms) { HAL_StatusTypeDef result; uint8_t rxDummyData; if(hdallas == NULL) return HAL_ERROR; // Отправка команды начала преобразования температуры result = DS18B20_StartConvTAll(hdallas->onewire); if(result != HAL_OK) { return result; } // // Проверка что преобразование началось // if(OneWire_ReadBit(onewire) == 1) // return HAL_ERROR; // Ожидание завершения преобразования, путем проверки шины if (waitCondition == DALLAS_WAIT_BUS) { result = DS18B20_WaitForEndConvertion(hdallas->onewire); return result; } // Ожидание завершения преобразования, путем задержки if (waitCondition == DALLAS_WAIT_DELAY) { uint32_t delayValueMs = 0; switch (dallas_delay_ms) { case DALLAS_CONFIG_9_BITS: delayValueMs = DALLAS_DELAY_MS_9_BITS; break; case DALLAS_CONFIG_10_BITS: delayValueMs = DALLAS_DELAY_MS_10_BITS; break; case DALLAS_CONFIG_11_BITS: delayValueMs = DALLAS_DELAY_MS_11_BITS; break; case DALLAS_CONFIG_12_BITS: delayValueMs = DALLAS_DELAY_MS_12_BITS; break; default: break; } HAL_Delay(delayValueMs); } return result; } /** * @brief Измеряет температуру на датчике * @param sensor Указатель на структуру датчика * @param waitCondition Условие ожидания завершения преобразования * @retval HAL Status */ HAL_StatusTypeDef Dallas_ConvertT(DALLAS_SensorHandleTypeDef *sensor, DALLAS_WaitConvertionTypeDef waitCondition) { HAL_StatusTypeDef result; uint8_t rxDummyData; if(sensor == NULL) return HAL_ERROR; if(sensor->isInitialized == 0) return HAL_ERROR; /* Проверка присутствует ли выбранный датчик на линии */ result = Dallas_IsConnected(sensor); if (result != HAL_OK) return result; // Отправка команды начала преобразования температуры result = DS18B20_StartConvT(sensor->hdallas->onewire, (uint8_t *)&sensor->sensROM); if(result != HAL_OK) { return result; } // Ожидание завершения преобразования, путем проверки шины if (waitCondition == DALLAS_WAIT_BUS) { result = DS18B20_WaitForEndConvertion(sensor->hdallas->onewire); if(result == HAL_TIMEOUT) { sensor->f.timeout_convertion_cnt++; } return result; } // Ожидание завершения преобразования, путем задержки if (waitCondition == DALLAS_WAIT_DELAY) { uint32_t delayValueMs = 0; switch (sensor->hdallas->scratchpad.ConfigRegister) { case DALLAS_CONFIG_9_BITS: delayValueMs = DALLAS_DELAY_MS_9_BITS; break; case DALLAS_CONFIG_10_BITS: delayValueMs = DALLAS_DELAY_MS_10_BITS; break; case DALLAS_CONFIG_11_BITS: delayValueMs = DALLAS_DELAY_MS_11_BITS; break; case DALLAS_CONFIG_12_BITS: delayValueMs = DALLAS_DELAY_MS_12_BITS; break; default: break; } HAL_Delay(delayValueMs); } /* Не считываем температуру, если не выбрано ожидание окончания преобразования */ if(waitCondition != DALLAS_WAIT_NONE) { result = Dallas_ReadTemperature(sensor); } return result; } /** * @brief Читает измеренную датчиком температуру * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_ReadTemperature(DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(sensor == NULL) return HAL_ERROR; if(sensor->isInitialized == 0) return HAL_ERROR; /* Проверка присутствует ли выбранный датчик на линии */ result = Dallas_IsConnected(sensor); if (result != HAL_OK) { return result; } result = DS18B20_CalcTemperature(sensor->hdallas->onewire, (uint8_t *)&sensor->sensROM, (uint8_t *)&sensor->hdallas->scratchpad, &sensor->temperature); if (result != HAL_OK) { sensor->f.read_temperature_err_cnt++; return result; } return HAL_OK; } /** * @brief Проверяет подключен ли датчик (чтение scratchpad) * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_IsConnected(DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(sensor == NULL) return HAL_ERROR; result = Dallas_ReadScratchpad(sensor); if (result == HAL_OK) { sensor->isConnected = 1; sensor->isLost = 0; return HAL_OK; } else { sensor->temperature = 0; if(sensor->isConnected == 1) { sensor->f.disconnect_cnt++; } sensor->isLost = 1; sensor->isConnected = 0; // Dallas_ReplaceLostedSensor(sensor); return HAL_BUSY; // использую busy, чтобы отличать ситуацию от HAL_ERROR } } /** * @brief Записывает пользовательские байты * @param sensor Указатель на структуру датчика * @param UserBytes12 Пользовательские байты 1 и 2 * @param UserBytes34 Пользовательские байты 3 и 4 * @param UserBytesMask Маска, какие байты записывать, а какие нет * @retval HAL Status * @details старший байт - UserByte4/UserByte2, младший - UserByte3/UserByte1. */ HAL_StatusTypeDef Dallas_WriteUserBytes(DALLAS_SensorHandleTypeDef *sensor, uint16_t UserBytes12, uint16_t UserBytes34, uint8_t UserBytesMask) { HAL_StatusTypeDef result; if(sensor == NULL) return HAL_ERROR; if(sensor->isInitialized == 0) return HAL_ERROR; /* Проверка присутствует ли выбранный датчик на линии */ result = Dallas_IsConnected(sensor); if (result != HAL_OK) return result; result = DS18B20_WriteUserBytes(sensor->hdallas->onewire, (uint8_t *)&sensor->sensROM, UserBytes12, UserBytes34, UserBytesMask); if (result != HAL_OK) { sensor->f.write_err_cnt++; return result; } result = Dallas_ReadScratchpad(sensor); if (result != HAL_OK) { return result; } return result; } HAL_StatusTypeDef Dallas_ReadScratchpad(DALLAS_SensorHandleTypeDef *sensor) { if(sensor == NULL) return HAL_ERROR; return DS18B20_ReadScratchpad(sensor->hdallas->onewire, (uint8_t *)&sensor->sensROM, (uint8_t *)&sensor->hdallas->scratchpad); } /** * @brief Инициализирует структуру датчика по ROM * @param hdallas Указатель на хендл для общения с датчиками * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_SensorInitByROM(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(hdallas == NULL) return HAL_ERROR; if(sensor == NULL) return HAL_ERROR; uint8_t ROM[8] = {0}; ROM[0] = (sensor->Init.InitParam.ROM >> (7*8)) & 0xFF; ROM[1] = (sensor->Init.InitParam.ROM >> (6*8)) & 0xFF; ROM[2] = (sensor->Init.InitParam.ROM >> (5*8)) & 0xFF; ROM[3] = (sensor->Init.InitParam.ROM >> (4*8)) & 0xFF; ROM[4] = (sensor->Init.InitParam.ROM >> (3*8)) & 0xFF; ROM[5] = (sensor->Init.InitParam.ROM >> (2*8)) & 0xFF; ROM[6] = (sensor->Init.InitParam.ROM >> (1*8)) & 0xFF; ROM[7] = (sensor->Init.InitParam.ROM >> (0*8)) & 0xFF; if(DS18B20_IsValidAddress(ROM) != HAL_OK) return HAL_ERROR; uint8_t comparebytes = DALLAS_ROM_SIZE; int ROM_ind = 0; for(int i = 0; i < hdallas->onewire->RomCnt; i++) { comparebytes = DALLAS_ROM_SIZE; for(int rom_byte = 0; rom_byte < DALLAS_ROM_SIZE; rom_byte++) { if(hdallas->ds_devices->DevAddr[i][rom_byte] == ROM[rom_byte]) comparebytes--; } if(comparebytes == 0) { ROM_ind = i; break; } } /* Проверка присутствует ли выбранный датчик на линии */ if(comparebytes == 0) { result = Dallas_SensorInit(hdallas, sensor, &hdallas->ds_devices->DevAddr[ROM_ind]); return result; } else { return HAL_ERROR; } } /** * @brief Инициализирует структуру датчика по пользовательским байтам * @param hdallas Указатель на хендл для общения с датчиками * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_SensorInitByUserBytes(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(hdallas == NULL) return HAL_ERROR; if(sensor == NULL) return HAL_ERROR; uint8_t UserByte1 = sensor->Init.InitParam.UserBytes.UserByte1; uint8_t UserByte2 = sensor->Init.InitParam.UserBytes.UserByte2; uint8_t UserByte3 = sensor->Init.InitParam.UserBytes.UserByte3; uint8_t UserByte4 = sensor->Init.InitParam.UserBytes.UserByte4; uint8_t UserByte12Cmp = 0; uint8_t UserByte34Cmp = 0; for(int i = 0; i < hdallas->onewire->RomCnt; i++) { /* Проверка присутствует ли выбранный датчик на линии */ result = DS18B20_ReadScratchpad(hdallas->onewire, (uint8_t *)&hdallas->ds_devices->DevAddr[i], (uint8_t *)&hdallas->scratchpad); if (result != HAL_OK) return result; /* Сравнение UserByte1 и UserByte2, если они не равны нулю */ if(UserByte1 | UserByte2) { if( (hdallas->scratchpad.tHighRegister == UserByte1) && (hdallas->scratchpad.tLowRegister == UserByte2)) { UserByte12Cmp = 1; } }/* Если сравнение UserByte1 и UserByte2 не выбрано, то считаем что они совпадают */ else { UserByte12Cmp = 1; } /* Сравнение UserByte3 и UserByte4, если они не равны нулю */ if(UserByte3 | UserByte4) { if( (hdallas->scratchpad.UserByte3 == UserByte3) && (hdallas->scratchpad.UserByte4 == UserByte4)) { UserByte34Cmp = 1; } }/* Если сравнение UserByte3 и UserByte4 не выбрано, то считаем что они одинаковые */ else { UserByte34Cmp = 1; } /* Если нашли нужный датчик - завершаем поиск */ if(UserByte12Cmp && UserByte34Cmp) { // sensor->isInitialized = 1; // sensor->Init.init_func = (HAL_StatusTypeDef (*)())Dallas_SensorInitByUserBytes; result = Dallas_SensorInit(hdallas, sensor, &hdallas->ds_devices->DevAddr[i]); return result; } } sensor->sensROM = 0; /* Возвращаем ошибку если не нашли */ return HAL_ERROR; } /** * @brief Инициализирует структуру датчика по порядковому номеру * @param hdallas Указатель на хендл для общения с датчиками * @param sensor Указатель на структуру датчика * @retval HAL Status * @details Порядковый номер датчика в списке найденных. * Т.е. каким по счету этот датчик был найден */ HAL_StatusTypeDef Dallas_SensorInitByInd(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor) { HAL_StatusTypeDef result; if(hdallas == NULL) return HAL_ERROR; if(sensor == NULL) return HAL_ERROR; result = Dallas_SensorInit(hdallas, sensor, &hdallas->ds_devices->DevAddr[sensor->Init.InitParam.Ind]); return result; } /** * @brief Инициализирует датчик для работы * @param hdallas Указатель на хендл для общения с датчиками * @param sensor Указатель на структуру датчика * @param ROM ROM датчика, который надо инициализировать * @retval HAL Status */ HAL_StatusTypeDef Dallas_SensorInit(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor, uint8_t (*ROM)[DALLAS_ROM_SIZE]) { HAL_StatusTypeDef result; if(sensor == NULL) return HAL_ERROR; if(hdallas == 0) return HAL_ERROR; sensor->hdallas = hdallas; sensor->sensROM = 0; sensor->sensROM = *(uint64_t *)(ROM); // for(int i = 0; i < DALLAS_ROM_SIZE; i++) // sensor->sensROM |= ((uint64_t)(*ROM)[i] << (56 - 8*i)); /* Проверка присутствует ли выбранный датчик на линии */ result = Dallas_ReadScratchpad(sensor); if (result == HAL_OK) { /* Установка разрешения */ result = DS18B20_SetResolution(hdallas->onewire, (uint8_t *)ROM, sensor->Init.Resolution); if (result == HAL_OK) { sensor->isInitialized = 1; return HAL_OK; } else { sensor->isInitialized = 0; return result; } } else { sensor->isInitialized = 0; return result; } } /** * @brief Деинициализирует структуру датчика * @param sensor Указатель на структуру датчика * @retval HAL Status */ HAL_StatusTypeDef Dallas_SensorDeInit(DALLAS_SensorHandleTypeDef *sensor) { if(sensor == NULL) return HAL_ERROR; memset(&sensor->f, 0, sizeof(sensor->f)); sensor->isConnected = 0; sensor->isInitialized = 0; sensor->isLost = 0; sensor->temperature = 0; sensor->sensROM = 0; return HAL_OK; }