12.アタッチメントの自動判別をしてみよう


アタッチメントの自動判別


明るさ設定は電源投入時直後に白レベルを読み取る
外部センサオプション番号を判別してライントレースとマイクを実行する
手かざし動作を追加
ADコンバータは全部で6つ用いていますが、同時には最大4つ用いています。従って、残りをアタッチメントの認識IDと使おうと思えば使えます。そこで、上のbitからAN11, AN10, AN7, AN6, AN5, AN4と割り当てて、その値からアタッチメントを判定するプログラムを作ってみます。下の表で、1,0はハードウェア的にはほぼ電源電圧、接地の電圧で、中間的な場合はそれぞれADコンバーターの値で100より大きいか小さいかを意味します。また、xはデバイスのその時の値であって、見てはいけないbitを示しています。ですから、ADコンバータは10bit全部計測する必要があります。幸い、計算スピードが問題とはなりませんので普通に整数型(16bit)の値にしています。
CdS100xxx
マイクxxx000
IRx10xxx

アタッチメントが何かを判定する


ここでは、確実な判定は行いません。プログラムの確認のため目的のアタッチメントを付けた場合LEDがどのように光るかを予想して実行してみてください。

「アタッチメントが何かを判定する」プログラム
// ファイル名 getOption.c
// アタッチメントが何かを判定する。
// 緑: ライントレース
// 白: CdS
// 消灯: マイク
#include <htc.h>
__CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS);

#define _XTAL_FREQ 20000000
#define PERIOD 100
#define false 0
#define true  1
#define AN4   0x91
#define AN5   0x95
#define AN6   0x99
#define AN7   0x9d
#define AN10  0xa9
#define AN11  0xad
#define ABS(x) ((x>=0) ? (x) : -(x))

typedef unsigned char byte;

void LED(byte n, byte times);
void Delay50();
void Delay100();
void initialize();
byte getOption();
void getAD(byte channel, byte* flag);

// グローバル変数の宣言
byte counter=0;
byte LeftCdS, CenterCdS, RightCdS,ExRCdS;
byte threshold[4];
byte ADch=0;
byte ConvEndFlag;
byte ADC[4]={AN4,AN5,AN6,AN11};
byte Leftspeed=208;
byte Centerspeed=208;
byte Rightspeed=208;

// 割り込み処理ルーチン
int ADvalue;
void interrupt Intr(void)
{
  // 約2ms毎に割り込む
  if(T0IF) {       // 割り込みがtimer0からか?
    counter++;
    TMR0 = PERIOD;
    T0IF = 0;                 // 割り込みフラグクリア
    return;
  }
  if(ADIF) {      // 割り込みがADコンバーターからか?
    ADvalue = ADRESH;
    ADvalue = ADvalue*256 + ADRESL;
    if(ADch==0) LeftCdS = ADvalue;
    else if(ADch==1) CenterCdS = ADvalue;
    else if(ADch==2) RightCdS = ADvalue;
    else if(ADch==3) ExRCdS = ADvalue;
    ConvEndFlag=true;         // データの更新あり
    ADIF = 0;                 // 割り込みフラグクリア
  }
}

main()
{
  #define SLOW  35
  #define  LOW  40
  #define MIDDLE 80
  #define MIDDLE2 120
  #define HIGH  160
  int i;
  byte state=0;

  initialize();

  while(true) {
    state = getOption();
    LED(state, 2);
    for(i=0; i<10; i++) Delay100();
  }
}


void initialize()
{
  PORTA = 0;                  // PORTAを0にする
  TRISA = 0;                  // PORTAを出力に設定する
  TRISB = 0x30;               // 4,5input
  PORTB = 0;
  PORTC = 0;                  // PORTCを0にする
  TRISC = 0x0f;               // PORTC下4bit入力、上4bit出力
  ANSEL = 0xF0;               // AN4,5,6,7 ON
  ANSELH = 0x0C;              // AN10,11 ON
  ADCON0 = AN4;               // ADFM=1(右詰)  AN4 adOn
                              // 1 = Right justified
  OPTION = 0;
                              // 1:8 prescale
  T1CON = 0x31;               // Timer1 settings
  TMR1IF = 0;                 // clear TMR1IF
  TMR1H = 0xf8;               // Initialize Timer1 register
  TMR1L = 0x00;

  ADC[0]=AN4;
  ADC[1]=AN5;
  ADC[2]=AN6;
  ADC[3]=AN11;
}

