C hakkında ilginç bir problem

Başlatan yamak, 24 Ekim 2014, 13:43:57

yamak

Aşağıdakine benzer bi kodum var.

typedef struct 
{
  unsigned char NoError:1;
  unsigned char LowEnergy:1;
  unsigned char LowVoltage:1;
  unsigned char LowCurrent1:1;
  unsigned char LowCurrent2:1;
  unsigned char HighCurrent1:1;
  unsigned char HighCurrent2:1;
}BatteryError;

BatteryError* error;

int main(void)
{
     ControlBattery(error); 
     while(1)
    {
    }

}
void ControlBattery(BatteryError* error)
{
  unsigned char voltageLevel,currentLevel1,currentLevel2;
  float voltage,current1,current2;
  *(unsigned char*)error=0;
  voltageLevel=ReadVoltageLevel();
  currentLevel1=ReadCurrent1Level();
  currentLevel2=ReadCurrent2Level();
  if(ChargeState<=CHARGE_LEVEL_1)
    error->LowEnergy=1;
  if(voltageLevel<=LOW_VOLTAGE_LEVEL)       
    error->LowVoltage=1;                   
  if(currentLevel1<=LOW_CURRENT_LEVEL)
    error->LowCurrent1=1;
  else if(currentLevel1>=HIGH_CURRENT_LEVEL)
    error->HighCurrent1=1;
  if(currentLevel2<=LOW_CURRENT_LEVEL)
    error->LowCurrent2=1;
  else if(currentLevel2>=HIGH_CURRENT_LEVEL)
    error->HighCurrent2=1;
  voltage=((0.6/0xFFFFFF)*((float)Voltage)+VOLTAGE_OFFSET)*VOLT_COEFF;
  current1=(((0.6/0xFFFFFF)*((float)Current))*SHUNT)/16.0;
  current2=(((0.6/0xFFFFFF)*((float)Current))*SHUNT)/16.0;
  energyCounter+=((voltage*(current1+current2))*DELTATIME)/3600.0;
}


Bu durumda hiç bir şekilde LowCurrent1 ve LowEnergy bit leri set edemiyorum.Ama structure ı mı aşağıdaki gibi değiştirince her şey gayet güzel çalışıyo.
typedef struct 
{
  unsigned char LowEnergy:1;
  unsigned char LowVoltage:1;
  unsigned char NoError:1;
  unsigned char LowCurrent1:1;
  unsigned char LowCurrent2:1;
  unsigned char HighCurrent1:1;
  unsigned char HighCurrent2:1;
  unsigned char No:1;
}BatteryError;


Bu problemin mantıklı bi açıklaması var mı?Kullanıdığım ortam IAR mcu msp430. Biraz forumlarda falan araştırınca millet bit field kullanmayaın falan diyo.Yani önermiyolar.Ama bu zamana kadar bir çok kez kullandım ve hiç bir sorunla karşılaşmadım.Var mı bu sorunun bi cevabı?Yoksa compiler problemi mi?

CLR

Hatanın sebebini asm'li çıktısından bulabilirsin ama hatanın sebebi MSP430 16bitlik işlemci olduğundan structları 16bit tanımlamalıydın, bit field'leri 16bit tanımlarsan compiler hatası yoksa sorun düzelecektir. Veya illa 8bit kullanmak istiyorum diyorsan bu struct 'ın olduğu alanı pack(1) yaparakta çözebilirsin.
Knowledge and Experience are Power

mir_as82

hocam if içindeki tür uyumsuzluğu olabilir mi?

yamak

Alıntı yapılan: CLR - 24 Ekim 2014, 14:01:42
Hatanın sebebini asm'li çıktısından bulabilirsin ama hatanın sebebi MSP430 16bitlik işlemci olduğundan structları 16bit tanımlamalıydın, bit field'leri 16bit tanımlarsan compiler hatası yoksa sorun düzelecektir. Veya illa 8bit kullanmak istiyorum diyorsan bu struct 'ın olduğu alanı pack(1) yaparakta çözebilirsin.
Neden?Böyle bi kural mı var?MSP430 16 bitlik olabilir ama byte erişim için instruction'lara sahip.Hem başka bi yerde 8 bitlik field kullanıyorum.

