春の訪れと体調不良

発熱 電子工作
発熱

師匠がUSから戻ってくると連絡があり、日本食が恋しくなったか、そろそろ鮨屋に集合だ。
といっても、板さんがいる鮨屋ではなく、もっと庶民的な回る方のお店を予約しておいた。

なのにだ、金曜日の夜に息苦しさで目覚める。
半分寝ぼけるいるが唾がうまく飲み込めない。痰でも絡まったのか?
たぶん、コレも老化現象などと勝手に勘違いして龍角散を服用し喉を軽くして、そう言えば晩年親父もこんな感じだったのかなぁと思いながらそのまま寝た。
朝早く起きるが何か怠くて熱っぽい。試しに体温を計ると38度の高熱だ。
以前にも書いたが当方、普段から低体温なので38度もあるともう高熱の領域だ。

やばい、明日は久しぶりにいろいろ話をしたいのにスケジュールが狂う。
個人輸入してる解熱鎮痛薬を飲んで寝る。直りますように。
インフルかコロナか風邪か、いずれかだろう。
夕方起きて、期限切れの三種検査薬をつかうと、見事何も出ていない。
たぶん、単なる風邪だ。ちょっと高い風邪薬(ベンザブロックLプレミアムDX)を追加で飲み、3時間くらい再度寝て起きると熱がぶり返していたが37度に変わっていた。薬が効いたのだろう。
ただし、会合は遠慮した。フロントソーサさんが治療の一環で免疫力が落ちているらしい。
当方の風邪を移すと一大事になるので今回は遠慮しておいた。

コロナのせいで感染症には注意していたが、東京の気温の乱加工に老いた体はついて行かなかったようだ。月曜日まで休んで安静にして休んでおこうと思う。ついでに出社も控えておこう。
ただ、あんまり長く安静にしておくと今度は腰が悲鳴をあげるという壊れた体には待ったなしの状態である。

海外文献で見つけた2chのモータードライバーVID6608(互換品としてSIT6608が存在)
元々は同じところから発売されているVID29 Series用のモータードライバーらしい。

主な特徴
2ch動作(上位に4chモデルもある:VID6606)
マイクロステップ駆動
全入力に 20ns 以下のパルスを無視するグリッチフィルタ(入力パルスは加工してるのであまり意味なし)
入力レベルシフタ内蔵(MCU 3.3V → IC 5V 駆動が可能)
動作電圧:4.5–5.5V

現在、PICマイコン(12F1822)を使用しているので5V電源が基本だが、その内、ESP32など現行のモデルを使おうと考えているのでレベルシフタがあるのは便利だと思う。
基本に戻ってどう動くかだけの検証を始めたいと考えているが、手配はまだ行われていない。
以下のソースは動くか分からないコード表である。
久しぶりに1から考えたら、大分全体まで変わってしまったが、概略しか考えてないので何か重要なことが抜けているような気がするが何であろうか・・自分で思いつかない。まあ、実際に動かせばそのボケも気付くで有ろうと考えます。

// ================================================================
// PIC12F1822 + VID6608 (Motor A) + X27.168 Tachometer Controller
// RA0: f(scx)A
// RA1: CW/CCWA
// RA2: RESET
// RA5: RPM pulse input (1 pulse = 1 rotation, from ignition secondary)
// ================================================================

#include <xc.h>
#define _XTAL_FREQ 32000000UL

#pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF
#pragma config CP = OFF, BOREN = ON, CLKOUTEN = OFF
#pragma config WRT = OFF, STVREN = ON, BORV = LO, LVP = OFF

#define PIN_FSCX   LATAbits.LATA0
#define PIN_DIR    LATAbits.LATA1
#define PIN_RESET  LATAbits.LATA2

#define STEPS_PER_DEG 12
#define MAX_DEG       300

unsigned int current_angle = 0;

// ---------------------------------------------------------------
// VID6608 PULSE OUTPUT
// ---------------------------------------------------------------
void vid_pulse(unsigned int delay_us)
{
    PIN_FSCX = 1;
    __delay_us(3);
    PIN_FSCX = 0;
    __delay_us(delay_us);
}