void LED(byte n, byte times)
{
  byte i;
  for(i=0; i<times; i++) {
    PORTA =  n;
    Delay50();                // 50msディレイ
    PORTA =  0;
    Delay50();                // 50msディレイ
  }
}

void Delay50()                // 50m秒ディレイ
{
  int i;
  for(i=0; i<5; i++)
    __delay_ms(10);
}

void Delay100()               // 100m秒ディレイ
{
  int i;
  for(i=0; i<10; i++)
    __delay_ms(10);
}

#define optTH 100

byte getOption()
{
  byte flag;
  byte x;

  getAD(AN4,&flag);
  getAD(AN5, &x);
  if(x) flag|=2;
  getAD(AN6, &x);
  if(x) flag|=4;
  getAD(AN7, &x);
  if(x) flag|=8;
  getAD(AN10, &x);
  if(x) flag|=0x10;
  getAD(AN11, &x);
  if(x) flag|=0x20;
  return flag;
}

void getAD(byte channel, byte* flag)
{
  int x;
  ADCON0 = channel;
  GODONE = 1;
  while(GODONE);
  x = ADRESH;
  x = x*256+ADRESL;
  *flag = x > optTH;
}

void getAD(byte channel, byte* flag)
指定されたADコンバータの値を読み取り、それが0なのか1なのかをflagとして戻す。
byte getOption()
ADコンバータから下位bitからAN4, AN5, AN6, AN7, AN10,AN11 の順番で0か1を判定して、bit列を作り、その値をflagとして戻します。

 

外部センサオプション番号を判別してライントレースとマイクを実行する

ライントレースとマイクの二つを判別して動作できるかどうかやってみます。

以下のプログラムをコピーして、貼り付けて使用してください。

「外部センサオプション番号を判別してライントレースとマイクを実行する」プログラム
// ファイル名 gtLineTrace.c
// 外部センサオプション番号を判別してライントレースとマイクを実行する。// 明るさ設定は電源投入時直後に白レベルを読み取る。
#include <htc.h>
__CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS);

#define _XTAL_FREQ 20000000
#define PERIOD 100
#define false 0
#define true  1
#define AN4   0x91
#define AN5   0x95
#define AN6   0x99
#define AN7   0x9d
#define AN10  0xa9
#define AN11  0xad
#define ABS(x) ((x>=0) ? (x) : -(x))

typedef unsigned char byte;

void LED(byte n, byte times);
void Delay50();
void Delay100();
void initialize();
void setIRThreshold(byte th);
byte checkIR();
void LineTrace();
byte getOption();
void getAD(byte channel, byte* flag);
void Mic();
void setInterrupt();

// グローバル変数の宣言
byte counter=0;
byte LeftCdS, CenterCdS, RightCdS,ExRCdS;
byte threshold[4];
byte ADch=0;
byte ConvEndFlag;
byte ADC[4]={AN4,AN5,AN6,AN11};
byte Leftspeed=208;
byte Centerspeed=208;
byte Rightspeed=208;

// 割り込み処理ルーチン
void interrupt Intr(void)
{
  // 約2ms毎に割り込む
  if(T0IF) {       // 割り込みがtimer0からか?
    counter++;
    TMR0 = PERIOD;
    T0IF = 0;                 // 割り込みフラグクリア
    return;
  }
  if(ADIF) {      // 割り込みがADコンバーターからか?
    if(ADch==0) LeftCdS = ADRESL;
    else if(ADch==1) CenterCdS = ADRESL;
    else if(ADch==2) RightCdS = ADRESL;
    else if(ADch==3) ExRCdS = ADRESL;
    ConvEndFlag=true;         // データの更新あり
    ADIF = 0;                 // 割り込みフラグクリア
  }
}

main()
{
  #define SLOW  35
  #define  LOW  40
  #define MIDDLE 80
  #define MIDDLE2 120
  #define HIGH  160
  int i;
  byte state=0;
  byte extOption; // 外部センサオプション番号
  
  initialize(); 
  extOption = getOption();
  if((extOption & 0x18)==0x10) {      // photo refrector
    setIRThreshold(13);               // ライントレース
    state=2;
    LED(state, 5);
  }
  else if((extOption & 0x07)==0) {    // マイクモード
    state=7;
    LED(state,5);
  }
  setInterrupt();           // タイマーとADの割り込み設定
  while(true) {
    switch(state) {
      case 2: LineTrace(); break;
      case 7: Mic();       break;
    }
  }
}