mesaj birleştirme:: 24 Ekim 2014, 14:07:42

Alıntı yapılan: mir_as82 - 24 Ekim 2014, 14:02:10
hocam if içindeki tür uyumsuzluğu olabilir mi?
Hocam onu da denedim unsigned char a type cast yaptım yine de olmadı.

AsHeS

typedef struct 
{
  volatile unsigned char NoError:1;
  volatile unsigned char LowEnergy:1;
  volatile unsigned char LowVoltage:1;
  volatile unsigned char LowCurrent1:1;
  volatile unsigned char LowCurrent2:1;
  volatile unsigned char HighCurrent1:1;
  volatile unsigned char HighCurrent2:1;
}BatteryError;


Bunu bir deneyebilir misin ? Benzer bir problem benimde STM32'de başıma gelmişti volatile yapınca çözülmüştü.

mir_as82

  if(currentLevel1<=LOW_CURRENT_LEVEL) bu kodda LOW_CURREN_LEVEL in türü ne hocam? Eğer türü int ise sıkıntı olabilir.

yamak

#6
Alıntı yapılan: AsHeS - 24 Ekim 2014, 14:08:12
typedef struct 
{
  volatile unsigned char NoError:1;
  volatile unsigned char LowEnergy:1;
  volatile unsigned char LowVoltage:1;
  volatile unsigned char LowCurrent1:1;
  volatile unsigned char LowCurrent2:1;
  volatile unsigned char HighCurrent1:1;
  volatile unsigned char HighCurrent2:1;
}BatteryError;


Bunu bir deneyebilir misin ? Benzer bir problem benimde STM32'de başıma gelmişti volatile yapınca çözülmüştü.
Hocam olmadı yaw.
Alıntı yapılan: mir_as82 - 24 Ekim 2014, 14:14:20
  if(currentLevel1<=LOW_CURRENT_LEVEL) bu kodda LOW_CURREN_LEVEL in türü ne hocam? Eğer türü int ise sıkıntı olabilir.
Hocam onlar define edilmiş sabitler.Yani türleri int.Fakat şöyle bi sıkıntı debug modda o satırın çalıştığını görüyorum.

CLR

#7
Alıntı yapılan: yamak - 24 Ekim 2014, 14:07:05
Neden?Böyle bi kural mı var?MSP430 16 bitlik olabilir ama byte erişim için instruction'lara sahip.Hem başka bi yerde 8 bitlik field kullanıyorum.

IAR'da çok kez bi field kullandım cortem3'lerde ama ya hep u32 yaptım yada packed alanda u8/u16 kullandım  o nedenle senin sorununla karşılaşmadım diye söylüyorum.
Mesela senin bakış açınla cortem m3'te de u8 erişimi var ama u8 olarak belirtmezsen u32'lik alana yerleştiriyor, demekki senin compilerda u8'lik değil u16'lık alana yerleştirebilir ve bit kayması oluşabilir.
Benimkisi sadece öneri u8'leri u16 yapıp test edeceksin sadece.
Knowledge and Experience are Power

mir_as82

Eğer define edilmiş sembolik sabit negatif bir değer değilse sıkıntı olmaz.

justice_for_all

C18 de bit tanımlaması yaparken unsigned diye yapılıyor bide oyle dene istersen.

unsigned NoError:1;


şeklinde

Deneyip de başaramayanları değil, yalnızca denemeye bile kalkışmayanları yargıla.   Gökhan Arslanbay

hasankara

#10
tam ben yazacaktım evet bende böyle kullanıyorum
unsigned NoError:1;

hatta 1 bit olduğunu belirtmeye de gerek kalmıyor.
unsigned NoError;


edit sebebi: yanlış bilgi paylaşımı.

yamak

