Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Convert 16-bit integer to ASCII with comma and signum
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ViKo
Есть 16-битовый знаковый результат с АЦП, нужно написать его в виде строки с целой и дробной частями и точкой в заданной позиции. Например, 336 нужно изобразить в виде +3.36. С выравниванием по правому краю. Рабочий пример показываю ниже. Использую буфер на 8 символов. Конец строки тоже входит в буфер, и поэтому число -0.32109 не помещается, будет выводиться в виде -.32109 (может, и не стоило так ограничиваться, но это позже всплыло). Пример не очень нравится, просто на скорую руку слепил. Если кому интересно поупражняться в программировании, покажите, как можно.
CODE

/*!*************************************************************************
@brief 16-bit integer convert to ASCII with comma and signum
@param num - число для преобразования
@param str - строка из 8 символов: знак, цифры, точка, конец строки
@param pointpos - позиция точки в строке (1..6, количество мест перед ней)
@param showplus - записывать символ '+'
@note при pointpos = 0, > 6 - точка не ставится
*/
void Half2TextPoint_conv(int16_t num, char *str, uint32_t pointpos, bool showplus)
{
char *strleft = str; // левая граница строки (только для знака)
*(uint32_t *)(str ) = ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24;
*(uint32_t *)(str + 4) = ' ' | ' ' << 8 | ' ' << 16 | '\0'<< 24;
bool fract = true; // дробная часть рассчитана или не нужна
if (pointpos >= 1 && pointpos <= 6) {
*(str + pointpos) = '.';
fract = false; // дробная часть нужна, пока не получена
}
char sign = ' ';
if (showplus)
sign = '+';
if (num < 0) {
sign = '-';
num = -num;
}
str += 6;
do {
if (*str == '.') {
str--;
fract = true;
}
*str = num % 10 + '0';
str--;
} while ((num /= 10) || !fract); // пока нужна дробная часть
if (str < strleft) str++; // проскочили из-за запятой в поз. 1 и числа < 1
*str = sign;
}
_pv
Код
void Half2TextPoint_conv (int16_t data, char * str, int pointpos, bool showplus){
  static const int16_t pow10_table[] = {10000, 1000, 100, 10, 1};
  bool add0 = false;
  if (data < 0) {*str++ = '-'; data =-data;}
  else if (showplus) *str++ = '+';
  for (int i = 0; i < 5; i++){
    if (i == 5-pointpos) {
      if (!add0) *str++ = '0';
      *str++ = '.';
      add0 = true;
    }
    int16_t pow10 = pow10_table[i];
    int digit = 0;
    while (data >= pow10) {
      data -= pow10;
      digit++;
    }
    if (digit) {*str++ = ('0' + digit); add0 = true;}
    else if (add0) *str++ = '0';
  }
  *str = 0;
}


pointpos показывает количество знаков после запятой.
ViKo
Я предполагал попробовать преобразовывать в два этапа - сначала преобразовать число, потом добавить знак, вставить точку и нуль перед ней и после нее, если надо.
bw429
А printf может всегда выводить знак, даже если "+"?
ViKo
А printf точку в середину числа не вставит.
bw429
Можно выводить частное от деления на 10000, потом точку, потом остаток.
k155la3
Цитата(bw429 @ Sep 8 2017, 13:31) *
А printf может всегда выводить знак, даже если "+"?

Да.
%-012.2f
Точно не понмю, но печатал всегда со знаком.
Вопрос в "ведущих" нулях. Надо курить реализацию форматов printf
на конкретном компиляторе, а также зависит от подулюченных библиотек.
Для IAR/MSP430 - отличается CLIB / DLIB



Цитата(ViKo @ Sep 8 2017, 13:42) *
. . . .

Если вопрос только в установке формата (места точки и размерах целой-дробной частей)
то в (s)printf есть параметр *, через который можно в нее (приннтф) передавать эти значения.
Т.о. вместо написания отдельной ф-ии, возможно, достаточно будет
реализовать макрос-обертку с установкой требуемого формата

#define MyPrint(target, var, point_left_, point_right) \
sprintf( target, "%*.*f", point_left, point_right, &var) \

В работе я эту конструкцию не проверял, небыло необходимости.
Получится или нет - надо курить док на printf.

Jenya7
После долгих мытарств решил делать так
Код
static inline int IntToStr(int x, char str[], int d)
{
    int i = 0;
    
     do { str[i++] = (x % 10) + '0'; }
     while ((x /= 10) > 0);
    
    // If number of digits required is more, then
    // add 0s at the beginning
    while (i < d)
        str[i++] = '0';

    Reverse(str, i);
    str[i] = '\0';
    return i;
}

void FtoA(float n, char *res, int afterpoint)
{
    int ap = afterpoint;
    
     //signed?
    if(n < 0)
    {
        n *= -1;
        *res = '-';
        res++;
    }
    
    // Extract integer part
    int ipart = (int)n;
    
    // Extract floating part
    float fpart = n - (float)ipart;
        
    // convert integer part to string
    int i = IntToStr(ipart, res, 0);

    // check for display option after point
    if (afterpoint != 0)
    {
        res[i] = '.';  // add dot

        // Get the value of fraction part up to given no.
        // of points after dot. The third parameter is needed
        // to handle cases like 233.007
        //fpart = fpart * pow(10, afterpoint);
        while (ap)
        {
            fpart *= 10;
            ap--;
        }

        IntToStr((int)fpart, res + i + 1, afterpoint);
    }
}

хотя это немного не то что требуется. ну пусть висит.
skripach
Цитата(bw429 @ Sep 8 2017, 13:31) *
А printf может всегда выводить знак, даже если "+"?

Может
Цитата(k155la3 @ Sep 8 2017, 19:31) *
Да.
%-012.2f

%+012.2f

Код
void Half2TextPoint_conv(int16_t num, char *str, uint32_t pointpos, bool showplus)
{
  char mod[]="%00.0f";
  if(showplus) mod[1] = '+';
  if(pointpos>6)  pointpos = 0;
  mod[4] = pointpos+0x30;
  sprintf(str, mod, ((float)num/pow(10,pointpos)));
}

santa2.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.