void vid_move_steps(unsigned long steps, unsigned int start_us, unsigned int end_us)
{
    long delta = (long)end_us - (long)start_us;

    for(unsigned long i = 0; i < steps; i++)
    {
        unsigned int d = start_us + (delta * (long)i) / (long)steps;
        vid_pulse(d);
    }
}

// ---------------------------------------------------------------
// ANGLE CONTROL API
// ---------------------------------------------------------------
void set_angle(unsigned int target_angle)
{
    if(target_angle > MAX_DEG) target_angle = MAX_DEG;

    if(target_angle == current_angle) return;

    long diff = (long)target_angle - (long)current_angle;
    unsigned long steps = (unsigned long)(labs(diff) * STEPS_PER_DEG);

    if(diff > 0)
    {
        PIN_DIR = 1; // CW
        vid_move_steps(steps, 1500, 300);
    }
    else
    {
        PIN_DIR = 0; // CCW
        vid_move_steps(steps, 300, 1500);
    }

    current_angle = target_angle;
}

// ---------------------------------------------------------------
// RPM → ANGLE (実車スケール・要検討)
// ---------------------------------------------------------------
unsigned int rpm_to_angle(unsigned int rpm)
{
    unsigned int angle;

    if(rpm <= 1000)
        angle = 10;
    else
        angle = 10 + (unsigned int)(20.0 * (rpm - 1000) / 1000.0);

    if(angle > MAX_DEG) angle = MAX_DEG;

    return angle;
}

// ---------------------------------------------------------------
// RPM MEASUREMENT (Timer1 external clock on RA5)
// ---------------------------------------------------------------
unsigned int read_rpm(void)
{
    unsigned int count = TMR1;
    TMR1 = 0;
    return count * 10;
}

// ---------------------------------------------------------------
// HOMING (原点復帰)
// ---------------------------------------------------------------
void homing(void)
{
    // CCW(逆回転)へゆっくり 350° 分パルスを送る
    // 350° × 12 = 4200 パルス
    PIN_DIR = 0; // CCW
    vid_move_steps(4200, 1500, 1500); // 一定低速で送る

    // ストッパーに当たってゼロ位置に固定されるはず・・
    current_angle = 0;
}

// ---------------------------------------------------------------
// MAIN
// ---------------------------------------------------------------
void main(void)
{
    OSCCON = 0b11110000;

    TRISA = 0b00101000;
    ANSELA = 0x00;

    // Timer1 external clock (RA5)
    T1CONbits.TMR1CS = 1;
    T1CONbits.T1CKPS = 0;
    T1CONbits.T1OSCEN = 0;
    TMR1 = 0;
    T1CONbits.TMR1ON = 1;

    // VID6608 RESET
    PIN_RESET = 0;
    __delay_ms(2);
    PIN_RESET = 1;
    __delay_ms(2);

    // ============================================================
    // ★ 電源投入時のホーミング(原点復帰)
    // ============================================================
    homing();
    __delay_ms(300);

    // ============================================================
    // ★ デモ動作(コメントアウト中)
    // ============================================================
    /*
    while(1)
    {
        set_angle(0);
        __delay_ms(500);

        set_angle(100);
        __delay_ms(500);

        set_angle(200);
        __delay_ms(500);

        set_angle(300);
        __delay_ms(500);

        set_angle(0);
        __delay_ms(1000);
    }
    */
    // ============================================================

    // ============================================================
    // ★ 実車モード(整形パルス入力で動作)
    // ============================================================
    while(1)
    {
        __delay_ms(100);
        unsigned int rpm = read_rpm();
        unsigned int angle = rpm_to_angle(rpm);
        set_angle(angle);
    }
}

ブレッドボード上で組み立てたらソースを流してみようかと考えているが、今回用意するモータドライバーはSOP16、テストでも変換基板が必要になりそうなので部品を買い足さねばと思う。

先日、書き上げたウインカーポジション回路を基板にするべく描いてみた。
実際のパターン図、上がウィンカーポジション、下が一年前に書いたヘッドライトブースターで小さく作ろうとして表面実装部品にしている。ウィンカーポジションの方は電球でも動かしてみようかと考えたもので以前の回路図から容量の大きいMOSFETに変更しています。
結局作るものは部品が少ない方にしてしまったが、動くかは神のみぞ知る。

コメント