#11
Alıntı yapılan: CLR - 24 Ekim 2014, 14:27:39
IAR'da çok kez bi field kullandım cortem3'lerde ama ya hep u32 yaptım yada packed alanda u8/u16 kullandım  o nedenle senin sorununla karşılaşmadım diye söylüyorum.
Mesela senin bakış açınla cortem m3'te de u8 erişimi var ama u8 olarak belirtmezsen u32'lik alana yerleştiriyor, demekki senin compilerda u8'lik değil u16'lık alana yerleştirebilir ve bit kayması oluşabilir.
Benimkisi sadece öneri u8'leri u16 yapıp test edeceksin.
Yapıp test ettim olmadı."Mesela senin bakış açınla cortem m3'te de u8 erişimi var ama u8 olarak belirtmezsen u32'lik alana yerleştiriyor" bu cümle ile de ne demek istediğini anlamadım.Bir de alligment ı compiler ın değişkenleri belleğin 4 katı ya da 16 bitlik sistemlerde 2 nin katı olan bölgelere yerleştirmesini istemediğimiz durumlarda kullanırız.Benim sorunumun alligment ile olan bağlantısını anlayamadım.Ayıca sen dedikten sonra cortex m4 te hiç alligment yapmadan unsigned char türünde bit field tanımladım ve bütün bitlere güzel güzel eriştim.

mesaj birleştirme:: 24 Ekim 2014, 14:48:20

Alıntı yapılan: justice_for_all - 24 Ekim 2014, 14:33:58
C18 de bit tanımlaması yaparken unsigned diye yapılıyor bide oyle dene istersen.

unsigned NoError:1;


şeklinde
Hocam unsigned dersem unsigned int olarak kabul eder.
Alıntı yapılan: hasankara - 24 Ekim 2014, 14:37:07
hatta 1 bit olduğunu belirtmeye de gerek kalmıyor.
unsigned NoError;

Nasıl yani 1 bit olduğunuz belirtmeye gerek kalmıyor.

mir_as82

siz global alanda bir pointer tanımlamışsınız(statik) ve hiç bir nesne adresi vermeden, o pointeri main içinde fonksiyonunuza parametre olarak geçmişsiniz. Yani NULL pointeri parametre olarak geçmişsiniz. Sorun buradan kaynaklanabilir mi?

CLR

İşlemcide 16 bit ama 8 biti destekleyen asm komutları var dedin diye söyledim. Aynı durum cortex m3'te de var çünkü. Byte/HWord alligment bahsetmiyorum bit alligment bazında bahsediyorum. Belki 16bit tanımlamadığın için yanlış yerleştiriyor olabilir dedim. 16bit tanımladıktan sonra hala set/reset etmemişse muhtemelen compiler sorunu görünüyor.

8 bitlik registeri 16/32bitlik işlemcide Packed etmezsen her defasında doğru çalışcağını garanti edemezsin. 
Knowledge and Experience are Power

yamak

#14
Alıntı yapılan: mir_as82 - 24 Ekim 2014, 14:54:14
siz global alanda bir pointer tanımlamışsınız(statik) ve hiç bir nesne adresi vermeden, o pointeri main içinde fonksiyonunuza parametre olarak geçmişsiniz. Yani NULL pointeri parametre olarak geçmişsiniz. Sorun buradan kaynaklanabilir mi?
Hocam normalde bu dediğiniz doğru ama benim asıl kodumda o değişken global değil.Ama bu gözümden kaçmış.Normalde pointer local de olsa global de olsa initialize etmek gerekir.Bir de ben bu soruyu sorarken asıl sormak istediğim kod normalde çalışmazken struct içindeki değişkenlerin yerini değiştirdiğimde neden çalışıyor olması.

Edit:Hatta şu an denedim sorun ortadan kalktı.
Ama en azından bu saçma hatayı görememem sayesinde şunu öğrendim:Msp430 forumlarındaki guru'lara göre bit field hiç önerilen bir şey değilmiş.