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

MCC18 constants declaration
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=4477
Страница 1 от 2

Автор:  [ Пет Юли 06, 2007 9:20 pm ]
Заглавие:  MCC18 constants declaration

Подразни ме следната недомислица в MCC18 3.12 на Microchip:
Код:
const float Pi = 22.0/7.0;
const float Pi2 = Pi * Pi;

const float cf_var1 = 68.0;
const float cf_var2 = 12.0;
const float cf_var3 = ( cf_var2 / ( cf_var1 + cf_var2 ) );

void main(void) {
float f_var;
   while( 1 ) {
      f_var = cf_var3 / Pi2;
   }
}


Горния код не иска да се компилира, плюе се следното съобщение:

Цитат:
Error [1214] constant expression expected in initializer


Обаче, ако се напише така:
Код:
void main(void) {
const float Pi = 22/7;
const float Pi2 = Pi * Pi;

const float cf_var1 = 68.0;
const float cf_var2 = 12.0;
const float cf_var3 = ( cf_var2 / ( cf_var1 + cf_var2 ) );

float f_var;
   while( 1 ) {
      f_var = cf_var3 / Pi2;
   }
}

се компилира, само че излиза, че трябва константите да ги декларирам във всяка подпрограма, където ще се използват.

Някой да е заобикалял този проблем ? С #define също не става, иска се непременно числена стойност.

Автор:  HCL [ Пет Юли 06, 2007 10:33 pm ]
Заглавие: 

Що не ги сметнеш е елката :D

Автор:  [ Пет Юли 06, 2007 10:42 pm ]
Заглавие: 

HCL написа:
Що не ги сметнеш е елката :D

Мразим да смятаме :D Кода е примерен, ако са по сложни изразите и се налага да правиш промени в коефициентите става една ...

Автор:  HCL [ Пет Юли 06, 2007 11:31 pm ]
Заглавие: 

само за информация, в Keil проблемьт го няма.

Автор:  [ Пет Юли 06, 2007 11:41 pm ]
Заглавие: 

HCL написа:
само за информация, в Keil проблемьт го няма.

Това си е бъг в MCC18 :D , няма как да го има и при Keil.

Автор:  Gogo [ Съб Юли 07, 2007 12:08 am ]
Заглавие: 

Е така става:
Код:
const float Pi, cf_var1, cf_var2;

#define Pi  22.0/7.0
const float Pi2 = (Pi * Pi);

#define cf_var1  68.0
#define cf_var2  12.0
const float cf_var3 = ( cf_var2 / ( cf_var1 + cf_var2 ) );

Ако Pi, cf_var1 и cf_var2 няма да ги ползваш в кода, може да не ги дефинираш като "const float"

Автор:  Цецо [ Съб Юли 07, 2007 3:05 pm ]
Заглавие: 

Ами аз по принцип на всичко де що е 8-16 бита константите гледам да ги правя с #define. От опит знам, че голямо количество от компилаторите за "малки" контролери се посират в такива ситуации.

Автор:  ps66 [ Съб Юли 07, 2007 8:22 pm ]
Заглавие: 

никога в никой компилатор не съм ползвал "const" за деклариране на константи - само #define

това не виждам причина да не работи:
Цитат:
#define Pi ((float)(22.0/7.0))
#define Pi2 ((float)(Pi * Pi))

#define cf_var1 ((float)68.0)
#define cf_var2 ((float)12.0)
#define cf_var3 ((float)cf_var2/(cf_var1+cf_var2))


по-принцип "const" може да има различни интерпретации/значения на различните компилатори ...

Автор:  [ Съб Юли 07, 2007 11:56 pm ]
Заглавие: 

Проблема е ясен: на дадено място в програмата няма проблеми с изчисляването на константен израз, на друго място има. #define не ги харесвам, защото често се бъркаш с какъв точно тип данни работиш. Лошото е, че и с #define не може да изчисли израза, ако декларирам константа-променлива на глобално ниво в рамките на един файл. Много малко съм използвал MCC18, мислех си, че е добър, но се оказа, че има много гювеч по него.

В тоя ред мисли, да задам още една гатанка ( за мен ): как мога, в Ц програма за МЦЦ18, да си декларирам unsigned int променлива, която променлива да разположа на адреса на ADRESH:ADRESL ? Целта ми е да имам максимално бърз достъп до тези клетки, без да ми се налага да правя от два 8-битови регистъра една 16-битова unsigned int променлива [ unsigned int res16 = ((unsigned int)(ADRESH<<8 )) | ADRESL ]

Автор:  ps66 [ Нед Юли 08, 2007 5:39 am ]
Заглавие: 

¶ написа:
Проблема е ясен: на дадено място в програмата няма проблеми с изчисляването на константен израз, на друго място има. #define не ги харесвам, защото често се бъркаш с какъв точно тип данни работиш. Лошото е, че и с #define не може да изчисли израза, ако декларирам константа-променлива на глобално ниво в рамките на един файл. Много малко съм използвал MCC18, мислех си, че е добър, но се оказа, че има много гювеч по него.

В тоя ред мисли, да задам още една гатанка ( за мен ): как мога, в Ц програма за МЦЦ18, да си декларирам unsigned int променлива, която променлива да разположа на адреса на ADRESH:ADRESL ? Целта ми е да имам максимално бърз достъп до тези клетки, без да ми се налага да правя от два 8-битови регистъра една 16-битова unsigned int променлива [ unsigned int res16 = ((unsigned int)(ADRESH<<8 )) | ADRESL ]


