• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C18(PIC18)でのシフト演算など)

C18(PIC18)でのシフト演算など

このQ&Aのポイント
  • PIC18で、加速度センサからの値を読み取るプログラムのif文の不具合を解消したい
  • 加速度センサとはHM55Bというもので、詳細はリンクを参照してください
  • プログラムの不具合原因を見つけることができず、アドバイスを求めています

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

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.8

楽できる関数を忘れてました。 atan2ですべて簡単に解決できます! 使っているコンパイラで利用できるか確認してみてください。 atan2でだめなら、元々の方位センサの値を疑ったほうが良さそうですよ。 で、その他の問題点。 問題点1. itoa((int)(dx*10000.f), com_xString); ← 10000倍するとintの有効桁を超えます! 問題点2. if((float)dx == 0 && (float)dy == 0){ ← floatに型変換する必要なし。 問題点3. itoa((int)(teta*10000.f), com_tetaString);← 10000倍するとintの有効桁を超えます!

-TaKaHiRo-
質問者

お礼

以下のプログラムで正しい方角のteta(単位:度)が表示されました。 計測の為の待ち時間(60ms)が不足していたことも原因でした。 長い間、ありがとうございました。 ------------------------------------------------------------------- //方位センサー val = 0; TRISBbits.TRISB1 = 0; TRISBbits.TRISB2 = 0; TRISBbits.TRISB3 = 0; TRISBbits.TRISB4 = 1; //RB4を入力モード sendCmnd(0); //resetコマンド送信 sendCmnd(1); //測定開始コマンド送信 Delay1KTCYx(240); //計測終了に60msの待ち時間が必要 ひとつで約23ms Delay1KTCYx(240); Delay1KTCYx(240); val = sendCmnd(2); //READコマンド送信 if((WORD)val == 0xc){ sendCmnd(2); //READコマンド送信 dx = sendCmnd(3); //11bitデータ呼び出し dy = sendCmnd(3); //11bitデータ呼び出し PORTBbits.RB3 = 1; //CSB = high } Delay10TCYx(10); //待ち時間 PORTBbits.RB3 = 0; //CSB = low sendCmnd(0); //resetコマンド送信 PORTBbits.RB3 = 1; //CSB = high TRISBbits.TRISB1 = 1; TRISBbits.TRISB2 = 1; TRISBbits.TRISB3 = 1; //負の数なら、16bitの補数にする if((dx & (1 << 10)) != 0) dx |= 0xf800; if((dy & (1 << 10)) != 0) dy |= 0xf800; //comxとcomyは実数型 comx = (float)dx; comy = (float)dy; //10進表示 degに変換 itoa((int)dx, com_xString); itoa((int)dy, com_yString); //角度(方位)の計算 teta = atan2(comy, comx); //teta10進表示 deg変換 teta = (teta*180.0f)/3.1415f; itoa((int)teta, com_tetaString); -------------------------------------------------------------------

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (8)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.9

追記:gccで動作確認してみました。 今のソースコードでは、10000倍している以外には問題がなかったです。 とすると、方位センサの値自体に問題がある可能性があります。 実際の方位とX,Y値をちゃんと検証してみないといけません。 直接X,Y値をチェックしてみてください。

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.7

今日見てみたら、ラジアン角もあやしいですね。 http://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%B8%E3%82%A2%E3%83%B3 360度=2πラジアンなので、90度づつ補正するなら2πラジアンの1/4,2/4,3/4の値しか出てこないはずです。 C言語のライブラリの三角関数はすべてラジアン角で扱いますので、ちゃんとラジアン角を理解してください。

-TaKaHiRo-
質問者

補足

if文と合わせて、再度検討してみます。 明らかに、結果が0になるところが多いので…

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.6

まず簡単にするためにきっちりと4つの象限に分けて書きましょう。 後で動いてから省略できるところは省略すればよいです。 それとcomxが0のとき、割り算するのは結果が無限大になってしまうので、if文で切り分けて別処理するか、分子と分母を入れ替えて割り算できる方法を考えましょう。 それと実際のデータを入力せずに45度づつぐらいのデータをダミーで作ってちゃんと角度が計算出来ているかテストしてください。 ラジアン角も理解していて、プログラムの作り方も方向的には合っているので、後は式として正しくすれば問題ないはずです。これから私は外出するので、細かい検証は出来てませんけど。 >itoa((int)teta*100, com_tetaString); intにしてから100倍しても小数部は失われています。100倍してからintにしましょう。 itoa((int)(teta*100.0f), com_tetaString); これ、ラジアン角のままですが度数法に直さなくて良いんですかね?

-TaKaHiRo-
質問者

補足

とりあえず、ラジアンで構わないので、結果を表示したいです。 プログラムの条件式を、以下のように訂正したのですが、 やはり上手く表示できません。ご指摘、お願いします。 (極限、例えばx=0とかのif文は必要ないかと思いますが、一応付けています) --------------------------------------------------------------------- //負の数なら、16bitの補数にする if((dx & (1 << 10)) != 0) dx |= 0xf800; if((dy & (1 << 10)) != 0) dy |= 0xf800; //10進変換 itoa((int)(dx*10000.f), com_xString); itoa((int)(dy*10000.f), com_yString); comx = (float)dx; comy = (float)dy; //teta = asin(comy / sqrt((comy*comy) + (comx*comx))); teta = atan(comy / comx); //例外処理 if((float)dx == 0 && (float)dy == 0){ teta = 9999.0f; } else{ //第1象限 if((float)dx > 0 && (float)dy > 0) teta = teta; //第2象限 if((float)dx < 0 && (float)dy > 0) teta = 3.1415f + teta; //第3象限 if((float)dx < 0 && (float)dy < 0) teta = 3.1415f + teta; //第4象限 if((float)dx > 0 && (float)dy < 0) teta = 2.0f * 3.1415f + teta; //極値0 if((float)dx > 0 && (float)dy == 0) teta = 0.0f; //極値pi/2 if((float)dx == 0 && (float)dy > 0) teta = 3.1415f/2.0f; //極値pi if((float)dx < 0 && (float)dy == 0) teta = 3.1415f; //極値3pi/2 if((float)dx == 0 && (float)dy < 0) teta = (3.0f*3.1415f)/2.0f; } itoa((int)(teta*10000.f), com_tetaString); ------------------------------------------------------------------

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.5

浮動小数点で参考になりそうなページ。 http://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html それとのPIC用のC言語(いくつかメーカーがあり仕様が各々違います)で、floatとdoubleが同じに精度の型として扱われているコンパイラもあるようですので確認してください。 参考↓ http://www.ee.fukui-nct.ac.jp/~yoneda/text/other/C/A_07.htm

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

atan関数は、float型の浮動小数点でアークタンジェントの計算を行う関数で、引き数として与えられるのはfloat型の変数だけです。 文字列の10進数は人間のために必要なだけで計算に使ってはいけません。表示にだけ使用してください。CPUで文字列10進数で計算を行うことは絶対ありません! int型からfloat型に変換するにはキャストを行う必要があります。 int a; float f; a = 10; f= (float)a; ← 2進から浮動小数点に変換されて代入されます。 それと、浮動小数点の数値は、3や6では無く3.0fや6.0fと書くようにしてください。 参考↓浮動小数点の仕様。 http://ja.wikipedia.org/wiki/IEEE_754 使いこなすためには、ちゃんと勉強する必要があります。 C言語の浮動小数点について本を読むかWEBサイトで勉強してください。 (注意)前にも書きましたが浮動小数点は処理が重く、プログラムメモリも大量に消費します。プログラムサイズと処理時間には十分に注意してください。PICはソフトウェアで浮動小数点を計算しています。x86系のCPUはCPU自身のハードで浮動小数点を計算できるので高速でコンパクトになります。

-TaKaHiRo-
質問者

補足

プログラムを以下のように改良したのですが、 どうも、tetaの計算が上手くいきません。 条件文もこれでいいのか、自信がありません。 ------------------------------------------------------------------ float comx, comy; comx = (float)dx; comy = (float)dy; if(dy < 0)  teta = atan(-comy / comx); if(dx > 0 && dy > 0 || dx < 0)  teta = atan(-comy / comx) + 3.1415f; if(dx < 0 && dy < 0)  teta = atan(-comy / comx) + 2.0f*3.1415f; itoa((int)teta*100, com_tetaString); ------------------------------------------------------------------- よろしくお願いします。

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

>if((dx & (1 << 10)) != 0) dx |= negbits; >if((dy & (1 << 10)) != 0) dy |= negbits; negbitsが0xf800なら問題ないと思います。これで-1024~1023までの値になります。 見てみましたが、uitoaはちゃんとしている様に見えます。 65530なのは、unsignedとして表示しているためで、signedとして処理すれば-6という値です。signedとして扱うにはitoa()を使えば良いと思います。使えないんでしたっけ? 文字化けするほうは、バッファの渡しの間違いか別の原因の気が。補足で書いてもらったソースには原因がなさそうなので。 >また、2進数から10進数(角度の計算をしたい)にするには、どうすればよいでしょうか? 基本的にCPUの中では2進法で計算します。WindowsPCだろうとPICだろうと同じことです。intは、2進法で計算するための型で符号付16ビットの値を計算に使うことができます。 で計算したいのでしたら、普通に加減除乗算をしてください。DX*=5;と書けば5倍されますし、2進法であることを意識するのは、32768を超えたりする値のときだけです。 もし、小数点以下を扱いたいという意味で聞いたのであれば、floatなどの浮動小数点が使えるとは思いますが、かなり重い処理なので、覚悟して使ってください。それとライブラリも大きなメモリサイズのものがリンクされます。メモリのサイズにも注意してください。 表示もsprintfなどを使わないと、自前で浮動小数点を10進法で表示させることは高度すぎて無理です。 通常、PICの貧弱なCPUでは整数のまま角度計算できるように工夫するのが普通です。少数以下がほしいときも10倍して計算するとか工夫すれば何とかできるものです。

-TaKaHiRo-
質問者

補足

文字化けは、単純なタイプミスでした。 itoa()が使えたので、正しく表示することもできました。 2進で計算する理由は分かるのですが、 今、角度(arctan)の計算をしないといけないので、 どうしても10進で計算したいのですが、動いてくれません。 PICの処理能力以前に、プログラムに問題があると思うのですが、 どこが問題かが分かりません。ご指摘お願いします。 ------------------------------------------------------------------- if((WORD)val == 0xc){   sendCmnd(2); //READコマンド送信   dx = sendCmnd(3); //11bitデータ呼び出し   dy = sendCmnd(3); //11bitデータ呼び出し   PORTBbits.RB3 = 1; //CSB = high }   Delay10TCYx(10);    //待ち時間   PORTBbits.RB3 = 0;   //CSB = low   sendCmnd(0);      //resetコマンド送信   PORTBbits.RB3 = 1;   //CSB = high   TRISBbits.TRISB1 = 1;   TRISBbits.TRISB2 = 1;   TRISBbits.TRISB3 = 1;      //負の数なら、16bitの補数にする   if((dx & (1 << 10)) != 0) dx |= 0xf800;   if((dy & (1 << 10)) != 0) dy |= 0xf800;      //10進変換   itoa(dx, com_xString);   itoa(dy, com_yString);   if(com_yString < 0)    teta = atan((-com_yString) / com_xString);   if(com_xString > 0 && com_yString > 0 || com_xString < 0)    teta = atan((-com_yString) / com_xString) + 3;   if(com_xString < 0 && com_xString < 0)    teta = atan((-com_yString) / com_xString) + 6;   itoa(teta, com_tetaString); -------------------------------------------------------------------

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

情報不足ですが、今わかるところだけ。 加速度センサーの制御フローと違っているように見えます。 http://www.hitachi-metals.co.jp/prod/prod01/p01_13_a1.htm#07 1100は送信するコマンドで、READを意味するコマンドです。 で、加速度の計測が終わって帰って来るビット列が11になるまでループで待ち続ける必要があると制御フローには書かれています。確認をしてみてください。 ちなみに、0x0cか12が1100というビット列なら正しい比較値です。

-TaKaHiRo-
質問者

補足

アドバイスありがとうございます。 質問投稿後、再度確認したところ、接続不良だったようで、 上のプログラムのif文が「0xc」で反応しました。 計測終了はOKなのですが、次のステップでまたつまずいてしまいました。 下のプログラムで、dxとdyの値がうまくとれません。 dxの方は、「65530」ぐらいが表示され、 dyの方は、完全に文字化けしてしまいました。 ちなみに、表示に使っている関数(uitoa)では、 例えば条件式の「0xc」を引数にすると、「12」と表示されます。 補数の計算をしたいので、2進数で値を得たいのですが、どうすればよいでしょうか? また、2進数から10進数(角度の計算をしたい)にするには、どうすればよいでしょうか? ------------------------------------------------------------------- if((WORD)val1 == 0xc){ //例のif文  sendCmnd(2); //READコマンド送信 おそらくOK  dx = sendCmnd(3); //11bitデータ呼び出し  dy = sendCmnd(3); //11bitデータ呼び出し  PORTBbits.RB3 = 1; //CSB = high } //測定終了時のリセット Delay10TCYx(10); //待ち時間 PORTBbits.RB3 = 0; //CSB = low val1 = sendCmnd(0); //resetコマンド送信 PORTBbits.RB3 = 1; //CSB = high TRISBbits.TRISB1 = 1; TRISBbits.TRISB2 = 1; TRISBbits.TRISB3 = 1; //負の数なら、16bitの補数にする if((dx & (1 << 10)) != 0) dx |= negbits; if((dy & (1 << 10)) != 0) dy |= negbits; ------------------------------------------------------------------- 文字表示用 ------------------------------------------------------------------- void uitoa(WORD Value, BYTE *Buffer) { BYTE i; WORD Digit; //桁 WORD Divisor; //除数 BOOL Printed = FALSE; if(Value) { for(i = 0, Divisor = 10000; i < 5; i++) { Digit = Value/Divisor; if(Digit || Printed) { *Buffer++ = '0' + Digit; Value -= Digit*Divisor; Printed = TRUE; } Divisor /= 10; } } else { *Buffer++ = '0'; } *Buffer = '\0'; } //#endif ------------------------------------------------------------------- よろしくお願いします。

全文を見る
すると、全ての回答が全文表示されます。
noname#65902
noname#65902
回答No.1

リンク先には HM55B は「方位センサ」と書かれてますが、 その為に期待する値が来ないのでは?

-TaKaHiRo-
質問者

補足

入力ミスでした。 「加速度センサ」は「方位センサ」の打ち間違いです。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C言語(PIC関連ですが・・・)

    センサーが接続されたPICマイコンでDCモータを制御する際に、前のセンサーと次のセンサーの間隔が長く、DCモータが停止してしまうので、前のセンサーの信号を次のセンサーの信号が入力されるまで保持されるようなプログラムを作りたいのですが、どのようなプログラムにしたらよいでしょうか・・・ ちなみに、下が試作プログラムの一部です。 if(b== 0x39) //センサ1が入力されたとき { PORTA = 0b00000010; Delay_ms(1); PORTC = 0b00000000; Delay_ms(1); PORTD = 0b00000001; Delay_us(350); PORTD = 0b00000000; Delay_us(300); } if(b== 0x3d) //センサ2が入力されたとき { PORTA = 0b00000001; Delay_ms(1); PORTC = 0b00000000; Delay_ms(1); PORTD = 0b00000001; Delay_us(325); PORTD = 0b00000000; Delay_us(300); }

  • PIC 出力を持続したい

    鉄道模型のコントローラーを作っています。 マイコンはPIC16F886です。 以下のようなプログラムを作りました。 (ただし、mainよりも前の設定等は今回の質問に関係ないと思われますので、省略してあります) 質問箇所は(1)~(5)です。 while(RC3==0)のときその部分がループされるようになっていまして、ループから抜けた時に(1)(2)(3)で変更された内容は保持されているのですが、(4)(5)はループを抜けた瞬間に0になってしまいます。 たとえば、(1)と(4)の条件を満たしてRA1=1、RB6=1となり、relay1とrelay3がONになります。 しかしループを抜けると、relay1はONのままなのですがrelay3がOFFになってしまいます。 なぜでしょうか。 出力しているピンの問題なのですか? ご回答よろしくお願いします。 以下プログラム (省略) main() { PORTA = 0x00; PORTB = 0x00; PORTC = 0x00; TRISA = 0b11111001; TRISB = 0b00111111; TRISC = 0b11111111; ANSEL = 0b00000001; ANSELH = 0b00111111; ADCON1 = 0b00000000; while(RC3==1); // マスコンを「非常」にしないと動作しない while(1) { if(RC3==0 && SPD==0) // マスコンが非常、かつ車両が停止している時 { while(RC3==0) // マスコンが非常のとき、無限ループ開始 { if(RC4==0) // 方向セレクトSWがRC4の時・・・(1) { RA2 = 0; // relay2をOFF DelayUs(20); RA1 = 1; // relay1をON } else if(RC5==0) // 方向セレクトSWがRC5の時・・・(2) { RA1 = 0; // relay1をOFF DelayUs(20); RA2 = 1; // relay2をON } else if(RC4==1 && RC5==1) // 方向セレクトSWが中立の時・・・(3) { RA1 = 0; // relay1をOFF DelayUs(20); RA2 = 0; // relay2をOFF } if(RC6==0) // 出力セレクトSWがRC6の時・・・(4) { RB6=1; // relay3をON } else if(RC7==0) // 出力セレクトSWがRC7の時・・・(5) { RB6=0; // relay3をOFF } } } ADCON0 = 0b10000001; // 最高速度をAN0から読み込む DelayUs(20); // ADCが安定するまで待つ GODONE=1; // ADC起動 while(GODONE); // ADC終了まで待つ MAX=ADRESH; // ADCの上位8ビットを最高速に代入 if(RA3==0) // マスコンが加速3の時 { ADCON0 = 0b10110101; // 加速度をAN13から読み込む } if(RA4==0) // マスコンが加速2の時 { ADCON0 = 0b10101101; // 加速度をAN11から読み込む } if(RA5==0) // マスコンが加速1の時 { ADCON0 = 0b10100101; // 加速度をAN9から読み込む } if(RC1==0) // マスコンが減速1の時 { ADCON0 = 0b10100001; // 加速度をAN8から読み込む } if(RC2==0) // マスコンが減速2の時 { ADCON0 = 0b10101001; // 加速度をAN10から読み込む } if(RC3==0) // マスコンが非常の時 { ADCON0 = 0b10110001; // 加速度をAN12から読み込む } DelayUs(20); // ADC安定するまで待つ GODONE=1; // ADC起動 while(GODONE); // ADC終了まで待つ ACC=ADRESH; // ADCの上位8ビットを加速度に代入 func01(); } }

  • PIC C Liteを使い加速度センサの値を読む

    始めまして。 最近PICの勉強を始めました。 ADWINのキットを買い、後閑さんの本を読んでいる最中ですが、質門があります。 【Kionix社の加速度センサ「KXP84-2050」を使い、その値を取り込むにはどうすればいいのでしょうか。】 学生時代にC言語を少し触っており簡単な気持ちで始めたら、大変なことになりました。 PC内部だけでプログラムするのとは分けが違い、途方に暮れています。 どうか、皆様のお力をお借りしたいです。 以下、質問の詳細です。 1.X軸の信号値を8個のLEDで8bitデータに見立てて表示しようと考えています。   センサを傾けると、 秋月電子でセンサーのモジュールを買いました。   私の理解では   ・あるポートのレジスタ(ここではRB0とします)をまずは入力ポートにする   ・センサーからの値を代入する   ・その値をLEDに出力する  です。 ここで、センサーの仕様書にはレジスタネーム「XOUT_H」のアドレスは0x00であり、これはMSBで送られてくる。(8bitデータ)I2Cでのデータ送受信時 センサ側のデータをどう受信して、値を格納すればいいのでしょうか? センサ側のアドレスを指定する? などがADWINの入門書ではまったく無いので・・・ PIC側とセンサー側のやり取りが分からず困っています。 シリアルでデータがくるので、8bitデータをもらうのには8回ループをまわして、別に定義した変数にセンサデータを入れればいいのでしょうか? センサーとPICを繋ぐ線は1つですので、シリアルデータの扱い方がわかりません。 PIC側で、 char X_data[8]のような配列を定義し を定義し、 そこに X_data[i]=XOUT_H[i]そして出力でしょうか? 私なりに、ネットも調べたのですが分からずじまいでした。 よろしくお願いします。 乱文申し訳ございません。   

  • C言語でプログラミングし、PICマイコンでLEDを制御する

    現在PICを使ってLEDを制御する事を勉強しています。 3つのLEDを3秒間隔で点灯させ、それを無限に繰り返すプログラムを考えてみました。LEDは一つのポートに一つのLEDを割り振るのではなく、ICを使って制御しています。 これを発展させ、待ち時間の3秒間にRA2ポートに入力があるとLEDの点灯をその場所で停止させ、もう一度RA2ポートに入力するとループが再開するといった内容にしようと考えていますが、調べてもどうすればいいのか分かりません、分かる方は教えて頂けないでしょうか # include <16f84a.h> # fuses HS, NOWDT, NOPROTECT # use delay(clock=20000000) int flag, sec, count; main() //main関数の開始宣言 { set_tris_a(0x10); set_tris_b(0x10); #use fast_io(a) //port_aの高速処理を行う設定 #use fast_io(b) //port_bの高速処理を行う設定 while(1){ //無限ループのwhile文の宣言 output_low(PIN_A0); //RA0の出力 output_low(PIN_B5); //RB5の出力 output_low(PIN_B6); //RB6の出力 output_low(PIN_B7); //RB7の出力 //LED1が点灯 delay_ms( 3000 ) ; //3秒待つ   output_high(PIN_A0); //RA0の出力 output_low(PIN_B5); //RB5の出力 output_low(PIN_B6); //RB6の出力 output_low(PIN_B7); //RB7の出力 //LED2が点灯 delat_ms( 3000 ) ; //3秒待つ        output_low(PIN_A0); //RA0の出力 output_high(PIN_B5); //RB5の出力 output_low(PIN_B6); //RB6の出力 output_low(PIN_B7); //RB7の出力 //LED3が点灯 delay_ms( 3000 ) ; //3秒待つ }

  • PICで小数点の演算

    PIC16F877Aを使ってプログラムを作っています。その内容がセンサー(例えば温度センサー等)から取り入れた電圧をPICのA/D変換(10bit)を行って、その値を使ってpicで計算し、その結果を液晶に表示するといった内容なのですが、その計算過程で小数を扱わなければならないのですが、その計算がうまくいきません。A/D変換後の値をxとし具体的に式で書くと、 v = x * 5 / 1023  ・・・(1) ここでvはセンサーから取り込んだ電圧値(値の範囲は0.935~1.748)です。 y = 218.5 - v / 0.008  ・・・(2) 又は y = 218.5 - 125 * v  ・・・(3) 上記の式はA/D変換後の値xを一度アナログ電圧値vに変換し(1)、そこから(2)又は(3)へ代入して得たい情報yを算出するといった少々面倒なものなのですが、これをアセンブラで書きたいのですが、このPICには乗除命令がないことや小数点の演算方法、16bitの乗除等の部分が引っかかってどうもうまくかけません。小数部分は固定小数点形式で考えて最終的にyは少数第二位を四捨五入したいと思っています。 どのようにプログラムを作ればよいのでしょうか。実際にソースを書いていただけると大変理解しやすいです。

  • PIC18でのA/D変換

    PIC18F67J60-l/PT(40MHz)で、C18を使ってA/D変換を行うプログラムを作成しました。 しかし、実際に接続をしてみると上手く動作しませんでした。 具体的には、Web上でA/D変換の結果を表示して確認しているのですが、 結果の値がばらついたり、0か1023が表示され、安定しません。 (1023以上の値が表示されないので、表示するプログラムには問題ないと思います) ピンの接続を何度も確認したり、接続状況を変えたのですが、 問題を解決するまでに至りませんでした。 プログラムに問題があるか、初心者なのでよく分かりません。 参考書や資料を見る限りではプログラムに問題はないと思うのですが、 皆様のご指摘を頂きたいと思います。 宜しくお願いします。 ------------------------------------------------------------------- (前提条件) Vref-はAN2(0V)、Vref+はAN3(3.3V)から取り、 入力をAN4、AN7、AN8、AN9から取り込む。 (作成したA/D変換プログラム)  //各レジスタの設定  ADCON1 = 0x35;  //VREF-はAN2、VREF+はAN3  TRISA = 0x2F;  //AN2,AN3は入力モード  TRISF = 0x1C;  //AN7~AN9を入力にする  ADCON2 = 0xB6;  //AN4用 加速度センサA1  ADCON0 = 0x11;  Delay10TCYx(0);  ADCON0bits.GO = 1;  while(ADCON0bits.GO);  Delay10TCYx(0);  uitoa(*((WORD*)(&ADRESL)), AN4String);  //AN7用 加速度センサA2  ADCON0 = 0x1D;  Delay10TCYx(0);  ADCON0bits.GO = 1;  while(ADCON0bits.GO);  Delay10TCYx(0);  uitoa(*((WORD*)(&ADRESL)), AN7String);  //AN8用 加速度センサB1  ADCON0 = 0x21;  Delay10TCYx(0);  ADCON0bits.GO = 1;  while(ADCON0bits.GO);  Delay10TCYx(0);  uitoa(*((WORD*)(&ADRESL)), AN8String);  //AN9用 加速度センサB2  ADCON0 = 0x25;  Delay10TCYx(0);  ADCON0bits.GO = 1;  while(ADCON0bits.GO);  Delay10TCYx(0);  uitoa(*((WORD*)(&ADRESL)), AN9String);  // AD converter errata work around (ex: PIC18F87J10 A2)  #if !defined(__18F452)  PRODL = ADCON2;  ADCON2bits.ADCS0 = 1;  ADCON2bits.ADCS1 = 1;  ADCON2 = PRODL;  #endif

  • マイコンによるDCモータの制御

    マイコンでDCモータの正転、逆転を制御したいのですがうまくいきません。 お力添えをお願いします。 ・使用するマイコン:PIC16F84A IC:TA7291P ・させたい動作 RB1のスイッチが押されると、2秒正転、2秒静止、2秒逆転、2秒静止→ループ ・問題点 マイコンからの出力をLEDに変えるとこの動作はうまくいくのですが、ICに出力するとうまくいきません。下にプログラムの一部を書きますが、while(s_f==1)のループに入れていないようです。 また、ICへの出力をマイコンからではなく、電源からの電流をスイッチングすると正転、逆転はうまくいきます。 マイコンとICの間に何かはさむ必要があるのでしょうか? while(1){ if(RB1==0) { while(s_f==1){ /*動作内容*/ RB4=1; RB5=0; delay(2000); //2秒待つ PORTB=0; delay(2000); RB4=0; RB5=0; delay(2000); RB4=0; RB5=1; delay(2000); } } }

  • PICマイコン 割り込み実行時間 (遅延時間)

    PICマイコン 割り込みの実行時間について、教えてください。 PICマイコン初心者です。 いろんな方々のプログラム例を参照させてもらっています。 PIC18F1320 を使って、外部割り込みを試していますが、トリガー信号の立ち上が入るタイミングで、割り込み処理を行いますが、トリガー信号から、割り込み動作Hが立ち上がりのが、遅くて困っております。トリガー信号から、遅れが少なくなる方法を教えてください。下記に現在のプログラ C言語を示します。 ・ポートRB1の外部割込 立ち上がりトリガー。 ・ポートRB0、RB2の状態をbstatに入れてIF文で、出力RB6 Hを出力したい。 ・トリガー立ち上がりから、約2usecも遅れてRB6がHに。遅延を出来るだけ少なくしたい。 ・ if (bstat==0)時で約2usec、if (bstat==3)時で約4usecと差が出るのも、改善したい。 #pragma code high_vector=0x8 //高位レベル割り込み void high_interrupt (void){ _asm GOTO high_isr _endasm } #pragma code //デフォルトコードセクションに戻る #pragma interrupt high_isr //割り込み処理関数宣言 void high_isr (void){ INTCON3bits.INT1IE=0; //外部割込みINT1の禁止 // INTCONbits.PEIE=0; //低位割り込み禁止 INTCONbits.GIE=0; //全割り込み禁止 INTCON3bits.INT1IF=0; //INT1の割り込みフラグをリセット if (bstat==0){ LATBbits.LATB6=1; // Delay1TCY(); //wait Delay1TCY(); //wait Delay1TCY(); //wait LATBbits.LATB6=0; // Delay1TCY(); //wait Delay1TCY(); //wait Delay1TCY(); //wait } else if(bstat==1){ LATBbits.LATB6=1; // Delay1TCY(); //wait Delay1TCY(); //wait LATBbits.LATB6=0; // Delay1TCY(); //wait Delay1TCY(); //wait } else if(bstat==2){ LATBbits.LATB6=1; // Delay1TCY(); //wait LATBbits.LATB6=0; // Delay1TCY(); //wait } else if(bstat==3){ LATBbits.LATB6=1; // Delay1TCY(); //wait LATBbits.LATB6=0; // Delay1TCY(); //wait } INTCON3bits.INT1IE=1; //外部割込みINT1の許可 // INTCONbits.PEIE=1; //低位割り込み許可 INTCONbits.GIE=1; //全割り込み許可 } // メインプログラム void main (void){ TRISB = 0b00000111; // RB0/1/2:input TRISA = 0xFF; // ALL A input // PORTB = 0; PORTA = 1; bstat= ((PORTBbits.RB0+0)+(PORTBbits.RB2*2));// RB0とRB2の状態を読み込み OpenRB1INT(PORTB_CHANGE_INT_ON & // ポートRB1の外部割込みオン RISING_EDGE_INT & //立上りエッジでオン PORTB_PULLUPS_OFF //Bポートの抵抗プルアップOFF ); RCONbits.IPEN=1; //割り込み優先順位制御ON(0:優先順位制御OFF) INTCON3bits.INT1IP=1; //INT1の割り込みを高順位割り込みにセット INTCON3bits.INT1IE=1; //INT1の割り込みを許可 INTCON2bits.INTEDG1=1; //立上がりエッジでオン // INTCONbits.PEIE=1; //低位割り込み許可 INTCONbits.GIE=1; //全割り込み許可 while (1) PIC関係サイトを探しても、割り込みでの遅れ時間については、ヒントがありませんでした。 相当な遅れは、あきらめるしかないのでしょうか? ご存知の方、アドバイスをお願い致します。

  • C言語に関する質問

    初期位置を1mとして、ある物体の自由落下をシミュレートするプログラムを 「高さ=1-1/2×重力加速度×経過時間の二乗」 という考え方を 「初期位置を1m,落下速度を「重力加速度×1ループにかかる時間」とし, 高さを,「1ループ前の高さ」+「落下速度×1ループにかかる時間」」という考え方に変更して計算するようなプログラムにしたいのですが、どのように変えれば分かりません。(というか意味が分からないです) 何か公式などのヒントやソースコードより、どの部分をこのように変えれば良いという指摘があれば分かりやすく教えてください。 #include <windows.h> #include <mmsystem.h> #include <stdio.h> #include <conio.h> #pragma comment(lib, "winmm.lib") int main(void) { int command;//キーボード入力の文字判別用変数 int quit_flag = 1;//プログラム終了フラグ 0で停止 int c_flag = 0;//カウント状態取得用フラグ 1:カウント中,0:停止中 int h,m,s,ms;//左から,時間,分,秒,ミリ秒 double y=1; DWORD start; printf("使い方:小文字の's'でカウントスタート.カウント中,小文字の's'で停止.次の's'でまた0からスタート\n"); printf("使い方:どんな状態でも小文字の'r'でカウントリセットして停止\n"); printf("使い方:qでプログラム終了\n\n"); h=m=s=ms=0; while(quit_flag != 0)//quit_flagが0以外ならループ { while(!_kbhit())//何かキーが押されるまでループ { if(c_flag != 0)//c_flagが0以外であればカウント中ということ. { h=m=s=ms = timeGetTime() - start; y=1-(1.0/2.0)*(9.8/1000000)*ms*ms; printf("t=%d[ms],y=%f[m]\r",ms,y); //printf("t=%02d:%02d:%02d:%03d,y=%f[m]\r",h/3600000,(m/60000)%60,(s/1000)%60,ms%1000,y); } //printf("%02d:%02d:%02d:%03d\r",h/3600000,(m/60000)%60,(s/1000)%60,ms%1000); if(c_flag==0){ printf("t=%d[ms],y=%f[m]\r",ms,y); //printf("t=%02d:%02d:%02d:%03d,y=%f[m]\r",h/3600000,(m/60000)%60,(s/1000)%60,ms%1000,y); } } command=_getch();//ループを抜けるために押されたキーの内容をcommandに代入. if(command=='s' && c_flag == 0) { printf("\n計測開始\n"); c_flag = 1; start = timeGetTime() ; h=m=s=ms=0; /* if(y==0){ printf("\n終了\n"); quit_flag = 0; } */ } else if(command=='s') { printf("\n計測中止\n"); c_flag = 0; } else if(command=='r') { printf("\nカウンタリセット,停止\n"); c_flag = 0; h=m=s=ms=0; } else if(command=='q') { printf("\n終了\n"); quit_flag = 0; } } return 0; }

  • C18 A/D変換 値の表示

    加速度センサから取得したデータ(x,y)を基に、 傾きを知るために以下のプログラムを作成しました。 x,yの値は正常に表示できたのですが、計算結果outg1が上手く表示できませんでした。 アドバイス、お願いします。 --------------------------------------------------------------------- //AN4用 加速度センサA1 ADCON0 = 0x11; Delay10TCYx(0); ADCON0bits.GO = 1; while(ADCON0bits.GO); Delay10TCYx(0); g1 = (int)((WORD*)(&ADRESL)); uitoa(*((WORD*)(&ADRESL)), AN4String); //AN7用 加速度センサA2 ADCON0 = 0x1D; Delay10TCYx(0); ADCON0bits.GO = 1; while(ADCON0bits.GO); Delay10TCYx(0); g2 = (int)((WORD*)(&ADRESL)); uitoa(*((WORD*)(&ADRESL)), AN7String); //加速度センサA 傾き計算 出力 outg1 = atan(g2/g1); outg1 = (outg1*180.0f)/3.1415f; itoa((int)outg1, out_g1String); -------------------------------------------------------------------