Помогите с переводом INT(НЕХ) в 2 BYTE.

Rulezzz
Offline
Зарегистрирован: 13.05.2014

Доброго времени суток, форумчане. Прошу помощи в проблеме.

Итак, есть десятичное число 8800, если его первести в шестнадцатеричное , то оно будет выглядеть так 2260. Суть вопроса: как мне перевести десятичное в шестнадцатеричное, разложить шестнадцатеричное  число 2260 на 22 и 60 и сделать из низ два байта вида 0x22 и 0x60. Так же необходима обратная операция: получаем два байта 0x25 и 0x4E, собираем в шестанцатеричное 254E и переводим в десятичное 9550.

Заранее спасибо.

__Alexander
Offline
Зарегистрирован: 24.10.2012

сдвиг не спасет отца русской демократии?

sva1509
Offline
Зарегистрирован: 07.12.2012

Я не понял. Вам необходимо int перевести в строку в вид HEX ? 

std
Offline
Зарегистрирован: 05.01.2012
//assemble
byte a=0x25;
byte b=0x4E;

word x=a*256+b; // = 0x254E = 0d9550

//disassemble

word x=8800; // = 0x2260

byte a=x>>8; //0x22
byte b=x<<8; //0x60

или

//disassemble

word x=8800; // = 0x2260

byte a=x/256;
byte b=x%256;

 

sva1509
Offline
Зарегистрирован: 07.12.2012

Правильней былобы так:

union {
      int x;
      byte b[2];
}itob;

void myfunc()
{
    itob.x = 8800;
    // теперь itob.b[0] младший байт itob.b[1] содержит старший байт
}

 

axill
Offline
Зарегистрирован: 05.09.2011

Rulezzz пишет:

Доброго времени суток, форумчане. Прошу помощи в проблеме.

Итак, есть десятичное число 8800, если его первести в шестнадцатеричное , то оно будет выглядеть так 2260. Суть вопроса: как мне перевести десятичное в шестнадцатеричное, разложить шестнадцатеричное  число 2260 на 22 и 60 и сделать из низ два байта вида 0x22 и 0x60. Так же необходима обратная операция: получаем два байта 0x25 и 0x4E, собираем в шестанцатеричное 254E и переводим в десятичное 9550.

Заранее спасибо.

мутно написали, но если правильно понял, вам нужно 16-ти битное число типа int разбить на два 8-ми битных

десятичное число есть только в вашем предствлении, все числа в МК представлены в виде двоичных чисел

вот несколько вариантов, все они архитектурно зависимы (т.е. на других МК могут работать неверно если там другая последовательность байт)

int a = 0x2260;

// вариант №1
uint8_t a0 = a & 0xff;
uint8_t a1 = a >> 8;

// вариант №2
uint8_t aa[2];

*(int*)aa = a;
a0 = aa[0];
a1 = aa[1];

// вариант №3
struct {
    uint8_t a0;
    uint8_t a1;
} ab;
*(int*)ab = a;
a0 = ab.a0;
a1 = ab.a1;

 

Datak
Offline
Зарегистрирован: 09.10.2014

axill пишет:
вот несколько вариантов, все они архитектурно зависимы (т.е. на других МК могут работать неверно если там другая последовательность байт)

Вариант №1 архитектурно независим. :)

sva1509
Offline
Зарегистрирован: 07.12.2012

Правильней не давать указатель на слово а использовать union - это гарантирует вас от архитектурнозависимых неприятностей (однажды натыкался, правда на ARM)

ну и если использовать указатель, то правильней было бы объявлять переменную int. А на нее уже указатель (uint8_t*). Потому как int больше и компилятор резервирует память для большей переменной учитывая архитектурные возможности. Короче каждый int может стать двумя uint8_t, но не каждые 2 uint8_t могут стать int.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Плюс здесь напрашивается беззнаковый int.

axill
Offline
Зарегистрирован: 05.09.2011

