• ベストアンサー

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秒待つ }

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★回答ではないが気になったので。 >main() //main関数の開始宣言  ↑  main関数の定義です。開始の宣言ではないです。記述の開始かな。 >while(1){ //無限ループのwhile文の宣言  ↑  while文の宣言という表現はおかしいね。  ちなみに無限ループなら for( ; ; ){ … } でも出来ます。 本題: ・LED の点灯と停止の方法  RA2ポートの入力状態のチェック方法  の2つを教えて下さい。 ・考え方としては delay_ms() 関数の部分にRA2ポートの入力状態をチェックしてその場で  停止したり、再開させたりすれば良いと思います。つまり、delay_ms() 関数で 3 秒間  のループを作ってそのループ内でRA2ポートの入力状態から停止、再開を出来るように  記述するわけです。    while (1){   // LED1の点灯   for ( int i = 0 ; i < 3000 ; ){    /*    RA2ポートの入力状態を読み出す    例えば flag 変数に停止なら 0、再開なら 1 を入れるとする    */    if ( flag ){ // 再開の時に処理     i++; // ここでインクリメント    }    delat_ms( 1 ); // 1ms待つ   }   // LED2の点灯   for ( int i = 0 ; i < 3000 ; ){      :    上と同じ処理      :   }   // LED3の点灯   for ( int i = 0 ; i < 3000 ; ){      :    上と同じ処理      :   }  } 最後に: ・for 文のループは関数にして3箇所に記述したほうが便利です。 ・以上。

chicken773
質問者

お礼

詳しい回答有難うございます 確かに日本語表現もおかしい所がありました、これでは分かり難くなってしまいますね。 for文でループを作るというのは考え付きませんでした! 確かにこれであれば【3秒間の間に信号を入れる→LED停止】という形になりそうです。 非常に参考になりました。

その他の回答 (3)

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

>つまりこの反転処理というのはflag変数を反転させるための処理ということなのですね。 その通りです。 チャタリングに関しては、ここが参考になるかと。 http://www.picgames.org/modules/tinyd1/index.php?id=5 高度な処理としては、チャタリングの処理をタイマー割り込みで処理させるとメインループがシンプルになるので、勉強が進んだら挑戦してみてください。 それとbeforeRA2はRA1の値を代入してからループに入るようにしてください。そうしないと、何も変化していないのにトリガ反転する恐れがあります。 おまけで、このプログラムをアセンブラのテクニックで書くとこんな感じにも書けます。参考まで。 int i; while( 1 ) { for( i=0 ; i<3 ; i++ ) { // PIN_A,PIN_Bは、ポートのレジスタを8bitでアクセスします。 PIN_A = (PIN_A & 0xfe) | (i & 0x01); PIN_B = (PIN_B & 0x1f) | ((i & 0x0e)<<4); delay_ms( 3000 ) ; //3秒待つ } }

chicken773
質問者

お礼

