ちょっと面白い作法を見かけたので、たまにはC言語のことも書こうと思う。
もちろん MPLAB X XC8、XC16、XC32 におけるC言語での話でC言語全般に通じる話なのかは知らない。
良く知らないけど、ただC言語だと思ってたら、実はいろんなのがあるらしい。
PICとかで使うCはその道のプロに言わせると亜種というか邪道というか、そんなものらしい。
そんなニュアンスな言い方をする方が通ぶって聞こえてかっこいいというだけのポーズなのか、確かにそうなのかは分らない。
いずれにしても超初心者のただの戯言、軽く流すか、お暇ならコメント欄にてアドバイスをいただけると幸いではある。
ともあれ、へえ、思ったのはこんな書き方。
1 2 3 |
#define _BV(x) (1<<x) #define LCD_RS 10 LATB&=~_BV(LCD_RS); |
RB10 を LCD の RS信号用に使っている場合に RS = Low にしたい場合の書き方だ。
まず、#define A B は、以後に登場する A を B に書き換えるという便利なことをやってくれる。
A の部分がプログラム中に複数あって、かつ変更する可能性が考えられる場合に、修正が1ヶ所で済んで便利だ。
なので、上の3行は結局は
LATB&=~(1<<10);
となる。
1<<10 は
0b0000001000000000
なので、~(1<<10) は
0b1111110111111111
となって、これと LATB との AND を取るので、結局「LATB の 10ビット目だけを書き換えて 0 にする」が実現できる。
ならば、
LATBbits.LATB10 = 1;
で良さそうなものだが、上に書いたとおり、これがプログラム中に何ヶ所もあるときには面倒だし、その数だけ間違える可能性が増す。
さらに、ほお、と思ってしばらく眺めてたのがこんな書き方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#define _BV(x) #define LCD_D4 12 #define LCD_D5 13 #define LCD_D6 14 #define LCD_D7 15 unsigned char cmd; unsigned short wk; wk = LATB; wk &= ~(_BV(LCD_D7) | _BV(LCD_D6) | _BV(LCD_D5) | _BV(LCD_D4)); wk |= ((cmd & 0x1)==0x1) ? _BV(LCD_D4):0; wk |= ((cmd & 0x2)==0x2) ? _BV(LCD_D5):0; wk |= ((cmd & 0x4)==0x4) ? _BV(LCD_D6):0; wk |= ((cmd & 0x8)==0x8) ? _BV(LCD_D7):0; LATB = wk; |
これも、ポイントは書き換える部分が最初の4行の#defineだけで済むというメリットの追求だが、とりあえず分りやすくすると、
1 2 3 4 5 6 7 8 9 |
unsigned char cmd; unsigned short wk; wk = LATB; wk &= ~((1<<15) | (1<<14) | (1<<13) | (1<<12); wk |= ((cmd & 0x1)==0x1) ? (1<<12):0; wk |= ((cmd & 0x2)==0x2) ? (1<<13):0; wk |= ((cmd & 0x4)==0x4) ? (1<<14):0; wk |= ((cmd & 0x8)==0x8) ? (1<<15):0; LATB = wk; |
となる。 ここで、私には初見だったのが、 a ? b : c という書き方で、「a が真なら b を実行、a が偽なら c を実行。」という「条件演算子(Ternary Conditional)」というものだそうだ。 初めて見るとギョッとするが、知ってしまえば別に何でもない書き方だ。 結果、どうなるかというと、cmd の下位4ビットが LATB の12~15ビットに代入される。 うなったのは、このやり方なら LATBでの配置が連続でなくても容易に対応できることだ。 同じことを私が書くとこうなって、
1 2 3 4 5 6 |
unsigned char cmd; unsigned short wk; unsigned short chardata; chardata = cmd; wk = LATB & 0x0FFF; LATB = ((chardata << 12) + wk); |
LATB を飛び飛びに使うという場合には別のコードを書かなければ対応できない。
Tweet