二進数マイコンロボットの製作
 C言語を使って、二進数マイコンロボットを作ろう。
 白黒の明るさを読み取るのは、フォトリフレクターという部品を使います。フォトリフレクターは、明るさによって、流れる電流が変化します。これを読み取るためのマイコンを撰びます。PIC12F1572は、アナログ入力で、電圧の変化を知ることができ、ラジコンサーボを動かすPWM信号を出力するハードウェアを内蔵しています。

  二進数は 0と1で表現されます。二進数を使うことで、モニターが白を0、黒を1とすることができます。これをスイッチとして使うことができそうですが、白と黒の境界をどうするかが問題になります。マイコンを使うことで、境界を判定して動作させることができるようになる、マイコンならではの二進数ロボットです。

  画面の明るさを読み取って、腕を上げるロボットを作ります。
 白い画面にセンサーを近づけて電源を入れると、
 明るさを調べて白と黒の境界値を決めます。
 境界値が決まると腕を上下します。失敗すると腕を下げます。
 
 白と黒の画面を作るプログラム作って、実行すると、センサーの下のカメが黒から白に変わるとラジコンサーボが動きます。黒にもどすとニュートラルの位置にもどります。

※ラジコンサーボは、分解して、中にある可変抵抗器を取り外すと、回転するようになります。
<準備>  1体あたりの製作費は、1500円程度です。
ラジコンサーボ・・・2個(450円~の安物で良い)
フォトリフレクタ(白黒で電流の流れが変化するセンサー) ・・・・2個(80円×2)
PICマイコン PIC12F1572・・・・1個(140円)、ICソケット・・・・1個(11円)
・抵抗 470Ω2本・・・・(数円)、300Ω2本・・・・(数円)
・スイッチ、電池ボックス(3本用)、スズメッキ線、導線


1.部品を配線する
 
 <電池ボックスの外に配線した例>
  
 
 <電池ボックスの上に配線した例>
 

2.プログラミングの準備
C言語でプログラミングするには、MPLAB X IDE を起動して、以下の手順で行います。
1 を起動します。
・起動すると、これまでに作ったプロジェクトがあると、左側に一覧で表示されます。

プロジェクトを作成します。
  ・プログラムは、プロジェクトごとに管理されます。1つのプログラムに1つのフォルダとして1つのプロジェクトになります。  プログラミングした内容は、プロジェクトの中にファイルとして作ります。
(1)  File → New Project...
(2)   Choose Project → Standard Project  
 (3)  Select Device → Family = Mid Range 8-bit → PIC12F683
 (4)  Select Compiler → XC8
(5)   Select Project Name and Folder → Project Name  
     


プログラムファイルを作ります。
  ・プロジェクトの中にファイルを作り、そこにプログラムを書いていきます。1つのプロジェクトに1つのファイルが普通で、複数のファイルを作ったときは1つのファイルとして考えます。
(1) ファイルを作る場所を指定する  
 (2)   File → Newfile...
 
 (3)  File Name を書き入れて 終わり
 


プロジェクトのプロパティーを設定します。
  ・作ったプログラムをPICに書き込めるように、PICkit3の電圧設定をします。  
(1) プロジェクト名を右クリックして、プロパティーを開く  
(2) PICkit3のPower を撰ぶ
(3)  チェックを入れて4.75Vに設定する
 
 


3.プログラミング
  ・プログラムファイルのプログラムを書いていきます。
  // ---------------------------------------------------------------------------------------------
// 2進数ROBOT PIC12F1572         (C)2025.12.27 inakakoubouKANAI
// フォトトランジスタ(LBR-127HLD受光部) 2個使い PCモニタ判定でサーボを動かす
//1 Vdd 電源 (+) 電源のプラス(3.3V〜5V)を接続
//2 RA5 デジタル入力 (未使用)※ADC不可。プルアップ
//3 RA4 アナログ入力(AN3) 左センサー(LBR-127HLDのEmitter)
//4 RA3 デジタル入力 ノイズ対策用(内部プルアップ設定済み)
//5 RA2 アナログ入力(AN2) 右センサー(LBR-127HLDのEmitter)
//6 RA1 PWM1出力 サーボ1(右側)の信号線へ
//7 RA0 PWM2出力 サーボ2(左側)の信号線へ
//8 Vss 電源 (-) 電源のマイナス(GND)を接続
// ---------------------------------------------------------------------------------------------
  #include <xc.h>
