Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Битови манипулаций в С++
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=6462
Страница 1 от 1

Автор:  RM [ Чет Яну 15, 2009 9:05 pm ]
Заглавие:  Битови манипулаций в С++

Има ли по лесен начин в C++(защото го пиша е такава среда и знам че се пише като на С) да се
отдели бит от байт и да се използва в случая като променлива char

Код:
// ПОРТ B следене на 4 вход-конфигурирани пина -целия байт пратен по RS232 като port_b_byte /00xxxx00/
//при приемане в компютъра
char port_b_byte=0x2B;  //  /001010111 /
char port_b_mask=0x3C;  // /00111100 /
char pin_3;
char pin_4;
char pin_5;
char pin_6;

pin_3=((port_b_byte & port_b_mask)>>2)&1;
pin_4=((port_b_byte & port_b_mask)>>3)&1; 
pin_5=((port_b_byte & port_b_mask)>>4)&1;
pin_6=((port_b_byte & port_b_mask)>>5)&1;

// или така

if(port_b_byte & 4) pin_3=1;
else pin_3=0;

Автор:  bobyk [ Чет Яну 15, 2009 9:27 pm ]
Заглавие: 

Ами мисля че второто ще генерира по-къс код. Иначе мога да ти каже че ако е за пик на асм може да стане с 3 инструкции, а авр може да го направи дори с 2 инструкции (има инструкции bit load, bit store)

Автор:  RM [ Чет Яну 15, 2009 10:01 pm ]
Заглавие: 

Код:
pin_3=(port_b_byte & 1<<2)>>2;

Така е правилно .... сбъркал съм по горе.
Използвах това по друг случай
Код:

switch ((port_b_byte & port_b_mask)>>2){
    case 1: .....;
    break;
    case2:
..............
    case 16:.....;
    break;
    };


Компилаторите за микроконтролери позволяват проненливи дефинирани като ...
Код:
char flags=0;
  #bit port_1_2=flags.0

Интересува ме как се прави в Borland C++.

Автор:  [ Чет Яну 15, 2009 11:55 pm ]
Заглавие: 

Какво искаш да правиш, след като си отделил бита и си го заредил в променлива тип char ? Искаш бита да е на същата позиция на която си е бил, или просто искаш да го заредиш като 1 или 0 в променливата тип char ?

Втория код ( ако е само да знаеш 1 или 0 ) може да стане още по-компактен ( като размер, не като скорост ), ако го напишеш така:
Код:
pin_3 = 0;
if( port_b_byte & 4 )
        pin_3=1;

Автор:  RM [ Пет Яну 16, 2009 10:18 am ]
Заглавие: 

Да 0 или 1 в променлива тип чар.
Искам да следя състояние на портове. Да се виждат в прозореца на програмата.Имам на платката 4 джъмпера, и тях искам да виждам на прозореца.
Искам да изписвам прочетените от ADC-стойности на няколко пина, и ми трябва най компактно прехвърляне по серийния порт ( промерно с 2 BCD za 4 цифри). И се чудя как да намаля размера на пакетите, за да се обновява най-бързо на екрана на PC-то.
Или по точно , имам една машина на която трябва да заменя скъпоструващото оригинално процесорно, с много, много по ефтино.
Но има процеси който трябва да се настройват много финно в реално време, за да е налице същия резултат.
Трябва да следя състоянието на мощните елементи и да се сигнализира при повреда, вентилатори да ли се въртят...

Автор:  ToHu [ Съб Яну 17, 2009 1:45 pm ]
Заглавие: 

То много зависи за какъв процесор го пишеш според мен ама .....

Автор:  Цецо [ Съб Яну 17, 2009 1:55 pm ]
Заглавие: 

За съжаление при подобни ситуации ти се налага да поназнайваш асемблер. Инак няма как да знаеш какво е натворил конкретния компилатор, за конкретния процесор. Всеки е със собствено мнение.

Автор:  RM [ Съб Яну 17, 2009 5:07 pm ]
Заглавие: 

Ще стане много трудно на асемблер, затова тъпо ама ще заложа на производителност, и повече Mhz.
Мисля си за Mega32. Важно ми е, и не искам да ползвам някоя SAM7 , все още не съм ги изучил добре.

Автор:  Zdrav [ Съб Яну 17, 2009 9:45 pm ]
Заглавие: 

Ако искаш да намалиш размера на пакетите и да стане по-бързо, предавай направо целия байт (port_b_byte). И остави ПС-то да се занимава с манипулирането на битовете. Освен това като напишеш веднъж фърмуеъра после е въпрос на развой върху ПС за да получиш информацията на монитора във вид в който ти е най-удобно.
Иначе ако въпроса ти е принципен, както Цецо ти каза гледай резултата в асемблера. При arm-elf-gcc например с включена оптимизация, както и да го напишеш на С в крайна сметка и двата варианта, които си дал ще се сведат до едно и също. :)

Автор:  miro_atc [ Съб Яну 17, 2009 11:13 pm ]
Заглавие: 

arm-elf-gcc вероятно ще се справи по-добре в първия случай, защото няма if() и при thumb ще се избегнат преходи (които тормозят конвейра) а при arm-mode може да се избегне условното изпълнение, т.е. вместо с 2 да стане с 1 инструкция. Друг е въпросът, arm-elf-gcc има алергия към char & short типове и много вероятно да вкара излишно шифтване напред-назад...

Това което буди недоумение е защо трябва да се пръскат битовете в отделни променливи. Обикновено много по-ефективно е в една променлива да се запиши стойността на целия порт.

Иначе и маската ако е константа е безсмислена...

Автор:  Zdrav [ Нед Яну 18, 2009 12:35 am ]
Заглавие: 

Абе да ти кажа не вложих толкова усилия в разсъждението относно arm-elf-gcc. Основната ми мисъл беше че маскирането обикновенно го свежда винаги до шифтване наляво и после надясно.
Ето един набързо скалъпен тест:
Код:

volatile unsigned char port_b_byte;
volatile unsigned char pin_4;
void   test_bit(void);
void   test_bit2(void);
unsigned char   test_bit3(unsigned char port_b);
unsigned char   test_bit4(unsigned char port_b);

int main(void)
{
   while(1);
   return 0;
}

void   test_bit(void)
{
   if(port_b_byte & 4)
      pin_4 = 1;
   else
      pin_4 = 0;
}

void   test_bit2(void)
{
   pin_4 = (port_b_byte>>2)&1;
}

unsigned char   test_bit3(unsigned char port_b)
{
   return (port_b>>2)&1;
}

unsigned char   test_bit4(unsigned char port_b)
{
   if(port_b & 4)
      return 1;
   return 0;
}

