Отговори на тема  [ 20 мнения ]  Отиди на страница 1, 2  Следваща
Работа с битове в C30 за PIC24 
Автор Съобщение
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 2:23 pm
Мнения: 3714
Местоположение: Високо в планината
Мнение Работа с битове в C30 за PIC24
Здравейте,
как се задава битова променлива в C30?

_________________
Хайде де!


Вто Сеп 21, 2010 4:26 pm
Профил
Ранг: Почетен член
Ранг: Почетен член

Регистриран на: Съб Окт 13, 2007 12:12 pm
Мнения: 712
Мнение 
http://www.microchip.su/showthread.php? ... hlight=c30


Вто Сеп 21, 2010 4:44 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Фев 25, 2005 1:58 pm
Мнения: 4585
Местоположение: US
Мнение 
С обединения ( union ), няма го като вградена променлива.

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


Сря Сеп 22, 2010 4:47 am
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

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

typedef enum {
FALSE = 0,
TRUE;
}BOOL;

Естествено това не е оптимално точно за Пик архитектурата. Но пък ще работи на всички процесори ако ти се наложи да прехвърляш кода след това.

Неудобството на битовите полета е че трябва да се съобразяваш къде и как си ги дефинирал - локални/глобални, стек, хип, как ще ги изкомбинираш и така нататък. Въобще битовите полета са правени за структурирани данни и са много неудобни когато ти трябват малко на брой отделени по смисъла си на използване битове из целия сорс. Например да си направиш локално флагче за една функцийка. Там използването на цяла дума (8,16 или 32 битова) в стека/регистър е някак си по разбираемо. Е губиш 7,15 или 31 бита на вятъра, ама.

Проблема при пиковете е, че имат еднотактови инструкции за работа с битове много удобни и бързи...ама ако пишеш на асемблер. Ама в ANSI C няма подходяща имплементация за целта. Просто стандарта е писан за процесори с друга архитектура.

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


Сря Сеп 22, 2010 12:40 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Фев 25, 2005 1:58 pm
Мнения: 4585
Местоположение: US
Мнение 
Цецо написа:
Проблема при пиковете е, че имат еднотактови инструкции за работа с битове много удобни и бързи...ама ако пишеш на асемблер. Ама в ANSI C няма подходяща имплементация за целта. Просто стандарта е писан за процесори с друга архитектура.


Понякога C30 компилатора се усеща и манипулациите на битовите полета ги прави с BTG, BSF & BCF.

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


Сря Сеп 22, 2010 1:48 pm
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 2:23 pm
Мнения: 3714
Местоположение: Високо в планината
Мнение 
1.Има ли значение дали ще го направя със struct или с union, щом вътре има само един "елемент"?
2.Ако го направя както е показано на руския сайт, т.е. така :
Код:
typedef struct {
    unsigned bit  :1;
} BITVAR;
....
BITVAR myBit1, myBit2;
...
myBit1.bit = 1;
myBit2.bit = 0;

компилатора как ще подреди променливите в паметта-ще използва ли един адрес за 16 бита?

_________________
Хайде де!


Сря Сеп 22, 2010 2:07 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Сеп 27, 2004 9:22 am
Мнения: 15501
Местоположение: София
Мнение 
¶ написа:
Понякога C30 компилатора се усеща и манипулациите на битовите полета ги прави с BTG, BSF & BCF.


Така е. Ама може ли да направи битово поле локално за функция (в стека или в регистър)? А да предаде битче от битово поле като параметър на функция? Нямам голям опит с тоя компилатор, ама се съмнявам да може такива чудесии.

Аз затова на пикове битови полета използвам само когато се нуждая от върховни времена за реакция - например в прекъсване. Или съм закъсал тотално за Рам. И ги правя глобални. Удобни са например за някакви глобални флагове, дето трябва да се виждат от разни места. Ама става доста "мръсен" кода. И не е особенно портабъл.

dan написа:
компилатора как ще подреди променливите в паметта-ще използва ли един адрес за 16 бита?


Ми пусни го и виж асемблерския листинг. Откъде да знаем, зависи сигурно и от опциите с които е извикан, къде точно си вмъкнал тия редове в сорса.... :)

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


Сря Сеп 22, 2010 2:09 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Фев 24, 2005 11:41 pm
Мнения: 1049
Местоположение: Pz
Мнение 
Ето един пример:
Код:
union
{unsigned int v;
   struct
   {   unsigned      f0:1;      //
      unsigned      f1:1;      //
      unsigned      f2:1;      //
      unsigned      f3:1;      //
      unsigned      f4:1;      //
      unsigned      f5:1;      //
      unsigned      f6:1;      //
      unsigned      f7:1;      //
      unsigned      f8:1;      //
      unsigned      f9:1;      //
      unsigned      fa:1;      //
      unsigned      fb:1;      //
      unsigned      fc:1;      //
      unsigned      fd:1;      //
      unsigned      fe:1;      //
      unsigned      ff:1;      //
   }f;
}
      prg_stat1, prg_stat2;

#define keybit      prg_stat1.f.f0
#define bitpres      prg_stat1.f.f1
#define klav      prg_stat1.f.f2
#define rpt      prg_stat1.f.f3
#define blink      prg_stat1.f.f4
#define blnk      prg_stat1.f.f5
#define action      prg_stat1.f.f6
#define comand      prg_stat1.f.f7
#define enter      prg_stat1.f.f8
#define esc      prg_stat1.f.f9
#define dog      prg_stat1.f.fa
#define off      prg_stat1.f.fb
#define reg_al      prg_stat1.f.fc
#define unlock      prg_stat1.f.fd
#define first      prg_stat1.f.fe
#define LOW      prg_stat1.f.ff

#define HIGH      prg_stat2.f.f0
#define manual      prg_stat2.f.f1
#define jDone      prg_stat2.f.f2
#define mod      prg_stat2.f.f3
#define endmod      prg_stat2.f.f4
#define rs232_ок      prg_stat2.f.f5
#define endset      prg_stat2.f.f6
#define case_m      prg_stat2.f.f7
#define wrt      prg_stat2.f.f8



int   main(void)
{
.
.
.
.
    prg_stat1.v = 0;
    prg_stat2.v = 0;
    keybit = 1;
    wrt = 1;
.
.
.
.
}


Сря Сеп 22, 2010 3:19 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Юни 01, 2008 9:54 pm
Мнения: 1503
Местоположение: Пловдив
Мнение 
я се загледайте какво прави отдолу асемблера и ще разберете, че тая операция си хаби доста редове asm код. не съм го правил точно със структури/обединения, а с промяна на бит от специалните регистри и като видях какво се случва ми се изправи косата - от тогава цялата желана стойност за рег-а се хвърля в него със съответното &=/ |=, никакви побитови операции в тоя стил, че ... жална майка като почне да не стига флаша!


Сря Сеп 22, 2010 3:36 pm
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Фев 25, 2005 1:58 pm
Мнения: 4585
Местоположение: US
Мнение 
Цецо написа:
Така е. Ама може ли да направи битово поле локално за функция (в стека или в регистър)? А да предаде битче от битово поле като параметър на функция? Нямам голям опит с тоя компилатор, ама се съмнявам да може такива чудесии.


Ако се използва класическия метод за предаването на параметрите на функция през стека на едното битче винаги ще се направи typecast до широчината на стека. Няма как да вкараш в стека 1 бит, понеже стека е 8, 16 и т.н. битов.
Затова битовите полета обикновено се предават чрез указатели като параметри на функция. Вътре във функцията си правиш локална променлива от тип битовото поле и си манипулираш бита който ти трябва. Тогава вече компилатора си използва наличните инструкции за манипулации на бит.

Ето един пример:


