複数(8個)のRCサーボ制御信号を1つのITUで作る
異なるパルス幅を持つ一連の連続パルスを連続して発生する動作を1つのITUで作る

Copyright(C) 16Nov2004
coskx

8つのRCサーボを同時に制御するための8つの独立したパルス幅のパルスの生成が必要です。8つのITUを使えば簡単ですが,5つしかITUはないので工夫が必要です。RCサーボの周期は20msec程度で,その中のパルスの幅が0.4〜2.2msec程度です。そこで1つのITUで8つのパルス幅のパルスを順番に作って,同時にあいているポートに何番目のパルスかを出力すればうまくゆきそうです。

ここでは,ITU3を使って8つのパルス幅を持つパルスを順番につくり,同時にP3のbit0-bit7にH信号を同期して順番に出力し,8このパルス発生を繰り返すようにしています。8つのAND回路を外付け(ITU3のoutputとP3のbit0,ITU3のoutputとP3のbit1,ITU3のoutputとP3のbit2,...)すれば,8つのRCサーボを制御できるようになります。(どのITUチャネルを使っても作ることが出来ますが,ここではITU3を用いた例を示します。)
ITU3はPWM動作を行ない,PWM周期は2.5msecとしました。8パルスを作ると,ちょうど20msecとなります。割り込みを用いて,1つのパルスが終了するごとに次のパルス幅を与え,8回のパルス発生で8つのパルス幅を持つパルスを順番につくっています。
割り込みはGRAコンペアマッチとGRBコンペアマッチの2つを使用しています。(GRBのみ使うと,パルス幅を長くする変更の時,同一周期中に2度目の割り込みが生じた時に,カウンタアップが不正動作を起こします。)

プログラムのダウンロード

DownLoad

multipulse.c

/*********************************************************
ITU ch3 を用いて8個の指定長のパルスを20msec間に出力する
1パルスは0.6msec以上2.4msec以下

TCNTとGRAのコンペマッチ
  TCNTのクリア
  TIOCAをH
  割り込み発生 カウンタアップ
TCNTとGRBのコンペマッチ
  TIOCAをL
  割り込み発生 GRB更新

出力はPWMモードなのでTIOCA3 2(CPUのpin) CN1-16になる

TCNTとGRBのコンペマッチ割り込み
  GRB更新
  (ポートP3へ何番目のパルスかを出力)

TCNTとGRAのコンペマッチ割り込み
カウンタアップ

一周期の様子
TCNT=0
  : TIOA=1
  : TIOA=1
  :  :
TCNT=GRB   割り込み(カウンタアップ)
  : TIOA=0
  : TIOA=0
  :  :
TCNT=GRA  TCNT=0 割り込み(GRBの更新)

 

データ配列
パルス幅に対応した値をしまっている配列
pulseWidth[8]

*********************************************************/

#include "h8-01.h"

/*パルス幅は最初1000,800,1200,900,1000,1000,2000,2000μsec*/
/*1クロック0.5μsecなので2倍して設定する*/
unsigned int pulseWidth[8]=
    {1000*2,800*2, 1200*2,900*2, 1000*2,1000*2, 2000*2,2000*2};
const unsigned char p3out[8]={1,2,4,8,0x10,0x20,0x40,0x80};
volatile int IntCounter; /*割り込み回数を数えるカウンタ 0-7を繰り返す*/

/*****初期化関数*****/
void initMultiPulseGen()
{
    ITU.TSTR.BIT.STR3=0; /*ITU ch3カウントストップ*/
    ITU.TMDR.BIT.PWM3=1; /*ITU ch3はPWMモード*/
    ITU3.TCR.BIT.TPSC=3; /*φ/8を使用(1クロック0.5μsec)*/
    ITU3.TCR.BIT.CCLR=1; /*GRAとのコンペアマッチでTCNTクリア*/
    ITU3.TCNT=0; /*カウンタクリア*/
    ITU3.GRA=2500*2-1; /*2.5msec周期でTCNTはクリア*/
    ITU3.TIER.BIT.IMIEB=1; /*GRBコンペアマッチで割込*/
    ITU3.TIER.BIT.IMIEA=1; /*GRAコンペアマッチで割込*/
    /*IMIA3の割り込み:36 0x90-0x93*/
    /*IMIB3の割り込み:37 0x94-0x97*/
}

