////////// (株)アイ・エス・ティ ////////// ライントレースマイクロロボット MR-LT-1406 サンプルプログラム ////////// ////////// コンパイル確認環境(1):Microchip MPLAB IDE v8.63 + HI-TECH C Compiler for PIC10/12/16 MCUs Lite mode v9.81 ////////// ////////// コンパイル確認環境(2):Microchip MPLAB X IDE v2.10 + MPLAB XC8 Free Edition v1.31 ////////// ////////// プリプロセッサとコンフィグレーション #include // ヘッダファイルを追加する。 // 「<>」で囲まれたヘッダファイルは、コンパイラのインストールされたフォルダ内にあるincludeフォルダから呼び出される。 // 参考として、""で囲まれたファイルの場合はこのソースファイルLinetrace_Kit_Standard_20MHz_HI-TECH_C.cが // また参考として、「""」で囲まれたヘッダファイルの場合は、このソースファイルが含まれているフォルダから呼び出される。 // つまり、もしも「""」と書いた場合は、ソースファイルをコンパイルする前にpic.hをProjectsのHeader Filesに追加しておかなければならない。 #define _XTAL_FREQ 4000000 // pic.hの中に記述されている__delay_msマクロ関数を使用するためにクロック周波数をHz単位で指定する。 // キットでは4MHzを使用するので、4000000Hzとなる。 __CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_ON & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CCPMX_RB2 & CP_OFF); // コンフィグレーションビットを設定する。上記の書式はHI-TECH C Compiler for PIC10/12/16 MCUs v9.81で用いられていたものであるが、 // その後継コンパイラであるXC8 v1.31ではこの旧い書式のままでも認識し、コンパイルすることが可能である。 // 一方、XC8本来の新しい書式では次のようになる。 // #pragma config FOSC = INTOSCIO, WDTE = OFF, PWRTE = ON, MCLRE = ON, BOREN = OFF, LVP = OFF, CPD = OFF, WRT_OFF, DEBUG = OFF, CCPMX = RB2, CP = OFF // 内部RC発振モード使用(RA6およびRA7はI/Oポートに設定)、ウォッチドッグタイマ不使用、 // パワーアップタイマ使用、RA5(MCLR)ピンは外部リセット端子として使用、ブラウンアウトリセット禁止、 // 低電圧プログラムをしない、データEEPROMのコードプロテクト禁止、フラッシュプログラムメモリ書き込み許可、 // デバッグモード禁止、CCP1の出力ピンをRB2に設定(RB3とどちらか一方に設定できるが、このサンプルプログラムでは無関係)、 // フラッシュプログラムメモリのコードプロテクト禁止 // MCLRピンを外部リセット端子として「使用しない」設定で書き込みを行ったPICに対し、再度プログラムの書き込みを行う場合、 // あるいはプログラムの読み出しを行う場合に、PICライタと信号の入出力をするにあたってPICのリセットがかからず、 // 書き込みあるいは読み出しが正常に行われない場合がある。 // このロボットにはMCLRピンを利用する外部リセット回路は存在しないものの、上記の問題を防ぐために // コンフィグレーションビットにおいてはMCLRピンを外部リセット端子として「使用する」設定としている。 ////////// ピン設定 #define SENSOR_LL RA3 // 左外側センサ入力ポートを指定:RA3(2番ピン) #define SENSOR_L RA2 // 左内側センサ入力ポートを指定:RA2(1番ピン) #define SENSOR_R RA1 // 右内側センサ入力ポートを指定:RA1(18番ピン) #define SENSOR_RR RA0 // 右外側センサ入力ポートを指定:RA0(17番ピン) #define LED_OUT RB5 // LED出力ポートを指定:RB5(11番ピン) #define MOTOR_L1 RB1 // MOTOR_L1出力ポートを指定:RB1(7番ピン) #define MOTOR_L2 RB4 // MOTOR_L2出力ポートを指定:RB4(10番ピン) #define MOTOR_R1 RB3 // MOTOR_R1出力ポートを指定:RB3(9番ピン) #define MOTOR_R2 RB2 // MOTOR_R2出力ポートを指定:RB2(8番ピン) // このキットでは、モータの極性(端子の名称)に関して次のように取り決めている。 // 左車輪を正転させる場合に+側とするべき左モータの端子:MOTOR_L1 // 左車輪を逆転させる場合に+側とするべき左モータの端子:MOTOR_L2 // 右車輪を正転させる場合に+側とするべき右モータの端子:MOTOR_R1 // 右車輪を逆転させる場合に+側とするべき右モータの端子:MOTOR_R2 // ここでの正転・逆転は、モータではなく車輪の回転方向を表している。 // 一般的に「モータが正転する」というのは、モータ出力軸側(負荷側)から見てその軸が反時計回りに回転することを示す。 // また、このロボットにおいては、モータとモータドライバ間の配線、モータ出力軸の回転方向と車輪の回転方向との関係、 // 車体左右の鏡像の関係などに注意が必要である。 ////////// 直進関数 // このプログラムにおいて、直進して走行するための一連の処理は同一のものを使用する場面が複数ある。そこでこれをあらかじめひとまとまりの関数として用意しておく。 // またこのプログラムでは、モータの駆動にPWM制御を採用している。これは簡単に言えば、モータへの通電を高速でON/OFFするタイミングによって回転数を制御するものである。 void straight() // 直進関数 { MOTOR_L1=1; // 左車輪正転 MOTOR_L2=0; MOTOR_R1=1; // 右車輪正転 MOTOR_R2=0; __delay_ms(2); // 処理が次へ進むのを設定した時間だけ遅延させる。 // この命令はHI-TECH C Compiler独特のもので、クロック周波数に依存する上限値が存在する。 // 今回のようにクロック周波数が4MHzの場合、指定できる時間は197msまでとなる。 // したがってそれより大きな時間を指定するときは、for文によるループを利用するなどの工夫が必要となる。 // また、この命令では指定する時間に変数を利用することができないため、直接定数を指定する必要がある。 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(3); // 処理が次へ進むのを設定した時間だけ遅延 } ////////// メイン関数 void main() // メイン関数 { OSCCON=0b01100000; // 内部クロックを4MHzに設定 ADCON1=0b00000110; // A/Dコンバータ不使用、アナログI/Oポートとしても使用可能なA0〜A4ポートををデジタルI/Oポートに設定する。 TRISA=0b00001111; // RA0からRA3までは入力に、RA4からRA7までは出力に設定 // このキットの例ではRA5からRA7までのように、未使用のポートはノイズ対策のため出力に設定しておくと良い。 TRISB=0b00000000; // RB0からRB7までを全て出力に設定 char j=0; // 文字型の変数jを宣言、初期値を0として周回数のカウントに利用する。 char k; // 文字型の変数kを宣言、for文の繰り返し命令に利用する。 while(1) // コンパイラの特性により、意図しないのにmain関数全体が無限ループとなってしまうのを防ぐため、 // ここでプログラムの区切りとしてwhile(1)による無限ループを設けておく。 // これを行わないと、このサンプルプログラムの例ではjやkのような変数の値などがその都度リセットされてしまうことになる。 // CCS C Compilerなど、コンパイラの種類によってはこのような対策は行わなくても良い場合がある。 { while(j<=2) // 以下の処理のループはjが2以下の場合に行われる。この場合、コースを2周したら走行終了となる。 { LED_OUT=1; // LEDを消灯 // 0ではなく1を出力して消灯するのは、ポートへのシンク電流を利用した回路の構成による。 if(SENSOR_LL==0 && SENSOR_L==0 && SENSOR_R==0 && SENSOR_RR==0) // 全てのセンサが黒(スタート・ゴールライン)を検出した場合、次の処理を行う。 { LED_OUT=0; // LEDを点灯 MOTOR_L1=1; // 左車輪ブレーキ MOTOR_L2=1; MOTOR_R1=1; // 右車輪ブレーキ MOTOR_R2=1; for(k=0;k<10;++k) // 繰り返し命令を利用し、処理が次へ進むのを設定した時間だけ遅延させる。 { __delay_ms(100); // この100msを10回繰り返して1sを作り出す。 } ++j; // jに1を加算し、これを周回数とする。 if(j<=2) // jが2以下の場合、次の処理を行う。 { for(k=0;k<30;++k) // 直進関数を複数回実行してわずかな距離だけ走行し、スタート・ゴールラインを抜け出す。 { straight(); // 直進関数を使用 } } } if(SENSOR_LL==1 && SENSOR_L==1 && SENSOR_R==1 && SENSOR_RR==1) // 全てのセンサが白(路面)を検出した場合、次の直進処理を行う。 { straight(); // 直進関数を使用 } if((SENSOR_L==0) || (SENSOR_LL==0 && SENSOR_L==0)) // 左内側センサが黒(ライン)を検出した場合、または左外側センサと // 左内側センサが黒(ライン)を検出した場合、次の左信地旋回処理を行う。 { LED_OUT=0; // LEDを点灯 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=1; // 右車輪正転 MOTOR_R2=0; __delay_ms(4); // 処理が次へ進むのを設定した時間だけ遅延 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(3); // 処理が次へ進むのを設定した時間だけ遅延 } if(SENSOR_LL==0) // 左外側センサが黒(ライン)を検出した場合、次の左超信地旋回処理を行う。 { LED_OUT=0; // LEDを点灯 MOTOR_L1=0; // 左車輪逆転 MOTOR_L2=1; MOTOR_R1=1; // 右車輪正転 MOTOR_R2=0; __delay_ms(2); // 処理が次へ進むのを設定した時間だけ遅延 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(3); // 処理が次へ進むのを設定した時間だけ遅延 } if((SENSOR_R==0) || (SENSOR_R==0 && SENSOR_RR==0)) // 右内側センサが黒(ライン)を検出した場合、または右内側センサと // 右外側センサが黒(ライン)を検出した場合、次の右信地旋回処理を行う。 { LED_OUT=0; // LEDを点灯 MOTOR_L1=1; // 左車輪正転 MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(4); // 処理が次へ進むのを設定した時間だけ遅延 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(3); // 処理が次へ進むのを設定した時間だけ遅延 } if(SENSOR_RR==0) // 右外側センサが黒(ライン)を検出した場合、次の右超信地旋回処理を行う。 { LED_OUT=0; // LEDを点灯 MOTOR_L1=1; // 左車輪正転 MOTOR_L2=0; MOTOR_R1=0; // 右車輪逆転 MOTOR_R2=1; __delay_ms(2); // 処理が次へ進むのを設定した時間だけ遅延 MOTOR_L1=0; // 左車輪フリー MOTOR_L2=0; MOTOR_R1=0; // 右車輪フリー MOTOR_R2=0; __delay_ms(3); // 処理が次へ進むのを設定した時間だけ遅延 } } // while(j<=2)の末端 // 走行が終了したことを示すためにLEDを点滅させる。以下の命令はWhile(1)の中に含まれているので無限ループとなる。 // クロック4MHzにおける__delay_ms命令の上限値197msを用いて、約0.2s間隔での点滅を行う。 LED_OUT=1; // LEDを消灯 __delay_ms(197); // 処理が次へ進むのを設定した時間だけ遅延 LED_OUT=0; // LEDを点灯 __delay_ms(197); // 処理が次へ進むのを設定した時間だけ遅延 } // while(1)の末端 } // void main()の末端