Тем не менее, успешно работает в ряде проектов:
os_uart.h
Спойлер
Код: Выделить всё
//////////////////////////////////////////////////////////////////////////
//
#ifndef _OS_UART1_H
#define _OS_UART1_H
//////////////////////////////////////////////////////////////////////////
//
#define UART1_READ_INTERVAL_TMOUT 4
#define UART_RECEIVED_DATA 3
#define UART_TRANSMITTING 2
#define UART_RECEIVING 1
#define UART_FREE 0
#define UART1_RX_DDR DDRD
#define UART1_RX_PORT PORTD
#define UART1_RX_IN PINE
#define UART1_RX_PIN (1<<PD2)
#define UART1_TX_DDR DDRD
#define UART1_TX_PORT PORTD
#define UART1_TX_IN PINE
#define UART1_TX_PIN (1<<PD3)
#define UART1_485_DDR DDRE
#define UART1_485_PORT PORTE
#define UART1_485_PIN (1<<PE7)
//////////////////////////////////////////////////////////////////////////
//
void UART1_Init(void);
void UART1_RcvTmOutCallBack(void);
uint8_t UART1_GetStatus(void);
uint8_t* UART1_GetRxBuffer(void);
uint8_t* UART1_GetTxBuffer(void);
uint8_t UART1_GetRxCount(void);
void UART1_RxRestart(void);
void UART1_SetRxBuffer(uint8_t *buff, uint8_t sizeOfBuff);
void UART1_SetTxBuffer(uint8_t *buff, uint8_t sizeOfBuff);
uint8_t UART1_ReceiveIntBuff(uint8_t *str, uint8_t lenght);
uint8_t UART1_Send(uint8_t *str, uint8_t lenght);
uint8_t UART1_SendIntBuff(uint8_t lenght);
#endif
os_uart1.c
Спойлер
Код: Выделить всё
#include <avr/interrupt.h>
#include <string.h>
#include "os_watchdog.h"
#include "os_systimer.h"
#include "os_uart1.h"
//////////////////////////////////////////////////////////////////////////
//
uint8_t *uart1TxBuff = 0; // указатель на передаваемую строку
volatile uint8_t uart1SizeOfTxBuff = 0;
volatile uint8_t uart1TxNum; // счетчик передаваемых байт
volatile uint8_t uart1TxCount = 0;
uint8_t *uart1RxBuff = 0;
volatile uint8_t uart1SizeOfRxBuff = 0;
volatile uint8_t uart1RxCount = 0;
volatile uint16_t uart1RxTmOut = 0;
volatile uint8_t uart1_bsy_flag = UART_FREE;
int64_t uart1_timers[1];
//////////////////////////////////////////////////////////////////////////
// Обработчик окончания передачи буфера
ISR(USART1_TX_vect)
{
UART1_485_PORT &= ~UART1_485_PIN; // RS485 на прием
if((uart1RxBuff != 0) && (uart1SizeOfRxBuff > 0)) // Буфер задан корректно?
{
UART1_RxRestart(); // Запускаем UART в работу на прием
}
else // иначе, блокируем его
{
UCSR1B = 0; // отключаем УСАПП
uart1_bsy_flag = UART_FREE; // освобождаем УСАПП
}
}
//////////////////////////////////////////////////////////////////////////
// Обработчик очереди передачи буфера
ISR(USART1_UDRE_vect)
{
if(uart1TxCount < uart1TxNum)// если есть еще данные на отправку
{
UDR1 = uart1TxBuff[uart1TxCount];// запихиваем следующий байт
uart1TxCount++; // инкрементируем индекс
}
else
{
UCSR1B = ((1<<TXCIE1)|(1<<TXEN1)); // иначе выставляем прерывание по окончанию передачи
uart1TxCount = 0;
}
}
//////////////////////////////////////////////////////////////////////////
// Обработчик приема данных
ISR(USART1_RX_vect) // Вектор прерывания по окончанию приема байта УСАПП
{
if(uart1RxCount == 0) // Если принят первый байт
{
uart1_bsy_flag = UART_RECEIVING; // Занимаем УСАПП, выставляя флаг "Идет сеанс приема данных"
uart1RxBuff[0] = UDR1; // Копируем принятый байт в начало буфера
uart1RxCount = 1; // Задаем индекс на следующий элемент буфера
SYSTIMER_Set(uart1_timers, 0, UART1_READ_INTERVAL_TMOUT); // Заводим таймер (таймаут между принимаемыми байтами)
}
else // Иначе, если это уже не первый за сеанс принятый байт
{
if(uart1RxCount < (uart1SizeOfRxBuff - 1)) // Если есть куда принимать (буфер не окончен)
{
uart1RxBuff[uart1RxCount] = UDR1; // Копируем принятый байт в буфер
uart1RxCount++; // Задаем индекс на следующий элемент буфера
SYSTIMER_Set(uart1_timers, 0, UART1_READ_INTERVAL_TMOUT); // Заводим таймер (таймаут между принимаемыми байтами)
}
else
{
uart1RxBuff[uart1RxCount] = UDR1; // Копируем принятый байт в последний элемент буфера
UCSR1B = 0; // Блокируем УСАПП полностью
uart1_bsy_flag = UART_RECEIVED_DATA; // Выставляем флаг "Есть принятые данные"
}
}
}
//////////////////////////////////////////////////////////////////////////
// Вызываемая системным таймером процедура проверки таймаута по приему (период = 1мс)
void UART1_RcvTmOutCallBack(void)
{
if(uart1_bsy_flag == UART_RECEIVING) // Если запущен сеанс приема
{
if(SYSTIMER_Test(uart1_timers, 0) <= 0) // Проверяем таймаут. Если истек, то ...
{
if(uart1RxCount == 0) // На всякий случай: Если счетчик принятых байтов равен нулю
{
uart1_bsy_flag = UART_FREE; // УСАПП свободен
}
else
{
uart1_bsy_flag = UART_RECEIVED_DATA; // Иначе, выставляем флаг "Есть принятые данные"
UCSR1B = 0; // Блокируем УСАПП полностью
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// Инициализация UART
void UART1_Init(void)
{
UBRR1H = 0;
UBRR1L = 103;//Bdr - 9600
UART1_485_PORT &= ~UART1_485_PIN;
UART1_485_DDR |= UART1_485_PIN;
//Parity control disable, parity mode - none
UCSR1C = ((1<<USBS1)|(3<<UCSZ10));
UCSR1A = 0;
UCSR1B = 0;
uart1_bsy_flag = UART_FREE;
}
//////////////////////////////////////////////////////////////////////////
// Текущее состояние трансивера
uint8_t UART1_GetStatus(void)
{
return uart1_bsy_flag;
}
//////////////////////////////////////////////////////////////////////////
uint8_t* UART1_GetRxBuffer(void)
{
return uart1TxBuff;
}
//////////////////////////////////////////////////////////////////////////
uint8_t* UART1_GetTxBuffer(void)
{
return uart1RxBuff;
}
//////////////////////////////////////////////////////////////////////////
void UART1_SetRxBuffer(uint8_t *buff, uint8_t sizeOfBuff)
{
uart1RxBuff = buff;
uart1SizeOfRxBuff = sizeOfBuff;
UCSR1B = ((1<<RXEN1) | (1<<RXCIE1));
}
//////////////////////////////////////////////////////////////////////////
void UART1_SetTxBuffer(uint8_t *buff, uint8_t sizeOfBuff)
{
uart1TxBuff = buff;
uart1SizeOfTxBuff = sizeOfBuff;
}
//////////////////////////////////////////////////////////////////////////
void UART1_RxRestart(void) // Запуск приема после обработки принятых данных
{
uart1RxCount = 0;
uart1_bsy_flag = UART_FREE;
UCSR1B = ((1<<RXEN1) | (1<<RXCIE1));
}
//////////////////////////////////////////////////////////////////////////
uint8_t UART1_Send(uint8_t *str, uint8_t lenght)
{
if(uart1_bsy_flag == UART_FREE)
{
uart1_bsy_flag = UART_TRANSMITTING;
uart1TxCount = 1;
uart1TxNum = lenght;
UART1_SetTxBuffer(str, lenght);
UART1_485_PORT |= UART1_485_PIN; // RS485 на передачу
UCSR1B = ((1<<TXEN1) | (1<<UDRIE1));
UDR1 = str[0];
return 1;
}
else
{
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
uint8_t UART1_SendIntBuff(uint8_t lenght)
{
if(uart1TxBuff == 0)
{
return 0;
}
if(((uart1_bsy_flag == UART_FREE) || (uart1_bsy_flag == UART_RECEIVED_DATA)) && (uart1TxBuff != uart1RxBuff))
{
uart1_bsy_flag = UART_TRANSMITTING;
UART1_485_PORT |= UART1_485_PIN; // RS485 на передачу
uart1TxCount = 1;
uart1TxNum = lenght;
UCSR1B = (1<<TXEN1);
UDR1 = uart1TxBuff[0];
UCSR1B = ((1<<TXEN1) | (1<<UDRIE1));
return 0;
}
else
{
return 1;
}
}
//////////////////////////////////////////////////////////////////////////
uint8_t UART1ReceiveIntBuff(uint8_t *str, uint8_t lenght)
{
if(uart1RxBuff == 0)
{
return 0;
}
else
{
for(uint8_t i = 0; i < uart1RxCount; i++)
{
if(i >= uart1SizeOfRxBuff)
{
return i;
}
else
{
str[i] = uart1RxBuff[i];
}
}
return uart1RxCount;
}
}
//////////////////////////////////////////////////////////////////////////
uint8_t UART1_GetRxCount(void)
{
return uart1RxCount;
}
Код: Выделить всё
#include "os_uart1.h"
***
UART1_Init();
UART1_SetTxBuffer(pnsTxBuffer, sizeof(pnsTxBuffer));
UART1_SetRxBuffer(pnsRxBuffer, sizeof(pnsRxBuffer));
***
if(UART1_GetStatus() == UART_RECEIVED_DATA)
{
// обрабатываем данные и за тем вызываем
UART1_RxRestart();
}
// Передача
if((UART1_GetStatus() == UART_FREE) || (UART1_GetStatus() == UART_RECEIVED_DATA))
{ // Если используется два буффера, то конструкция верна, иначе следует проверять только на UART_FREE
pnsTxBuffer[ADDR] = pnsAddr;
pnsTxBuffer[CMD] = SET_CTRL_ONE;
pnsTxBuffer[DATA_SIZE] = SZ_SET_CTRL_ONE;
pnsTxBuffer[DATA_BEGIN] = ctrl;
pnsTxBuffer[(DATA_BEGIN + 1)] = ~ctrl;
UART1_SendIntBuff((SZ_HEAD + SZ_SET_CTRL_ONE));
}
Сами признаки имеются, только в виде таймаутов между принятыми байтами.
Может кому и пригодится.