Datak пишет:

Вариант №1 архитектурно независим. :)

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

axill
Offline
Зарегистрирован: 05.09.2011

kisoft пишет:
Плюс здесь напрашивается беззнаковый int.

напрашивается uin16_t, но в описанном применение int ничему не вредит применительно к AVR. Ибо int на AVR это двухбайтное число. Так как мы знаковые операции не используем, то int или uint16_t нет разницы

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Как угодно, но разница есть, 40000 как записать в int?
Разумеется это все фантазии, ТС про это ни слова не сказал.

axill
Offline
Зарегистрирован: 05.09.2011

sva1509 пишет:

Правильней не давать указатель на слово а использовать union - это гарантирует вас от архитектурнозависимых неприятностей (однажды натыкался, правда на ARM)

union это еще один вариант:

union {
   int aa;
   struct {
       uint8_t a0;
       uint8_t a1;
   } ab;
} a;

a.aa = 8800;
uint8_t a0 = a.ab.a0;
uint8_t a1 = a.ab.a1;

sva1509 пишет:
ну и если использовать указатель, то правильней было бы объявлять переменную int. А на нее уже указатель (uint8_t*). Потому как int больше и компилятор резервирует память для большей переменной учитывая архитектурные возможности. Короче каждый int может стать двумя uint8_t, но не каждые 2 uint8_t могут стать int.

напишите лучше пример кода, а то ход мыслей не понятен, здесь очень важны детали

axill
Offline
Зарегистрирован: 05.09.2011

kisoft пишет:
Как угодно, но разница есть, 40000 как записать в int? Разумеется это все фантазии, ТС про это ни слова не сказал.

я исхожу из постановки задачи. Дальше уже либо фантазии отвечающих либо отдельное обсуждение о корректности постановки задачи

axill
Offline
Зарегистрирован: 05.09.2011

kisoft пишет:
Как угодно, но разница есть, 40000 как записать в int? Разумеется это все фантазии, ТС про это ни слова не сказал.

ну если тупо есть желание записать 40000 в  int ))) то ниже просто теоретический вариант лишенный практического смысла

int b;

*((uint16_t*)&b) = 40000;

 

Rulezzz
Offline
Зарегистрирован: 13.05.2014

Опишу более подробно: в FM-трансмиттере (VMR6512) частота 88,00 МГц (8800 - десятичное значение, 2260 - шестнадцатеричное значение) задается командой из трех байт b1, b2, b3, где:

b1 = 0x01 - команда на установку частоты.

b2 = 0x22 - значение частоты.

b3 = 0x60 - значение частоты.

Байты b2 и b3 - 2 части целого 2260.

Частота может задаваться от 8800 до 10800 (88,00 МГц - 108,00 МГц) с шагом 0,10 МГц.

Заводим переменную int frec = 8800. Нужно ее преобразовать в byte b2 = 0x22 и byte b3 = 0x60.

Или наоборот: получаем два байта byte b2 = 0x22 и byte b3 = 0x60. Нужно преобразовать в int frec = 8800.

sva1509
Offline
Зарегистрирован: 07.12.2012

Все очень просто:

union {
    uint16_t freq;
    struct {
        uint8_t b3;
        uint8_t b2;
    } byte;
} bfreq;

...
....
bfreq.freq = 8800;
....
send(bfreq.byte.b2);
send(bfreq.byte.b3);
...
...
bfreq.byte.b2 = recv(b2);
bfreq.byte.b3 = recv(b3);
/// далее в bfreq.freq хранится ваша частота

 

 

 

axill
Offline
Зарегистрирован: 05.09.2011

Вы повторили мой пример выше

но вопрос был не про union. А не понял хода мыслей касательно применения указателей

sva1509
Offline
Зарегистрирован: 07.12.2012

2Axill

