/** ****************************************************************************** * @file : onewire_uart.c * @brief : Драйвер для работы с шиной 1-Wire через UART * @author : MicroTechnics (microtechnics.ru) ****************************************************************************** @details Этот файл реализует базовые функции для работы с 1-Wire через UART. Он включает в себя методы для передачи и приёма битов и байтов, а также выполнение reset-команды для устройств 1-Wire. UART передает специально сформированные импульсы, эмулируя 1-Wire. *****************************************************************************/ /* Includes ----------------------------------------------------------------*/ #include "onewire_uart.h" /* Declarations and definitions --------------------------------------------*/ /* Functions ---------------------------------------------------------------*/ /** * @brief Устанавливает скорость передачи данных для UART. * @param huart Указатель на структуру UART * @param baudrate Требуемая скорость передачи (бит/с) * @details Функция изменяет скорость передачи UART в зависимости от используемой шины * (PCLK1 или PCLK2). Это важно для эмуляции временных параметров 1-Wire. */ static void UARTSetBaudrate(UART_HandleTypeDef *huart, uint32_t baudrate) { uint32_t pclk = 0; huart->Init.BaudRate = baudrate; #if defined(USART6) && defined(UART9) && defined(UART10) if ((huart->Instance == USART1) || (huart->Instance == USART6) || (huart->Instance == UART9) || (huart->Instance == UART10)) { pclk = HAL_RCC_GetPCLK2Freq(); } #elif defined(USART6) if ((huart->Instance == USART1) || (huart->Instance == USART6)) { pclk = HAL_RCC_GetPCLK2Freq(); } #else if (huart->Instance == USART1) { pclk = HAL_RCC_GetPCLK2Freq(); } #endif /* USART6 */ else { pclk = HAL_RCC_GetPCLK1Freq(); } #if defined(USART_CR1_OVER8) if (huart->Init.OverSampling == UART_OVERSAMPLING_8) { huart->Instance->BRR = UART_BRR_SAMPLING8(pclk, huart->Init.BaudRate); } else { huart->Instance->BRR = UART_BRR_SAMPLING16(pclk, huart->Init.BaudRate); } #else huart->Instance->BRR = UART_BRR_SAMPLING16(pclk, huart->Init.BaudRate); #endif /* USART_CR1_OVER8 */ } /** * @brief Передает и принимает один бит через 1-Wire. * @param huart Указатель на структуру UART * @param bit Бит для передачи (0 или 1) * @return Полученный бит (0 или 1) * @details Передача осуществляется отправкой специального импульса, длина которого определяет передаваемый бит. * Ответное значение читается сразу после передачи. */ uint8_t OneWireUART_ProcessBit(UART_HandleTypeDef *huart, uint8_t bit) { uint8_t txData; uint8_t rxData = 0x00; if (bit == 1) { txData = ONEWIRE_PULSE_SHORT; // Короткий импульс для передачи '1' } else { txData = ONEWIRE_PULSE_LONG; // Длинный импульс для передачи '0' } HAL_UART_Transmit(huart, &txData, 1, ONEWIRE_UART_TIMEOUT); HAL_UART_Receive(huart, &rxData, 1, ONEWIRE_UART_TIMEOUT); if (rxData == 0xFF) { bit = 1; // Короткий импульс для передачи '1' } else { bit = 0; // Длинный импульс для передачи '0' } return bit; } /** * @brief Передает и принимает байт через 1-Wire. * @param huart Указатель на структуру UART * @param byte Отправляемый байт * @return Принятый байт * @details Отправляет 8 бит последовательно, используя @ref OneWire_ProcessBit. * Каждый полученный бит собирается в байт и возвращается. */ uint8_t OneWireUART_ProcessByte(UART_HandleTypeDef *huart, uint8_t byte) { uint8_t rxByte = 0x00; uint8_t txBit = 0; uint8_t rxBit = 0; for (uint8_t i = 0; i < 8; i++) { txBit = (byte >> i) & 0x01; // Извлекаем очередной бит для отправки rxBit = OneWireUART_ProcessBit(huart, txBit); rxByte |= (rxBit << i); // Собираем принятые биты в байт } return rxByte; } /** * @brief Выполняет 1-Wire Reset и проверяет наличие устройств на шине. * @param huart Указатель на структуру UART * @return HAL Status * @details Процедура Reset требует изменения скорости UART, чтобы сформировать * большой по длительности импульс сброса. Если устройство ответило, шина в рабочем состоянии. */ HAL_StatusTypeDef OneWireUART_Reset(UART_HandleTypeDef *huart) { HAL_StatusTypeDef status = HAL_OK; uint8_t txByte = ONEWIRE_RESET; uint8_t rxByte = 0x00; UARTSetBaudrate(huart, ONEWIRE_RESET_BAUDRATE); // Устанавливаем низкую скорость для Reset-импульса HAL_UART_Transmit(huart, &txByte, 1, ONEWIRE_UART_TIMEOUT); HAL_UART_Receive(huart, &rxByte, 1, ONEWIRE_UART_TIMEOUT); UARTSetBaudrate(huart, ONEWIRE_BAUDRATE); // Возвращаем стандартную скорость if (rxByte == txByte) { status = HAL_ERROR; // Если ответ совпадает с отправленным байтом, значит, устройств нет } return status; }