#define _XTAL_FREQ 16000000
// CONFIGURATION BITS
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config BOREN = ON
#pragma config LVP = OFF
 
・このPICをどれくらいのクロックで使うか、ピンの役割をどうするかなどの設定。





・#pragma config LVP は、電圧が下がったときのリセット機能だが OFF にしておかないとRA3ピンを入力ピンとして使えない。
  unsigned int GS_RA1;
unsigned int GS_RA0;
unsigned int pulse1;
unsigned int pulse2;  
int THRESHOLD1;
int THRESHOLD2;
・プログラムで使うグローバル変数の宣言。
   // ADC読み取り関数
unsigned int read_ADC(unsigned char channel) {
// チャンネル選択(RA2=AN2, RA4=AN3)
ADCON0 = (unsigned char)((channel << 2) | 0x01);
__delay_us(50); // サンプリング時間を多めに確保
ADGO = 1;
while(ADGO);
return ((unsigned int)((ADRESH << 8) | ADRESL));
}
・アナログ信号を受け取るための設定。 
  void set_calibration()
{
THRESHOLD1 = 1023;
// 左センサー(RA4)
unsigned int val_left = read_ADC(3); // RA4(AN3)
while (val_left < THRESHOLD1)
{
val_left = read_ADC(3); // RA4(AN3)
THRESHOLD1 -=10;
if (THRESHOLD1<10){
THRESHOLD1 = 10;
break;
}
}
THRESHOLD1 -=10;

THRESHOLD2 = 1023;
// 右センサー(RA2)
unsigned int val_right = read_ADC(2); // RA2(AN2)
while (val_right < THRESHOLD2)
{
val_right = read_ADC(2); // RA2(AN2)
THRESHOLD2 -=10;
if (THRESHOLD2<10){
THRESHOLD2 = 10;
break;
}
}
THRESHOLD2 -=10;
// --- キャリブレーションの成否 ---
if ((THRESHOLD1==0)||(THRESHOLD1==1013)||(THRESHOLD2==0)||(THRESHOLD2==1013))
{
out_PWM1(4000);
out_PWM2(2000);
__delay_ms(100);
}
else
{
// 1回目:両腕上げ
out_PWM1(2000); // 右上げ
out_PWM2(4000); // 左上げ
__delay_ms(300);

// 2回目:両腕ニュートラル
out_PWM1(3000);
out_PWM2(3000);
__delay_ms(300);

// 3回目:もう一度両腕上げ
out_PWM1(2000);
out_PWM2(4000);
__delay_ms(300);

// 最後にニュートラルに戻して終了
out_PWM1(3000);
out_PWM2(3000);
__delay_ms(500); // 落ち着くまで少し待つ
}
}
・フォトリフレクターからの読取り感度のキャリブレーションを行う。

・紙の白黒で動作させるときは、白の紙ぶフォトリフレクターを向けて電源を入れる。

・PCモニターの白黒で動作させるときは、フォトリフレクターのLED電源のソケットを抜いて、フォトリフレクターを画面の白の上に向けて電源を入れる。




















・キャリブレーションが成功すると腕を上下に動かす。
  void p_initialize()
{
OSCCON = 0b01111000; // 16MHz

// ANSELA: RA4(AN3), RA2(AN2)をアナログ入力に設定
ANSELA = 0b00010100;

// TRISA: RA0,RA1=出力, 他=入力
TRISA = 0b00111100;

// ADC設定: 右詰め, Fosc/16, Vref=Vdd
ADCON1 = 0b10100000;

// ノイズ対策:未使用ピン(RA3, RA5)のプルアップ
OPTION_REGbits.nWPUEN = 0;
WPUA = 0b00101000;

INTCON = 0x00;
PORTA = 0b00000000;
}
 