в Вашем примере №2 Вы по адресу массива uint8_t записываете int это не во всех платформах проходит. Кпримеру в ARM int выровнян на 4 байта а short на 2, char на 1. таким образом если компилятор выделит память для uint8_t c нечетного адреса, то произойдет ошибка. Так как uint16_t нельзя записать в нечетный адрес. По этому я и братил внимание что былобы правильней так:

uint16_t aa;
uint8_t *ap;

ap = (uint8_t*)&aa;

a0 = ap[0];
a1 = ap[1];

хотя в данном контексте я думаю это не принципиально.

axill
Offline
Зарегистрирован: 05.09.2011

sva1509 я специально сделал оговорку про привязку к платформе чтобы не затевать никаких обсуждения

но вы не удержались ) нет смысла обсуждать в этой теме ARM

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

axill пишет:

kisoft пишет:
Как угодно, но разница есть, 40000 как записать в int? Разумеется это все фантазии, ТС про это ни слова не сказал.

ну если тупо есть желание записать 40000 в  int ))) то ниже просто теоретический вариант лишенный практического смысла

int b;

*((uint16_t*)&b) = 40000;

 


Записать то можно, но использовать без гемора не получится.
Все, ТС сказал про частоту, значит нужен беззнаковый.
Ок, останемся при своих.

axill
Offline
Зарегистрирован: 05.09.2011

kisoft пишет:
Записать то можно, но использовать без гемора не получится. Все, ТС сказал про частоту, значит нужен беззнаковый. Ок, останемся при своих.

да я согласен) если понимаешь что делаешь можно делать как угодно используя какие угодно типы. Но это плохая практика, которая ведет к ошибкам. Вот и с типом int - в диапазоне значений частоты трансивера нет разницы использовать int или unsigned int. Но грамотно все же использовать unsigned ибо задача в принципе не подразумевает отрицательных значений

Datak
Offline
Зарегистрирован: 09.10.2014

axill пишет:

Datak пишет:

Вариант №1 архитектурно независим. :)

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

Порядок бит одинаковый для всех платформ (из тех что я встречал) - старший слева, младший справа.

Разный у них порядок байт - в слове, в двойном слове и т.д. Но правильно собирать/разбирать слова на байты это не мешает.

Datak
Offline
Зарегистрирован: 09.10.2014

Rulezzz пишет:

Заводим переменную int frec = 8800. Нужно ее преобразовать в byte b2 = 0x22 и byte b3 = 0x60.

Или наоборот: получаем два байта byte b2 = 0x22 и byte b3 = 0x60. Нужно преобразовать в int frec = 8800.

Ну так, всё же правильно написано, осталось только перевести на С. :)

Распаковка:







unsigned int freq = 8800;

byte b2 = ( byte )( freq >> 8 );
byte b3 = ( byte )freq;

И упаковка:







freq = ( ( unsigned int )b2 << 8 ) | b3;

 

Rulezzz
Offline
Зарегистрирован: 13.05.2014

Спасибо всем, кто откликнулся. Задача разрешилась. Век живи, век учись. )))

flat
Offline
Зарегистрирован: 05.02.2015

похожая проблемма ... читаю цвет из файла, он в 10-чной. а установка цвета в mcufriend  в 16-ричной. не могу перевести. цвет 16 бит ... тоесть к примеру из 48664 получить 0xBE18. попробовал последний варик ... не менятеся ничего .... 

 

uint16_t B = 0x0000;
uint16_t G = 0x0000;
..........

    B=myFile.read();
    G=myFile.read();
    Serial.print (B);
    Serial.print (" ");
    Serial.print (G);
    Serial.print (" ");
    temvar = G*256+B;
    byte b2 = (byte)( temvar >> 8);
    byte b3 = (byte)temvar;
    temvar = ((unsigned int)b2<<8)|b3;

    Serial.println (temvar);

 

arduinec
Offline
Зарегистрирован: 01.09.2015

flat пишет:

