Передача данных по UART в Keil C51 пример кода

Как передать данные по uart keil c51

Как передать данные по uart keil c51

UART (Universal Asynchronous Receiver/Transmitter) – один из самых распространённых интерфейсов для обмена данными между микроконтроллерами и периферийными устройствами. В Keil C51 работа с UART реализуется через регистры SBUF, SCON и PCON, а также прерывания ES и TI/RI. Для 8051-совместимых контроллеров стандартная скорость передачи задаётся таймером Timer 1 в режиме автоперезагрузки (режим 2), где формула расчёта значения регистра TH1 выглядит так:

TH1 = 256 — (Fosc / (12 × 32 × BaudRate))

Например, при тактовой частоте 11.0592 МГц и скорости 9600 бод значение TH1 составит 0xFD. Неправильный подбор этого параметра приводит к искажению данных или полному отсутствию связи. Для отладки рекомендуется использовать логический анализатор или терминал (например, PuTTY или Tera Term) с настройками 8N1 (8 бит данных, без контроля чётности, 1 стоп-бит).

В Keil C51 инициализация UART включает настройку таймера, разрешение прерываний и установку режима работы порта. Пример базовой конфигурации:

SCON = 0x50; // Режим 1 (8-битный UART), разрешение приёма

TMOD |= 0x20; // Timer 1 в режиме 2 (8-битный автоперезагруз)

TH1 = 0xFD; // Значение для 9600 бод при 11.0592 МГц

TR1 = 1; // Запуск таймера

ES = 1; // Разрешение прерывания UART

EA = 1; // Глобальное разрешение прерываний

Для передачи данных используется регистр SBUF, запись в который автоматически запускает отправку байта. Приём осуществляется через прерывание RI, где принятый байт считывается из SBUF. Важно учитывать, что флаг TI (передача завершена) и RI (приём завершён) необходимо сбрасывать программно в обработчике прерывания. Игнорирование этого правила приводит к блокировке дальнейшего обмена.

При работе с большими объёмами данных рекомендуется использовать кольцевые буферы для приёма/передачи. Это позволяет избежать потерь данных при высокой скорости обмена. Пример реализации кольцевого буфера на 16 байт:

unsigned char rx_buffer[16];

unsigned char rx_head = 0, rx_tail = 0;

В обработчике прерывания RI данные помещаются в буфер, а основная программа периодически проверяет наличие новых данных. Такой подход минимизирует задержки и повышает надёжность системы.

Передача данных по UART в Keil C51: пример кода

Для инициализации UART на микроконтроллерах семейства 8051 в Keil C51 используйте регистры SCON и TMOD. Установите режим работы UART (например, режим 1 с 8-битной передачей и переменной скоростью) через SCON: SCON = 0x50;. Для задания скорости обмена данными настройте таймер 1 в режим автоперезагрузки (TMOD = 0x20) и загрузите в TH1 значение, соответствующее требуемой скорости. Например, для 9600 бод при частоте кварца 11.0592 МГц используйте TH1 = 0xFD;. Не забудьте разрешить прерывания UART, если планируете асинхронный прием: ES = 1; EA = 1;.

Пример функции передачи байта по UART в синхронном режиме без прерываний:

void UART_SendByte(unsigned char dat) {
  SBUF = dat;
  while (!TI);
  TI = 0;
}

Здесь TI – флаг завершения передачи, который необходимо сбрасывать вручную. Для передачи строки используйте цикл, вызывающий эту функцию для каждого символа. Учтите, что при работе с высокими скоростями (например, 115200 бод) может потребоваться оптимизация задержек или переход на прерывания.

Для приема данных в режиме прерываний реализуйте обработчик прерывания UART:

void UART_ISR(void) interrupt 4 {
  if (RI) {
    unsigned char received = SBUF;
    RI = 0;
    // Обработка принятого байта
  }
}

RI – флаг приема, который также требует ручного сброса. Храните принятые данные в кольцевом буфере, чтобы избежать потерь при высокой скорости обмена. Размер буфера выбирайте исходя из максимальной длины ожидаемого сообщения и частоты опроса.

При отладке UART в Keil C51 используйте встроенный симулятор или аппаратный анализатор логических уровней. Проверяйте соответствие скоростей на обоих концах линии, корректность подключения (TX-RX, RX-TX) и наличие согласующих резисторов (обычно 1–10 кОм) при длинных линиях. Для тестирования передачи отправляйте фиксированные последовательности (например, 0x55 или 0xAA) и анализируйте сигнал на осциллографе – это позволит выявить искажения фронтов или неверную скважность.

Настройка регистров UART в микроконтроллере 8051 для работы на заданной скорости

Настройка регистров UART в микроконтроллере 8051 для работы на заданной скорости

Основные шаги настройки:

  • Задайте режим таймера 1: TMOD = (TMOD & 0x0F) | 0x20 (режим 2, таймер 1).
  • Установите скорость: TH1 = 0xFD (для 9600 бод при 11.0592 МГц).
  • Настройте UART: SCON = 0x50 (режим 1, REN=1).
  • Запустите таймер: TR1 = 1.
  • Для других частот используйте формулу: TH1 = 256 - (Fosc / (12 * 32 * Baud)), где Fosc – тактовая частота, Baud – требуемая скорость.

Инициализация прерываний UART для приёма и передачи данных в Keil C51

Для работы с UART в режиме прерываний в Keil C51 необходимо настроить регистры SCON, TMOD и IE. Установите SCON в режим 1 (8-битный UART с переменной скоростью) и активируйте приёмник (REN=1). Таймер 1 (TMOD=0x20) используйте в режиме автоперезагрузки для генерации тактовой частоты UART. Скорость задаётся значением TH1: для 9600 бод при 11.0592 МГц установите TH1=0xFD. Разрешите прерывания UART через IE (EA=1, ES=1). Обработчик прерывания должен проверять флаг RI (приём) или TI (передача) в SCON и сбрасывать его вручную после обработки.

Вектор прерывания UART в Keil C51 располагается по адресу 0x0023. Пример обработчика: void UART_ISR(void) interrupt 4 { if (RI) { buffer = SBUF; RI = 0; } if (TI) { TI = 0; } }. Для корректной работы избегайте длительных операций в обработчике – используйте буферы FIFO или флаги для передачи данных в основной цикл программы. При передаче данных через прерывания инициализируйте TI=1 перед первой отправкой байта, чтобы запустить механизм прерываний.

Реализация функции отправки одного байта по UART с проверкой готовности передатчика

Реализация функции отправки одного байта по UART с проверкой готовности передатчика

Для микроконтроллеров семейства 8051 проверка готовности передатчика UART реализуется через флаг TI (Transmit Interrupt) в регистре SCON. Перед отправкой байта необходимо убедиться, что предыдущая передача завершена: флаг TI устанавливается аппаратно после освобождения сдвигового регистра передатчика. Пример функции на C51:

void UART_SendByte(unsigned char data) {
while (!TI); // Ожидание установки флага TI (готовность передатчика)
TI = 0; // Сброс флага перед новой передачей
SBUF = data; // Запись байта в буфер передачи
}

Критические моменты: сброс флага TI должен выполняться программно, так как аппаратный сброс не предусмотрен. Для повышения надежности добавьте тайм-аут ожидания флага, например, через счетчик циклов или таймер, чтобы избежать зависания при аппаратных сбоях. На частоте 11.0592 МГц стандартная скорость 9600 бод обеспечивается значением TH1 = 0xFD в режиме 2 таймера 1.

Организация буфера FIFO для последовательной передачи строки через UART

Организация буфера FIFO для последовательной передачи строки через UART

Буфер FIFO (First-In-First-Out) для UART в микроконтроллерах семейства 8051 решает проблему асинхронной передачи данных без потерь при высокой загрузке шины. Типичный размер буфера – 16–256 байт, выбирается исходя из частоты тактирования и скорости передачи. Например, при скорости 115200 бод и тактовой частоте 11.0592 МГц, задержка между байтами составляет ~86 мкс, что требует буфера не менее 32 байт для компенсации задержек обработки прерываний.

Реализация кольцевого FIFO требует двух указателей: head (запись) и tail (чтение). Указатели инкрементируются по модулю размера буфера, например, для 64-байтного буфера: head = (head + 1) & 0x3F. Критическая секция защищается запретом прерываний на время модификации указателей, чтобы избежать состояния гонки при одновременном доступе из основного цикла и обработчика прерывания.

