PIC24FBGとAndroidを使ったYPVSコントローラですが、長期化しつつあります。
というのも、
・USBを接続に使うので、デバッグが捗らない
・Android側でOpenGLを使い始めたというアホな理由
・PIC24FBGがそこら辺に売っておらず、入手性が悪く、また金額も高い
という様々な理由があります。

あんまりにもアレなので、せめてアナログ回路の正しさ、ロジックの検証の為に、シンプルPIC12Fでひとつ作りました。
ざっくり動作しました。
iPhone 009

PIC12Fは単純なのでこれでアナログとロジックの検証しようかと思います。
安いから焼けても痛くないし・・・。

丁度よい箱が無い為、場所が余りまくりです。半分で良いですね。
iPhone 019

手組ですが、ジャンパーも無く出来ました。
あぁええわぁPIC12F。シンプルイズ最強ですね。

ロジックはこれからです。
ウィンウィン動かしながら調整していきます。
モータ制御にはTA8428Kを12Vで使っていますので容量的には十分だろうと思っています。
PICとポテンションメータはJRCの7805レギュレータで5V作っています。
USBと違ってほとんど電流を流さない為、熱的にも全く問題は無いようです。

PIC12FのInputCaptureについて、使い方が詳しく乗っているサイトもが無くてアレだったのですが、マニュアル読んで組んでみたところ無事動作している感じです。

久々にペンタさんのHPを除いてみたら、YPVSコントローラのA/D変換は5ビット程度の分解能だろうとの記事がありました。
32階層しか無いって事ですね〜。
対して今回作ったYPVS12F(仮称)は10ビットアナログコンバータを使っているので、1024階層です。
これは決して良い話って訳でもなくて、実際敏感すぎます。
サーボモータからのフィードバックはポテンションメータを通して行われますが、ノイズだって乗るでしょうし、敏感過ぎて収束せず、ずっとモータが行ったり来たりする可能性大です。
まぁそういう制御もありますから、一概にどうかって事は言えないのですが、、、。
この辺りは反応の鋭さと、モータの発振抑制との間でのせめぎあいになるのかも知れません。
抑制もアナログ回路でやるのか、ソフトウェアでやるのか、など等。

まずはモータにつけて動作比較をしてみようかと思います。

PIC12Fで機能を満足するだけの全く「素」の状態でのコードは以下です。
不具合もたくさん残っており、当然このままでは使い物になりませんが、割り込み処理などPICの使い方の参考にはなるかも知れません。
実験的にノーマルより低回転側でYPVSがやや閉まる方向でやっています。
2〜3馬力アップするらしいので・・・。
これを元に帳尻併せ、、、じゃなかったソフトウェアチューニングを行っていきます。

