Printf останавливает работу терминала

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

Это код C:

#include "mss_uart.h"
#include <stdio.h>

#define RX_BUFF_SIZE    64
#define MSS_UART_57600_BAUD     57600
uint8_t g_rx_buff[RX_BUFF_SIZE];
uint8_t g_rx_idx;

void uart0_rx_handler( mss_uart_instance_t * this_uart )
{
MSS_UART_get_rx( &g_mss_uart0, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff) );
if(g_rx_buff[g_rx_idx] > 96 && g_rx_buff[g_rx_idx] < 123)
{
    uint8_t message[55] = "De letter was: x, de uppercase letter van : x is y.\n\r";
    message[15] = g_rx_buff[g_rx_idx];
    message[44] = g_rx_buff[g_rx_idx];
    message[49] = g_rx_buff[g_rx_idx] - 32;

    MSS_UART_polled_tx( &g_mss_uart0, message, sizeof(message) );
}
else if(g_rx_buff[g_rx_idx] > 64 && g_rx_buff[g_rx_idx] < 91)
{
    uint8_t message[55] = "De letter was: x, de lowercase letter van : x is y.\n\r";
    message[15] = g_rx_buff[g_rx_idx];
    message[44] = g_rx_buff[g_rx_idx];
    message[49] = g_rx_buff[g_rx_idx] + 32;

    MSS_UART_polled_tx( &g_mss_uart0, message, sizeof(message) );
}
else if(g_rx_buff[g_rx_idx] > 47 && g_rx_buff[g_rx_idx] < 58)
{
    int number = g_rx_buff[g_rx_idx] - '0';
            int number2 = number * number;
            int number3 = number2 * number;
            int number4 = number3 * number;

    printf("Getallenreeks: %d, %d, %d, %d.\n\r", number, number2, number3, number4);

}
else
{
    uint8_t message[10] = "Error.\n\r";
    MSS_UART_polled_tx( &g_mss_uart0, message, sizeof(message) );
}
}

int main(void)
{
MSS_UART_init
(
        &g_mss_uart0,
        MSS_UART_57600_BAUD,
        MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
);

MSS_UART_set_rx_handler( &g_mss_uart0, uart0_rx_handler, MSS_UART_FIFO_SINGLE_BYTE    );

while ( 1 )
{}
return(0);
}

void uart0_rx_handler является обработчиком прерываний, а MSS_UART_get_rx помещает входные данные в g_rx_buff[g_rx_idx].

Я попытался напечатать числа с помощью той же функции MSS_UART_polled_tx, которую я использую для символов, но безуспешно. Он печатает неправильные значения ascii:

if(g_rx_buff[g_rx_idx] > 47 && g_rx_buff[g_rx_idx] < 58)
{
    int number = g_rx_buff[g_rx_idx] - '0';
    int number2 = number * number;
    int number3 = number2 * number;
    int number4 = number3 * number;

    uint8_t message[15] = "Getallenreeks: ";
    uint8_t komma[2] = ", ";
    uint8_t end[5] = ".\n\r";

    char numberstring2[2];
    char numberstring3[3];
    char numberstring4[4];

    sprintf(numberstring2, "%d", number2);
    sprintf(numberstring3, "%d", number3);
    sprintf(numberstring4, "%d", number4);

    uint8_t messagenumber[1];
    uint8_t messagenumber2[1];
    uint8_t messagenumber3[1];
    uint8_t messagenumber4[1];

    messagenumber[0] = '0' + number;
    messagenumber2[0] = '0' + number2;
    messagenumber3[0] = '0' + number3;
    messagenumber4[0] = '0' + number4;      

    http://imageshack.us/photo/my-images/843/testlan.jpg/( &g_mss_uart0, message, sizeof(message) );
    MSS_UART_polled_tx( &g_mss_uart0, messagegetal, sizeof(messagenumber) );
    MSS_UART_polled_tx( &g_mss_uart0, komma, sizeof(komma) );
    MSS_UART_polled_tx( &g_mss_uart0, messagegetal2, sizeof(messagenumber2) );
    MSS_UART_polled_tx( &g_mss_uart0, komma, sizeof(komma) );
    MSS_UART_polled_tx( &g_mss_uart0, messagegetal3, sizeof(messagenumber3) );
    MSS_UART_polled_tx( &g_mss_uart0, komma, sizeof(komma) );
    MSS_UART_polled_tx( &g_mss_uart0, messagegetal4, sizeof(messagenumber4) );
    MSS_UART_polled_tx( &g_mss_uart0, end, sizeof(end) );       
 }

