Есть ли простой способ преобразовать число в шестнадцатеричные символы ASCII в C? - PullRequest
3 голосов
/ 09 сентября 2010

Я работаю с программой прошивки C для встроенного устройства. Я хочу отправить массив шестнадцатеричных значений через последовательный порт. Есть ли простой способ преобразовать значение в шестнадцатеричный ASCII?

Например, если массив содержит 0xFF, я хочу отправить строку ASCII "FF" или для шестнадцатеричного значения 0x3B я хочу отправить "3B".

Как это обычно делается?

У меня уже есть функции последовательной отправки, чтобы я мог это сделать ...

char msg[] = "Send this message";
SendString(msg);

и функция SendString вызывает эту функцию для каждого элемента в переданном массиве:

// This function sends out a single character over the UART
int SendU( int c)
{
    while(U1STAbits.UTXBF);
    U1TXREG = c;
    return c;
}

Я ищу функцию, которая позволила бы мне сделать это ...

char HexArray[5] = {0x4D, 0xFF, 0xE3, 0xAA, 0xC4};
SendHexArray(HexArray);

//Output "4D, FF, E3, AA, C4"

Ответы [ 5 ]

17 голосов
/ 09 сентября 2010

Запишите число в строку, используя sprintf, а затем используйте существующую функцию SendString, чтобы отправить ее через UART.Конечно, вы можете делать это одно число за раз:

char num_str[3];
sprintf( num_str, "%02X", 0xFF );
SendString(num_str);

%02X - это строка формата для семейства функций printf.от 0 до ширины 2 и отформатируйте элемент как шестнадцатеричное число.

Часть 02 гарантирует, что когда вы хотите напечатать 0x0F, вы получите 0F вместо просто F в потоке вывода.Если вы используете строчную букву x, вы получите строчные буквы (например, ff вместо FF).

10 голосов
/ 10 сентября 2010

Классическая уловка из 8-битного микро в эпоху ассемблера заключается в том, чтобы разбить преобразование ниббла на два сегмента. Значение от 0 до 9 и значение от 10 до 15. Затем простая арифметика сохраняет 16-байтовую таблицу поиска.

void SendDigit(int c) {
    c &= 0x0f;
    c += (c <= 9) ? '0' : 'A'-10;
    SendU(c);
}

void SendArray(const unsigned char *msg, size_t len) {
    while (len--) {
        unsigned char c = *msg++;
        SendDigit(c>>4);
        SendDigit(c);
    }
}

Пара дополнительных примечаний в порядке. Во-первых, это работает, потому что цифры и буквы в ASCII находятся в непрерывном диапазоне. Если вам не повезло хотеть EBCDIC , это все равно работает, так как буквы от 'A' до 'F' также являются смежными (но остальная часть алфавита разбита на три пролета).

Во-вторых, я изменил подпись SendArray(). Моя версия старается сделать буфер без знака, что обычно безопаснее при планировании преобразования байтов в какой-то больший целочисленный тип для выполнения арифметики. Если они подписаны, то такой код, как nibble[(*msg)>>4], может попытаться использовать отрицательный индекс в массиве, и результат будет бесполезен.

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

Редактировать: Исправлена ​​ошибка: для цифр свыше 10 арифметика равна c + 'A' - 10, а не c + 'A'. Спасибо Бруксу Моисею за то, что он это понял.

7 голосов
/ 09 сентября 2010

Я бы начал с поиска в массиве.

char *asciihex[] = {
    "00", "01", "02", ..., "0F",
    "10", "11", "12", ..., "1F",
    ...,
    "F0", "F1", "F2", ..., "FF"
};

а потом просто посмотри ...

SendString(asciihex[val]);

Редактировать

Включение идеи откусывания Dysaster:

void SendString(const char *msg) {
    static const char nibble[] = {'0', '1', '2', ..., 'F'};
    while (*msg) {
        /* cast to unsigned char before bit operations (thanks RBerteig) */
        SendU(nibble[(((unsigned char)*msg)&0xf0)>>4]); /* mask 4 top bits too, in case CHAR_BIT > 8 */
        SendU(nibble[((unsigned char)*msg)&0x0f]);
        msg++;
    }
}
2 голосов
/ 09 сентября 2010

sprintf сделает это.

sprintf (dest, "%X", src);

0 голосов
/ 09 сентября 2010

Если ваш компилятор поддерживает , вы можете использовать itoa .В противном случае я бы использовал sprintf, как в ответах Натана и Марка.Если itoa поддерживается и производительность является проблемой, попробуйте провести некоторое тестирование, чтобы определить, что быстрее (прошлый опыт подсказывает, что itoa будет быстрее, но YMMV).

...