void startMultiPulse()
{
    E_INT(); /*CPU割り込み許可*/
    ITU3.GRB=pulseWidth[0];
    IntCounter=0;
    ITU.TSTR.BIT.STR3=1; /*ITU ch3カウントスタート*/
}

#pragma interrupt(imib3INT)/*この名前の関数は割り込みルーチン仕様である*/
                           /*プログラム中から呼び出してはならない*/
/*IMIB3の割り込み関数*/
/*割り込みテーブルはIntTbl.srcに書いてある*/
void imib3INT()
{
    IntCounter++;
    IntCounter&=7;
    P3.DR.BYTE=p3out[IntCounter];
    ITU3.TSR.BIT.IMFB=0; /*Clear IMFB*/
}

#pragma interrupt(imia3INT)/*この名前の関数は割り込みルーチン仕様である*/
                           /*プログラム中から呼び出してはならない*/
/*IMIA3の割り込み関数*/
/*割り込みテーブルはIntTbl.srcに書いてある*/
void imia3INT()
{
    ITU3.GRB=pulseWidth[IntCounter];
    ITU3.TSR.BIT.IMFA=0; /*Clear IMFA*/
}

main()
{
    initSCI1(); /*SCI-ch1の初期化*/
    P3.DDR=0xff; /*P3はすべて出力に設定*/
    initMultiPulseGen(); /*multiwidthpulse発生器の初期化*/
    startMultiPulse(); /*multiwidthpulse発生器起動*/
    while (1)
    {
        /*ここでpulseWidth[8]の値を変更すれば出力パルス幅が変化する*/
    }
}

IntTbl.src

;************************************************************************
;interrupt vector table    IntTbl.src    Copyright (C) 2002 coskx
; 28 Aug 2002
; 割り込みを使用する場合はここに割り込みベクトルを記述すること
;************************************************************************
    .CPU 300HA
;   .IMPORT _timer1INT
    .IMPORT _imia3INT
    .IMPORT _imib3INT
   
    .SECTION A,DATA,LOCATE=H'000000

;   .ORG     H'000070  ;IMIA1
;   .DATA.L  _timer1INT
    .ORG     H'000090  ;IMIA3
    .DATA.L  _imia3INT
    .ORG     H'000094  ;IMIB3
    .DATA.L  _imib3INT
    .END

 

オシロスコープで確認

ch1はP3B7を検出しているので,系列7の出力時にHになる。周期は20msecである。
ch2はTIOCA3を検出しているので,系列0,1,2,..,6,7が順に出力され,これが繰り返されている。
ch1のパルスに同期がとれているところが系列7の2000μsecのパルスである。

 

ホストPCのターミナルソフト(例えばハイパーターミナルで動作を擬似的に確認できるようにしたもの)

multipulse.c

/*********************************************************
ITU ch3 を用いて8個の指定長のパルスを20msec間に出力する
1パルスは0.6msec以上2.4msec以下

TCNTとGRAのコンペマッチ
  TCNTのクリア
  TIOCAをH
  割り込み発生 カウンタアップ
TCNTとGRBのコンペマッチ
  TIOCAをL
  割り込み発生 GRB更新

出力はPWMモードなのでTIOCA3 2(CPUのpin) CN1-16になる

TCNTとGRBのコンペマッチ割り込み
  GRB更新
  (ポートP3へ何番目のパルスかを出力)

TCNTとGRAのコンペマッチ割り込み
カウンタアップ

一周期の様子
TCNT=0
  : TIOA=1
  : TIOA=1
  :  :
TCNT=GRB   割り込み(カウンタアップ)
  : TIOA=0
  : TIOA=0
  :  :
TCNT=GRA  TCNT=0 割り込み(GRBの更新)

 

データ配列
パルス幅に対応した値をしまっている配列
pulseWidth[8]

*********************************************************/

#include "h8-01.h"

/*パルス幅は最初1000,800,1200,900,1000,1000,2000,2000μsec*/
/*1クロック0.5μsecなので2倍して設定する*/
unsigned int pulseWidth[8]=
    {1000*2,800*2, 1200*2,900*2, 1000*2,1000*2, 2000*2,2000*2};
