Экспериментальная хуета

Тут у нас приемник сообщений с DWIN панели, который принимает данные через хардварный UART в лупе и передает через софтварный UART на PB3:

#define F_CPU 16000000UL  // Тактовая частота МК — 16 мегагерц
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>  // Для uint8_t и т.д.

// Настройки для аппаратного UART (115200 бод, F_CPU = 16 МГц, с U2X для лучшей точности)
#define BAUD_HARD 115200
#define UBRR_HARD_VALUE ((F_CPU / (8UL * BAUD_HARD)) - 1)

// Настройки для программного UART (9600 бод)
#define BAUD_SOFT 9600
#define BIT_DELAY_US (1000000.0 / BAUD_SOFT)  // Точный расчет: ~104.1667 us для снижения ошибки тайминга

// Максимальный размер пакета (на основе примеров, добавляем запас)
#define MAX_PACKET_SIZE 20

// Инициализация аппаратного UART с U2X
void UART_Hard_Init(void) {
	UBRR0H  = (UBRR_HARD_VALUE >> 8); // Старший байт делителя
	UBRR0L  = UBRR_HARD_VALUE;       // Младший байт делителя
	UCSR0A |= (1 << U2X0);          // Включаем двойную скорость для снижения ошибки baud rate
	UCSR0B  = (1 <<  RXEN0) | (1 << TXEN0); // Включение RX и TX
	UCSR0C  = (1 << UCSZ01) | (1 << UCSZ00); // 8 бит данных, без паритета, 1 стоп-бит
}

// Чтение байта из аппаратного UART
uint8_t UART_Hard_Receive(void) {
	while (!(UCSR0A & (1 << RXC0))); // Ждем, пока данные не придут
	return UDR0;
}

// Инициализация программного UART (PB3 - TX)
void UART_Soft_Init(void) {
	DDRB |= (1 << PB3); // PB3 как выход
	PORTB |= (1 << PB3); // Устанавливаем высокий уровень (idle)
}

// Отправка байта через программный UART
void UART_Soft_Transmit(uint8_t data) {
	// Стартовый бит (0)
	PORTB &= ~(1 << PB3);
	_delay_us(BIT_DELAY_US);
	
	// Отправка 8 бит данных (LSB first)
	for (uint8_t i = 0; i < 8; i++) {
		if (data & (1 << i)) {
			PORTB |= (1 << PB3); // Устанавливаем 1
			} else {
			PORTB &= ~(1 << PB3); // Устанавливаем 0
		}
		_delay_us(BIT_DELAY_US);
	}
	
	// Стоп-бит (1)
	PORTB |= (1 << PB3);
	_delay_us(BIT_DELAY_US);
}

// Функция для отправки строки через программный UART
void UART_Soft_Send_String(const char *str) {
	while (*str) {
		UART_Soft_Transmit(*str++);
	}
}

// Функция для преобразования байта в HEX-строку и отправки (только два символа, без пробела)
void UART_Soft_Send_Hex_Byte(uint8_t byte) {
	const char hex_chars[] = "0123456789ABCDEF";
	
	// Высокий ниббл
	UART_Soft_Transmit(hex_chars[(byte >> 4) & 0x0F]);
	// Низкий ниббл
	UART_Soft_Transmit(hex_chars[byte & 0x0F]);
}

int main(void) {
	// Настройка PD6 как выход и установка высокого уровня
	DDRD |= (1 << PD6);
	PORTD |= (1 << PD6);
	
	// Инициализация UART
	UART_Hard_Init();
	UART_Soft_Init();
	
	// Тестовое сообщение при старте
	UART_Soft_Send_String("System initialized.\r\n");
	
	while (1) {
		// Ждем начала пакета: 0x5A
		uint8_t header1 = UART_Hard_Receive();
		if (header1 != 0x5A) continue;
		
		// Ждем второго байта заголовка: 0xA5
		uint8_t header2 = UART_Hard_Receive();
		if (header2 != 0xA5) continue;
		
		// Читаем длину (количество байт после length, включая command и data)
		uint8_t length = UART_Hard_Receive();
		
		// Буфер для пакета (заголовок + length + data)
		uint8_t packet[MAX_PACKET_SIZE];
		packet[0] = 0x5A;
		packet[1] = 0xA5;
		packet[2] = length;
		
		// Читаем оставшиеся байты (length байт)
		for (uint8_t i = 0; i < length; i++) {
			packet[3 + i] = UART_Hard_Receive();
		}
		
		// Полный размер пакета
		uint8_t total_size = 3 + length;
		
		// Отправляем префикс без переноса строки
		UART_Soft_Send_String("Next data Received from DWIN: \n");
		
		// Отправляем пакет как HEX-строку с пробелами между байтами, без trailing space
		for (uint8_t i = 0; i < total_size; i++) {
			UART_Soft_Send_Hex_Byte(packet[i]);
			if (i < total_size - 1) {
				UART_Soft_Transmit(' ');
			}
		}
		
		// Завершаем строку
		UART_Soft_Send_String("\r\n");
	}
	
	return 0;
}

 А тут тоже самое, только уже через USARTRXvect