void setInterrupt()
{ 
  // Timer0 の設定
  T0IE=1;                     // Timer0 の割り込みON
  T0IF=0;                     // 割り込みフラグクリア
  
  // ADコンバーターの設定
  ADIE = 1;                   // ADコンバータの割り込み許可
  ADIF = 0;                   // 割り込みフラグクリア
  PEIE = 1;                   // 周辺装置の割り込み許可
  GIE  = 1;                   // CPUへの割り込み許可
}
    
void initialize()
{
  PORTA = 0;                  // PORTAを0にする
  TRISA = 0;                  // PORTAを出力に設定する
  TRISB = 0x30;               // 4,5input
  PORTB = 0;
  PORTC = 0;                  // PORTCを0にする
  TRISC = 0x0f;               // PORTC下4bit入力、上4bit出力
  ANSEL = 0xF0;               // AN4,5,6,7 ON
  ANSELH = 0x0C;              // AN10,11 ON
  ADCON0 = AN4;               // ADFM=1(右詰)  AN4 adOn
                              // 1 = Right justified
  OPTION = 0;
                              // 1:8 prescale
  T1CON = 0x31;               // Timer1 settings
  TMR1IF = 0;                 // clear TMR1IF
  TMR1H = 0xf8;               // Initialize Timer1 register
  TMR1L = 0x00;

  ADC[0]=AN4;
  ADC[1]=AN5;
  ADC[2]=AN6;
  ADC[3]=AN11;
}

void LineTrace()
{
  while(RA3)
  {
    switch(checkIR()){
      case 3: Rightspeed=Leftspeed=MIDDLE2;  // 直進   青
              RC5=0; RC7=0;
              break;
      case 7:
      case 6: Rightspeed = 100; Leftspeed = MIDDLE; //左に行く 紫
              RC5=0; RC7=0;
              break;
      case 4: Rightspeed = MIDDLE; Leftspeed = ~SLOW;  //左に行く 赤
              RC5=0; RC7=1;
              break;
      case 11:
      case 9: Rightspeed = MIDDLE;  Leftspeed = 100;   // 水色
              RC5=0; RC7=0;
              break;
      case 8: Rightspeed = ~SLOW;  Leftspeed = MIDDLE;    //  緑
              RC5=1; RC7=0;
              break;
    } // switch
    RC4 = (counter<Rightspeed)?1:0;
    RC6 = (counter<Leftspeed)?1:0;
  
  }  // while
}

void LED(byte n, byte times)
{
  byte i;
  for(i=0; i<times; i++) {
    PORTA =  n;
    Delay50();                // 50msディレイ
    PORTA =  0;
    Delay50();                // 50msディレイ
  }
}

void Delay50()                // 50m秒ディレイ
{
  int i;
  for(i=0; i<5; i++)        
    __delay_ms(10); 
}

void Delay100()               // 100m秒ディレイ
{
  int i;
  for(i=0; i<10; i++)        
    __delay_ms(10); 
}

void setIRThreshold(byte th)
{
  byte i, j, x;
  int average[4]={0,0,0,0};
  GIE=0;
 // 明るいときの値 明るいと大きい値
  ADC[0]=AN4;
  ADC[1]=AN5;
  ADC[2]=AN6;
  ADC[3]=AN11;
  for(j=0; j<40; j++) {
    for(i=0; i<4; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
    }
  }
  for(i=0; i<4; i++)
    threshold[i]=average[i]*th/20;
  GIE=1;
}

byte checkIR()
{
  byte status;

  if(ConvEndFlag) { // AD変換が終わったらすぐに次のチャンネルの変換を行う
    ConvEndFlag = false;
    if(++ADch==4) ADch=0;
    ADCON0 = ADC[ADch];  // 変換スタート
    GODONE = 1;
  }
  PORTA=0;
  status = 0;
  RA2 = ExRCdS<threshold[3];
  RA1 = CenterCdS<threshold[1];
  RA0 = LeftCdS<threshold[0];

  status = RightCdS<threshold[2];
  status += RA1 ? 2 : 0;
  status += RA0 ? 4 : 0;
  status += RA2 ? 8 : 0;
  return status;
}