const unsigned char p3out[8]={1,2,4,8,0x10,0x20,0x40,0x80};
volatile int IntCounter; /*割り込み回数を数えるカウンタ 0-7を繰り返す*/
volatile int pulseID; /*出力中のパルスID*/
volatile int debugout;

/*****初期化関数*****/
void initMultiPulseGen()
{
    ITU.TSTR.BIT.STR3=0; /*ITU ch3カウントストップ*/
    ITU.TMDR.BIT.PWM3=1; /*ITU ch3はPWMモード*/
    ITU3.TCR.BIT.TPSC=3; /*φ/8を使用(1クロック0.5μsec)*/
    ITU3.TCR.BIT.CCLR=1; /*GRAとのコンペアマッチでTCNTクリア*/
    ITU3.TCNT=0; /*カウンタクリア*/
    ITU3.GRA=2500*2-1; /*2.5msec周期でTCNTはクリア*/
    ITU3.TIER.BIT.IMIEB=1; /*GRBコンペアマッチで割込*/
    ITU3.TIER.BIT.IMIEA=1; /*GRAコンペアマッチで割込*/
    /*IMIA3の割り込み:36 0x90-0x93*/
    /*IMIB3の割り込み:37 0x94-0x97*/
}

void startMultiPulse()
{
    E_INT(); /*CPU割り込み許可*/
    ITU3.GRB=pulseWidth[0];
    IntCounter=0;
    ITU.TSTR.BIT.STR3=1; /*ITU ch3カウントスタート*/
}

#pragma interrupt(imib3INT)/*この名前の関数は割り込みルーチン仕様である*/
                           /*プログラム中から呼び出してはならない*/
/*IMIB3の割り込み関数*/
/*割り込みテーブルはIntTbl.srcに書いてある*/
void imib3INT()
{
    IntCounter++;
    IntCounter&=7;
    P3.DR.BYTE=p3out[IntCounter];
    ITU3.TSR.BIT.IMFB=0; /*Clear IMFB*/
}

#pragma interrupt(imia3INT)/*この名前の関数は割り込みルーチン仕様である*/
                           /*プログラム中から呼び出してはならない*/
/*IMIA3の割り込み関数*/
/*割り込みテーブルはIntTbl.srcに書いてある*/
void imia3INT()
{
    ITU3.GRB=pulseWidth[IntCounter];
    ITU3.TSR.BIT.IMFA=0; /*Clear IMFA*/
}

void memdump(void) /*for Debug*/
{
    int ptr, p10;
    SCI1_printf("     +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F\n");
   
    for (p10 = 0 ; p10<0x200 ; p10+=0x10) {
        SCI1_printf("%04x", p10);
        for (ptr = 0; ptr<0x10; ptr++) {
            SCI1_printf(" %02x", *(unsigned char *)(p10+ptr));
        }
        SCI1_printf("\n");
    }
}

main()
{
    int i;
    initSCI1(); /*SCI-ch1の初期化*/
    putCharSCI1('\n'); /*for Debug*/
    memdump(); /*for Debug*/
    for (i=0;i<8;i++) SCI1_printf("%5d",pulseWidth[i]); /*for Debug*/
    putCharSCI1('\n'); /*for Debug*/
    P3.DDR=0xff; /*P3はすべて出力に設定*/
    initMultiPulseGen(); /*multiwidthpulse発生器の初期化*/
    startMultiPulse(); /*multiwidthpulse発生器起動*/
    while (1)
    {
        if(debugout) {
            putCharSCI1('0'+pulseID);
        } else {
            putCharSCI1('.');
        }
    }
}

IntTbl.src

;************************************************************************
;interrupt vector table    IntTbl.src    Copyright (C) 2002 coskx
; 28 Aug 2002
; 割り込みを使用する場合はここに割り込みベクトルを記述すること
;************************************************************************
    .CPU 300HA
;   .IMPORT _timer1INT
    .IMPORT _imia3INT
    .IMPORT _imib3INT
   
    .SECTION A,DATA,LOCATE=H'000000

;   .ORG     H'000070  ;IMIA1
;   .DATA.L  _timer1INT
    .ORG     H'000090  ;IMIA3
    .DATA.L  _imia3INT
    .ORG     H'000094  ;IMIB3
    .DATA.L  _imib3INT
    .END