コンパイルするとメモリサマリーが出ますが、今こんな感じです。
Memory Summary:
    Program space        used   48Ch (  1164) of   800h words   ( 56.8%)
    Data space           used    51h (    81) of    80h bytes   ( 63.3%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    Configuration bits   used     1h (     1) of     1h word    (100.0%)
    ID Location space    used     0h (     0) of     4h bytes   (  0.0%)

 約6割程度を使っていますが、今後のチューニングで埋まる程よいサイズだと思います。
PIC12Fジャストサイズ。

#include #include <htc.h>

#define _XTAL_FREQ 8000000 // 8MHz
#define LED GP1
#define MC1 GP4
#define MC2 GP5
#define MODE GP3

#define TRUE 1
#define FALSE 0

#define INSENSITIVE_RANGE 10 


__CONFIG(
  FOSC_INTOSCIO &  // 発振機 内臓利用
  WDTE_OFF &    // ウォッチドッグ 無効
  PWRTE_ON &    // パワーアップタイマー 有効
  BOREN_ON &    // ブラウンアウト検出 有効
  MCLRE_OFF &    // ~MCLR 無効
  CP_OFF &      // コードプロテクション 無効
  IESO_OFF &    // IEスイッチオーバー 無効
  FCMEN_OFF      // フェイルセーフクロック 無効
  );

// ポテンションメータテーブル
const int gPotTable[] = {
  180, // 0:    0rpm
  180, // 1: 1000rpm
  180, // 2: 2000rpm
  180, // 3: 3000rpm
  180, // 4: 4000rpm
  180, // 5: 5000rpm
  266, // 6: 6000rpm
  348, // 7: 7000rpm
  430, // 8: 8000rpm
  485, // 9: 9000rpm
  485, //10:10000rpm 
};
#define POT_FULL_OPEN_TAGET (gPotTable[10])
#define POT_FULL_CLOSE_TARGET (gPotTable[0])

// Engine state
typedef enum{
  EG_STARTED,    // EG_STARTED
  EG_INIT_OPEN1,  // 電源オン時の最初の全開動作
  EG_INIT_CLOSE,  // その次の全閉
  EG_INIT_OPEN2,  // その次の全開
  EG_INITIALIZED,  // 全開のままエンジン起動待ち
}EG_STATE;

// Moter state
/*
IN1 IN2 OUTA OUTB  
H   H   L    L  BRAKE
L   H   L    H  逆転
H   L   H    L  正転
L   L   OFF     (ハイインピーダンス)  ストップ
*/
typedef enum{
  MT_BRAKE,
  MT_OPEN,
  MT_CLOSE,
  MT_STOP
}MT_STATE;  

#define MTBrake() {MC1=1;MC2=1;}
#define MTOpen()  {MC1=0;MC2=1;}
#define MTClose() {MC1=1;MC2=0;}
#define MTStop()  {MC1=0;MC2=0;}

EG_STATE gEGState = EG_STARTED;
unsigned int gRPM = 0;
unsigned int gPot = 0;

void MoterHead(unsigned int pot, unsigned int rpm);

/** -----------------------------------------------------------------
          1|VDD    PIC12F687    VSS|8
  MTR_C<- 2|GP5(MC2)        GP0/AN0|7 <-Potension meter Analog IN
  MTR_O<- 3|GP4(MC1)        GP1/AN1|6 ->LED
  MODE -> 4|GP3/~MCLR  GP2/AN2/CCP1|5 <-PULSE
------------------------------------------------------------------ */

/** -----------------------------------------------------------------
 void main(void)
 メイン関数
------------------------------------------------------------------ */
void main(void)
{
  OPTION_REG = 0b10000010;  // PUしない
  WPU        = 0b00000000;  // PUしない
  OSCCON     = 0b01110000;  // 8MHz
  TRISIO     = 0b00001101;  // IN: GP0/GP2/GP3/ OUT:GP1/GP4/GP5
  ANSEL      = 0b01010001;  // AN0選択、Tad(Fosc/16)=2.0us
  CMCON0     = 0x7;      // コンパレータ無効
  ADCON0     = 0b10000001;  // 右詰、VDD、AN0利用

  gEGState = EG_INIT_OPEN1;

  MTStop();  // モータ初期値

  // Input capture初期化(*1)
  CCP1CON = 0;  // 一度リセットする必要がある
  //CCP1CON    = 0b00000101;  // every rising edge
  CCP1CON    = 0b00000110;  // every 4th rising edge
  //CCP1CON    = 0b00000111;  // every 16th rising edg
  CCP1IF = 0;  // 設定後は必ずIFをリセット

  // タイマー初期化
  T1CON     = 0b00110100;    // T1CKPS 1:8
  TMR1IF = 0;
  TMR1L=0;
  TMR1H=0;
  
  // 割り込み初期化
  GIE = 1;
  PEIE = 1;
  TMR1IE = 1;    // Timer1 intterupt on
  TMR1ON = 1;    // Timer1 start
  CCP1IE = 1;    // Capture interrupt on
  
  // メインループ
  while(1) {
    GO_DONE = 1;    // 変換開始
    while(GO_DONE);  // 変換待ち Tad*11=220us
    gPot = (ADRESH * 256 + ADRESL)+1;  // Analog input
    MoterHead(gPot, gRPM);
  }
}

/** -----------------------------------------------------------------
  void MoterHead(unsigned int pot, unsigned int rpm)
  モータ制御
  @param pot ポテンションメータ(1〜1,024)
  @param rpm 回転数(0〜9,999)
------------------------------------------------------------------ */
void MoterHead(unsigned int pot, unsigned int rpm)
{
  // モータドライバTA8228Kは切り替えにSTOP時間100us必要
  // A/D変換で220us使うので状態が変わるときは一度MT_STOPすればOK
  static MT_STATE pre_mt_state = MT_STOP;
  MT_STATE next_mt_state;
  
  unsigned int index, target;
  double ax;

  switch(gEGState) {
  case EG_STARTED:
    
    if( rpm > 10000 ) rpm = 9999;
    index = rpm/1000;
    
    // ターゲット算出 (*2)
    ax = ((gPotTable[index+1] - gPotTable[index]) * ((rpm%1000)/1000));
    target = (unsigned int)ax + gPotTable[index]; 
    break;

  // 電源オン時の最初の全開動作
  case EG_INIT_OPEN1:
    if( pot >= POT_FULL_OPEN_TAGET )
      gEGState = EG_INIT_CLOSE;
    else  
      target = POT_FULL_OPEN_TAGET;
    break;
  
  // その次の全閉
  case EG_INIT_CLOSE:
    if( pot <= POT_FULL_CLOSE_TARGET )
      gEGState = EG_INIT_OPEN2;
    else
      target = POT_FULL_CLOSE_TARGET;
    break;
  
  // その次の全開
  case EG_INIT_OPEN2:
    if( pot >= POT_FULL_OPEN_TAGET )
      gEGState = EG_INITIALIZED;
    else  
      target = POT_FULL_OPEN_TAGET;
    break;
  
  // 全開のままエンジン起動待ち
  case EG_INITIALIZED:
    target = POT_FULL_OPEN_TAGET;
    // パルスが入ればEG_STATEDへ遷移
    if( rpm > 1000 ) {
      gEGState = EG_STARTED;  
    }  
    break;

  default:
    break;
  }
  
  // モーター制御
  if(target > pot+INSENSITIVE_RANGE)
    next_mt_state = MT_OPEN;
  else if(target+INSENSITIVE_RANGE < pot)
    next_mt_state = MT_CLOSE;
  else
    next_mt_state = MT_BRAKE;
  
  // 前回と違う場合は一旦STOPを入れる
  if( pre_mt_state != MT_STOP && pre_mt_state != next_mt_state ) {
    next_mt_state = MT_STOP;
  }

  switch( next_mt_state ) {
    case MT_BRAKE: MTBrake(); break;
    case MT_OPEN:  MTOpen();  break;
    case MT_CLOSE: MTClose(); break;
    case MT_STOP:  MTStop();  break;
    default:       MTStop();  break;
  }
  pre_mt_state = next_mt_state;
  
}  

/** -----------------------------------------------------------------
  void interrupt ISR(void)
  割り込み制御関数
  Timer1、Captureを処理する
------------------------------------------------------------------ */

void interrupt ISR(void)
{
  // Input capture 
  if(CCP1IF) {
    // タイマーリセット
    TMR1L=0;
    TMR1H=0;
    
    // 1000rpm -> gRPM=1000, 10000rpm -> gRPM=10000
    gRPM = 60000L/(((CCPR1H*256)+CCPR1L)/100/4);
    if(gRPM >= 10000) {
      gRPM = 9999;    // 1万以上は使わないので
    }else if(gRPM >=1000) {
      gEGState = EG_STARTED;
    }
    CCP1IF = 0;
  }  

  // Timer1 タイムアウト→エンジン停止と判断
  if(TMR1IF) {
    gRPM = 0;
    if(EG_STARTED == gEGState) {
      gEGState = EG_INIT_OPEN1;
    }
    TMR1IF = 0;
  }
}