2007年10月23日

ビットフィールドアクセスの共通化

汎用ポートのアクセスに、ビットフィールドを利用していたんだけど
ポートの番号とビットの番号(意味わかるかなあ?)を指定して
目的のデータビットにアクセスする処理を作ることになって。

(個人的には(せっかく?)定義されてるビットフィールドを
 無駄にする気がしてしかたがないのだけれど。)



ーー(省略)ーー
struct st_p1 {
  union {
  unsigned char BYTE;
struct {
  unsigned char B7:1;
unsigned char B6:1;
unsigned char B5:1;
unsigned char B4:1;
unsigned char B3:1;
unsigned char B2:1;
unsigned char B1:1;
unsigned char B0:1;
} BIT;
}DR;
}
ーー(省略)ーー
#define P1(*(volatile struct st_p1 *)ポートのアドレス);
#define P2(*(volatile struct st_p2 *)ポートのアドレス);
#define P3(*(volatile struct st_p3 *)ポートのアドレス);

ーー(省略)ーー


↑みたいな構造体を使ってアクセスしてたのを、
ポート番号、ビット番号を指定して共通の関数で
アクセスするように変更するんだけど・・・

P1.DR.BIT.B1= ON、をSetPort(PORT1,BIT1,ON);こんな感じ?

問題はどうやって実現しようかなあ、というところで。

//const unsigned char *PortTbl[ ] = {
※コメントで間違いを指摘していただきましたが、よく考えたらconstつけちゃうと、参照先に書き込みができないですね?・・・orz
unsigned char * const PortTbl[ ] = {

&(P1.DR.BYTE),
&(P2.DR.BYTE),
&(P3.DR.BYTE),
 ・
 ・
};

const unsigned char BitCheck[ 8 ] = {
0x01,
0x02,
0x04,
0x08,
0x10,
0x20,
0x40,
0x80
};

void SetPort( UI_8 port,UI_8 bit, B_8 data ){
UI_8 temp;
ーー(省略)ーー
 temp = *PortTbl[port];
 temp |= BitCheck[bit];
 *PortTbl[port] = temp;
ーー(省略)ーー
 return;
}

こんな感じのを考えてみたんだけど、どうだろう?
もっといい手があれば知りたいデス。

コメント(9)

まず、

>const unsigned char PortTbl[]={

これ、宣言間違えてますよね。

unsigned char * const PortTbl[]={

かな?
// const unsigned char * PortTbl[]={
// は誤り。

>temp = *PortTbl[port];
>temp |= BitCheck[bit];
>*PortTbl[port] = temp;

仮引数dataが使われていないようですがいいんでしょうか。
あとこれだとONにはできてもOFFにできないような…?


良い案が浮かびません(^^;

おはようございます。

コメントどうもです。
>>const unsigned char PortTbl[]={
>これ、宣言間違えてますよね。

そうですね。間違えてるwww

>仮引数dataが使われていないようですがいいんでしょうか。
>あとこれだとONにはできてもOFFにできないような…?

えーと、その辺は「ーー(省略)ーー」がミソでw
ホントは、
 temp = *PortTbl[port];
 if(data == ON){
 //ONの時
  temp |= BitCheck[bit];
 }
 else{
 //ON以外の時
 temp |= (~BitCheck[bit]);
 }
 *PortTbl[port] = temp;

んー・・こんな感じだったかな?

>//ON以外の時
>temp |= (~BitCheck[bit]);
これ正しくは
temp &= (~BitCheck[bit]);
ですかね。


私ならテーブル使わずに

if(data==ON){
temp |= (UI_8)(1u << bit);
}else{
temp &= ~(UI_8)(1u << bit);
}

同じ記述が2カ所にあるのが気に入らないですがこんな感じでしょうか。
# テーブル使った方が早いのかな?

>temp &= (~BitCheck[bit]);

デスネ。昨日、別な人からも指摘されましたw

処理速度についてはよくわかりません~。
が、どっかでビットシフトだとステップ数が少し多いとか
聞いたような・・・

>同じ記述が2カ所にある
自分もあまり好きじゃないです(^-^;

>const unsigned char *PortTbl[ ] = {

NGです。

>constつけちゃうと、参照先に書き込みができないですね?

そうです。
ポインタの参照先は非constで
ポインタのテーブル自体はconstであるべきです。
つまりconstの位置が問題です。ですから上で

>unsigned char * const PortTbl[]={
>かな?
>// const unsigned char * PortTbl[]={
>// は誤り。

と書いたんですが…(^^;

>ポインタの参照先は非constで
>ポインタのテーブル自体はconstであるべきです。
>つまりconstの位置が問題です。

んー、それなんですが自分もそれを期待してたんですけどね?(まあ、間違えてますけど)
なんか、Tblって言ってるけど普通の配列なので
どっちについてても効果が一緒?みたいな話が出てて。
今のところ単純な静的変数の配列にしてあります(^^;)

ターゲットマイコン用のコンパイラが届いてから試そうかな、と思ってたんですけど・・あー、VCとか使ってやってみればいいのか。

>どっちについてても効果が一緒?みたいな話が出てて。

そんなわけないです。

試しにVS2005で以下のコードを実行させてみましたが、
明らかに結果が異なります。
組込みの世界ではROM/RAMリソースの割り当てにも関わってくるので重要な事だと思います。

void Hoge(void)
{
unsigned char a, b, c;
const unsigned char * p1[]={&a,&b,&c};
unsigned char * const p2[]={&a,&b,&c};

p1[0] = &b; // OK
*p1[0] = 0; // コンパイルエラー

p2[0] = &b; // コンパイルエラー
*p2[0] = 0; // OK
}

コメントどうもです。
(私も実際に試してみました、VC6ですが。)

>>どっちについてても効果が一緒?
なのは↓みたいな場合のことを言っていたようです。

const unsigned int *p;
unsigned int const *p;

これだと確かに同じですよね。

>これだと確かに同じですよね。

ですね。

const unsigned int *p と宣言してあったら
「constなunsigned int型変数」への「ポインタp」であり
unsigned int const *pは
「unsigned int型のconst変数」への「ポインタp」って感じですかね。(同じ意味)
unsigned int * const p と宣言してあったら
「unsigned int変数」への「constポインタp」という意味ですので、
左から順番に読んで「*」を「~への」と訳すと割と判りやすいかもです(^^)

…そうでもないかも?w

コメントする