2009年12月1日 星期二

[Programming C] bit field/ bit-accessing

之前使用過CC5X,裡頭有一個功能非常好用,就是可以針對記憶體(RAM)的位元個別設定,例如
char a
a.0=1; //設定變數a的bit0為1
也可以個別做位元判斷,例如
if(a.0==1)
.....

這對MCU有限的RAM可以有效的利用,但到了MPLAB C18 C Compiler卻無法直接這樣使用,經筆者測試可以透過宣告的方式來使用,例如:





1 typedef struct char
2 {
3 unsigned bit0:1;
4 unsigned bit1:1;
5 unsigned bit2:1;
6 unsigned bit3:1;
7 unsigned bit4:1;
8 unsigned bit5:1;
9 unsigned bit6:1;
10 unsigned bit7:1;
11 }uns8_bits;
12
13 union
14 {
15 uns8_bits t_temp;
16 char char_t_temp;
17 }union_flag;
18
19
20 #define bit_12_pm union_flag.t_temp.bit0
21 #define bit_1sec_action union_flag.t_temp.bit1
22 #define bit_count_sec_begin union_flag.t_temp.bit2



1~11 為結構宣告,並令uns8_bits為新的資料型態
13~17 為共用空間的使用,目的是讓uns8_bits資料型態宣告的資料變數,能與char資料型態其他變數做資料的交換,例如
char a;
a=1;
union_flag.char_t_temp = a; //相當於 union_flag.t_temp.bit0=1 或者 bit_12_pm=1;
20~22 為了簡化輸入一長串英文字母的麻煩,又可讓整個程式看起來簡單明瞭有意義

以上為使用bit的相關設定,希望對各位有幫助!!

////////////////////////////////////
[結構化的資料型態二]

位元欄(Bit Field)是C語言中一個很特別資料型態

2.位元欄


位元欄(Bit Field)是C語言中一個很特別資料型態 ,在很多他之前的語言都沒有,之後的則有抄襲這一個型態的。使用位元欄有很多好處,一、可以節省記憶體空間,布林運算值直接取用,相類似的資料放在同一組字(Word)中,不用一一佔不同字的空間。二、與硬體觀念中的旗標可以輕鬆配合使用。三、有益於與系統硬體,與周邊硬體直接做暫存器位元的傳輸與指定。

好用強大的功能通常都會伴隨著更強大的限制使用與更多的注意事項,底下我們將一一講解位元欄的規則:

位元欄的使用

位元欄是以結構為基礎的資料型態。他的表示方法,在結構元素後面加一個冒號:以及一個正整數的欄位長度。例如下面的範例,我們將看到一個ALU(Arithmetic Logic Unit 計算邏輯處理單元)的相關旗標,每一個旗標都佔一個位元的空間。zero代表某一輸入有零,overflow代表溢位,underflow代表不足位,carryout代表有進位。
struct bitfield
{
unsigned zero:1;
unsigned overflow:1;
unsigned underflow:1;
unsigned carryout:1;
}
位元欄中的資料多半以unsigned型態來宣告,你也可以使用signed或是int的方式來宣告,即使如此一般的編譯器也都換自動將位元欄的資料型態轉換成unsigned的型態。為了程式的相通性,最好還是以unsigned的寫法。
位元欄一樣會佔據適當的記憶體空間,至於佔用的順序,是由表示方法的由上到下,對應到記憶體的高位元到低位元;或者是由低位元到高位元,這必須由系統製造商決定。x86的相容PC與工作站剛好相反。怎麼擺其實不重要,重要的是千萬不要依賴他的順序
位元欄的大小有沒有限制?有的。一般以一個字為限,一般字都是由兩個位元組所構成,共十六位元。
一起宣告的位元欄,並不一定是連續的記憶體空間。當前面的位元欄使用剩的空間不足以放下這一組位元欄,則這一組位元欄會放在下一組字中,而不會讓該位元欄跨越字。
位元欄沒有相對應的指標型態,所以也無法以陣列表示。
位元欄可以與其他型態的資料共同運算,這時位元欄的資料型態會先轉換成整數型態,以整數為基準再作適當調整。
同一結構中,即使有位元欄還是可以有其他的資料型態。

要瞭解一個東西有多好用,就是拿起來用用看就知道。底下我們看一個簡單的例子,這一個程式模擬兩個數做加法的動作(參看邏輯設計與Verilog寫作手冊)。