аз в #define винаги указвам типа който да се връща, и всичко е в () за всеки случай ... при смятането на изрази винаги указвам типа на резултата (за всеки случай :))

Цитат:
декларирам unsigned int променлива, която променлива да разположа на адреса на ADRESH:ADRESL


това много не го схванах ... може би искаш:

#define ADRES_PTR(adr) ((unsigned int *)(adr))
#define ADRES(adr) *ADRES_PTR(adr)

така с:

....
ADRES(12345) = 23456;
unsigned int temp = ADRES(12345); // temp == 23456

на адрес 12345 ще запишеш 23456 ... от това по-бързо не се сещам а и за компилатора би трябвало да е ясно какво да прави.
виж му asm кода за да прецениш !

PS: стига компилатора ти да поддържа макродефиниции :)

Автор:  [ Нед Юли 08, 2007 8:53 am ]
Заглавие: 

С указател е ясно, че може :-), но с указателя се харчи много време, да се заредят FSRxH:FSRxL, да се извлече единия байт, после да се извлече втория. Идеята е, на адреса на 2-те 8-битови клетки за резултата от АЦП-то да разположа моя 16-битова променлива, тя ще е с директен достъп, няма да се иска превключване на банки, операндите с които ще се използва тази 16-битова променлива са също с директетн достъп, така ще стане най-бърз кода, все едно, че е на асемблер :-) Има някакви директиви, с които се твърди, че може да се направят overlay променливи, обаче като задам такава променлива да бъде в адресното пространство 0xF00-0xFFF компилатора се сърди и не иска да я възприеме. Уж 18-та серия са разширен набор от инструкции, което теоретчно ги прави доста по-бързи от 16-та, но МЦЦ18 компилатора бълва толкова код, че бързодействието на 18-та серия се губи, става като на 16-та :-)
Ето например какво излиза, когато искам да извлека резултата от АЦП-то:
Код:
unsigned int res16;
   res16 = (((unsigned int)ADRESH)<<8) | ADRESL;
  0180    50C4     MOVF 0xfc4, W, ACCESS
  0182    6E02     MOVWF 0x2, ACCESS
  0184    C002     MOVFF 0x2, 0x3
  0186    F003     NOP
  0188    6A02     CLRF 0x2, ACCESS
  018A    50C3     MOVF 0xfc3, W, ACCESS
  018C    0100     MOVLB 0
  018E    1002     IORWF 0x2, W, ACCESS
  0190    6E00     MOVWF 0, ACCESS
  0192    C003     MOVFF 0x3, 0x1
  0194    F001     NOP
  0196    C000     MOVFF 0, 0xfde
  0198    FFDE     NOP
  019A    C001     MOVFF 0x1, 0xfdd
  019C    FFDD     NOP


Това на асемблер би станало така:
Код:
movff ADRESH, res16+1
movff ADRESL, res16+0


демек 4 цикъла на асемблер, 15 цикъла на Ц :-(

Автор:  ps66 [ Нед Юли 08, 2007 10:00 am ]
Заглавие: 

от пикове не разбирам :)

обаче не мога да разбера защо правиш сметките по-долу за res16 !?

Цитат:
unsigned int res16;
res16 = (((unsigned int)ADRESH)<<8) | ADRESL;


ако целта ти е:
Цитат:
movff ADRESH, res16+1
movff ADRESL, res16+0


по-добре би било:

*((unsigned char *)&res16) = ADRESL;
*(((unsigned char *)&res16)+1) = ADRESH;

не виждам причина от горните два реда компилатора да генерира нещо по-различно от
Цитат:
movff ADRESL, res16+0
movff ADRESH, res16+1

Автор:  Gogo [ Нед Юли 08, 2007 7:14 pm ]
Заглавие: 

За да стане това:
Код:
movff ADRESH, res16+1
movff ADRESL, res16+0

ползвам това:
Код:
rеs16 = (*(unsigned int *)(&ADRESL));


:partyman:

Автор:  Цецо [ Пон Юли 09, 2007 8:15 am ]
Заглавие: 

Аз тия работи ги правя така
Код:
#define highbyte(x) (*(((unsigned char *)&x)+1))
#define lowbyte(x) (*((unsigned char *)&x))


и после

Код:
unsigned int n;

lowbyte(n) = ADRESL;
highbyte(n) = ADRESH;


тва ме светна някой тука във форума и все него си ползвам. На пикльовския компилер си генерира точно каквото очаквам :)

Автор:  [ Пон Юли 09, 2007 5:23 pm ]
Заглавие: 

Бахтий компилатора, шибан :-)

Ето така става най-кратко:

Код:
typedef unsigned int uint16;
#pragma udata access my_access
near uint16 ui_Uout16;
#define ui_adres16 (*(uint16 *)(&ADRESL))
....
  ui_Uout16 += ui_adres16;
....


Но въпреки всичко си избълва 2 ненужни инструкции movlb, явно за да си върже гащите :-)

Код:
  045C    010F     MOVLB 0xf ; ненужна инструкция, ui_adres16 е в access bank
  045E    50C3     MOVF 0xfc3, W, ACCESS
  0460    2602     ADDWF 0x2, F, ACCESS
  0462    010F     MOVLB 0xf ; ненужна инструкция, ui_adres16 е в access bank
  0464    50C4     MOVF 0xfc4, W, ACCESS
  0466    2203     ADDWFC 0x3, F, ACCESS


Все пак е вече приемливо, 6 инструкции, срещу 20-тина инструкции преди това.
Мерси за идеите.

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