Пример структуры буфера для Keil C51:

Поле Тип Назначение
buffer[64] unsigned char Хранилище данных
head volatile unsigned char Указатель записи
tail volatile unsigned char Указатель чтения
count volatile unsigned char Текущее количество байт в буфере

Функция записи в буфер должна проверять переполнение: if (count < BUFFER_SIZE). При успешной записи инкрементируется head и count. Чтение из буфера выполняется в обработчике прерывания TI (Transmit Interrupt), где байт извлекается по указателю tail, после чего tail и count обновляются. Если буфер пуст, флаг TI сбрасывается вручную.

Для передачи строки через FIFO используется функция-обёртка, например:

void UART_SendString(const char *str) {
while (*str) {
while (fifo.count >= BUFFER_SIZE);  // Ожидание освобождения места
EA = 0;  // Запрет прерываний
fifo.buffer[fifo.head] = *str++;
fifo.head = (fifo.head + 1) & (BUFFER_SIZE - 1);
fifo.count++;
EA = 1;  // Разрешение прерываний
if (!TI) TI = 1;  // Запуск передачи, если не активна
}
}

Оптимизация производительности достигается за счёт использования аппаратного буфера UART (1 байт в 8051) как промежуточного звена. При этом FIFO заполняется только при опустошении аппаратного буфера, что снижает нагрузку на процессор. В обработчике прерывания TI проверяется наличие данных в FIFO: если fifo.count > 0, следующий байт передаётся в SBUF, иначе флаг TI остаётся сброшенным.

Тестирование буфера проводится с помощью генерации потока данных с переменной скоростью. Например, при скорости 9600 бод и буфере 32 байта, максимальная задержка между байтами не должна превышать 3.3 мс. Для проверки используются осциллограф или логический анализатор, подключённый к линии TX. При переполнении буфера рекомендуется реализовать механизм уведомления (например, установка флага ошибки) или динамическое расширение буфера до 128 байт при необходимости.

Обработка прерывания приёма данных по UART с сохранением в кольцевой буфер

Обработка прерывания приёма данных по UART с сохранением в кольцевой буфер

Кольцевой буфер (circular buffer) – оптимальное решение для асинхронного приёма данных по UART в микроконтроллерах 8051, где критически важна скорость и предсказуемость обработки. Типичный размер буфера – 32 или 64 байта, что достаточно для большинства задач при скорости передачи до 115200 бод. Структура буфера включает два указателя: head (позиция записи) и tail (позиция чтения), а также массив данных фиксированной длины. При переполнении буфера старые данные перезаписываются, что требует контроля со стороны основной программы.

Пример реализации прерывания для UART в Keil C51:

  • Инициализируйте буфер и указатели в глобальной области:
    #define BUFFER_SIZE 64
    volatile unsigned char rx_buffer[BUFFER_SIZE];
    volatile unsigned char rx_head = 0, rx_tail = 0;
  • В обработчике прерывания void UART_ISR(void) interrupt 4 используйте SBUF для чтения байта и записывайте его в буфер:
    if (RI) {
    RI = 0;
    rx_buffer[rx_head] = SBUF;
    rx_head = (rx_head + 1) % BUFFER_SIZE;
    if (rx_head == rx_tail) {
    rx_tail = (rx_tail + 1) % BUFFER_SIZE; // Переполнение
    }
    }
  • Для проверки переполнения сравнивайте rx_head и rx_tail перед записью. Если они равны – буфер полон.

Основная программа должна периодически извлекать данные из буфера, например, в цикле while(1). Для этого реализуйте функцию чтения, которая возвращает байт и сдвигает rx_tail:

unsigned char uart_read(void) {
if (rx_head == rx_tail) return 0xFF; // Буфер пуст
unsigned char data = rx_buffer[rx_tail];
rx_tail = (rx_tail + 1) % BUFFER_SIZE;
return data;
}

Приоритет обработки прерывания должен быть выше, чем у других задач, чтобы избежать потери данных. В Keil C51 установите приоритет прерывания UART через регистр IP (например, PS = 1;).

Ссылка на основную публикацию