Код:
typedef struct {
   union {
      struct {
         uint8    fRun:1;
         uint8    fExpire:1;
      };
      struct {
         uint8   m_flags;
      };
   }/*flags*/;
   uint16   ui_Timer16;
} MyTimer;

56:                void StartTimer(MyTimer *pTimer,uint16 timeout)   {
  24F2  FA0004     lnk #0x4
  24F4  780F00     mov.w 0x0000,[0x001c]
  24F6  980711     mov.w 0x0002,[0x001c+2]
57:                   pTimer->ui_Timer16 = timeout;
  24F8  78001E     mov.w [0x001c],0x0000
  24FA  90009E     mov.w [0x001c+2],0x0002
  24FC  980011     mov.w 0x0002,[0x0000+2]
58:                   pTimer->fRun = 1;
  24FE  78009E     mov.w [0x001c],0x0002
  2500  780011     mov.w [0x0002],0x0000
  2502  A00000     bset 0x0000,#0
  2504  780880     mov.w 0x0000,[0x0002]
59:                   pTimer->fExpire = 0;
  2506  78009E     mov.w [0x001c],0x0002
  2508  780011     mov.w [0x0002],0x0000
  250A  A11000     bclr 0x0000,#1
  250C  780880     mov.w 0x0000,[0x0002]
60:                }
  250E  FA8000     ulnk
  2510  060000     return


Понеже не използвам локална променлива ами директно манипулирам битовото поле чрез указател, то ясно се вижда, че компилатора първо извлича в регистър стойността на битовото поле от паметта, след това използва blcr/bset за да присвои нова стойност, после обратно копира регистъра в паметта. Дори обаче да бях използвал локална променлива, компилатора отново ще използва същия брой инструкции, защото bclr/bset инструкциите могат да работят само с директна адресация, т.е. предварително те трябва да знаят адреса в паметта. Ако професора позволяваше индиректна адресация с битовите инструкции компилатора нямаше да се замисли да ги използва. PIC30/33/24 компилаторите са GCC компилатори и са много добре оптимизирани, поне досега не съм намерил парче код, който бих го направил кой знае колко по-бърз, ако започна да го оптимизирам на ръка.

Ако обаче вътре във функцията дефинирам моето битово поле като static, тогава компилатора използва директната адресация на bclr/bset и си манипулира директно битовете:
Код:
void StartTimer(MyTimer *pTimer,uint16 timeout)   {
  24F2  FA0004     lnk #0x4
  24F4  780F00     mov.w 0x0000,[0x001c]
  24F6  980711     mov.w 0x0002,[0x001c+2]
57:                static MyTimer mt;
58:                   /*pTimer->ui_Timer16 = timeout;
59:                   pTimer->fRun = 1;
60:                   pTimer->fExpire = 0; */
61:                   mt = *pTimer;
  24F8  78001E     mov.w [0x001c],0x0000
  24FA  BE0010     mov.d [0x0000],0x0000
  24FC  8853C0     mov.w 0x0000,0x0a78
  24FE  8853D1     mov.w 0x0002,0x0a7a
62:                   mt.ui_Timer16 = timeout;
  2500  90001E     mov.w [0x001c+2],0x0000
  2502  8853D0     mov.w 0x0000,0x0a7a
63:                   mt.fRun = 1;
  2504  A80A78     bset.b 0x0a78,#0
64:                   mt.fExpire = 1;
  2506  A82A78     bset.b 0x0a78,#1
65:                   *pTimer = mt;
  2508  78001E     mov.w [0x001c],0x0000
  250A  8053C2     mov.w 0x0a78,0x0004
  250C  8053D3     mov.w 0x0a7a,0x0006
  250E  BE8802     mov.d 0x0004,[0x0000]
66:                }
  2510  FA8000     ulnk
  2512  060000     return


По принцип идеята на bclr/bset/btg инструкциите е за манипулиране на служебните регистри плюс глобално дефинираните променливи ( които са статични ).

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


