353.シリアル通信でPCD4511パルスモータ制御(PIC16F873)


2003/11/28 【ソフトウエア編TOPに戻る】

今回は、115.PCD4511でステッピングモータ制御のページでH8-3048用に作ったプログラムをPIC16F873用に移植してみましたのでご紹介します。環境はCCSのCコンパイラに適用します。また、シリアル通信によってコマンドを受け取り、ステッピングモータを制御する機能なども付加してみましたので、併せてご紹介します。ハードウエアは9.PIC学習用ボード14.PCD4511パルスモータテストボードでご紹介しているボードを利用します。


353−1.PIC16F873のピン割り当て

PIC16F873にはRAに6ポート、RBRCにそれぞれ8ポートの各PIOがあります。今回のプログラムでは、それぞれを以下の役割に割り当ててみました。

RA

用 途

RB

用 途

RC

用 途

RA0

未使用

RB0

DATA0

RC0

CSチップセレクト信号

RA1

未使用

RB1

DATA1

RC1

RD書き込み信号

RA2

未使用

RB2

DATA2

RC2

WR読み出し信号

RA3

未使用

RB3

DATA3

RC3

A0アドレス信号

RA4

未使用

RB4

DATA4

RC4

A1アドレス信号

RA5

BUSY入力

RB5

DATA5

RC5

RSTリセット信号

 

端子なし

RB6

DATA6

RC6

RS232C TXD信号

 

端子なし

RB7

DATA7

RC7

RS232C RXD信号

RA5BUSY信号だけが入力端子で、その他は全てPCD4511を制御するための出力端子です。RA0〜4は現在未使用ですが、今後はRS485通信を行う際のアドレス情報として利用しようと考えています。また、CSチップセレクト信号やRSTリセット信号は、ソフトウエアを介さずに完全にハードウエアで処理してしまうことも可能ですが、今の所はPIOに割り当てておきます。

 


353−2.主要部分はヘッダファイルにする

PCD4511を制御する上で作ったいくつかの関数類は、ヘッダファイルとしてひとつにまとめてしまったほうが取り扱いが楽です。ここではH8版からの移植と同時にヘッダファイルにしました。

ここをクリックするとダウンロードできます。pcd4511.H  ダウンロードしたヘッダファイルは、CCS CコンパイラをインストールしたファイルのDevicesというフォルダに入れて使います。関数は今後必要に応じて増やしたり修正を加えて行くことになるかと思いますが、その都度、ここのファイルを更新することにしましょう。

以下にヘッダファイルの内容を掲載します。

/////////////////////////////////////////////////////////
// 日本パルスモータ PCD4511制御用ヘッダ                 2003.11.23 
// PIC16F873                                                        PCD4511.H
//S字加減速の基本的動作
//ピンファンクションは以下の通り
//Port C              Port B                 PortA
// 0:CS      OUT    0:DATA0    OUT    0:---      OUT
// 1:RD      OUT    1:DATA1    OUT    1:---      OUT
// 2:WR     OUT     2:DATA2   OUT     2:---      OUT
// 3:A0      OUT     3:DATA3   OUT     3:---      OUT
// 4:A1      OUT     4:DATA4   OUT     4:---      OUT
// 5:RST    OUT     5:DATA5   OUT     5:BUSY   IN
// 6:TxD    OUT     6:DATA6    OUT
// 7:RxD    IN        7: DATA7   OUT
/////////////////////////////////////////////////////////

#use delay(clock = 10000000)           // clock 10MHz
#use fast_io(A)                               //RA IO固定
#use fast_io(B)                               //RB IO固定
#use fast_io(C)                               //RC IO固定

#define CS     PIN_C0
#define RD     PIN_C1
#define WR     PIN_C2
#define A0      PIN_C3
#define A1      PIN_C4
#define RST    PIN_C5
#define BUSY  PIN_A5

int START_CMD;                            // スタートモードコマンド
int CTRL_CMD;                              // 制御モードコマンド
int REG_CMD;                                // レジスタセレクトコマンド
int OUT_CMD;                                // 出力モードコマンド

void pcd_init();                               //コントローラ初期化
void pcd_cmdwr(int cmd_data);         //コマンドバッファ書き込み関数
void pcd_reg(int reg);                      //レジスタ選択関数
void pcd_datah(int data_h);              //上位データ書き込み関数
void pcd_datam(int data_m);            //中位データ書き込み関数
void pcd_datal(int data_l);                //下位データ書き込み関数
void pcd_precnt(long precnt);          //プリセット値書き込み関数
void pcd_speed(int speed);              //回転速度書き込み関数
void pcd_start();                           //回転開始関数
void pcd_stop();                            //回転停止関数
void pcd_cw(int rotate);                 //回転方向設定関数
void pcd_ots(int ots);                    //OTS出力関数
void pcd_wr();                              //書き込みパルス出力関数

/* コントローラ初期化 ***************************************/

void pcd_init(){

set_tris_a(0x20);                         //PortA input
set_tris_b(0x00);                         //PortB output
set_tris_c(0x80);                         //PortC 7in 6-0out

output_bit(RST,0);                     //RESET信号出力
output_bit(CS,1);                       //CS信号出力
output_bit(RD,1);                       //RD信号出力
output_bit(WR,1);                      //WR信号出力
output_bit(A0,1);                       //A0信号出力
output_bit(A1,1);                       //A1信号出力

// RESET 処理
delay_ms(1);                            //1ms待機 パルス幅1ms
output_bit(RST,1);                    //RST信号戻し

// CS(CHIP SELECT)処理
output_bit(CS,0);                      //CS信号LOW

// 制御モードコマンドの設定
pcd_cmdwr(0x64);                     //S字加速,OTS=0,動作+方向,プリセット有効,SD/ORG無効
CTRL_CMD = 0x64;                  //制御モードコマンドの保存

// レジスタセレクトコマンドの設定
pcd_cmdwr(0x80);                    //外部スタートINTなし,SD_INTなし,プリセットカウント動作
//レジスタはR0にしておく
REG_CMD = 0x80;                   //レジスタセレクトコマンドの保存

// R4レジスタ(倍率)設定→2倍(300 0x012C)
pcd_reg(4);                            //R4レジスタ選択
pcd_datam(0x01);                   //中位バイト書き込み
pcd_datal(0x2c);                     //下位バイト書き込み

// R1レジスタ(初速度FL)設定→50pps (25 0x0019)
pcd_reg(1);                            //R1レジスタ選択
pcd_datam(0x00);                   //中位バイト書き込み
pcd_datal(0x19);                     //下位バイト書き込み

// R6レジスタ(アイドリングパルス)設定→0
pcd_reg(6);                            //R6レジスタ選択
pcd_datal(0x00);                     //下位バイト書き込み

// 出力モードコマンドの設定
pcd_cmdwr(0xF0);                  //拡張モニタ,低感度,加減速動作,励磁出力,パルス出力
OUT_CMD = 0xF0;                 //出力モードコマンドの保存

// R3レジスタ(加減速レート)設定→0.468s (1023 0x03FF)
pcd_reg(3);                           //R3レジスタ選択
pcd_datam(0x03);                  //中位バイト書き込み
pcd_datal(0xFF);                   //下位バイト書き込み

// R5レジスタ(スローダウンポイント)設定→25パルス (0x0019)
pcd_reg(5);                          //R5レジスタ選択
pcd_datam(0x00);                 //中位バイト書き込み
pcd_datal(0x19);                   //下位バイト書き込み

// スタートコマンドの設定
pcd_cmdwr(0x05);                 //INTなし,高速モード,外部スタートなし,FH速度
START_CMD = 0x05;             //スタートモードコマンドの保存

pcd_ots(0);                          //OTS出力なし

}

/* コマンドバッファ書き込み ****************************/
// cmd_data : 書き込みデータ
pcd_cmdwr(int cmd_data){
    output_bit(A0,0);               //コマンドバッファ指定
    output_bit(A1,0);
    output_b(cmd_data);          //cmd_data出力
    pcd_wr();                         //書き込み信号出力
}

/* レジスタ選択 ****************************************/
// REG : レジスタ番号0〜7の指定
pcd_reg(int reg){

    output_b(REG_CMD);        //現在のレジスタセレクトコマンドをロード

    output_bit(A0,0);              //コマンドバッファ指定
    output_bit(A1,0);
    output_bit(PIN_B7,1);        //D7 レジスタセレクトコマンド選択
    output_bit(PIN_B6,0);        //D6
    output_bit(PIN_B3,0);        //D3

    switch(reg){
        case 0:                      //R0選択
            output_bit(PIN_B0,0);
            output_bit(PIN_B1,0);
            output_bit(PIN_B2,0);
            break;
        case 1:                      //R1選択
            output_bit(PIN_B0,1);
            output_bit(PIN_B1,0);
            output_bit(PIN_B2,0);
            break;
        case 2:                      //R2選択
            output_bit(PIN_B0,0);
            output_bit(PIN_B1,1);
            output_bit(PIN_B2,0);
            break;
        case 3:                      //R3選択
            output_bit(PIN_B0,1);
            output_bit(PIN_B1,1);
            output_bit(PIN_B2,0);
            break;
        case 4:                      //R4選択
            output_bit(PIN_B0,0);
            output_bit(PIN_B1,0);
            output_bit(PIN_B2,1);
            break;
        case 5:                      //R5選択
            output_bit(PIN_B0,1);
            output_bit(PIN_B1,0);
            output_bit(PIN_B2,1);
            break;
        case 6:                      //R6選択
            output_bit(PIN_B0,0);
            output_bit(PIN_B1,1);
            output_bit(PIN_B2,1);
            break;
        case 7:                      //R7選択
            output_bit(PIN_B0,1);
            output_bit(PIN_B1,1);
            output_bit(PIN_B2,1);
            break;
        }
        pcd_wr();                   //書き込み信号出力

        REG_CMD = input_b();  //変更後のレジスタセレクトコマンドの保存
}

/* 上位データ書き込み **************************/
// data_h : 書き込みデータ
pcd_datah(int data_h){
    output_bit(A0,1);              //レジスタ上位バイトの指定
    output_bit(A1,1);
    output_b(data_h);             //上位バイトの書き込み
    pcd_wr();                        //書き込み信号出力
}

/* 中位データ書き込み **************************/
// data_m : 書き込みデータ
pcd_datam(int data_m){
    output_bit(A0,0);              //レジスタ中位バイトの指定
    output_bit(A1,1);
    output_b(data_m);            //中位バイトの書き込み
    pcd_wr();                        //書き込み信号出力
}

/* 下位データ書き込み **************************/
// data_l : 書き込みデータ
pcd_datal(int data_l){
    output_bit(A0,1);              //レジスタ下位バイトの指定
    output_bit(A1,0);
    output_b(data_l);              //下位バイトの書き込み
    pcd_wr();                        //書き込み信号出力
}

/* R0 プリセットカウンタ設定 ********************************/
// precnt : long型プリセットカウント値
pcd_precnt(long precnt){
long dummy;
    pcd_reg(0);                     //R0レジスタ選択

    pcd_datah(0);                 //上位バイト書き込み 強制0固定

    dummy = (precnt >> 8) & 0x0000FF; //中位データの抽出
    pcd_datam((int)dummy);  //中位バイト書き込み

    dummy = precnt & 0x0000FF; //下位データの抽出
    pcd_datal((int)dummy);   //下位バイト書き込み

}

/* R2 動作速度FH設定 ********************************/
// speed : int型回転速度 pps
pcd_speed(int speed){
int dummy;

    speed/=2;                      //speed = speed / 2

    pcd_reg(2);                     //R2レジスタ選択

    dummy = (speed >> 8) & 0x00FF; //中位データの抽出
    pcd_datam(dummy);        //中位バイト書き込み

    dummy = speed & 0x00FF; //下位データの抽出
    pcd_datal(dummy);          //下位バイト書き込み
}

/* スタート制御 ********************************************/
// 
pcd_start(){

    output_b(START_CMD);   //現在のスタートモードコマンドのロード

    output_bit(A0,0);             //コマンドバッファ指定
    output_bit(A1,0);
    output_bit(PIN_B7,0);       //D7 スタートモードコマンド選択
    output_bit(PIN_B6,0);       //D6
    output_bit(PIN_B3,0);       //D3 ストップ制御 OFF
    output_bit(PIN_B4,1);       //D4 スタート制御 ON
    pcd_wr();                       //書き込み信号出力

    START_CMD = input_b();  //変更後のスタートモードコマンドの保存
}

