160 lines
4.8 KiB
C
160 lines
4.8 KiB
C
/**
|
||
******************************************************************************
|
||
* @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);
|
||
|
||
return rxData;
|
||
}
|
||
|
||
/**
|
||
* @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 < ONEWIRE_BITS_NUM; i++)
|
||
{
|
||
txBit = (byte >> i) & 0x01; // Извлекаем очередной бит для отправки
|
||
uint8_t tempRxData = OneWireUART_ProcessBit(huart, txBit);
|
||
|
||
if (tempRxData == 0xFF)
|
||
{
|
||
rxBit = 1; // В случае высокого уровня на линии интерпретируем как '1'
|
||
}
|
||
else
|
||
{
|
||
rxBit = 0;
|
||
}
|
||
|
||
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;
|
||
}
|