#define optTH 100

byte getOption()
{
  byte flag;
  byte x;

  getAD(AN4,&flag);
  getAD(AN5, &x);
  if(x) flag|=2;
  getAD(AN6, &x);
  if(x) flag|=4;
  getAD(AN7, &x);
  if(x) flag|=8;
  getAD(AN10, &x);
  if(x) flag|=0x10;
  getAD(AN11, &x);
  if(x) flag|=0x20;
  return flag;
}

void getAD(byte channel, byte* flag)
{
  int x;
  ADCON0 = channel;
  GODONE = 1;
  while(GODONE);
  x = ADRESH;
  x = x*256+ADRESL;
  *flag = x > optTH;
}


#define MICTH 4
#define MIDLOW 80
void Mic()
{
  byte i;
  int average[3]={0,0,0};
  int average2[3]={0,0,0};
  int x,y,diff[3];

  byte a,b,c,max;
  unsigned int cnt=0;
  
  GIE=0;
  ADC[0]=AN7;
  ADC[1]=AN10;
  ADC[2]=AN11;
  for(cnt=0; cnt<1000; cnt++) {
    for(i=0; i<3; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
      if(x > average[i])
        average2[i] = (average2[i]*11+x)/12;
    }
  }
  // 半永久ループ
  while(RA3){  // スイッチが押されたら抜ける
    for(i=0; i<3; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
      if(x > average[i])
        average2[i] = (average2[i]*11+x)/12;
      diff[i] = average2[i] - average[i];
    }
    if((diff[0] >MICTH) || (diff[1]>MICTH) || 
        (diff[2]>MICTH)) {
      a=diff[0]; b=diff[1]; c=diff[2];
      if(a>b) {
        if(a>c) { max=0; }
        else    { max=2;}
      }
      else if(b>c) { max = 1; }
      else { max=2; }

      GIE=1;
      x=500;       // 回転カウント
      switch(max){
        case 2: // Left
              PORTA = 4;
              Rightspeed = ~MIDLOW;  Leftspeed = MIDLOW;
              RC5=1; RC7=0;
              break;
        case 1: // backward
              PORTA = 2;
              if(diff[1]&1){  // たまに逆回りする
                Rightspeed = ~MIDLOW;  Leftspeed = MIDLOW;
                RC5=1; RC7=0;
              }
              else {
                Rightspeed = MIDLOW;  Leftspeed = ~MIDLOW;
                RC5=0; RC7=1;
              }
              x = 700;
              break;
        case 0: // Right
              PORTA = 1;
              Rightspeed = MIDLOW; Leftspeed = ~MIDLOW;
              RC5=0; RC7=1;
              break;
        default:
              PORTC &= 0x0f;
      }
      counter=0;
      cnt=0;
      while(cnt!=x) {
        if(counter==0) cnt++;
        RC4 = (counter<Rightspeed)?1:0;
        RC6 = (counter<Leftspeed)?1:0;
        if(!RA3) return;
      }
      PORTC &= 0x0f;
      PORTA = 0;
      GIE=0;
      Delay100();
      for(cnt=0; cnt<500; cnt++) {
        for(i=0; i<3; i++) {
          ADCON0 = ADC[i];
          GODONE = 1;
          while(GODONE);
          x = ADRESL;
          average[i] = (average[i]*9+x)/10;
        }
      } 
      for(i=0; i<3; i++) average2[i] = average[i];

    } //if
  }
  GIE=1;
}

手かざし動作を追加

CdSのアタッチメントも判別できるか追加してみます。

以下のプログラムをコピーして、貼り付けてください。

「手かざし動作を追加」プログラム
// ファイル名 gtLineTrace2.c
// 外部センサオプション番号を判別してライントレースとマイク、手かざし動作を実行する。
// 明るさ設定は電源投入時直後に白レベルを読み取る。
#include <htc.h>
__CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS);

#define _XTAL_FREQ 20000000
#define PERIOD 100
#define false 0
#define true  1
#define AN4   0x91
#define AN5   0x95
#define AN6   0x99
#define AN7   0x9d
#define AN10  0xa9
#define AN11  0xad
#define ABS(x) ((x>=0) ? (x) : -(x))

typedef unsigned char byte;

