Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Помогите перетасовать биты.


Автор: =Женек= 7.4.2013, 13:41
Господа, есть 16-ти битное исходное число SRC.

И есть переменная DST в которую нужно переписать некоторые биты из SRC НЕ ТРОГАЯ остальные биты в DEST.

А именно 
DST.0 - SRC.2
DST.1 - SRC.3
DST.8 - SRC.13
DST.9 - SRC.14
DST.10 - SRC.15
DST.14 - SRC.0
DST.15 - SRC.1


Как это сделать?

Автор: Alexeis 7.4.2013, 13:56
Объявите структуру на 16 битовых полей и манипулируйте ими как нужно
Код

struct mytype
{
bool b0 : 1;
bool b1 : 1;
bool b2 : 1;
bool b3 : 1;
bool b4 : 1;
//...
bool b15 : 1;
};

Если биты означают что-то осмысленное, то можно назвать поля по человечески. Это не самый быстрый способ, но пожалуй самый читабельный. 

Автор: =Женек= 7.4.2013, 14:16
мне нужно проще без структур - пишу для микроконтроллера.
Сделал пока так:
EB |=((SRC>>2) & 0x0003) | (SRC<<14) | ((SRC & 0xE000)>>5);
Но биты, однажды установленные в единицу в следующий раз не обнуляются.

Автор: Dem_max 7.4.2013, 14:18
Код для микроконтроллеров 

Код

typedef struct _BITS
{
   int bit0: 1;
   int bit1: 1;
   int bit2: 1;
   int bit3: 1;
   int bit4: 1;
   int bit5: 1;
   int bit6: 1;
   int bit7: 1;
} SBITS;
 
typedef union _BYTE
{
   unsigned char BYTE;
   SBITS BITS;
 
   operator [] (int i)
   {
      switch(i){
         case 0: return BITS.bit0;
         case 1: return BITS.bit1;
         case 2: return BITS.bit2;
         case 3: return BITS.bit3;
         case 4: return BITS.bit4;
         case 5: return BITS.bit5;
         case 6: return BITS.bit6;
         case 7: return BITS.bit7; 
      }
   }
} REGISTR;
 
REGISTR R0, R1, R2, R3;
 
int main()
{
      R0.BYTE = 0x00;
      int g = R0.BITS[1];
      R0.BITS.bit5 = 1;
      printf("Write R0 = %X", R0.BYTE);
      WritePort(R0.BYTE);
      R0.BYTE = ReadPort();
      printf("Read R0 = %X", R0.BYTE);
      WritePort(R0.BYTE);

      R0.BITS.bit5 = R3.BITS.bit7;
}

Автор: =Женек= 7.4.2013, 14:38
от вашей конструкции компилятор переклинило....
Я хотел проще, пример привел. Чисто битовые операции.

Автор: Alexeis 7.4.2013, 14:58
Структура не отнимает нисколько памяти. Так что это не сложно, но раз без структуры, то сначала нужно очистить в DST все биты которые нужно скопировать одной маской, затем записать, например вашим способом. 

Автор: =Женек= 7.4.2013, 15:11
Господа, чтобы Вам понять в каком направлени двигаться приведу в пример аналогичную задачу - там 16-ти битное число нужно раскидать по двум портам напополам.
И делается это так:
Код

void Write_Dat(uint16_t LCD_Dat)
{
    LCD_CS = 0;
    LCD_RS = 1;
    GPIOC->ODR = (GPIOC->ODR&0xff00)|(LCD_Dat&0x00ff);
    GPIOB->ODR = (GPIOB->ODR&0x00ff)|(LCD_Dat&0xff00);
    LCD_WR = 0;
    LCD_WR = 1;    
    LCD_CS = 1;
}


uint16_t LCD_ReadReg(uint16_t LCD_Reg)
{
    uint16_t temp;
    Write_Cmd(LCD_Reg);  //дÈëÒª¶ÁµÄ¼Ä´æÆ÷ºÅ  
 
    GPIOB->CRH = (GPIOB->CRH & 0x00000000) | 0x44444444; //½«¶Ë¿Ú¸ß8λÅäÖóÉÊäÈë
    GPIOC->CRL = (GPIOC->CRL & 0x00000000) | 0x44444444; //½«¶Ë¿ÚµÍ8λÅäÖóÉÊäÈë  
    LCD_CS = 0;
    LCD_RS = 1;
    LCD_RD = 0;
    temp = ((GPIOB->IDR&0xff00)|(GPIOC->IDR&0x00ff)); //¶ÁÈ¡Êý¾Ý(¶Á¼Ä´æÆ÷ʱ,²¢²»ÐèÒª¶Á2´Î)    
    LCD_RD = 1;
    LCD_CS = 1; 
    GPIOB->CRH = (GPIOB->CRH & 0x00000000) | 0x33333333; //ÊͷŶ˿ڸß8λΪÊä³ö
    GPIOC->CRL = (GPIOC->CRL & 0x00000000) | 0x33333333; //ÊͷŶ˿ڵÍ8λΪÊä³ö
    return temp;   
}

Автор: Alexeis 7.4.2013, 15:25
Код

DST &= 0x38FC; //очищаем все биты которые будем копировать
DST |= (SRC & 0x0004) >> (2-0); //выделили 2й бит и сдвинули его на нулевую позицию
DST |= (SRC & 0x0008) >> (3-1);//выделили 3й бит и сдвинули на 1ю позицию
DST |= (SRC & 0x1000) >> (13-8);//выделили 13й бит и сдвинули на 8ю позицию

Автор: feodorv 7.4.2013, 15:45
Цитата(=Женек= @  7.4.2013,  16:11 Найти цитируемый пост)
(GPIOB->CRH & 0x00000000)