/* ストップ制御 ********************************************/
// 
pcd_stop(){

    output_b(START_CMD);   //現在のスタートモードコマンドのロード

    output_bit(A0,0);            //コマンドバッファ指定
    output_bit(A1,0);
    output_bit(PIN_B7,0);     //D7 スタートモードコマンド選択
    output_bit(PIN_B6,0);     //D6
    output_bit(PIN_B3,1);     //D3 ストップ制御 ON
    output_bit(PIN_B4,0);     //D4 スタート制御 OFF
    pcd_wr();                     //書き込み信号出力

    START_CMD = input_b(); //変更後のスタートモードコマンドの保存
}

/* 方向制御 ********************************************/
// rotate : 0 → 正転、1 → 逆転
pcd_cw(int rotate){

    if((rotate == 0) || (rotate == 1)){

        output_b(CTRL_CMD);       //現在の制御モードコマンドのロード
        output_bit(A0,0);               //コマンドバッファ指定
        output_bit(A1,0);
        output_bit(PIN_B7,0);         //D7 制御モードコマンド選択
        output_bit(PIN_B6,1);         //D6
        output_bit(PIN_B3,rotate);  //D3 0:正転 1:逆転
        pcd_wr();                        //書き込み信号出力

        CTRL_CMD = input_b();     //変更後の制御モードコマンドの保存
    }
}

/* OTS出力制御 ********************************************/
// ots : 0 → 出力しない、1 → 出力する
pcd_ots(int ots){

    if((ots == 0) || (ots == 1)){

        output_b(CTRL_CMD);       //現在の制御モードコマンドのロード
        output_bit(A0,0);               //コマンドバッファ指定
        output_bit(A1,0);
        output_bit(PIN_B7,0);         //D7 制御モードコマンド選択
        output_bit(PIN_B6,1);         //D6
        output_bit(PIN_B4,ots);       //D3 0:なし 1:あり
        pcd_wr();                         //書き込み信号出力

        CTRL_CMD = input_b();      //変更後の制御モードコマンドの保存
    }
}

/* WR信号出力 ********************************************/
pcd_wr(){
    output_bit(WR,0);
    delay_us(10);
    output_bit(WR,1);                   //コマンド書き込みタイミング
    delay_us(10);
}

ここではヘッダファイル内部のプログラムについての解説は省略させて頂きます。ステッピングモータコントローラPCD4511の設定動作に深く関係する内容ですので、115.PCD4511でステッピングモータ制御のページをご参照下さい。

【先頭に戻る】

 


353−3.ステッピングモータ制御用プログラム例1 npm102.C

 

次に、上のヘッダファイルを利用したプログラム事例をご紹介します。正転方向に480パルス分回転して3秒停止します。次に逆転方向に480パルス分回転して再び3秒停止します。これの繰り返しです。正転後の停止は通電状態の静止なので、強い静止トルクが得られ、逆転後の停止は無通電状態の停止なので、フリーの状態です。

ここをクリックするとダウンロードできます。npm102.c

 

/********************************************************
PCD4511ステッピングコントローラテスト RIKIYA 2003.11.22 
PIC16F873 npm102.c 
S字加減速の基本的動作 H8-3048 npmtest2.Cからの移植
**********************************************************/

#include <16f873.h>
#include <pcd4511.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock = 10000000) // clock 10MHz

/* メイン関数 **********************************************/
void main(){
int i;

    pcd_init();                                //PCD4511の初期化

    for(i=0;i<50;i++){
        while(input(BUSY) == 0){}      //動作中次の処理を待機
        pcd_ots(0);                         //OTS出力なし
        pcd_cw(0);                         //正転
        pcd_precnt(480);                //カウント数480にセット
        pcd_speed(200);                 //200ppsを回転速度に設定 
        delay_ms(3000);                 //3000mS待機
        pcd_start();                       //スタート
 
        while(input(BUSY) == 0){}    //動作中次の処理を待機
        pcd_ots(1);                       //OTS出力あり
        pcd_cw(1);                       //逆転
        pcd_precnt(480);               //カウント数480にセット
        pcd_speed(200);                //200ppsを回転速度に設定 
        pcd_ots(0);                       //OTS出力なし
        delay_ms(3000);                //3000mS待機
        pcd_start();                      //スタート
    }
    pcd_stop();                           //ストップ
    while(1){}
}

 