void LED(byte n, byte times);
void Delay50();
void Delay100();
void initialize();
void setIRThreshold(byte th);
byte checkIR();
void LineTrace();
byte getOption();
void getAD(byte channel, byte* flag);
void Mic();
void setInterrupt();
byte checkCdS();
void setThreshold(byte th);
void overHand();

// グローバル変数の宣言
byte counter=0;
byte LeftCdS, CenterCdS, RightCdS,ExRCdS;
byte threshold[4];
byte ADch=0;
byte ConvEndFlag;
byte ADC[4]={AN4,AN5,AN6,AN11};
byte Leftspeed=208;
byte Centerspeed=208;
byte Rightspeed=208;
byte CdSInt;

// 割り込み処理ルーチン
void interrupt Intr(void)
{
  // 約2ms毎に割り込む
  if(T0IF) {                  // 割り込みがtimer0からか?
    counter++;
    TMR0 = PERIOD;
    T0IF = 0;                 // 割り込みフラグクリア
    return;
  }
  if(ADIF) {                  // 割り込みがADコンバーターからか?
    if(CdSInt) {              // それはCdS使用か?
      if(ADch==0) LeftCdS = ADRESH;
      else if(ADch==1) CenterCdS = ADRESH;
      else if(ADch==2) RightCdS = ADRESH;
    }
    else {  
      if(ADch==0) LeftCdS = ADRESL;
      else if(ADch==1) CenterCdS = ADRESL;
      else if(ADch==2) RightCdS = ADRESL;
      else if(ADch==3) ExRCdS = ADRESL;
    }
    ConvEndFlag=true;         // データの更新あり
    ADIF = 0;                 // 割り込みフラグクリア
  }
}

main()
{
  #define SLOW  35
  #define  LOW  40
  #define MIDDLE 80
  #define MIDDLE2 120
  #define HIGH  160
  int i;
  byte state=0;
  byte extOption; // 外部センサオプション番号
  
  initialize(); 
  
extOption = getOption();
  if((extOption & 0x38)==0x20) { // 手かざしモード
    state=6;
    LED(state, 5);               // 水色
    CdSInt = true;
    setThreshold(65);            // 白レベルの値から閾値(65%)に決める
  }
  else if((extOption & 0x07)==0) {    // マイクモード
    state=7;
    LED(state,5);
    CdSInt = false;
  }
  else if((extOption & 0x18)==0x10) {      // photo refrector
    setIRThreshold(13);               // ライントレース
    state=2; 
    LED(state, 5);                    // 青
    CdSInt = false;
  }
  setInterrupt();             // タイマーとADの割り込み設定
  GODONE = 1;                 // AD変換スタート
  while(true) {
    switch(state) {
      case 2: LineTrace(); break;
      case 6: overHand();  break; // CdSでモーターを動かす
      case 7: Mic();       break;
    }  
  }
}

void setInterrupt()
{ 
  // Timer0 の設定
  T0IE=1;                     // Timer0 の割り込みON
  T0IF=0;                     // 割り込みフラグクリア
  
  // ADコンバーターの設定
  ADIE = 1;                   // ADコンバータの割り込み許可
  ADIF = 0;                   // 割り込みフラグクリア
  PEIE = 1;                   // 周辺装置の割り込み許可
  GIE  = 1;                   // CPUへの割り込み許可
}
    
void initialize()
{
  PORTA = 0;                  // PORTAを0にする
  TRISA = 0;                  // PORTAを出力に設定する
  TRISB = 0x30;               // 4,5input
  PORTB = 0;
  PORTC = 0;                  // PORTCを0にする
  TRISC = 0x0f;               // PORTC下4bit入力、上4bit出力
  ANSEL = 0xF0;               // AN4,5,6,7 ON
  ANSELH = 0x0C;              // AN10,11 ON
  ADCON0 = AN4;               // ADFM=1(右詰)  AN4 adOn
                              // 1 = Right justified
  OPTION = 0;
                              // 1:8 prescale
  T1CON = 0x31;               // Timer1 settings
  TMR1IF = 0;                 // clear TMR1IF
  TMR1H = 0xf8;               // Initialize Timer1 register
  TMR1L = 0x00;

  ADC[0]=AN4;
  ADC[1]=AN5;
  ADC[2]=AN6;
  ADC[3]=AN11;
  
  CdSInt = false;             // CdSは付いていない
}