Не нравится мне это...

Автор: =Женек= 7.4.2013, 16:16
Спасибо, но что-то вы напутали.
Если я ввожу в исходное число 0xFFFF то получаю 0b0000 0000 1000 0011, а должен получить 0b1100 0111 0000 0011

Автор: Dem_max 7.4.2013, 16:17
Цитата

от вашей конструкции компилятор переклинило....

Смени компилятор

Автор: =Женек= 7.4.2013, 16:29
Цитата(Dem_max @ 7.4.2013,  16:17)
Цитата

от вашей конструкции компилятор переклинило....

Смени компилятор

обязательно. Когда закончу разработку)))

Автор: =Женек= 7.4.2013, 17:00
Оххх.. получилось вот так:

Код

EB=((SRC <<3) & 0xFF80);





DB &= ~(0xC703); //очищаем все биты которые будем копировать
DB |= (SRC & 0x0004) >> (2-0); //выделили 2й бит и сдвинули его на нулевую позицию
DB |= (SRC & 0x0008) >> (3-1);//выделили 3й бит и сдвинули на 1ю позицию
DB |= (SRC & 0x2000) >> (13-8);//выделили 13й бит и сдвинули на 8ю позицию
DB |= (SRC & 0x4000) >> (14-9);//выделили 14й бит и сдвинули на 9ю позицию
DB |= (SRC & 0x8000) >> (15-10);//выделили 15й бит и сдвинули на 10ю позицию

DB |= (SRC & 0x0001) << (14);//выделили 0й бит и сдвинули на 14ю позицию
DB |= (SRC & 0x0002) << (14);//выделили 1й бит и сдвинули на 15ю позицию




А теперь по аналогии научите читать)))

Автор: volatile 8.4.2013, 00:31
Цитата(=Женек= @  7.4.2013,  17:00 Найти цитируемый пост)
Оххх.. получилось вот так:

мда уж, в итоге читабельность кода на грани фантастики.

я бы написал функцию, что-то типа 
Код

void move_bit (const int & src, int src_bit, int & dst, int dst_bit)
{
   int dst_mask = 1U << dst_bit;
   if (src & (1U << src_bit))
      dst |= dst_mask;
   else
      dst &= ~dst_mask;
}

теперь можно понятно перемещать биты, например:
Код

move_bit (SRC, 3, DST, 1);  //выделили 3й бит и сдвинули на 1ю позицию

сравните:
Цитата(=Женек= @  7.4.2013,  17:00 Найти цитируемый пост)
DB |= (SRC & 0x0008) >> (3-1);//выделили 3й бит и сдвинули на 1ю позицию


походу и обнулять изменяемые биты вначале не придецца.


Автор: =Женек= 8.4.2013, 05:13
Цитата

походу и обнулять изменяемые биты вначале не придецца.



Вы, видимо, не знаете тонкостей роаботы с микроконтроллерами. 
Я уже объяснял выше, что код должен быть низкоуровневый. Не на ассемлблере, конечно, но низкоуровневый.
А мне упорно шлют высший пилотаж.
Цитата

мда уж, в итоге читабельность кода на грани фантастики.

зато ваш код тормозной. Ну зачем каждый раз проверять состояние бита, если его можно записать как есть? Частота контроллера всего 72 МГц, а задача - работа с дисплеем.

Автор: math64 8.4.2013, 07:24
Примерно как написал volatile, но не функцию, а макрос - у контроллера обычно C без плюсов.
Код

#define MOVE_BIT(src, src_bit, dst, dst_bit) \
   ( \
     ((src) & (1U << (src_bit))) ? \
     ((dst) |= (1U << (dst_bit))) : \
     ((dst) &= ~(1U << (dst_bit))) \
   )

Если src_bit и dst_bit - константы, сдвиги выполнит компилятор.
Можно добавить параметр bit_cnt для перемещения нескольких бит сразу.

Автор: bsa 8.4.2013, 11:06
gcc довольно хреново оптимизирует сдвиги. Например, для avr классический код получения старшего байта слова (x >> 8) будет выглядеть как восемь сдвигов всего числа... Что очень неоптимально. Чтобы это обойти я использовал объединение:
Код
union Word
{
   uint16_t word;
   uint8_t bytes[2];
};
При его использовании код получается корректным (т.е. одна инструкция передачи из регистра в регистр).
Более того, для работы с битами на AVR есть встроенная функция gcc: __builtin_avr_insert_bits(), которая позволяет тасовать биты.

Автор: xvr 8.4.2013, 13:17
Цитата(=Женек= @  8.4.2013,  05:13 Найти цитируемый пост)
Я уже объяснял выше, что код должен быть низкоуровневый.

А какой у вас МК и компилятор? К примеру gcc под ARM (с достаточным уровнем оптимизации) свернет код от volatile до прямого копирования битов (IMHO). Посмотрите ассемблерный выхлоп от компилятора - вас ждет сюрприз  smile 

Автор: Dem_max 8.4.2013, 15:24
Я так подозреваю у тебя Cortex у него компилятор не должен ругаться на мою конструкцию

Автор: volatile 9.4.2013, 23:40
Цитата(=Женек= @  8.4.2013,  05:13 Найти цитируемый пост)
Вы, видимо, не знаете тонкостей роаботы с микроконтроллерами. 

вы видимо не знаете что такое с/с++ компилятор. Этот код должен работать никак не медленнее вашего.
особенно если учесть, что там фактически, вообще нет сдвигов.
Цитата(=Женек= @  8.4.2013,  05:13 Найти цитируемый пост)
зато ваш код тормозной.

забыли добавить "по моим предположениям, ..."

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)