プログラムの動作はコメント分を参照して下さい。頭にpcd_と付いている関数は、全て上でご紹介しているヘッダファイルpcd4511.hに記載しているものです。プログラムの始めに#include <pcd4511.h>と宣言している点にご注意下さい。


【先頭に戻る】


353−4.ステッピングモータ制御用プログラム例2 npm103.C

 

せっかくなので、もう少しだけ高度なプログラムも作ってみましょう。パソコンからシリアル通信でコマンドとパラメータを受け取り、ステッピングモータの動作を制御します。パソコン側はハイパーターミナルを利用してコマンドを送信します。ハイパーターミナルの通信条件は以下の通りです。

 

 

使用できる制御コマンドは以下の通りです。

No コマンド 意 味 パラメータ
s 回転開始 なし
2 e 回転停止 なし
3 c 回転方向  0:正転 1:逆転
4 p 回転速度  pps(1秒あたりのパルス数)で設定
5 r 回転角度 回転パルス数
6 o OTSビット 0:ドライバハイインピーダンス(無効) 1:ドライバ動作(有効)

例 ) r480 と入力してEnter  → 回転角度を480パルス分にプリセット。(まだ回転しない)

      p200と入力してEnter → 回転速度を200ppsにプリセット。(まだ回転しない)

       s と入力してEnter → 200ppsで回転を開始して、480パルス後に停止する。

  

注意)

OTSビットでモータドライバの動作を有効か無効に設定しています。無効の場合はモータのコイルをドライブする出力がハイインピーダンス状態となり、モータはフリー状態となり動作しません。有効状態でモータドライバが動作します。有効状態でモータが停止している場合は通電状態なので強い停止トルクが得られます。

 

ここをクリックするとダウンロードできます。npm103.C

 

/********************************************************
PCD4511ステッピングコントローラテスト              RIKIYA 2003.11.23 
PIC16F873                                                                 npm103.c 

シリアル通信でコマンドを受け取り、ステッピングモータの
制御を行う。
**********************************************************/

#include <16f873.h>
#include <stdlib.h>
#include <pcd4511.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock = 10000000) // clock 10MHz
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

/* メイン関数 **********************************************/
void main(){
int i;
long p_data;
char rxdata[10],para[9];

    pcd_init();               //PCD4511の初期化
    pcd_ots(0);             //OTS出力なし
    pcd_cw(0);             //正転
    pcd_speed(200);     //200ppsを回転速度に設定 

    while(1){
        printf("Input Command and Enter \r\n");
        gets(rxdata);
        puts(rxdata);
        //パラメータ部分の抽出
        for(i=0;i<9;i++){
                para[i] = rxdata[i+1];
                if(rxdata[i+1] == '\0') i = 9;
        }
        //パラメータの数値化
        p_data = atol(para);

        switch(rxdata[0]){
        case 's':                    //回転開始
            pcd_start();
            break;
        case 'e':                   //回転停止
            pcd_stop();
            break;
        case 'c':                   //回転方向
            pcd_cw(p_data);
            break;
        case 'p':                   //回転速度
            pcd_speed(p_data/2);
            break;
        case 'r':                   //回転角度
            pcd_precnt(p_data);
            break;
        case 'o':                   //OTS出力
            pcd_ots(p_data);
            break;
        default:
       }
    }
}

 

プログラムの説明

以下に要点だけをご説明します。

 

■1.PICでのシリアル通信設定

 

#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

上記のプリプロセッサで、RS232C通信のボーレート9600bpsと、送信端子RC-6ピンと受信端子RC−7ピンの設定をしています。CCS Cコンパイラでは、シリアル通信機能(USART)を持たないPICでも、ソフト的にシリアル通信機能を持たせることができますが、今回はPIC16F873USART機能を利用する形とします。

 

■2.ステッピングモータの初期設定

 

    pcd_init();               //PCD4511の初期化
    pcd_ots(0);             //OTS出力なし
    pcd_cw(0);             //正転
    pcd_speed(200);     //200ppsを回転速度に設定 

ここでは、ステッピングモータを制御するためのデバイスPCD4511に、基本的な情報を書き込んでいます。

 