Сря Сеп 22, 2010 7:11 pm
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Сеп 27, 2004 9:22 am
Мнения: 15501
Местоположение: София
Мнение 
¶ написа:
По принцип идеята на bclr/bset/btg инструкциите е за манипулиране на служебните регистри плюс глобално дефинираните променливи ( които са статични ).


Аха де и аз това казвам. :) За нормални флагчета, какъвто му беше въпроса на чиляка, по-лесно и разбираемо е да и маа на ниво дума, а не бит.

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


Чет Сеп 23, 2010 10:31 am
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 2:23 pm
Мнения: 3714
Местоположение: Високо в планината
Мнение 
Направих го със структура и typedef.
Изникна обаче следващия проблем:когато искам да използвам тази пременлива в друг файл от този проект, нещо не става.
Направих така:
Код:
typedef struct _bit{   
unsigned bit      :1;
            }bitvar;

bitvar error_m_B;

В друг .c файл съм направил това:
Код:
extern bitvar error_m_B;

излиза ми следната грешка:
Цитат:
pwm.c:6: error: syntax error before 'error_m_B'

и за мястото, където се обръщам към бита:
Цитат:
pwm.c:116: error: request for member 'bit' in something not a structure or union

Странното е, че всичко работеше, докато нещата ми бяха в един файл. Щом пробвах да ги разделя в два файла- работата се оплеска.

_________________
Хайде де!


Чет Сеп 23, 2010 11:47 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Юни 01, 2008 9:54 pm
Мнения: 1503
Местоположение: Пловдив
Мнение 
първо: не вижда къде си указал какво е bitvar, за това мяка - трябва да му инклиднеш .h файла където си разписал typedef на bitvar. обаче се чудя защо я правиш тая акробатика като можеш да ползваш това (виж приложението). не помня дали съм го копал отделно или е дошло с C30-ката, ама съм го ползвал за една 24-ка (сефте ги ползвах, както и C за PIC).


Прикачени файлове:
GenericTypeDefs.h [4.34 KiB]
258 пъти
Пет Сеп 24, 2010 9:57 am
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Сеп 27, 2004 9:22 am
Мнения: 15501
Местоположение: София
Мнение 
dan написа:
Направих го със структура и typedef.
Изникна обаче следващия проблем:когато искам да използвам тази пременлива в друг файл от този проект, нещо не става......


Начи не става ясно как втория .c фаил (този в който имаш extern) вижда дефиницията на новия тип "bitvar".

Ако в второто си includ-нал първото, ще имаш проблем, щото два пъти дефинираш едно и също (bitvar error_m_B). Ако не си го includ-нал (което вероятно не си направил), пак имаш проблем щото във второто ползваш типа (bitvar) без да си го дефинирал преди това.

Обикновенно практиката е в един съвсем отделен фаил да се сложат всички typdef които ползваш насам натам. Точно по начина по който ти показа head_up преди мен. После този фаил си го инклудваш където ползваш тези типове и си ок. Обърни внимание обаче на редовете:

#ifndef Generic_Type_Defs_h
#define __Generic_Type_Defs_h
#endif //__GENERIC_TYPE_DEFS_H_

Те са ти задължителни!

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


Пет Сеп 24, 2010 10:04 am
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 2:23 pm
Мнения: 3714
Местоположение: Високо в планината
Мнение Ново 20
Направих един общ .h файл с всички променливи, но като го инклудна на няколко места дава грешката "multiple definition of...".
После преместих променливите в друг файл var.c, а в vars.h ги зададох като extern. Въпреки това проблема с "multiple definition of..." си остава.
Ако пък махна дефиницията на променливите от хедъра (т.е. вместо extern int а=10 напиша extern int a), излиза съобщениято за грешка "undefined reference to..."
What could i do? (Както пее Махалия Джаксън :))

_________________
Хайде де!


Пет Сеп 24, 2010 12:07 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 20 мнения ]  Отиди на страница 1, 2  Следваща

Кой е на линия

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


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

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