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

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

zwiの回答

  • 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); -------------------------------------------------------------------

関連する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); -------------------------------------------------------------------