• ベストアンサー

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; }

質問者が選んだベストアンサー

  • ベストアンサー
  • techa
  • ベストアンサー率60% (41/68)
回答No.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につけたキャストは蛇足かもしれません。

appleuser
質問者

お礼

>y=(x/0xff)*voltage; >なんてすると必ず0にしかなりませんよね 言われてみればその通りです。 おかげで解決しました。本当にありがとうございました。

その他の回答 (3)

  • techa
  • ベストアンサー率60% (41/68)
回答No.3

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++; } } とでもしてみたらいかがです? ループ内での左辺代入構文がある場合、最適化は効かないという条件があれば、うまく行くかもしれません。

appleuser
質問者

補足

ご指摘の通りwait関数を書き換えたところ、うまく動作しました。 ところが、main関数に x=read_a2d(1); y=(x/0xff)*voltage; このような2行を入れて、入力値を調べようとしたところ、うまく動作しなくなってしまいました。これも文法的なミスなのでしょうか?

  • techa
  • ベストアンサー率60% (41/68)
回答No.2

どのコンパイラをつかっているのかわからないので何ともいえませんが、TRISBはTRIS_Bレジスタのアドレスが正しく定義されているでしょうか。ちなみにPICでは入力指定は1、出力設定は0ですからアドレスさえあっていれば定義は間違っていないと思います。 同じく、PORTBののアドレスも確認してください。 ここまで正しく定義されていると仮定した場合、 void main(){ TRISB = 0x00; while(1){ PORTB = 0x01; } } として、IOがそもそも出力できるかどうかを確認すべきでしょう。 また、wait関数も疑問なのですが、このCのintのサイズはどうなっていますか? CCSではintは8ビットですし、仮に16bitであったとしてもunsigned の指定がないため、場合によってはオーバーフローしてしまう可能性がありますね。 また、最適化の効くコンパイラだと何もしないループは最適化の際に削除されてしまうこともあります。 とにかく、最低限、どこまでうごいているのかを確認しましょう

appleuser
質問者

補足

回答ありがとうございました。コンパイラは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++); } しかし変化はありませんでした。 最適化されてループが削除されないようにする方法はあるのでしょうか?

回答No.1

マイコン、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が原因、もしくはプルアップとかしないと駄目なのかも知れません。 こんな感じでも参考になりますか?

appleuser
質問者

補足

回答ありがとうございました。 1に関しては、”0”は出力設定なので間違いではありません。 2ですが、このことに関しても考慮しています。十数分間待っても変化がありませんでした。 ご指摘の通り、 RB0=0; wait(5); RB0=1; のようにプログラムを変更したところLOWのままだったので、やはりwait関数がおかしいのでしょうか?