void LineTrace()
{
  while(RA3)
  {
    switch(checkIR()){
      case 3: Rightspeed=Leftspeed=MIDDLE2;  // 直進   青
              RC5=0; RC7=0;
              break;
      case 7:
      case 6: Rightspeed = 100; Leftspeed = MIDDLE; //左に行く 紫
              RC5=0; RC7=0;
              break;
      case 4: Rightspeed = MIDDLE; Leftspeed = ~SLOW;  //左に行く 赤
              RC5=0; RC7=1;
              break;
      case 11:
      case 9: Rightspeed = MIDDLE;  Leftspeed = 100;   // 水色
              RC5=0; RC7=0;
              break;
      case 8: Rightspeed = ~SLOW;  Leftspeed = MIDDLE;    //  緑
              RC5=1; RC7=0;
              break;
    } // switch
    RC4 = counter < Rightspeed;
    RC6 = counter < Leftspeed;
  
  }  // while
}

void LED(byte n, byte times)
{
  byte i;
  for(i=0; i<times; i++) {
    PORTA =  n;
    Delay50();                // 50msディレイ
    PORTA =  0;
    Delay50();                // 50msディレイ
  }
}

void Delay50()                // 50m秒ディレイ
{
  int i;
  for(i=0; i<5; i++)        
    __delay_ms(10); 
}

void Delay100()               // 100m秒ディレイ
{
  int i;
  for(i=0; i<10; i++)        
    __delay_ms(10); 
}

void setIRThreshold(byte th)
{
  byte i, j, x;
  int average[4]={0,0,0,0};
  GIE=0;
 // 明るいときの値 明るいと大きい値
  ADC[0]=AN4;
  ADC[1]=AN5;
  ADC[2]=AN6;
  ADC[3]=AN11;
  for(j=0; j<40; j++) {
    for(i=0; i<4; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
    }
  }
  for(i=0; i<4; i++)
    threshold[i]=average[i]*th/20;
  GIE=1;
}

byte checkIR()
{
  byte status;

  if(ConvEndFlag) { // AD変換が終わったらすぐに次のチャンネルの変換を行う
    ConvEndFlag = false;
    if(++ADch==4) ADch=0;
    ADCON0 = ADC[ADch];  // 変換スタート
    GODONE = 1;
  }
  PORTA=0;
  status = 0;
  RA2 = ExRCdS<threshold[3];
  RA1 = CenterCdS<threshold[1];
  RA0 = LeftCdS<threshold[0];

  status = RightCdS<threshold[2];
  status += RA1 ? 2 : 0;
  status += RA0 ? 4 : 0;
  status += RA2 ? 8 : 0;
  return status;
}

#define optTH 100

byte getOption()
{
  byte flag;
  byte x;

  getAD(AN4,&flag);
  getAD(AN5, &x);
  if(x) flag|=2;
  getAD(AN6, &x);
  if(x) flag|=4;
  getAD(AN7, &x);
  if(x) flag|=8;
  getAD(AN10, &x);
  if(x) flag|=0x10;
  getAD(AN11, &x);
  if(x) flag|=0x20;
  return flag;
}

void getAD(byte channel, byte* flag)
{
  int x;
  ADCON0 = channel;
  GODONE = 1;
  while(GODONE);
  x = ADRESH;
  x = x*256+ADRESL;
  *flag = x > optTH;
}