チャダリングについて理解できました! これを知らないでプログラムをしたらおかしな動作をしそうです(汗 プログラムというのは奥が深いですね、今回は非常に参考になりました、ありがとうございます。

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

ANo.2の方の答えで、ほぼ問題ないと思います。 ただし、RA2の入力がSWからの場合はチャタリング対策処理されていることが必要です。そこは大丈夫ですか? それと、トリガ反転するプログラムも組む必要があります。使われているのはCCS Cだと思うのですが使った事が無いので、それっぽくイメージで書かせてもらいます。 // トリガ反転処理。 if( RA2 != beforeRA2 ) { //1回前のRA2と状態が違う場合 beforeRA2 = RA2; //状態を保存する。 if( RA2 == 1 ) { //SWが1ならトリガ反転する。 flag ^= 1; //フラグの状態を反転する。 } }

chicken773
質問者

お礼

間違いに気づきました、入力はRA2でなくRA1でした、申し訳ありません。 チャダリング処理、トリガ反転・・・全く意識していませんでした まだまだ勉強不足な事が多いようです。 つまりこの反転処理というのはflag変数を反転させるための処理ということなのですね。

  • SRitchie
  • ベストアンサー率21% (103/470)
回答No.1

文面及び添付ソースから詳細はわかりませんが、添付ソースにポートAの入力or割り込みをチェックするルーチンが無いですよね。

関連するQ&A

  • PICによるLED制御について

    大学の講義でPICのLED制御の課題がよくわかりません。 どなたか教えていただけないでしょうか? [問]  PIC16F84Aにおいて、動作を実現するプログラムを示せ。  メインルーチンでLED出力の点燈箇所を1秒ごとに巡回させる。   RA3=Low(OFF)のとき、左向きに巡回シフト(RLF命令)させる。   RA3=High(ON)のとき、右向きに巡回シフト(RRF命令)させる。  また割り込みルーチンによって、RA0~RA2の3ビットの値に応じて  点灯速度を変化させる(値が大きいほど速く)  ただし、ポートAは全て入力モード、ポートBはRB0以外を出力モードとし(RB0は割り込み用)、ポートBの初期出力を0000100*(LED出力の初期点燈位置は第3ビットのみ)とせよ。

  • C言語のPICプログラミングなんですが、

    C言語のPICプログラミングなんですが、 これのどこがおかしいか教えてください。 if(input(PIN_B1)) { while(input(PIN_B2) == 0) { output_high(PIN_B7); //前進後進パルス出力 delay_us(50); //変換待ち output_low(PIN_B7); delay_us(16000); //共通遅延16000us } break; } if(input(PIN_B1)) { while(input(PIN_B2) == 0) { output_high(PIN_B7); //前進後進パルス出力 delay_us(50); //変換待ち output_low(PIN_B7); delay_us(16000); //共通遅延16000us } break; }

  • PICでのプログラミングについて教えて下さい。

    現在電圧計を製作していて4桁の7セグダイナミック点灯で行き詰っております(超初心者です)。 PICは16F873Aを使用、コンパイラはCCS、書き込みはピックライタ、あとシリアルデバッカを使用しています。 外部から電圧をかけそれをAD変換し、AD変換結果(0~5V)を7セグに表示させようとしています。 一応今の状態でも電圧表示はできていることはできているのですが一桁目から4桁目まで目で追えるくらい遅いスピードでこれを改善したいです。ソースは下記のソースを製作しました。この状態で3日間悩んでおります...知恵をお貸しいただけないでしょうか。 よろしくお願いします。 #include <16F873a.h> #device ADC=10 //A/D変換10bitモード #use fast_io(A) /* TRISレジスタの設定が必要 */ #use fast_io(B) #use fast_io(C) #use delay (clock=10000000) //10MHz #use RS232( BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, PARITY = N, BITS = 8 ) #fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP #define VOLTAGE PIN_A0 // (in) #define CORRENT PIN_A1 // (in) #define VREF1 PIN_A2 // (in) #define VREF2 PIN_A3 // (in) #define RESERVE1 PIN_A4 // (out) #define RESERVE2 PIN_A5 // (out) #define LED_DP PIN_B0 // (out) #define LED_A PIN_B1 // (out) #define LED_B PIN_B2 // (out) #define LED_C PIN_B3 // (out) #define LED_D PIN_B4 // (out) #define LED_E PIN_B5 // (out) #define LED_F PIN_B6 // (out) #define LED_G PIN_B7 // (out) #define DIG_0 PIN_C0 // (out) #define DIG_1 PIN_C1 // (out) #define DIG_2 PIN_C2 // (out) #define DIG_3 PIN_C3 // (out) #define INI_TRIS_A_VAL 0x0F // 7:x 6:x 5:out 4:out 3in 2:in 1:in 0:in #define INI_TRIS_B_VAL 0x00 // 7:out 6:out 5:out 4:out 3out 2:out 1:out 0:out #define INI_TRIS_C_VAL 0x80 // 7:in 6:out 5:out 4:out 3:out 2:out 1:out 0:out int ct;//数字の更新間隔 long val;//表示する数字 int digit;//表示する桁 //表示パターン int segment_data[]={0x81,0xF3,0x49,0x61,0x33,0x25,0x05,0xF1,0x01,0x31}; char st[4]; void main() { float ata1,data2,data3,data4; long data5; long val; SET_TRIS_A( INI_TRIS_A_VAL ); SET_TRIS_B( INI_TRIS_B_VAL ); SET_TRIS_C( INI_TRIS_C_VAL ); setup_adc_ports(AN0_AN1_VSS_VREF); setup_adc(ADC_CLOCK_DIV_32); //Fosc/32 最高速度 digit=0; ct=1;//数字を更新する周期 val=0;//表示する値 while(1) { output_low(RESERVE2); //動作ランプ //////////////////////電圧測定///////////////////////////////// set_adc_channel(0); delay_us(50); //アクイジションタイム待ち(マイクロ秒) data1 = read_adc(); //AD変換結果読み込み printf("ADC V %9.3f \r\n", data1 ); //AD変換データ表示 data2 = (data1 * 4.959695) / 1024; //BCDに変換 printf("Volt %6.3f \r\n", data2 ); //変換データ表示 data5 = data2 * 1000 ; //data2を整数に変換 val = data5 ; printf("val %ld \r\n", val); //整数にし表示 /////////////////////7SEG表示////////////////////////////////// ct --; if(ct == 0){//数字の更新 st[3]=val/1000; //4桁目数値取り出し st[2]=val/100-st[3]*10;//3桁目数値取り出し st[1]=val/10-((st[3]*100)+(st[2]*10));//2桁目数値取り出し st[0]=val%10;//あまり val++; if(val==1000) val=0; ct=20; } if(digit== 3){//第4桁の表示 output_b( segment_data[st[3]]); output_bit(DIG_0,1);  //4桁表示開始 output_low(LED_DP);  //小数点表示  delay_us (5); //表示期間(ミリ秒) output_bit(DIG_0,0); //表示を消す output_high(LED_DP); //小数点を消す delay_us(50); //待ち(マイクロ秒) } if(digit== 2){ output_b( segment_data[st[2]]); output_bit(DIG_1,1); delay_ms (5); output_bit(DIG_1,0); delay_us(50); } if(digit== 1){ output_b( segment_data[st[1]]); output_bit(DIG_2,1); delay_ms (5); output_bit(DIG_2,0); delay_us(50); } if(digit == 0){ output_b( segment_data[st[0]]); output_bit(DIG_3,1); delay_ms (5); output_bit(DIG_3,0); delay_us(50); } digit ++;//表示桁を変更 if(digit ==4 ) digit=0; } }

  • C言語でLEDを点灯させるプログラムです

    C言語を使ってLEDを点灯させるプログラムです。 以下のプログラムを変更して、Aポートの入力(下位4ビット) と、Cポートの入力(下位4ビット)を加算した値をBポートに出力しなさい 。 という問題なのですが、加算した値を出力するにはどうプログラムを記述すればいいか 分かりません。教えてください。 また、加算するというのは、たとえばどういうふうにしろ ということなのか、教えてください。 #include<18F452/h> #device HIGH_INTS=TRUE #priority ext,rb #fuses NOOSCSEN,HS,BORV45,NOBROWNOUT,PUT #fuses WDT128,NOWDT #fuses NODEBUG,NOLVP,NOSTVREN #fuses NOPROTECT,NOCPD,NOCPB #fuses NOWRT,NOWRTD,NOWRTB,NOWRTC,NOEBTR,NOEBTRB #use delay (CLOCK=20000000) #use fast_io(A) #use fast_io(B) #use fast_io(C) #use fast_io(D) #use fast_io(E) #byte port_a=0xf80 #byte port_b=0xf81 #byte port_c=0xf82 #byte port_d=0xf83 #byte port_e=0xf84 int i=0,j=0; void main() { if(input(PIN_b4)){output_high(PIN_d4);} else{output_low(PIN_d4);} if(input(PIN_b5)){output_high(PIN_d5);} else{output_low(PIN_d5);} if(input(PIN_b6)){output_high(PIN_d6);} else{output_low(PIN_d6);} if(input(PIN_b7)){output_high(PIN_d7);} else{output_low(PIN_d7);} while(1) { output_c(0b10101010); } }

  • PICによる7セグLED3桁制御

    PICによる7セグLED3桁制御 度々こちらに、お世話になっております。 今回は、3桁のLEDを1から999までカウント表示する プログラムに取組んでいるところ希望通りに、動いてはくれません。 このソースのベースは2桁(1から99までカウントUP)の ソースコードを変更して、3桁表示させる様にしてみました。 コード概要はtimer0割込みで3.2msのインターバルタイムの間、 LEDをダイナミック点灯させ、timer1では、100msのインターバルタイムを 10回繰り返し(1秒毎に)counterを1プラスしてLEDの表示を1ずつ 増して999まで表示後、また000から繰返すと言う単純な動作のものです。 main()関数内はtimer0とtimer1の割込み設定及び 割込み開始、許可を繰返すだけです。 問題の#timer0,#timer1割込み関数処理部分における実行結果は、 000から111と言う具合に3桁が同時にカウント表示されてしまい、 しかも繰り上がる時間は1秒毎の筈が、100秒毎になります。 このコードはCCS-Cコンパイラに準拠していて、 標準Cとは多少異なる部分があり解りにくいと思いますが どうかどなた様からも検証より不具合コード部分のご指摘と修正を 頂くことが出来るなら、大変光栄に思います。 そこで、PICにおけるconfigu部分は省き、概ねのコードを記します。 //// 1:static long int number; 2:static int counter; 3:int const LED_SEG[11]= {0x7E,0xCC,...略} 4:#int_timer0 5:void isr() { 6:static int a,b,c = 0; 7:int x; 8:out_low(PIN_C0); // LED 1桁目off 9:out_low(PIN_C1); // LED 2桁目0ff 10:out_low(PIN_C2);// LED 3桁目0ff 11:a = number % 10; 12:x = number/10; 13:b = x % 10; 14:c = x / 10; 15:output_b(LED_SEG[a]); 16:output_high(PIN_C0);//1桁目ON 17:output_b(LED_SEG[b]); 18:output_high(PIN_C1);//2桁目ON 19:output_b(LED_SEG[c]); 20:output_high(PIN_C2);//3桁目ON } 21:#int_timer1 22:void isr() { 23:set_timer1(0x0BDC);//100ms再設定 24:counter++; 25:if(counter>9)//10回か { 26:counter = 0; 27:number++; } 28:if(number>1000) { 29:number = 0; } } 30:void main() { 略 31:setup_timer0(3.2msセット) 32:setup_timer1(100msセット) 33:timer0割り込み許可 34:timer1割り込み許可 35:GLOBAL全体割り込み許可 36:while(1){} } //// 以上宜しくお願いいたします。

  • PIC マイコンの原因不明の破壊

    PIC16F873A を使用してます RB ポートの入力に変化があったとき、RB の内容によってあるパターンを1秒間だけ RC に出力する内容で動作させています ところが、おそらく電源の ON/OFF のタイミングで RB ポートが壊れてしまいます 具体的な症状として、入力ポートにもかかわらず勝手に Low 状態(著しく電圧が下がる状態)になり、そのまま Low 状態と誤認識してしまいます 一度 Low に落ちてしまったピンは、プログラムを書き直してもずっと Low の状態です RB ポートのうち、どのポートが壊れるのかはランダムです 複数壊れる場合もあります RB へのプルアップ抵抗は 100K Ωです 電源はバッテリーから DCDC コンバーター(OBR05SC0512)で5Vにしたものを供給しています ノイズ対策の為、DCDC コンバーターは別の基盤に取り付け、該当の基盤から離しています 4.98V で安定出力しているようです PIC の電源付近にノイズ対策のため、積層セラミックコンデンサの 104 を置いてます 該当箇所のプログラムは以下のとおりです if (InputMemory != input_b()) { InputMemory = nput_b(); if ((!input(PIN_B0)) && (CountStart != TRUE)) { output_c(Speed0); } else if ((!input(PIN_B1)) && (CountStart != TRUE)) { output_c(Speed1); } else if ((!input(PIN_B2)) && (CountStart != TRUE)) { output_c(Speed2); } else if ((!input(PIN_B3)) && (CountStart != TRUE)) { output_c(Speed3); } else if ((!input(PIN_B4)) && (CountStart != TRUE)) { output_c(Speed4); } else if ((!input(PIN_B5)) && (CountStart != TRUE)) { output_c(Speed5); } CountStart = TRUE; TimerCount = 0; for (; CountStart == TRUE; ) { if (InputMemory == input_b()) { TimerCount++; delay_ms(100); if (TimerCount == 10) { output_c(0b11111111); CountStart = FALSE; } } else { CountStart = FALSE; } } } else { output_c(0b11111111); } お手数ですが、ご解答よろしくお願いいたします

  • 16F88を用いてLEDの点灯パターンを制御する

    16F88を用いてLEDの点灯パターンを制御するプログラムを作ったのですが、思うように動作してくれません。 電源を入れたときはLEDはすべて消灯しており、スタートのためのスイッチを押すとすべてのLEDが3回点滅するはずなのですが、実際のところ、全てのLEDが点灯しっぱなしになってしまいます。 心当たりはコンフィギュレーションビットの設定が間違っている、PICの出力が間違っている(A/Dが正しく設定されていない)といったことを考えたのですが、結局解決には至りませんでした。 ほぼ同じプログラムを16F84Aにて作ったところ正常に作動したため、PICの移行に伴って不具合が生じてしまったのでしょうか。 どなたかお力をお貸しください。 プログラムはMPLAB v8.85 にて作成しており、コンパイラはHI-TECH ANSI C Compiler で、書き込みにはPICKIT2を用いています。 RB0~7にLEDが接続されており、RA0にスイッチが接続されています。 以下、ソースコードになります。 #define _LEGACY_HEADERS #include <htc.h> #define _XTAL_FREQ 20000000 __CONFIG ( HS & WDTDIS & PWRTDIS & UNPROTECT & MCLREN & BOREN & LVPDIS & DEBUGDIS & IESODIS & FCMDIS); void kaeru(void){ ////////////準備点灯3回////////////// PORTB=0xFF; __delay_ms(500); PORTB=0x00; __delay_ms(500); PORTB=0xFF; __delay_ms(500); PORTB=0x00; __delay_ms(500); PORTB=0xFF; __delay_ms(500); PORTB=0x00; __delay_ms(800); //////////////////////////////////// //スペースの都合で省略しています。 } void main(void) { ANSEL=0b00000000;//16F88のPORTAのA/D変換の無効化 OPTION=0x7F;//PORTBのプルアップ PORTA=0x00;//初期設定 PORTB=0x00;//初期設定 TRISA=0x01;//RA0を入力 TRISB=0x00;//RB0~7を出力 if(RA0==1) kaeru(); }

  • マイコンによる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マイコンでLEDの点滅をC言語で記述法を教えてください

    PICマイコン(PIC16F84A)にLEDを1個接続し点滅だけのプログラムをC言語で記述を書きたいのですが、教えていただけないでしょうか? CCS社のコンパイラを用いた時の記述の書き方を教えていただけないでしょうか? 条件は、 ・電池を繋げるとLEDが点滅、スイッチ素子は用いません。 ・LEDは1秒間隔で点滅し、永遠に点滅 ・LEDは、PICマイコン(PIC16F84A)の9番ピン(RB3に該当)に接続 ・水晶発振子は、10MHzを使用。 ・コンパイラは、CCS社を使用 私が分かる範囲は下記なのですが、これから先の記述方法が分かりません。 #include <16f84a.h> #fuses HS, NOWDT, NOPROTECT #use delay(clock=10000000) #byte port_b=6 main() { この中身の記述方法が分かりません。 教えていただけないでしょうか? } よろしくお願いします。

  • PIC I2C について

    8ビットのデータを送り、そのままスレーブのLEDに反映させるプログラムを組んでいます。 マスターからはリピートして何度もデータを送ります。 このとき、なぜか一瞬アドレスのビットデータをLEDに反映させてから本来のデータを表示します。 つまり、アドレスとデータを交互にLEDに表示する状況です。 たとえば、アドレスが 0b1111111 データが 0b00000000 だとします。 本来LEDは消灯状態にならなくてはいけないのですが、なぜか一瞬アドレスデータの内容で光ります 原因がお分かりの方はいらっしゃいますか? 使用PIC PIC16F873A //master #use i2c(MASTER, SDA=PIN_C4, SCL=PIN_C3, SLOW, RESTART_WDT, FORCE_HW) output_float(PIN_C3); output_float(PIN_C4); while (1) { i2c_start(); i2c_write(AddData << 1); i2c_write(sBitData); i2c_stop(); delay_ms(50); } //slave #use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0x00, SLOW, RESTART_WDT, FORCE_HW) output_float(PIN_C3); output_float(PIN_C4); while (1) { if (i2c_poll()) { indata = i2c_read(); output_b(indata); } }

専門家に質問してみよう