похожая проблемма ... читаю цвет из файла, он в 10-чной. а установка цвета в mcufriend  в 16-ричной. не могу перевести. цвет 16 бит ... тоесть к примеру из 48664 получить 0xBE18. попробовал последний варик ... не менятеся ничего .... 

Может так получиться:
Serial.print(B, HEX);

MacSim
Offline
Зарегистрирован: 28.11.2012

sva1509 пишет:

Правильней былобы так:

union {
      int x;
      byte b[2];
}itob;

void myfunc()
{
    itob.x = 8800;
    // теперь itob.b[0] младший байт itob.b[1] содержит старший байт
}

 

спасибо за информацию. ...век учись. записал под карандаш

flat
Offline
Зарегистрирован: 05.02.2015

решено . спасибо

 

 

gonzales
Offline
Зарегистрирован: 13.07.2015

Подниму тему, чтобы не плодить новую. 

А как разобрать знаковый int на байты? И как потом собрать обратно, чтобы знак опять же остался?

gonzales
Offline
Зарегистрирован: 13.07.2015

Можно конечно банально, сначала прибавить 32768, получив unsigned int, а потом уже в байты, но может есть более изящное решение?

b707
Offline
Зарегистрирован: 26.05.2017

gonzales пишет:

может есть более изящное решение?

варианты:

а) описать как унион

б) поменять тип указателя с int* на byte*

gonzales
Offline
Зарегистрирован: 13.07.2015

Круто, union будет и со знаком правильно работать, ничего придумывать не надо?

b707
Offline
Зарегистрирован: 26.05.2017

gonzales пишет:

Круто, union будет и со знаком правильно работать, ничего придумывать не надо?

он вообще не будет никак с ним "работать", унион просто дает доступ к каждому байту отдельно, на содержание байтов ему фиолетово.

Хотя я вот так обычно делаю, без всяких унионов:

int16_t val = 3567;
byte* ptr = (byte*) &val;

Serial.print("First byte: "); Serial.print(ptr[0], HEX);
Serial.print(" Second byte: "); Serial.print(ptr[1], HEX);

 

gonzales
Offline
Зарегистрирован: 13.07.2015

b707 пишет:

gonzales пишет:

Круто, union будет и со знаком правильно работать, ничего придумывать не надо?

он вообще не будет никак с ним "работать", унион просто дает доступ к каждому байту отдельно, на содержание байтов ему фиолетово.

Хотя я вот так обычно делаю, без всяких унионов:

int16_t val = 3567;
byte* ptr = (byte*) &val;

Serial.print("First byte: "); Serial.print(ptr[0], HEX);
Serial.print(" Second byte: "); Serial.print(ptr[1], HEX);

 

спасибо, учту

b707
Offline
Зарегистрирован: 26.05.2017

gonzales пишет:

спасибо, учту

если не понимаешь этой записи - делай через унион, меньше вероятности ошибок

Green
Offline
Зарегистрирован: 01.10.2015

С ptr как то не экономненько.)))

b707
Offline
Зарегистрирован: 26.05.2017

Green пишет:

С ptr как то не экономненько.)))

два байта со стека жалко? :)

Green
Offline
Зарегистрирован: 01.10.2015

Да уж.) Давеча писал программулину для pic10f200 - так у него стек (правда железный) аж на 2 байта! Да и с программным в 16-ти байтах сильно не развернёшься.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Да уж.) Давеча писал программулину для pic10f200 - так у него стек (правда железный) аж на 2 байта! Да и с программным в 16-ти байтах сильно не развернёшься.)

Писал для контроллеров на PIC16F84 и даже не задумывался о глубине стека, девайсы отработали годы без нареканий (в вязальных машинках), судьба )))

Green
Offline
Зарегистрирован: 01.10.2015

Всё норм. Это ж простые ус-ва, стеку то куда деваться. А компилятор просчитывает глубину и выдаёт предупреждение.
Удивительно то, что в 10f можно программно выдавать на выход системную частоту. И это всё в SOT23!