Пример вывода кода: http://imageshack.us/photo/my-images/843/testlan.jpg/ Левый терминал показывает использование функции printf, правый терминал показывает использование функции MSS_UART_polled_tx для чисел (показана во втором блоке кода ).


person Glenn    schedule 21.03.2012    source источник
comment
Рассмотрите возможность использования '0' и '9'>= и <=) вместо 47 и 58.   -  person pmg    schedule 21.03.2012
comment
Я не вижу увеличения g_rx_idx в этом фрагменте, в то время как вы, кажется, потребляете байт. Может быть, ваш код управления циклическим буфером где-то застревает (может быть, здесь)?   -  person wildplasser    schedule 21.03.2012
comment
Вы должны использовать isdigit() для обнаружения цифр, а не жестко кодировать закодированные значения. Если у вас нет isdigit(), воспользуйтесь советом @pmg.   -  person unwind    schedule 21.03.2012
comment
@ pmg, раскрутись: это не исправит. Он вводит оператор if, где сравнивает значение ascii со значениями цифр от 0 до 9. Строка с правильными значениями также генерируется правильно, но как только она печатается в терминале, она не реагирует ни на какие действия пользователя. больше. Также курсор помещается на полпути к следующей строке. Это наводит меня на мысль, что функция printf не знает, когда остановить печать, и застревает на этом.   -  person Glenn    schedule 21.03.2012
comment
@wildplasser: g_rx_idx не следует увеличивать, он просто содержит код входного символа в буфере в этом месте.   -  person Glenn    schedule 21.03.2012
comment
Если этот код выполняется внутри обработчика прерывания (или обработчика сигнала), использование printf() вызывает подозрения. (printf() и друзья не реентерабельны) ТАКЖЕ: пожалуйста, добавьте полный код для управления кольцевым буфером. Без контекста в приведенном выше фрагменте нет явных ошибок (кроме printf)   -  person wildplasser    schedule 21.03.2012
comment
Обновлен мой вопрос с большим количеством кода.   -  person Glenn    schedule 21.03.2012
comment
Вы понимаете, что ваши текстовые строки имеют длину всего 52+1 байт? Подсказка: strlen(константный строковый литерал) будет перехвачен компилятором; просто добавьте один. Или используйте char message[] = "literal"; (в этом случае сообщение sizeof будет включать нулевой терминатор). Использование слишком большого размера (55), вероятно, приведет к выводу мусора. Вы действительно хотите вывести NUL?   -  person wildplasser    schedule 21.03.2012
comment
Вы имеете в виду код для печати символов? Потому что они отлично работают. Моя единственная проблема заключается в том, что когда я использую функцию printf, терминал больше не отвечает. Пример вывода: imageshack.us/photo/my-images/843/testlan. jpg (терминал слева использует функцию printf, терминал справа показывает использование функции MSS_UART_polled_tx для чисел).   -  person Glenn    schedule 21.03.2012
comment
Я уже говорил вам, что printf небезопасен в обработчиках прерываний и обработчиках сигналов.   -  person wildplasser    schedule 21.03.2012


Ответы (2)


Я думаю, что самая большая ошибка заключалась в подсчете длины "\r\n" как 4 (она равна 2), другая ошибка - использование `sizeof stringarray', который включает пространство, используемое завершающим NUL-байтом.

  /** added */
#include <stdint.h>
#include <stdio.h>

struct xx;
typedef struct xx mss_uart_instance_t;

void MSS_UART_get_rx( mss_uart_instance_t * the_uart, uint8_t buff[] , size_t len );
void MSS_UART_polled_tx( mss_uart_instance_t * the_uart, uint8_t buff[] , size_t len );
    /** End added */

#define RX_BUFF_SIZE    64
#define MSS_UART_57600_BAUD     57600

uint8_t g_rx_buff[RX_BUFF_SIZE];
uint8_t g_rx_idx;

void uart0_rx_handler( mss_uart_instance_t * this_uart )
{
    MSS_UART_get_rx( this_uart, &g_rx_buff[g_rx_idx], sizeof g_rx_buff );
    if(g_rx_buff[g_rx_idx] >= 'a' && g_rx_buff[g_rx_idx] <= 'z')
    {
        uint8_t message[] = "De letter was: x, de uppercase letter van : x is y.\n\r";
        message[15] = g_rx_buff[g_rx_idx];
        message[44] = g_rx_buff[g_rx_idx];
        message[49] = g_rx_buff[g_rx_idx] - ('a' - 'A');

        MSS_UART_polled_tx( this_uart, message, strlen(message) ); /* 52 */
    }
    else if(g_rx_buff[g_rx_idx] >= 'A' && g_rx_buff[g_rx_idx] <= 'Z' )
    {
        uint8_t message[] = "De letter was: x, de lowercase letter van : x is y.\n\r";
        message[15] = g_rx_buff[g_rx_idx];
        message[44] = g_rx_buff[g_rx_idx];
        message[49] = g_rx_buff[g_rx_idx] + ('a' - 'A');

        MSS_UART_polled_tx( this_uart, message, strlen(message) ); /* 52 */
    }
    else if(g_rx_buff[g_rx_idx] >= '0' && g_rx_buff[g_rx_idx] <= '9')
    {
        uint8_t bigbuff[70] ;
        size_t buflen;
        int number = g_rx_buff[g_rx_idx] - '0';
                int number2 = number * number;
                int number3 = number2 * number;
                int number4 = number3 * number;

        buflen = sprintf(bigbuff, "Getallenreeks: %d, %d, %d, %d.\n\r", number, number2, number3, number4);
        MSS_UART_polled_tx( this_uart, bigbuff, buflen );

    }
    else
    {
        uint8_t message[] = "Error.\n\r";
        MSS_UART_polled_tx( this_uart, message, strlen(message) ); /* 8 */
    }
}
person wildplasser    schedule 21.03.2012
comment
Хорошо, это работает, спасибо! Функция sprintf сделала свое дело, я также отредактировал длину строк. - person Glenn; 21.03.2012
comment
Как правило: не редактируйте длину строк. Позвольте компилятору сделать расчеты за вас либо по strlen(), либо по sizeof buff -1 - person wildplasser; 21.03.2012

Я думаю, у вас есть две проблемы.

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

Вторая проблема связана с вашими ожиданиями относительно результата второго примера. Они выглядят нормально для меня. Вы умножаете довольно большие числа, а затем добавляете их к значению char. Это приведет к тому, что один символ может быть буквой или символом, который вам не нужен. Например

'0' + 16 == '@'

Что вы видите в одном из ваших примеров. Если вы хотите вывести «16», то есть два символа «1» и «6», и вам нужно проделать дополнительную работу, чтобы вычислить отдельные символы (включая деление на 10).

person blueshift    schedule 21.03.2012
comment
Когда я размещаю printf() вне обработчика, в основном цикле while с логическим значением все равно выдается та же ошибка. Ты прав насчет значений char, глупый я. Я использовал sprintf(), упомянутый wildplasser, для их автоматического преобразования! - person Glenn; 21.03.2012