関連するQ&A

  • PICのプログラミングについて

    PIC16F819のプログラムをC言語で行っています。 PORTAは全てアナログ入力、PORTBは全てディジタル出力に設定しています。 試しにRB0に接続してある振動モータを動かそうと思い、RB0をHighにするだけのプログラムを作ったのですが動作しません。 A/D変換などは二の次で、単純にRB0から5V出力されるプログラムを組みたいだけなんですが、どうすればいいのでしょうか?ぜひご教授よろしくお願いします。 ---抜粋--- /***Sample code to set up the A2D module********/ void init_a2d(void){ ADCON0=0x00; ADCON1=0x00; ADON=1; } /***Return an 8 bit result**********************/ unsigned char read_a2d(unsigned char channel){ channel&=0x07; ADCON0&=0xC5; ADCON0|=(channel<<3); ADCON0|=0x04; while(ADCON0&0x04)continue; return(ADRESH); } /***Main関数*************************************/ void main(void){   TRISB=0x00; RB0=1; }

  • PIC16F819

    PIC16F819のADコンバータを使用しています。 RA0からアナログ信号を入力して、PORTBのそれぞれのピンから1bitずつ(計8bit)のデジタル信号を出力させるためのプログラムを書いてみましたが、まったく動作しません。レジスタの設定なども変えてみましたが動作しませんでした。特にPORTBを全てHighにした場合、なぜかRB6とRB7からの出力を確認することができませんでした。 動作しない原因がまったく分からないので困っています。原因が分かる方がおられましたらご教授お願いします。 #include <pic.h> __CONFIG(DEBUGEN&WDTDIS&LVPDIS&HS&PWRTEN); void init_a2d(void){  ADCON0=0x40;  ADCON1=0x40;  ADON=1; } unsigned char read_a2d(unsigned char channel){  channel&=0x07;  ADCON0&=0xC5;  ADCON0|=(channel<<3);  GODONE=1;  while(GODONE)continue;  return(ADRESH); } void main(void){  unsigned char x1;  init_a2d(); //initialise the A2D module  GIE=0; // we don't want interrupts  TRISB=0x00;     // PORTB will be used in output mode  PORTB=0x00;  x1=read_a2d(1); // sample the analog value on RA0  PORTB=x1; }

  • PIC16F819のADC機能について

     PIC16F819のA/D変換プログラムをC言語で作りたいのですが、参考になるサイトや本がないのでどこから手をつけていいのかまったく分かりません。  試しにPICC Compilerの期間限定版をダウンロードして、その中にあったサンプルプログラムを見てみました。PIC16F87X用のADCのサンプルプログラムがあったので、とりあえずMPLABでコンパイルしてみましたが、ADGOの部分でエラーが出てしまいました。どうもPIC16F819ではADGOが使用できないようですが、どうすれば改善されるのでしょうか?  分かる方がいましたら、御教授よろしくおねがいします。 サンプルプログラム #include <pic.h> __CONFIG(DEBUGEN&WDTDIS&LVPDIS); /***Sample code to set up the A2D module********/ void init_a2d(void){ ADCON0=0; ADCON1=0; ADON=1; } /***Return an 8 bit result**********************/ unsigned char read_a2d(unsigned char channel){ channel&=0x07; ADCON0&=0xC5; ADCON0|=(channel<<3); ADGO=1; while(ADGO)continue; return(ADRESH); } /***Main関数*************************************/ void main(void){ unsigned char x; init_a2d(); GIE=0; TRISB=0xF0; for(;;){ x=read_a2d(1); PORTB=(8>>(x>>6)); } }

  • PIC A/D変換での問題

    PIC16F690を使用しLCDにA/D変換をした数値を表示させる物を作ったのですが 抵抗を一定の速度で回しても数値が一定の速度で変化しません。 詳しく説明しますと、今回書いたプログラムは8bitで255までの値を表示させるものです。 抵抗をめいいっぱい回して数値を1にし(0にはどうしてもなりません。おそらく抵抗の問題) そこからゆっくりと一定の速度で抵抗を回すと数値が上がっていきます。 30辺りまでは一定の速度で数値が変化するのですが、そこから少し回すといきなり数値が220ぐらいにまで上がります。(一応30~210までの数値も出ている様なのでいきなり飛んでるわけではない) 抵抗を1Kのものから10Kものに変えてみたりしたのですが症状に変化はありませんでした。 どうしても解決できなかったので質問をした次第です。 解決方法がわかる方がいらっしゃいましたらお教え下さい。 プログラムを載せておきます。 #include<pic.h> #include<stdio.h> #include "lcd.h" unsigned int temp; unsigned int x = 1; unsigned char outString[20]; unsigned char count[20]; void init_a2d(void){ ADCON1=0x10; // A/D Clock Fosc/8 ADCON0=0x01; // A2D 入力をChannel 0 (RA0), // Left justified, A/D をON } // 指定された入力チャネルをA/D変換し8 bitの結果を返す unsigned char read_a2d(unsigned char channel){ channel&=0x0F; // 4 bitsを確認し ADCON0&=0xC3; // 現行入力チャネルをクリア ADCON0|=(channel<<2); // 新入力チャネルを設定 GODONE=1; // 変換開始 while(GODONE)continue; // 変換終了を待つ return(ADRESH); // 8 bitの結果を返 } void main(void) { pic_init(); init_a2d(); // A/D モジュール初期化 lcd_init(); lcd_goto(0x00); while(1) { __delay_us(50); // 50uS待ち(AD充電待ち) temp=read_a2d(0); sprintf(outString,"A/D=%2d",temp); lcd_puts(outString); lcd_goto(0x40); sprintf(count,"Count=%d",x); lcd_puts(count); x++; __delay_ms(100); lcd_clear(); } }

  • PICのプログラムについて質問です

    使用するPICは16F84Aで、MPLAB IDEv8.88を使ってこのようなプログラムを作りました。 #include"pic.h" static void pic_init(); static void Delay_ms(unsigned char ms); static void Delay_1ms(); void main(){ pic_init(); while(1) { RB0 = 1 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); RB0 = 0 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); } static void pic_init() { // GPIO = 0b00000000; TRISA = 0xFF ; TRISB = 0x00 } static void Delay_ms(unsigned char ms) { unsigned char c; for (c=ms ; c>0 ; c--) { Delay_1ms(); } } static void Delay_1ms() { unsigned int cnt; unsigned int i; cnt = 76; for (i=0 ; i<cnt ; i++) { NOP(); } } ポートB0の出力を0から1にするプログラムなのですが、実行すると Error [314] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 52.24 ";" expected Error [254] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 77.0 undefined variable: "pic_init" ********** Build failed! ********** というエラーが出ます。このようなエラーが出る原因を教えて頂けないでしょうか。お願いします。

  • PICマイコンのI/Oについて教えてください。

    PIC16F1936を使っています。 各ポートをデジタル出力にしLEDを順に点灯させていますが RB0に接続したLEDのみうっすらとしか光りません。 (プログラムで意図したとおり点滅はします。) テスターで電流を計測したところRB0のみほとんど流れていませんでした。 また電源投入時にRB0に接続したLEDだけ一瞬光ります。 PICは初期状態でI/Oは入力になっているので光らないと思うんですが・・・ MPLABX+XC8で開発しています。 以下の切り分けを行いました。 ・LED単体での点灯:正常点灯 ・他のLEDをRB0に接続:現象再現 ・他のブレットボードで作動:現象再現 データシートとかなり睨めっこしたんですがそれっぽい部分がみつかりません ご教示いただけると助かります。 ソースは以下のとおりです。 #include <xc.h> #pragma config CLKOUTEN = OFF,\ WDTE = OFF,\ PWRTE = ON,\ CP = OFF,\ BOREN = OFF,\ FCMEN = OFF,\ MCLRE = ON,\ CPD = OFF,\ IESO = OFF,\ FOSC = INTOSC,\ STVREN = OFF,\ BORV = LO,\ LVP = OFF,\ VCAPEN = OFF,\ WRT = OFF,\ PLLEN = ON #define uchar unsigned char #define uint unsigned int void init(void){ //ポート初期化 PORTA = 0b00000000; PORTB = 0b00000000; PORTC = 0b00000000; PORTE = 0b00000000; TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b00000000; TRISE = 0b00000000; //全てデジタル ANSELA = 0b00000000; ANSELB = 0b00000000; //8mhz OSCCON = 0b11110000; OPTION_REG = 0b00000000; APFCON = 0; WPUE = 0; } void Wait(unsigned int num){ for (int i=0 ; i<num ; ++i) { for( int j = 0; j < 100; ++j){ NOP(); } } } void main(void){ init(); while(1){ PORTC = 0b00000100; Wait(1000); PORTC = 0b00000000; PORTB = 0b00001000; Wait(1000); PORTB = 0b00100000; Wait(1000); PORTB = 0b00000001; Wait(1000); PORTB = 0b00000000; } }

  • PICのコンフィグレーションワードの書き方

    MPLAB + PICC-Lite + PICkit2 で PIC16F877(20MHz)を使用しようとしています。 今まで、16F627Aを使用していて、今回が初めての16F877です。最初にDポートのLED4つを点滅させるプログラムを実行しようとしました。 最初、ディパッガーでも動かなかったのですが、MPLAB IDEのConfigureメニューのConfiguration BitsをHSに変更したら動きました。 ところがPICkitを外して、16F877単体で動きません。 おそらく、コンフィグレーションワードで、HSを書き込まなければだめらしいということは、わかったのですが、その書き方がわかりません。 現在のソースファイルは以下の通りです。 ----------------------- #include <pic.h> void delay(void) { unsigned char i, j; for (i = 0; i < 254; i++) { for (j = 0; j < 254; j++) { } } } void main(void) { TRISD = 0; unsigned char led = 0x01; do { PORTD = led; if (led == 0x08) { led = 0x01; } else { led <<= 1; } delay(); } while (1); }

  • PICの割り込み機能

    現在電子工作をしており、それにPIC16F84Aを使っています。 正直アセンブリはよくわからないので、C言語でプログラムを作っています。 コンパイラはPICCLITEで、LEDの点灯・消灯に関するプログラムです。 機能としては ・RA0に入力があったときRB0につないであるLEDが消灯しているならLEDを点灯。 ・RA0に入力があったときRB0につないであるLEDが点灯しているならLEDを消灯。 ・RA1に入力があったときLEDが点灯しているなら5秒後にLEDを消灯。 というものを目指しています。 1つ目、2つ目の項目はif文で簡単に実現できましたが、割り込みがうまくいかず、 消えている状態でRA1に入力を入れたときなぜか5秒後に点灯してしまいます。 だからRB0の出力を逆にしてみたんですがうまくいかず・・・。 ハード的には、RB0には反対側から5Vをかけ、 RB0=0の時は点灯 RB0=1の時は消灯 としています。 またセラロックは10MHzのものを使用しています。 現在のプログラムとしては #include "pic.h" #define XTAL_FREQ 10MHZ #define MHZ*1000 void DelayUs(unsigned char cnt){ //時間待ち関数  unsigned char i;  i=(cnt)/(12MHZ/(XTAL_FREQ))|1;  while(--i!=0) continue; } void DelayMs(unsigned int cnt){ //時間待ち関数  unsigned char i;  do{   i=4;   do{    DelayUs(250);   }while(--i);  }while(--cnt); } int cnt,SW; //SWが0なら消灯 //SWが1なら点灯 void interrupt isr(void){ //割り込み関数  if(T0IF==1){   T0IF=0;   cnt--;  }  if(cnt==0){   RB0=1; //消灯   SW=0;   cnt=190;   T0IE=0;   GIE=0;  } } main() {  TRISA=0xFF; //入出力設定  TRISB=0x00;  PORTA=0x00;  PORTB=0x00;  SW=0;  OPTION=0x87; //プリスケーラの設定  TMR0=0x00;  T0IF=0;  T0IE=1;  cnt=190;  while(1){   if(RA0==1){    DelayMs(60); //チャタリング防止    if(RA0==1){     if(SW==0){      RB0=0;      SW=1;     }    else{     RB0=1;     SW=0;    }   }  }  if(RA1==1){   DelayMs(60); //チャタリング防止    if(RA1==1 && SW==1){     TMR0=0;     T0IF=0;     T0IE=1; //割り込み許可     GIE=1; //全体割り込み許可    }   }  } } インターネット上での割り込みのプログラムをいくつか見てみたのですが、 どれもすべて動作を終えて、あとはwhile(1)で割り込みを待つだけ というプログラムばかりでした。 僕のは基本的にRA0の入力によってLEDを点灯・消灯させつつ RA1の入力で割り込みを開始。 5秒後に消えたら割り込みを禁止する。 という仕様にしたいのですが・・・・・・。 1ヶ月ぐらいやってますがうまくいきません。 良ければご回答をお願いします。

  • pic12f675の待ち時間関数について

    初めて質問します。 現在pic12f675で遊んでいるのですが、 http://homepage3.nifty.com/mitt/pic/picc/picc675_04_1.html にある、 // =================== 50uSウェイトルーチン =============== static void wait_50uS() { unsigned int cnt; unsigned int i; cnt = 2; for (i=0 ; i<cnt ; i++) { NOP(); } } の意味がわかりません。 特にfor (i=0 ; i<cnt ; i++) { NOP(); } の箇所です。 これでなぜ、50μsの待ち時間関数になるのでしょうか? どなたか答えてくれませんか?

  • 配列の長さについて

    現在課題で書いているプログラムに以下のような関数があるのですが、 unsigned char key[32]; int w[60]; int data[NB]; int nk; int nr; int data2[32]; int Cipher(int *); int invCipher(int *); void encryptEBC(int *); void decryptEBC(int *); main(){ unsigned char keys[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; unsigned char iv[]={0xcb,0x70,0x05,0x9e,0x27,0x2f,0x4e,0xd2, 0xd0,0xbe,0x0b,0x06,0xbf,0x16,0xec,0x5a}; unsigned char init2[]={'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0', '1','2','3','4','5','6','7','8','9','0',0x0a}; //unsigned char init2[]={'h','e','l','l','o'}; int isize = sizeof(init2)/sizeof(init2[0]); int dsize2 = sizeof(data2)/sizeof(data2[0]); printf("%d,%d\n",isize,dsize2); FILE *fp; char *fname = "test.txt"; unsigned char init[16]; int i = 0; int c; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } while( (c = fgetc( fp )) != EOF ){ init[i] = c; i = i+1; } fclose( fp ); memcpy(key,keys,16); nk = 4; nr = nk + 6; KeyExpansion(key); memcpy(data,init,16); memcpy(data2,init2,isize); printf("%d\n",dsize2); datadump("PLAINTEXT: ",data,16); datadump("KEY: ",key,16); Cipher(data); datadump("Cipher: ",data,16); invCipher(data); datadump("invCipher: ",data,16); printf("\n"); printf("%d\n",dsize2); datadump("PLAINTEXT: ",data2,dsize2); encryptEBC(data2); printf("%d\n",dsize2); datadump("EBCCipher: ",data2,dsize2); decryptEBC(data2); datadump("invCipher: ",data2,dsize2); printf("\n"); return 0; } void encryptEBC(int data[]){ int dsize = sizeof(data)/sizeof(data[0]); int tmp[16]; int i,j,k; printf("%d\n",dsize); KeyExpansion(key); for (i = 0; i < dsize; i += 16) { for (j = 0; j < 16; j++){ tmp[j] = data[i + j]; } Cipher(tmp); for(k=0;k<16;k++){ data[i+k] = tmp[k]; } } } 関数encryptEBC内のdsizeの値がこの場合だとmain内の配列data2の長さ32になってほしいのですが、1になってしまいます。 非常に見ずらいプログラムで申し訳ないのですが、どなたか1になってしまう理由、またどうすれば正しくdata2の長さを求められるか教えていただけないでしょうか?

専門家に質問してみよう