/*
Bitwise addition . Action as 8-bits a ripple adder
bitadd.c
*/
#include

#include

main()
{
int i, j, k;
struct unit
{
unsigned a0:1;
unsigned a1:1;
unsigned a2:1;
unsigned a3:1;
unsigned a4:1;
unsigned a5:1;
unsigned a6:1;
unsigned a7:1;
}input1, input2, sum;
printf ("Please input addend and augend ranged from 1 ~ 255\n");
printf ("First, input addend = ");
scanf ("%d", &i);
while(i<0> pow(2.0, 8.0))
{
printf ("Wrong input value range. Again, input addend = ");
scanf ("%d", &i);
}

input1.a0=i%2;k=(i-input1.a0)/2;
input1.a1=k%2;k=(k-input1.a1)/2;
input1.a2=k%2;k=(k-input1.a2)/2;
input1.a3=k%2;k=(k-input1.a3)/2;
input1.a4=k%2;k=(k-input1.a4)/2;
input1.a5=k%2;k=(k-input1.a5)/2;
input1.a6=k%2;k=(k-input1.a6)/2;
input1.a7=k%2;k=(k-input1.a7)/2;
printf("%3d --> %d%d%d%d%d%d%d%d\n", i, input1.a7, input1.a6, input1.a5 \
, input1.a4, input1.a3, input1.a2, input1.a1, input1.a0);
j=i;
printf ("Second, input augend = ");
scanf ("%d", &i);
while(i<0> pow(2.0, 8.0))
{
printf ("Wrong input value range. Again, input addend = ");
scanf ("%d", &i);
}

input2.a0=i%2;k=(i-input2.a0)/2;
input2.a1=k%2;k=(k-input2.a1)/2;
input2.a2=k%2;k=(k-input2.a2)/2;
input2.a3=k%2;k=(k-input2.a3)/2;
input2.a4=k%2;k=(k-input2.a4)/2;
input2.a5=k%2;k=(k-input2.a5)/2;
input2.a6=k%2;k=(k-input2.a6)/2;
input2.a7=k%2;k=(k-input2.a7)/2;
printf("%3d --> %d%d%d%d%d%d%d%d\n", i, input2.a7, input2.a6, input2.a5 \
, input2.a4, input2.a3, input2.a2, input2.a1, input2.a0);
/* addition */
sum.a0=input1.a0^input2.a0^0;k=input1.a0&input2.a0;
sum.a1=input1.a1^input2.a1^k;k=(input1.a1&input2.a1)|(k&input1.a1)|(k&input2.a1);
sum.a2=input1.a2^input2.a2^k;k=(input1.a2&input2.a2)|(k&input1.a2)|(k&input2.a2);
sum.a3=input1.a3^input2.a3^k;k=(input1.a3&input2.a3)|(k&input1.a3)|(k&input2.a3);
sum.a4=input1.a4^input2.a4^k;k=(input1.a4&input2.a4)|(k&input1.a4)|(k&input2.a4);
sum.a5=input1.a5^input2.a5^k;k=(input1.a5&input2.a5)|(k&input1.a5)|(k&input2.a5);
sum.a6=input1.a6^input2.a6^k;k=(input1.a6&input2.a6)|(k&input1.a6)|(k&input2.a6);
sum.a7=input1.a7^input2.a7^k;k=(input1.a7&input2.a7)|(k&input1.a7)|(k&input2.a7);
printf("%3d --> %d%d%d%d%d%d%d%d\tcarry =%d\n", i+j, sum.a7, sum.a6, sum.a5\
, sum.a4, sum.a3, sum.a2, sum.a1, sum.a0, k);

}

程式執行結果如下
Please input addend and augend ranged from 1 ~ 255
First, input addend = 127
127 --> 01111111
Second, input augend = 100
100 --> 01100100
227 --> 11100011 carry =0
Please input addend and augend ranged from 1 ~ 255
First, input addend = 200
200 --> 11001000
Second, input augend = 223
223 --> 11011111
423 --> 10100111 carry =1


3.共用


共用(Union)型態可以讓多種不同型態的變數共用同樣的記憶體空間。使用方法如下
union name
{
datatype name1;
....
datatype namen;
}
n個元素共用同樣的記憶體空間,記憶體空間的大小由佔空間最大的資料型態決定。他的型態與結構相同,所以結構有的他都有。他有:一、有指標。二、每一個元素都可以使用,但是同一時間只有一個是有效的。三、共用型態內的資料型態,每一種你學過的都可以用。