#define F_CPU 16000000UL  // Тактовая частота МК — 16 МГц
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>
// -------------------- Размеры буферов --------------------
#define MAX_PACKET_SIZE 64  // с запасом под типичные DWIN-кадры
// -------------------- Программный UART TX (PB3) --------------------
static inline void UART_Soft_Init(void) {
	DDRB  |= (1 << PB3);     // PB3 — выход
	PORTB |= (1 << PB3);     // idle = 1 (линия в "1" в простое)
}
static inline void UART_Soft_Transmit(uint8_t data) {
	cli();                   // на время передачи блокируем прерывания
	PORTB &= ~(1 << PB3);    // стартовый бит (0)
	_delay_us(104);          // 104 мкс для 9600 бод

	for (uint8_t i = 0; i < 8; i++) {
		if (data & (1 << i)) PORTB |=  (1 << PB3); // 1
		else                 PORTB &= ~(1 << PB3); // 0
		_delay_us(104);
	}

	PORTB |= (1 << PB3);     // стоп-бит (1)
	_delay_us(104);
	sei();
}
static inline void UART_Soft_Send_String(const char *s) {
	while (*s) UART_Soft_Transmit((uint8_t)*s++);
}
static inline void UART_Soft_Send_HEX(uint8_t b) {
	static const char H[] = "0123456789ABCDEF";
	UART_Soft_Transmit(H[(b >> 4) & 0x0F]);
	UART_Soft_Transmit(H[b & 0x0F]);
}
static inline void UART_Soft_Send_Space(void) {
	UART_Soft_Transmit(' ');
}
// -------------------- Аппаратный UART0 (RX от DWIN) --------------------
static inline void UART_Hard_Init(void) {
	// Настройка скорости: 115200 бод при 16 МГц с U2X=1
	UBRR0H = 0;              // старший байт UBRR
	UBRR0L = 16;             // UBRR = 16 для 115200 бод при U2X=1
	UCSR0A = (1 << U2X0);    // двойная скорость
	UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // RX, TX, прерывание RX
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8N1
}
// -------------------- Парсер DWIN --------------------
// Текущий собираемый пакет
volatile uint8_t packet[MAX_PACKET_SIZE];
volatile uint8_t packet_index = 0;
// «Сырое» сообщение (готовый кадр) для внешней логики/другой программы
volatile uint8_t dwin_raw[MAX_PACKET_SIZE];
volatile uint8_t dwin_len = 0;      // фактическая длина готового кадра
volatile uint8_t dwin_ready = 0;    // флаг «готов к обработке/печати»
static inline void parser_reset(void) {
	packet_index = 0;
}
// Вспомогательное: безопасная запись байта в packet[]
static inline uint8_t packet_push(uint8_t byte) {
	if (packet_index >= MAX_PACKET_SIZE) return 0;
	packet[packet_index++] = byte;
	return 1;
}
// -------------------- Прерывание приёма UART0 --------------------
ISR(USART_RX_vect) {
	uint8_t data = UDR0;
	// Ждём заголовок 0x5A 0xA5
	if (packet_index == 0) {
		if (data != 0x5A) return;             // пока не 0x5A — игнор
		} else if (packet_index == 1) {
		if (data != 0xA5) { parser_reset(); return; }
	}
	// Пишем байт
	if (!packet_push(data)) {
		parser_reset(); // защита от переполнения
		return;
	}
	// Как только есть хотя бы 3 байта, можем проверить полноту
	if (packet_index >= 3) {
		uint8_t len = packet[2];         // длина полезной части после байта длины
		uint8_t need_total = (uint8_t)(3 + len); // 2 заголовка + 1 длина + len
		if (packet_index == need_total) {
			// Пакет полностью собран — копируем в «сырое» хранилище
			uint8_t copy_len = need_total;
			if (copy_len > MAX_PACKET_SIZE) copy_len = MAX_PACKET_SIZE;
			for (uint8_t i = 0; i < copy_len; i++) dwin_raw[i] = packet[i];
			dwin_len   = copy_len;
			dwin_ready = 1;   // сигнал в main()
			parser_reset();   // готовимся к следующему кадру
			} else if (packet_index > need_total) {
			// рассинхронизация — сброс
			parser_reset();
		}
	}
}
// -------------------- main --------------------
int main(void) {
	// PD6 — индикатор (по желанию)
	DDRD  |= (1 << PD6);
	PORTD |= (1 << PD6); // подтянем в "1"
	UART_Hard_Init();
	UART_Soft_Init();
	sei(); // глобальные прерывания
	UART_Soft_Send_String("System initialized.\r\n");
	for (;;) {
		if (dwin_ready) {
			// Делаем атомарный «снимок» готового кадра, чтобы ISR не переписал хвост
			uint8_t local_len;
			uint8_t local_buf[MAX_PACKET_SIZE];
			cli();
			local_len = dwin_len;
			if (local_len > MAX_PACKET_SIZE) local_len = MAX_PACKET_SIZE;
			for (uint8_t i = 0; i < local_len; i++) local_buf[i] = dwin_raw[i];
			dwin_ready = 0;  // сбрасываем флаг только после копирования
			sei();
			// Красивый вывод всего пакета за один раз
			UART_Soft_Send_String("Next data Received from DWIN: \n");
			for (uint8_t i = 0; i < local_len; i++) {
				UART_Soft_Send_HEX(local_buf[i]);
				if ((i + 1) < local_len) UART_Soft_Send_Space();
			}
			UART_Soft_Send_String("\r\n");
			// --- Место для твоей логики работы с «сырым» кадром ---
			// Используй local_buf (длина local_len) или
			// dwin_raw/dwin_len, если удобнее.
			// Пример: номер кнопки часто лежит в последнем байте local_buf[local_len - 1].
		}
		// Остальной код твоего приложения ...
	}
	// До сюда не дойдём
	// return 0;
}