■3.コマンドの受信と返信

 

        printf("Input Command and Enter \r\n");
        gets(rxdata);
        puts(rxdata);

CCS Cコンパイラでは、printf文を利用して簡単に外部へのデータ送信が可能になっていて便利です。ここではハイパーターミナルにコマンド入力を促すメッセージを送信しています。

その後gets(rxdata);でハイパーターミナルからのコマンド入力を受け付けます。gets( );関数はシリアルポートからCRコード(Enterキー)が入力されるまで文字列を受信し、最後にNULLコード'\0'を付け加えます。受信した文字列は、ここではrxdata[10]の配列変数に格納されることになります。

そして、利用者が入力したコマンドを、puts(rxdata);でハイパーターミナルに返信します。本当は利用者が1文字入力するごとに返信したいところですが、今回はこれらの関数を使って文字列ごとに受信/返信を行って簡単にすませているので、利用者がコマンドを入力し終わってEnterキーを押すまで返信されません。

CCS Cコンパイラを使うと、シリアル通信のプログラムがこんなに簡単に組めてしまいます。

 

■4.パラメータ部分の抽出

 

        for(i=0;i<9;i++){
                para[i] = rxdata[i+1];
                if(rxdata[i+1] == '\0') i = 9;
        }

利用者がハイパーターミナルから入力するのは、先頭の1文字が動作の種類を決めるコマンドで、それに続く数値が動作の範囲や内容を決めるパラメータという取り決めをしています。なので、パラメータ部分は必ず2文字目以降ということになり、それをpara[9]という配列変数に格納することによってパラメータ部分だけを抽出しています。

 

■5.パラメータの数値化

 

        p_data = atol(para);

抽出したパラメータは文字列なので数字としての意味を持っていません。ここではatol( );関数を使って、文字列をlong型の数値に変換しています。atol( );関数はC言語の標準関数ですが、これを利用するためにプログラムの先頭部分で #include <stdlib.h> を追加している点に注意して下さい。


■6.コマンドごとの処理

 

残りのswitch文の部分では、受信した1文字目のコマンドごとにその処理内容を変えて、ステッピングモータの実際の制御を行っています。

 

■動作上の注意

 

今回、pcd_init( );関数内でPCD4511の初期設定を行っていますが、数ある動作モードの中でS字加減速で指定パルス分回転したら自動的に停止するプリセット動作としています。この場合、回転開始を始める前に、必ずプリセット値(回転パルス数→ここでは回転角度に相当)を設定しないと動作しません。

今回の事例では、必ず コマンドでパルス数を指定してから s コマンドで回転を開始させる必要があります。それ以外には特に制約事項はなく、 e コマンドで停止させたり、c コマンドで回転方向を変えたり、p コマンドで回転速度を変えたりという操作は、モーター回転途中でも実行させることが可能です。

【先頭に戻る】


353−5.実験風景

 

ごちゃごちゃしてて分かり辛いと思いますが、左の写真が実験風景です。左側からステッピングモータ、中央がドライバ用テスト基板、そして右側がPIC用実験基板です。その上にある小さな基板は、PICとドライバを接続するためのコネクタ変換を行っています。

ドライバ用テスト基板は、もともとH8と直接接続することを前提としているため、PIC用実験基板とはちょっと合わない部分があるためです。変換基板は以下のような接続になっています。

単純に言うと、RAポート側に行ってしまったBUSY信号の入力端子を、その他の制御用出力信号と一緒のコネクタにまとめてから、ドライバ用テスト基板に接続するためのものです。

【先頭に戻る】


今回の実験をもとに、次の段階ではRS485制御による多ノード間の通信へ発展させようと思います。

PCD4511の持つS字加減速動作は、非常に短い時間内での指定しかできません。なので、見るからに関節を滑らかに動かすといった比較的長い時間をかけてのS字加減速はできません。自然な加減速でロボットアームを動かすような場合は、CPU側から断続的に回転速度の制御を行ってあげる必要があるかもしれません。

今のところ、PCD4511に対してはコマンドやパラメータの書き込み制御しか行っていません。しかしデバイスとしては内部状態の読み出しにも対応しているため、ソフトウエアの組み方次第によっては、もっと木目の細かい制御が可能ではないかと思います。

 

【ソフトウエア編TOPに戻る】


【表紙に戻る】