・8本あるピンの使い方の設定。
それぞれのピンが入力か出力か、デジタルかアナログか、内部抵抗を使うか、使わないかなので、設定ができるが、PICの種類による規定がある場合もある。
  void out_Initialize(void)
{
unsigned int PWM_PERIOD = 31999;

// 実績のある設定に基づき周期を設定
PWM1PRH = (PWM_PERIOD >> 8) & 0xFF;
PWM1PRL = PWM_PERIOD & 0xFF;
PWM2PRH = (PWM_PERIOD >> 8) & 0xFF;
PWM2PRL = PWM_PERIOD & 0xFF;

// クロック源設定
PWM1CLKCON = 0b00000000;
PWM2CLKCON = 0b00000000;

PWM1TMR = 0;
PWM2TMR = 0;

// プリスケーラー 1:64 (0b110 << 3)
PWM1CLKCON &= 0b11100111;
PWM1CLKCON |= (0b110 << 3);
PWM2CLKCON &= 0b11100111;
PWM2CLKCON |= (0b110 << 3);

// PWM有効化
PWM1CON = 0b11000000;
PWM2CON = 0b11000000;

// 初期デューティ (1.5ms)
PWM1DCH = (3000 >> 8) & 0xFF;
PWM1DCL = 3000 & 0xFF;
PWM2DCH = (3000 >> 8) & 0xFF;
PWM2DCL = 3000 & 0xFF;

PWM1PHH = 0; PWM1PHL = 0;
PWM2PHH = 0; PWM2PHL = 0;

// ロード更新
PWM1LDCONbits.LDA = 1;
PWM2LDCONbits.LDA = 1;
while(PWM1LDCONbits.LDA == 1 || PWM2LDCONbits.LDA == 1);
・PWMを作るための設定。
実際の出力をオシロスコープで検証しながら設定した。PICに書かれた仕様書と異なるがこれで正常に動作する。 
  void out_PWM1(unsigned int GSP)
{
PWM1DCH = (GSP >> 8) & 0xFF;
PWM1DCL = GSP & 0xFF;
PWM1LDCONbits.LDA = 1;
while(PWM1LDCONbits.LDA == 1);
}

void out_PWM2(unsigned int GSP)
{
PWM2DCH = (GSP >> 8) & 0xFF;
PWM2DCL = GSP & 0xFF;
PWM2LDCONbits.LDA = 1;
while(PWM2LDCONbits.LDA == 1);
・ラジコンサーボを動かすデジタル信号をPICに内蔵されたハードウェアでPWMとして出力するための設定。
PICによって、この機能があるのと無いのとがある。 
  void out_steering()
{
// アナログ値の読み取り
unsigned int val_left = read_ADC(3); // RA4(AN3)
unsigned int val_right = read_ADC(2); // RA2(AN2)

// 左センサー(RA4) -> PWM2(RA0)
if(val_left > THRESHOLD) {
GS_RA0 = 4000; // 左
} else {
GS_RA0 = 3000; // ニュートラル
}
out_PWM2(GS_RA0);

// 右センサー(RA2) -> PWM1(RA1)
if(val_right > THRESHOLD) {
GS_RA1 = 2000; // 右
} else {
GS_RA1 = 3000; // ニュートラル
}
out_PWM1(GS_RA1);
}

 
・フォトリフレクターからの信号によって、どのようにラジコンサーボを動かすかを設定している。
  void main(void)
{
p_initialize();
out_Initialize();
set_calibration();
while(1)
{
out_steering();
__delay_ms(10);
}
}  
・プログラムが起動したとき最初に実行されるメインルーチン。 






・while(1)で永久ループにしておく。


4.ビルド
・ を左クリックして、プログラムをコンパイルして、PICに書き込める形にします。

 Loading completed と出たら、ビルド成功です。

5.書込み
・PIC12F1572をセットして、を左クリックして、コンパイルしたファイルを書き込みます。
 

 Programming/Verify complete と出たら書込み成功です。


6.完成
フォトリフレクターが白黒を読み取って、白だとラジコンサーボの腕を上げます。
 

 白黒の紙で動かすときは、白い紙をフォトリフレクターの前に置いて電源を入れます。

 電源が入り、腕が上がります。

 白い紙を無くすと腕が前になります。
 
 

 PCの画面で動かすときは、フォトリフレクターのLEDの電源ソケットを抜いて、

 白い画面にフォトリフレクターを向けて電源を入れます。

 キャリブレーションが終わると、腕を上下します。


 画面が白から黒に変わると、腕を前にします。
 
 


クレーンゲームの賞品に組み込んでみました。