Резултата е:
Код:
400007a0 <_Z8test_bitv>:
400007a0:   e59f201c    ldr   r2, [pc, #28]   ; 400007c4 <_Z8test_bitv+0x24>
400007a4:   e5d23000    ldrb   r3, [r2]
400007a8:   e2132004    ands   r2, r3, #4   ; 0x4
400007ac:   159f3014    ldrne   r3, [pc, #20]   ; 400007c8 <_Z8test_bitv+0x28>
400007b0:   059f3010    ldreq   r3, [pc, #16]   ; 400007c8 <_Z8test_bitv+0x28>
400007b4:   13a02001    movne   r2, #1   ; 0x1
400007b8:   15c32000    strbne   r2, [r3]
400007bc:   05c32000    strbeq   r2, [r3]
400007c0:   e12fff1e    bx   lr
400007c4:   40004000    .word   0x40004000
400007c8:   40004001    .word   0x40004001

400007cc <_Z9test_bit2v>:
400007cc:   e59f3014    ldr   r3, [pc, #20]   ; 400007e8 <_Z9test_bit2v+0x1c>
400007d0:   e5d32000    ldrb   r2, [r3]
400007d4:   e59f3010    ldr   r3, [pc, #16]   ; 400007ec <_Z9test_bit2v+0x20>
400007d8:   e1a02122    lsr   r2, r2, #2
400007dc:   e2022001    and   r2, r2, #1   ; 0x1
400007e0:   e5c32000    strb   r2, [r3]
400007e4:   e12fff1e    bx   lr
400007e8:   40004000    .word   0x40004000
400007ec:   40004001    .word   0x40004001

400007f0 <_Z9test_bit3h>:
400007f0:   e1a00120    lsr   r0, r0, #2
400007f4:   e2000001    and   r0, r0, #1   ; 0x1
400007f8:   e12fff1e    bx   lr

400007fc <_Z9test_bit4h>:
400007fc:   e1a00120    lsr   r0, r0, #2
40000800:   e2000001    and   r0, r0, #1   ; 0x1
40000804:   e12fff1e    bx   lr

Това е в arm режим.
Тука се вижда един дефект на компилатора, който имам инсталиран на домашния компютър. В първата функция има ненужно дублиране на унструкции. Нещо беше скапана тази версия(4.2.2) която инсталирах тогава с YAGARTO. В предишната както и в последната тези магарии ги няма.
Но се вижда че последните две функции са еднакви. :) Макар че не точно това имах впредвид.
А за пръскането на битовете в отделни байтове и аз това имах впредвид - не е нужно.

Автор:  miro_atc [ Нед Яну 18, 2009 1:11 am ]
Заглавие: 

Избягвай char... в случая

unsigned char test_bit4(unsigned char port_b)

е по-добре да е:

unsigned int test_bit4(unsigned int port_b)


Самата функция декрарина и по двата начина ще ти даде един и същ код, но при извикването може да те изненада ако я викнеш така:

test_bit4(port_b_byte +1);

просто ще вкара два ненужни шифта за да направи параметър char, демек да махне евентуален пренос в старшия байт...

Автор:  Zdrav [ Нед Яну 18, 2009 1:39 am ]
Заглавие: 

miro_atc написа:
Избягвай char... в случая
...

Това е ясно. :)
Написах го с char само за примера. Явно стратегията на компилатора е да маскира старшите байтове извън функцията, при извикването и, и затова наистина в примерите не се вижда това което искаше да кажеш в предния пост. Дано не сме забъркали по-голяма каша в главата на RM с "академичното" отклонение към arm-elf-gcc.

Автор:  Yanek [ Нед Яну 18, 2009 2:53 pm ]
Заглавие: 

Компилаторите, които използвам за С и С++ за микроконтролери обикновено позволяват побитови структури. Ето пример на IAR:

Код:
__no_init union
{
  char MyByte;
  struct
  {
    unsigned char bit0 : 1;
    unsigned char bit1 : 1;
    unsigned char bit2 : 1;
    unsigned char bit3 : 1;
    unsigned char bit4 : 1;
    unsigned char bit5 : 1;
    unsigned char bit6 : 1;
    unsigned char bit7 : 1;
  } MyByte_bit;
} @ 0x300;

//upotreba

MyByte =0x01;
MyByte_bit.bit0=1;



Този пример е с абсолютно задаване на адреса на променливата.

по друг начин:

Код:

union
{
char MyByte;
struct
  {
    unsigned char bit0 : 1;
    unsigned char bit1 : 1;
    unsigned char bit2 : 1;
    unsigned char bit3 : 1;
    unsigned char bit4 : 1;
    unsigned char bit5 : 1;
    unsigned char bit6 : 1;
    unsigned char bit7 : 1;
  }  MyByte_bit;
}
MyUnion;

//upotreba:

MyUnion.MyByte =0x01;// =0;
MyUnion.MyByte_bit.bit0=1;



В клас:

Код:

#define  RISE 1

typedef   unsigned char BOOL;

typedef union
{
  char MyByte;
  struct
  {
    unsigned char bit0        : 1;
    unsigned char bit1        : 1;
    unsigned char bit2        : 1;
    unsigned char bit3        : 1;
    unsigned char bit4        : 1;
    unsigned char bit5        : 1;
    unsigned char bit6        : 1;
    unsigned char bit7        : 1;
  } MyByte_bit; 
}
MyUnion;

class A
{
private:
  MyUnion mu;
public:

  A(){mu.MyByte=0;}

  char get_Bit3()
  {
   return mu.MyByte_bit.bit3;
  }
  void set_Bit3(char bit)
  {
   mu.MyByte_bit.bit3 = bit;
  }
  BOOL check_Bit3()
  {
   return (mu.MyByte_bit.bit3==1);
  }

};
// upotreba

  A myclass;
 
  myclass.get_Bit3();
  myclass.set_Bit3(RISE);
  if(myclass.check_Bit3())
  {

  }



Редакция: Редно е компилатора да изписка от подобно неявно преобразуване на char в unsigned char, но IAR-а явно счита, че не може да се получи загуба на информация (наистина е така) и си мълчи. Затова и съм го оставил така.

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/