- ベストアンサー
PICプログラミング
テストプログラムとして以下のようなプログラムを作ってみました。 RB0を一定時間だけHIGHにした後に、LOWに戻すプログラムなのですが、テスターで測定したところRB0は結果的にHIGHのままでした。wait関数が間違っているのかと思いましたが、どう考えても文法的な間違いはないと思います。 原因がまったく分からないので、分かる方がいましたらヒントだけでもいいので是非教えてください。よろしくお願いします。 PIC16F819 セラロック20MHz #include <pic.h> __CONFIG(DEBUGEN&WDTDIS&LVPDIS&HS&PWRTEN); #define voltage 5.0 void wait(int a){ int i,j; for(i=0;i<=30000;i++) for(j=0;j<=2000*a;j++); } void init_a2d(void){ ADCON0=0x80; ADCON1=0x00; ADON=1; } unsigned char read_a2d(unsigned char channel){ channel&=0x07; ADCON0&=0xC5; ADCON0|=(channel<<3); // GODONE=1; // while(GODONE)continue; ADCON0|=0x04; while(ADCON0&0x04)continue; return(ADRESH); } void main(void){ int i,j; unsigned char x; double y; init_a2d(); GIE=0; TRISB=0x00; PORTB=0x00; RB0=1; wait(5); RB0=0; }
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>x=read_a2d(1); >y=(x/0xff)*voltage; メインに上記2行を足したとのこと。 そもそも、read_a2d()の戻り値はcharなので8ビットですよね。 となるとxに代入されるのは常に0~ffまでの値しかとり得ません。これを y=(x/0xff)*voltage; なんてすると必ず0にしかなりませんよね。 またvoltageは型指定がありませんが、実数指定になっているにもかかわらず、計算される対象であるxはcharですし、代入先はdoubleですので、計算結果は保証されません。 本当にdoubleなんて桁数がいるのかどうかは知りませんがとりあえず動くようにするなら y=(double)x * (double)voltage; とでもすべきでしょうか。まあ、voltageにつけたキャストは蛇足かもしれません。
その他の回答 (3)
- techa
- ベストアンサー率60% (41/68)
PORTB = 0x01; だけでなく、 RB0=1; でも出力されることは確認されたのですね? となると本当にwait関数がくさそうですね。 私はCCS-Cをいつも使っているので、HITECH-Cのことは わからないのですが、どうやら最適化オプションの指定があるようです。まずは最適化なしが選べれば越したことがないのですが。 マイコン用GCCなどではvolatile 変数に指定することで最適化を禁止できるのですが、PIC用ではどうか微妙ですね。 ためしに、 void wait(int a){ unsigned int i,j; unsigned int dmy=0; for(i=0;i<=250;i++){ for(j=0;j<=50*a;j++){ dmy++; } } とでもしてみたらいかがです? ループ内での左辺代入構文がある場合、最適化は効かないという条件があれば、うまく行くかもしれません。
補足
ご指摘の通りwait関数を書き換えたところ、うまく動作しました。 ところが、main関数に x=read_a2d(1); y=(x/0xff)*voltage; このような2行を入れて、入力値を調べようとしたところ、うまく動作しなくなってしまいました。これも文法的なミスなのでしょうか?
- techa
- ベストアンサー率60% (41/68)
どのコンパイラをつかっているのかわからないので何ともいえませんが、TRISBはTRIS_Bレジスタのアドレスが正しく定義されているでしょうか。ちなみにPICでは入力指定は1、出力設定は0ですからアドレスさえあっていれば定義は間違っていないと思います。 同じく、PORTBののアドレスも確認してください。 ここまで正しく定義されていると仮定した場合、 void main(){ TRISB = 0x00; while(1){ PORTB = 0x01; } } として、IOがそもそも出力できるかどうかを確認すべきでしょう。 また、wait関数も疑問なのですが、このCのintのサイズはどうなっていますか? CCSではintは8ビットですし、仮に16bitであったとしてもunsigned の指定がないため、場合によってはオーバーフローしてしまう可能性がありますね。 また、最適化の効くコンパイラだと何もしないループは最適化の際に削除されてしまうこともあります。 とにかく、最低限、どこまでうごいているのかを確認しましょう
補足
回答ありがとうございました。コンパイラはPICC-Compilerの期間限定版を使用しています。 PORTBとTRISBレジスタのアドレスを確認しましたが合っていました。 出力していることは確認して、 RB0=0; wait(5); RB0=1; のようにプログラムを書き換えたところ、出力されなかったので、wait関数に問題があるようです。ご指摘の通り、intを8bitと仮定して、この様に書き換えてみました void wait(int a){ unsigned int i,j; for(i=0;i<=250;i++) for(j=0;j<=50*a;j++); } しかし変化はありませんでした。 最適化されてループが削除されないようにする方法はあるのでしょうか?
- silverbear
- ベストアンサー率25% (163/639)
マイコン、DSPばかりで、PICは使ったことが無いので全て予想で回答します。 エラーは出てないんですよね。 1、PORTB=0x00;というのは、ポートBの入出力設定だと思うのですが、0って入力じゃないですか?(勘です。)PORTB=0xff;とかにしたら直ったりしませんか? 2、wait(5)の中身ですが、単純に3億回もループしてます。20MHzで1ループ1クロックだとしても15秒。そんなことは無いと思うので1分くらいかかるかもしれませんが、それは計算に入ってますか? RB0=1; wait(5); RB0=0; の部分を RB0=0; wait(5); RB0=1; にすると出力は変える前と変わってますか?変わらないのなら1が原因、もしくはプルアップとかしないと駄目なのかも知れません。 こんな感じでも参考になりますか?
補足
回答ありがとうございました。 1に関しては、”0”は出力設定なので間違いではありません。 2ですが、このことに関しても考慮しています。十数分間待っても変化がありませんでした。 ご指摘の通り、 RB0=0; wait(5); RB0=1; のようにプログラムを変更したところLOWのままだったので、やはりwait関数がおかしいのでしょうか?
お礼
>y=(x/0xff)*voltage; >なんてすると必ず0にしかなりませんよね 言われてみればその通りです。 おかげで解決しました。本当にありがとうございました。