HI-TECH software PICC compiler
PICのアセンブラは一通り見てみたので、本格的なプログラム開発というとやはりCを使いたいと思う。最近MPLAB IDEにはHI-TECH softwareのPICCコンパイラ(V9.60あたりから正式にはHI-TECH C PRO for the PIC10/12/16 MCU Familyに変わったようだ)が附属している。ネットを見る限りコンパイラとしての評判も良いようです。
Lite modeでは制限があるが、私の書くプログラムの規模であれば問題はなさそう。
というわけで、しばらくはPICCを使って開発を行なってみようと思うが幾つか気づいた点があったので御参考まで。
MPLAB SIMでは変数の値やアドレスが見れますが、Cで開発するとこれがみれません。
少々面倒ですが、コンパイルした時に生成されるmapファイルで変数のポインタを確認しておき、これをMPLAB SIMでWatch対象とすることでワークアラウンドになります。
mapファイルのSymbol Tableでは_<関数名>_<変数名>という命名規則になっているようです。例えば、次の例ではソース中で
void Puts_LCD4(char *ptr)
と宣言されています。
Symbol Table
??_Puts_LCD4 fnauto0 0012 ??_main fnauto0 000C
?_Puts_LCD4 fnauto0 0012 ?_main fnauto0 000C
:
:
_PS1 (abs) 0409 _PS2 (abs) 040A
_PSA (abs) 040B _Puts_LCD4 text9 03E6
_Puts_LCD4_ptr fnauto0 0012 _RA0 (abs) 0028
:
:
文字列を宣言する際に、関数の頭で配列に入れずに、文字列をダブルクォーテーションで括って直接引数として渡すと、メモリ上に文字列が格納されずにNULLが渡されるようだ。
例えば、次のようなプログラムは動かない。
void Puts_LCD4(char *ptr){
while(*ptr){
PORTB=*ptr++;
}
}
void main(void){
GIE=0;
TRISB=0x0;
Puts_LCD4("Test");
}
このようにすると問題無く動作する。
void main(void){
char buf[]="Test";
GIE=0;
TRISB=0x0;
Puts_LCD4(buf);
}
HI-TECH softwareに聞いてみたところ、これは9.60PL4で修正されているバグだそうです。私はPL3を使っていたのですが、PL5にしてみたところ動作するようになりました。
PICはメモリが少ないため、bit型がサポートされているが、これは引数として渡すことは出来ない模様。次のようなコードをコンパイルすると、エラーになります。
function(bit a){
:
}
main(){
function(0);
}
内部動作を考えると仕方ないかなという気もしますが。
MPLAB IDEの'Disassembly list'画面で最終行画表示されていないようだ。
例えば次のようなソースで試すと、
void main(void){
PORTD=0;
while(1){
PORTD--;
}
}
次のようなdisassembly listが生成されるのだが、アドレス0018にあるはずの'SUBWF PORTD, F'命令が表示されない。
:
:
18: PORTD=0;
0010 1003 BCF STATUS, 0
0011 1283 BCF STATUS, 0x5
0012 1303 BCF STATUS, 0x6
0013 3000 MOVLW 0
0014 1803 BTFSC STATUS, 0
0015 3001 MOVLW 0x1
0016 0088 MOVWF PORTD
19: while(1){
0019 2817 GOTO 0x17
20: PORTD--;
0017 3001 MOVLW 0x1
<-- ここが抜けている
表示されていないだけで、シュミレーションは正しく動作する。
asm()でソースコード中で任意のアセンブラコードを使用することができるが、この関数はマクロ中で使用することは出来ないようだ。コンパイルエラーも発生しないので要注意。
例えば、次のようなコードを作成するために、
BSF PORTB, 0
NOP
BCF PORTB, 0
このようなソースを書くと、
#include
#define STROBE_DELAY(x) (x)=1;asm("nop");(x)=0
__CONFIG(HS & WDTDIS & PWRTEN & BOREN & LVPDIS & DUNPROT & WRTDIS & DEBUGDIS & UNPROTECT);
void main(void){
TRISB=0;
STROBE_DELAY(RB0);
}
次のようなコードが生成される。asm()以降の命令しか解釈していない模様。
12: STROBE_DELAY(RB0);
000A 1283 BCF STATUS, 0x5
000B 1303 BCF STATUS, 0x6
000C 1406 BSF PORTB, 0
LCDへのデータ読み込みなどの用途で使用できると結構便利な気がするのですが。関数にするほどでもないし。