底下來一個例子看看,怎樣利用這一個結構來取出字元的二進位值。
/*
transfer the char to binary form
union.c
*/
#include
#include

main()
{
char c;
struct unit
{
unsigned a0:1;
unsigned a1:1;
unsigned a2:1;
unsigned a3:1;
unsigned a4:1;
unsigned a5:1;
unsigned a6:1;
unsigned a7:1;
};

union bits
{
char word;
struct unit bit;
}digit;

printf ("Please input a character = ");
c= getchar();
while(!isalpha(c))
{
fflush(stdin); /* clean Standard input buffer */
printf ("Wrong input value range. Again, character = ");
c=getchar();
}
digit.word=c;
printf("\n%c=%3d --> %d%d%d%d%d%d%d%d\n", c, c,digit.bit.a7, digit.bit.a6,\
digit.bit.a5, digit.bit.a4, digit.bit.a3, digit.bit.a2, \
digit.bit.a1, digit.bit.a0);

}

程式執行結果如下
Wrong input value range. Again, character = 9
Wrong input value range. Again, character = 0
Wrong input value range. Again, character = =
Wrong input value range. Again, character = -
Wrong input value range. Again, character = f
f=102 --> 01100110



////////////////////////////////////

[How to initial bit-field for the data-type declaration..]
Especially checking for color[8] array

struct
{
unsigned char red :1;
unsigned char orange :1;
unsigned char yellow :1;
unsigned char green :1;
unsigned char blue :1;
unsigned char violett :1;
}color[8]={
1,0,1,0,1,0,
0,1,0,1,0,1,
0,0,0,0,0,0,
0,0,0,0,0,0,
1,1,1,1,1,1,
1,1,1,1,1,1,
};
//***************************************************************************
int main (void)
{
//***************************************************************************
unsigned int i;
PLL_init();
RS232_init(115200);
printf("Bitfield array in C\n");
for(i=0;i<8;i++)
{
color[i].orange = ~color[i].red;//"~" or "!" which i correct?
color[i].yellow = !color[i].red;
}
for(i=0;i<8;i++)
{
printf("%u ",color[i].red);
printf("%u ",color[i].orange);
printf("%u ",color[i].yellow);
printf("%u ",color[i].green);
printf("%u ",color[i].blue);
printf("%u ",color[i].violett);
printf("\n");
}
while(1){}
}



////////////////////////////////////

Take the Dev-C++ (Win32Intel) compiler do the following testing..

Herewith the below whole code in "main.C":

===========================
#include
#include

#define FALSE 0
#define TRUE 1

typedef struct
{
unsigned char : 7;
unsigned char bIsDataChange: 1;
} _MY_APP_NET_DATA_FLAG;


typedef struct
{
unsigned char : 4;
unsigned char bIsEEPROM: 1;
unsigned char bIsState: 1;
unsigned char bIsNumeric: 1;
unsigned char bIsStringBuf: 1;
} _MY_APP_NET_DATA_TYPE;


_MY_APP_NET_DATA_TYPE MyAppNetValueType[3] = {
{0, 1, 0, 0}, //0: EEPROM/x, IsState/v, IsNumeric/x, IsStringBuf/x
{1, 1, 0, 0}, //1: EEPROM/v, IsState/v, IsNumeric/x, IsStringBuf/x
{1, 0, 0, 1} //2: EEPROM/v, IsState/x, IsNumeric/x, IsStringBuf/v
}
;


int main(int argc, char *argv[])
{

printf("MyAppNetValueType[0]: %d (%c) \r\n", MyAppNetValueType[0], MyAppNetValueType[0]);
printf("MyAppNetValueType[1]: %d (%c) \r\n", MyAppNetValueType[1], MyAppNetValueType[1]);
printf("MyAppNetValueType[2]: %d (%c) \r\n", MyAppNetValueType[2], MyAppNetValueType[2]);

if(1 == MyAppNetValueType[1].bIsState)
printf("MyAppNetValueType[1] has state-type \r\n");


if(FALSE == MyAppNetValueType[2].bIsState)
printf("MyAppNetValueType[2] has no state-type \r\n");



system("PAUSE");
return 0;
}
===========================

(that's ALL)
////////////////////////////////////

沒有留言: