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 — LED1
    • PB1 — LED2
    • PB2 — LED3
  • Подключение к UART через USB-UART адаптер

🛠 Как работает

  1. 📡 UART принимает байты, каждый байт помещается в буфер
  2. ⏱ Если в течение 2 мс нет новых байтов — буфер считается завершённым сообщением
  3. 🔀 Буферы rx_buffer1 и rx_buffer2 чередуются, чтобы не терять данные
  4. 🧾 После завершения приёма строка передаётся в парсер команд
  5. 💡 В зависимости от команды включается или выключается соответствующий светодиод

💬 Пример диалога

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