Отговори на тема  [ 14 мнения ] 
Битови манипулаций в С++ 
Автор Съобщение
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Нед Окт 19, 2008 7:26 pm
Мнения: 673
Мнение Битови манипулаций в С++
Има ли по лесен начин в 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;


Чет Яну 15, 2009 9:05 pm
Профил
Ранг: Ориентиран
Ранг: Ориентиран
Аватар

Регистриран на: Пон Яну 09, 2006 11:32 am
Мнения: 276
Местоположение: Kozloduy
Мнение 
Ами мисля че второто ще генерира по-къс код. Иначе мога да ти каже че ако е за пик на асм може да стане с 3 инструкции, а авр може да го направи дори с 2 инструкции (има инструкции bit load, bit store)


Чет Яну 15, 2009 9:27 pm
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Нед Окт 19, 2008 7:26 pm
Мнения: 673
Мнение 
Код:
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 10:01 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Фев 25, 2005 1:58 pm
Мнения: 4585
Местоположение: US
Мнение 
Какво искаш да правиш, след като си отделил бита и си го заредил в променлива тип char ? Искаш бита да е на същата позиция на която си е бил, или просто искаш да го заредиш като 1 или 0 в променливата тип char ?

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

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


Чет Яну 15, 2009 11:55 pm
Профил WWW
Ранг: Почетен член
Ранг: Почетен член
Аватар

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


Пет Яну 16, 2009 10:18 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30686
Местоположение: София
Мнение 
То много зависи за какъв процесор го пишеш според мен ама .....


Съб Яну 17, 2009 1:45 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Сеп 27, 2004 9:22 am
Мнения: 15501
Местоположение: София
Мнение 
За съжаление при подобни ситуации ти се налага да поназнайваш асемблер. Инак няма как да знаеш какво е натворил конкретния компилатор, за конкретния процесор. Всеки е със собствено мнение.

_________________
"Да еба и шибаната държава" мислеше си Гошо, докато се опитваше да улучи кофата за боклук от балкона на осмия етаж.


Съб Яну 17, 2009 1:55 pm
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Нед Окт 19, 2008 7:26 pm
Мнения: 673
Мнение 
Ще стане много трудно на асемблер, затова тъпо ама ще заложа на производителност, и повече Mhz.
Мисля си за Mega32. Важно ми е, и не искам да ползвам някоя SAM7 , все още не съм ги изучил добре.


Съб Яну 17, 2009 5:07 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

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

_________________
Най-опасният враг на истината и свободата е мнозинството.


Съб Яну 17, 2009 9:45 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

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

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

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


Съб Яну 17, 2009 11:13 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
Абе да ти кажа не вложих толкова усилия в разсъждението относно 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. В предишната както и в последната тези магарии ги няма.
Но се вижда че последните две функции са еднакви. :) Макар че не точно това имах впредвид.
А за пръскането на битовете в отделни байтове и аз това имах впредвид - не е нужно.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Нед Яну 18, 2009 12:35 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Фев 26, 2006 6:52 pm
Мнения: 11266
Местоположение: Добрич
Мнение 
Избягвай char... в случая

unsigned char test_bit4(unsigned char port_b)

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

unsigned int test_bit4(unsigned int port_b)


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

test_bit4(port_b_byte +1);

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


Нед Яну 18, 2009 1:11 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
miro_atc написа:
Избягвай char... в случая
...

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

_________________
Най-опасният враг на истината и свободата е мнозинството.


Нед Яну 18, 2009 1:39 am
Профил
Ранг: Новодошъл
Ранг: Новодошъл

Регистриран на: Пет Юни 29, 2007 10:59 pm
Мнения: 113
Мнение 
Компилаторите, които използвам за С и С++ за микроконтролери обикновено позволяват побитови структури. Ето пример на 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-а явно счита, че не може да се получи загуба на информация (наистина е така) и си мълчи. Затова и съм го оставил така.


Нед Яну 18, 2009 2:53 pm
Профил ICQ
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 14 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 3 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни