ATMEGA И УПРАВЛЕНИЕ ДИОДИКАМИ ЧЕРЕЗ ПРОСТЕНЬКИЙ ПАРСЕР КОМАНД, ПРИНИМАЕМЫХ ПО ЛИНИИ RX, АППАРАТНЫЙ UART.
💡 AVR: UART-команды для управления светодиодами
Этот проект реализует управление тремя светодиодами по UART с использованием микроконтроллера AVR (например, ATmega328P), используя прерывания, двойной буфер и таймер.
🧠 Основные функции
- 📥 Приём команд по UART (9600 бод)
- 🔁 Буферизация входящих данных с автоматическим определением конца команды по таймауту
- 💡 Управление светодиодами: включение/выключение LED1, LED2, LED3 по командам Enable/Disable
- 📤 Ответ по UART на каждую команду
📦 Поддерживаемые команды
Команда | Описание |
---|---|
Enable1 |
Включить светодиод 1 (PB0) |
Disable1 |
Выключить светодиод 1 |
Enable2 |
Включить светодиод 2 (PB1) |
Disable2 |
Выключить светодиод 2 |
Enable3 |
Включить светодиод 3 (PB2) |
Disable3 |
Выключить светодиод 3 |
⚙️ Аппаратная часть
- Микроконтроллер: ATmega328P
- Светодиоды подключены через резисторы (220–470 Ом)
- Пины:
PB0
— LED1PB1
— LED2PB2
— LED3
- Подключение к UART через USB-UART адаптер
🛠 Как работает
- 📡 UART принимает байты, каждый байт помещается в буфер
- ⏱ Если в течение 2 мс нет новых байтов — буфер считается завершённым сообщением
- 🔀 Буферы rx_buffer1 и rx_buffer2 чередуются, чтобы не терять данные
- 🧾 После завершения приёма строка передаётся в парсер команд
- 💡 В зависимости от команды включается или выключается соответствующий светодиод
💬 Пример диалога
PC → Enable1 Микроконтроллер → >> Enable1 Микроконтроллер → LED1 ON PC → Disable2 Микроконтроллер → >> Disable2 Микроконтроллер → LED2 OFF
🧪 Отладка и тестирование
- Используйте любой терминал (например,
HTerm
илиPuTTY
) - Скорость: 9600 бод, 8N1
- Команды можно посылать с клавиатуры (без перевода строки или с
\r\n
)
🔐 Безопасность и устойчивость
- Защита от переполнения буфера
- Автоматический XON/XOFF-поток для поддержки программного контроля
📁 Полный исходный код
Смотри раздел «Исходный код программы» выше или внизу страницы 👇
#define F_CPU 16000000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> // UART параметры #define BAUD 9600 #define MYUBRR (F_CPU / 16 / BAUD - 1) // UART управление потоком #define XON 0x11 #define XOFF 0x13 #define BUFFER_SIZE 64 #define TIMEOUT_LIMIT 2 // === Глобальные переменные === volatile uint8_t transmission_enabled = 1; char rx_buffer1[BUFFER_SIZE]; char rx_buffer2[BUFFER_SIZE]; volatile char *current_rx_buffer = rx_buffer1; volatile char *sending_buffer = NULL; volatile uint8_t rx_index = 0; volatile uint8_t message_length = 0; volatile uint8_t message_complete = 0; volatile uint8_t timeout_counter = 0; // === Прототипы === void UART_init(unsigned int ubrr); void UART_transmit(unsigned char data); void UART_putstring(const char *s); void UART_transmit_buffer(const volatile char *buffer, uint8_t length); void Timer1_init(void); void Timer1_reset(void); void setup(void); void loop(void); void process_command(const char *cmd); // === UART init === void UART_init(unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr >> 8); UBRR0L = (unsigned char)ubrr; UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); } void UART_transmit(unsigned char data) { while (!(UCSR0A & (1 << UDRE0))); UDR0 = data; } void UART_putstring(const char *s) { while (*s) { while (!transmission_enabled); UART_transmit(*s++); } } void UART_transmit_buffer(const volatile char *buffer, uint8_t length) { for (uint8_t i = 0; i < length; i++) { while (!transmission_enabled); UART_transmit(buffer[i]); } } void Timer1_init(void) { TCCR1B = (1 << WGM12); OCR1A = 249; // 1 мс при 16 МГц и делителе 64 TCCR1B |= (1 << CS11) | (1 << CS10); TIMSK1 |= (1 << OCIE1A); } void Timer1_reset(void) { TCNT1 = 0; } // === Обработка команд === void process_command(const char *cmd) { if (strncmp(cmd, "Enable1", 7) == 0) { PORTB |= (1 << PB0); UART_putstring("LED1 ON\r\n"); } else if (strncmp(cmd, "Disable1", 8) == 0) { PORTB &= ~(1 << PB0); UART_putstring("LED1 OFF\r\n"); } else if (strncmp(cmd, "Enable2", 7) == 0) { PORTB |= (1 << PB1); UART_putstring("LED2 ON\r\n"); } else if (strncmp(cmd, "Disable2", 8) == 0) { PORTB &= ~(1 << PB1); UART_putstring("LED2 OFF\r\n"); } else if (strncmp(cmd, "Enable3", 7) == 0) { PORTB |= (1 << PB2); UART_putstring("LED3 ON\r\n"); } else if (strncmp(cmd, "Disable3", 8) == 0) { PORTB &= ~(1 << PB2); UART_putstring("LED3 OFF\r\n"); } else { UART_putstring("Unknown command\r\n"); } } // === Настройка системы === void setup(void) { UART_init(MYUBRR); Timer1_init(); sei(); // Настройка пинов PB0, PB1, PB2 как выходов DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB2); PORTB &= ~((1 << PB0) | (1 << PB1) | (1 << PB2)); // Все выключены memset((void *)rx_buffer1, 0, BUFFER_SIZE); memset((void *)rx_buffer2, 0, BUFFER_SIZE); UART_putstring("madmentat.ru ready\r\n"); } void loop(void) { while (1) { if (message_complete) { cli(); if (sending_buffer != NULL) { sending_buffer[message_length] = '\0'; // Завершаем строку UART_putstring(">> "); UART_transmit_buffer(sending_buffer, message_length); UART_putstring("\r\n"); process_command((const char *)sending_buffer); memset((void *)sending_buffer, 0, BUFFER_SIZE); sending_buffer = NULL; message_complete = 0; message_length = 0; } sei(); } } } // === Прерывание по приёму байта === ISR(USART_RX_vect) { unsigned char received = UDR0; if (received == XOFF) { transmission_enabled = 0; } else if (received == XON) { transmission_enabled = 1; } else { if (rx_index < BUFFER_SIZE - 1) { current_rx_buffer[rx_index++] = received; timeout_counter = 0; Timer1_reset(); } } } // === Прерывание таймера — 1 мс === ISR(TIMER1_COMPA_vect) { if (rx_index > 0) { timeout_counter++; if (timeout_counter >= TIMEOUT_LIMIT) { sending_buffer = current_rx_buffer; current_rx_buffer = (current_rx_buffer == rx_buffer1) ? rx_buffer2 : rx_buffer1; message_complete = 1; message_length = rx_index; rx_index = 0; timeout_counter = 0; } } else { timeout_counter = 0; } } // === main === int main(void) { setup(); loop(); return 0; }
🤖 Автор
Создано и протестировано инженером-энтузиастом. Сайт: madmentat.ru