Top.Mail.Ru
Уведомления
Очистить все

Разработка TUI через UART с прерываниями с HAL для STM32F1xx

(@arm-programmer)
New member

Всем привет. Открыл отдельную тему для вопроса. Нужна помощь с проектом.

Занимаюсь реализацией TUI через UART на STM32F1xx с HAL. Описание функциональности:

- Неблокирующий ввод

- Завершение ввода при нажатии Enter

- При нажатии на Backspace предыдущий символ удаляется (при наличии)

- Видимые символы отображаются

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

При написании кода использую кольцевой буфер (ring/circular buffer) для хранения строк. Он представляет из себя отдельную библиотеку.

Вот код проекта:

static UART_HandleTypeDef *console_uart = NULL;
static char line_buffer[CONSOLE_MAX_RX_DATA_LENGTH];
static uint16_t line_len = 0;

// TX Buffer
static ring_buffer_t tx_buffer;
static volatile uint8_t tx_busy = 0;
static volatile uint8_t tx_byte;

// RX Buffer
static ring_buffer_t rx_buffer;
static volatile uint8_t rx_byte;
static volatile uint8_t rx_ready = 0;

static void console_rx_callback(UART_HandleTypeDef *);
static void console_tx_callback(UART_HandleTypeDef *);

uint8_t console_init(UART_HandleTypeDef *huart) {
    if (huart == NULL || console_uart != NULL) {
        return 1;
    }

    console_uart = huart;

    ring_buffer_init(&tx_buffer);
    tx_busy = 0;    

    ring_buffer_init(&rx_buffer);
    rx_ready = 0;

    HAL_UART_RegisterCallback(
        console_uart,
        HAL_UART_RX_COMPLETE_CB_ID,
        console_rx_callback
    );

    HAL_UART_RegisterCallback(
        console_uart,
        HAL_UART_TX_COMPLETE_CB_ID,
        console_tx_callback
    );

    HAL_UART_Receive_IT(console_uart, (uint8_t *) &rx_byte, 1);
    return 0;
}

void console_print(const char *str) {
    HAL_UART_Transmit(console_uart, (uint8_t *) str, strlen(str), 10);
    // ring_buffer_write(&tx_buffer, (uint8_t *) str, strlen(str));

    // if (tx_busy == 0) {
    //     tx_busy = 1;
    //     tx_byte = ring_buffer_pop(&tx_buffer);
    //     HAL_UART_Transmit_IT(console_uart, &tx_byte, 1);
    // }
}

void console_clear() {
    console_print("\033[2J\033[H");
}

// Берет на себя всю обработку символов: backspace, enter и echo
void console_poll() {
    while (ring_buffer_get_length(&rx_buffer) > 0 && rx_ready == 0) {
        uint8_t ch = ring_buffer_pop(&rx_buffer);
        if ((ch == '\b' || ch == 0x7F) && line_len > 0) {
            line_len--;
            console_print("\b \b");
        }
        else if (ch == '\r' || ch == '\n') {
            line_buffer[line_len] = '\0';
            rx_ready = 1;
            console_print("\r\n");
            return;
        }
        else if (line_len < CONSOLE_MAX_RX_DATA_LENGTH - 1) {
            line_buffer[line_len++] = ch;
            char echo[2] = {ch, 0};
            console_print(echo);
        }
    }
}

uint8_t console_ready() {
    return rx_ready;
}

void console_read(char *buffer) {
    if (buffer == NULL || rx_ready == 0) {
        return;
    }
    
    strcpy(buffer, line_buffer);
    rx_ready = 0;
    line_len = 0;
    line_buffer[0] = '\0';
}

static void console_tx_callback(UART_HandleTypeDef *console) {
    if (ring_buffer_get_length(&tx_buffer) == 0) {
        tx_busy = 0;
    }
    else {
        tx_byte = ring_buffer_pop(&tx_buffer);
        HAL_UART_Transmit_IT(console_uart, &tx_byte, 1);
    }
}

static void console_rx_callback(UART_HandleTypeDef *console) {
    ring_buffer_push(&rx_buffer, rx_byte);
    HAL_UART_Receive_IT(console_uart, &rx_byte, 1);
}

Использование в приложении примерно такое:

while(1) {
    console_poll();
    if (console_ready()) {
        console_read(consoleBuffer);
        // Действия с console buffer
    }
}

 

При подключении через утилиту screen на скорости 115200 выводит следующее (вводил просто '?'):

Rebooeot system
?. menu
cm>>
Unknoan
oy en
symenu
cm

То есть вывод максимально ломаный.

Знающие люди, подскажите, пожалуйста, что не так с этим кодом и в чем именно проблема. Нейронки не помогают, а в DMA сейчас не планирую лезть - хочу сперва разобраться с прерываниями.

Благодарю за любую помощь, спасибо!


Цитата
Создатель темы Размещено : 13.02.2026 12:55
Aveal
(@aveal)
Top level Admin

Приветствую!

Тут суть процессов-то не сложная, в UART выводятся данные, на выходе эти данные неверные. Посмотри просто под отладчиком, какие именно данные, почему и когда отправляются.


ОтветитьЦитата
Размещено : 13.02.2026 13:29
Поделиться:
Обзор конфиденциальности

На этом сайте используются файлы cookie, что позволяет нам обеспечить наилучшее качество обслуживания пользователей. Информация о файлах cookie хранится в вашем браузере и выполняет такие функции, как распознавание вас при возвращении на наш сайт и помощь нашей команде в понимании того, какие разделы сайта вы считаете наиболее интересными и полезными.