#define MICTH 4
#define MIDLOW 80
void Mic()
{
  byte i;
  int average[3]={0,0,0};
  int average2[3]={0,0,0};
  int x,y,diff[3];

  byte a,b,c,max;
  unsigned int cnt=0;
  
  GIE=0;
  ADC[0]=AN7;
  ADC[1]=AN10;
  ADC[2]=AN11;
  for(cnt=0; cnt<1000; cnt++) {
    for(i=0; i<3; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
      if(x > average[i])
        average2[i] = (average2[i]*11+x)/12;
    }
  }
  // 半永久ループ
  while(RA3){  // スイッチが押されたら抜ける
    for(i=0; i<3; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESL;
      average[i] = (average[i]*9+x)/10;
      if(x > average[i])
        average2[i] = (average2[i]*11+x)/12;
      diff[i] = average2[i] - average[i];
    }
    if((diff[0] >MICTH) || (diff[1]>MICTH) || 
        (diff[2]>MICTH)) {
      a=diff[0]; b=diff[1]; c=diff[2];
      if(a>b) {
        if(a>c) { max=0; }
        else    { max=2;}
      }
      else if(b>c) { max = 1; }
      else { max=2; }

      GIE=1;
      x=500;       // 回転カウント
      switch(max){
        case 2: // Left
              PORTA = 4;
              Rightspeed = ~MIDLOW;  Leftspeed = MIDLOW;
              RC5=1; RC7=0;
              break;
        case 1: // backward
              PORTA = 2;
              if(diff[1]&1){  // たまに逆回りする
                Rightspeed = ~MIDLOW;  Leftspeed = MIDLOW;
                RC5=1; RC7=0;
              }
              else {
                Rightspeed = MIDLOW;  Leftspeed = ~MIDLOW;
                RC5=0; RC7=1;
              }
              x = 700;
              break;
        case 0: // Right
              PORTA = 1;
              Rightspeed = MIDLOW; Leftspeed = ~MIDLOW;
              RC5=0; RC7=1;
              break;
        default:
              PORTC &= 0x0f;
      }
      counter=0;
      cnt=0;
      while(cnt!=x) {
        if(counter==0) cnt++;
        RC4 = counter < Rightspeed;
        RC6 = counter < Leftspeed;
        if(!RA3) return;
      }
      PORTC &= 0x0f;
      PORTA = 0;
      GIE=0;
      Delay100();
      for(cnt=0; cnt<500; cnt++) {
        for(i=0; i<3; i++) {
          ADCON0 = ADC[i];
          GODONE = 1;
          while(GODONE);
          x = ADRESL;
          average[i] = (average[i]*9+x)/10;
        }
      } 
      for(i=0; i<3; i++) average2[i] = average[i];

    } //if
  }
  GIE=1;
}

byte checkCdS()
{
  byte status;

  if(ConvEndFlag) { // AD変換が終わったらすぐに次のチャンネルの変換を行う
    ConvEndFlag = false;
    if(++ADch==3) ADch=0;
      ADCON0 = ADC[ADch];     // ADチャンネル変更
      GODONE = 1;             // AD変換スタート
  }
    
  PORTA=0;
  RA2 = RightCdS  < threshold[2];  // 赤
  RA1 = CenterCdS < threshold[1];  // 緑
  RA0 = LeftCdS   < threshold[0];  // 青
  
  status = RA2;
  status += RA1 ? 2 : 0;
  status += RA0 ? 4 : 0;
  return status;
}

void setThreshold(byte th)    // 平均の指定%を閾値にする
{
  byte i, j, x, g;
  int average[3]={0,0,0};
  g = GIE;                    // 割り込み状態の保存
  GIE=0;                      // 割り込みは使わない
 // 明るいときの値 明るいと大きい値
  ADC[0]=AN4&0x7f;
  ADC[1]=AN5&0x7f;
  ADC[2]=AN6&0x7f;
  for(j=0; j<40; j++) {       // 平均の明るさを求める
    for(i=0; i<3; i++) {
      ADCON0 = ADC[i];
      GODONE = 1;
      while(GODONE);
      x = ADRESH;
      average[i] = (average[i]*9+x)/10;
    }
  }
  for(i=0; i<3; i++)
    threshold[i]=average[i]*th/100;
  GIE = g;                    // CPUへの割り込み状態を戻す
}

void overHand()
{
  while(RA3){
    switch(checkCdS()) {
      case 7: Rightspeed=Leftspeed=MIDDLE;    // 直進
              RC5 = RC7 = 0;
              break;
      case 6: Rightspeed = LOW;  Leftspeed = MIDDLE;
              RC5 = 0; RC7 = 0;
              break;
  
      case 4: Rightspeed = ~MIDDLE;  Leftspeed = MIDDLE;
              RC5 = 1; RC7 = 0;
              break;
      case 3: Rightspeed = MIDDLE; Leftspeed = LOW;
              RC5 = 0; RC7 = 0;
              break;
      case 1: Rightspeed = MIDDLE; Leftspeed = ~MIDDLE;
              RC5 = 0; RC7 = 1;
              break;
      case 2:
              Rightspeed=Leftspeed=~MIDDLE;
              RC5 = RC7 = 1;
              break;
      default:
      case 0: Rightspeed=Leftspeed=255;
              RC5 = RC7 = 1;
              break;
    }
    RC4 = counter<Rightspeed;
    RC6 = counter<Leftspeed;
  }  
}
 

目次へ戻る