6.1 予約語

以下の単語は予約されているので、信号名、パラメータ名、ユーザ関数名として使うことはできません。
ただし大文字と小文字を区別しますので、同じ綴りであっても文字の大きさが異なれば使用できます。
予約語のほとんどは関数の名前です。

記述用の予約語
else elsif for if init proc
return while
 
宣言用の予約語
adOS adRange alias array dtMsec farray
include uForm var period_PWM xType
 
関数名としての予約語
abs acos Ain Aout asin atan
atan2 auxfunc average Bin Bout bqApf
bqBpf bqHpf bqLpf bqBef Cin cos
cosh currTime delay deriv Din Dout
exp Fin fir gauss hysteresis iir
int integral lag1 leadlag limit log
log10 mulMatV pi pid polyLine Pin
Pout pow pulse random sin sinh
tan sqrt stepLine trigger w_pwm w_saw
w_sqr w_tri Xin w_udef Xout w_sin

 

6.2 ソースコード

プログラムのソースコードは、AprocSのプログラムウィンドウでソースコードエリアに表示されている内容です。 ソースコードエリアに複数のページが表示されている場合は、それら全てが対象になります。

複数のソースコードからなるプロジェクトでは、ソースコードエリアの左端のページをメインソース、 それ以外のページをサブソースと呼びます。 メインソースは全てのプロジェクトで必要なコードです。 サブソースは必要に応じてユーザが追加します。

サブソースのあるプロジェクトでは、全ソースコードは画面の右端のページから順番に処理されて、 最後に左端のメインソースが処理されます。 下の図はソースコードエリアの表示と処理される全ソースコードの関係を示しています。 これは3つのソースコードから成るプロジェクトの例ですが、 3つを1つのファイルにまとめれば、サブソースの無いプロジェクトにすることもできます。 サブソースはユーザ関数などを他のプロジェクトでも利用したい場合に役に立ちます。

複数のサブソースにユーザ関数を定義し、あるユーザ関数から別のユーザ関数が呼び出される場合は、 呼び出されるユーザ関数は、呼び出すユーザ関数よりも上位(画面では右側)になければなりません。 サブソース画面を右クリックして調整してください。

ソースコードの管理方法については、「5.1 プログラミングウィンドウ」 を参照してください。

 

 

作者を含め、この画面での編集が気に入らないユーザも多いと思います。それで、1.64以降では ファイルを参照することにより、お好みのテキストエディタを利用できるようにしました。

たとえば、上図プロジェクトでサブソースを画面から消し、 その代わりに、メインソースからサブソースのファイルを参照することができます。

include "subsrc2.txt";
include "subsrc1.txt";
proc
{
	.......
	
}

さらに、このproc{ … } の記述も別のファイル( たとえば mainsrc.txt )に移せば下記となります。

include "subsrc2.txt";
include "subsrc1.txt";
include "mainsrc.txt";

 

 

さて、ソースプログラムは以下の3つの部分から構成されます。

  1. メイン処理部
  2. 宣言部
  3. ユーザ関数部

このうちメイン処理部は必須です。他は必要に応じて追加します。

 

6.3 メイン処理部

 

  1. 書式

    メイン処理部は、予約語 proc と、それに続く{ }から成ります。 { }の中は文の集合であり、装置の運転時には、それらの文が指定した周期で繰返し実行されます。 メイン関数の書式は以下です。

       proc
       {
            1個以上の文
       }
    

    文とその要素について以下に説明します。

     

  2. 代入文、出力文、および制御文の3種類があります。

    代入文と出力文は、「{ またはセミコロン(;)」 の次の文字から 次のセミコロンまでの文字列です。改行があっても無視され、セミコロン(;)が現れるまでは1つの文とみなされます。 逆に改行が無くてもセミコロン(;)があればその文は終了します。 よって、複数行で1文にしたり、1行に複数の文を記述することもできます。

    これに対して制御文は、条件式とそれに続く{ }から成る文字列です。 この{ }の中にも、制御文を含めて1個以上の文を記述することができます。

     

  3. 代入文

    代入文は以下の構造を持ちます。この文が実行されると、左辺の信号に右辺の式の値が代入されます。

    信号 = 式;

 

  1. 式は信号(変数)、パラメータ(定数)、関数、数字などの要素、またはそれらの要素を演算子を介して結合させたもので、 その表現に基づく値を表します。以下に式の例を示します。

    【式の例1】  abc

    abcは予約されていない文字列なので、ユーザがつくった信号またはパラメータであり、 この式はabcが保有する値を表します。

    【式の例2】  -2.5 + sin( time ) * amp

    timeを角度とする正弦値にampの値を乗算し、それに-2.5という値を加算した値を表します。 ここでsin は予約された算術関数であり、amp、time はユーザが作った信号またはパラメータです。 通常の式と同様、乗除算は加減算に優先します。

    【式の例3】  max > ( min + 2 )

    max が min+2 より大きければ1を、同じか小さければ0を表します。

    【注意】( )を省略して max > min + 2 と記述すると、 ( max > min ) + 2 と解釈され、異なる結果を与えます。
    → 不等号の説明はこちら

    【式の例4】  max > -min

    max が -min より大きければ1を、同じか小さければ0を表します。

    符号反転を表す「-」 には乗除算よりも高い優先度がありますので 敢えて max > (-min) とする必要はありません。 同様に、a * -b という記述は a * (-b) と同じです。

     

  2. 信号

    英字で始まり英数字から成る予約語以外の文字列で、 宣言部で信号宣言されているか、または、代入文の左辺にあるものは、信号と見なされます。 信号やパラメータはIEEE754形式の単精度(32bit)浮動小数点値です。信号は運転中の履歴を記録することができます。

     

  3. パラメータ

    英字で始まり英数字から成る任意長の文字列のうち、信号でも予約語でもないものは、 パラメータと見なされます。 ただし、宣言部で定数宣言された文字列は無条件にパラメータです。 パラメータの値は、宣言部で定義されたものを除いて、操作画面(オペレーションウィンドウ)で設定・変更することができます。 しかし、プログラムでパラメータに値を代入することはできません。

     

  4. 数値

    数字で表された文字列で、負号や小数点を含むこともあり、この文字列で表現される10進数を IEEE754形式の単精度(32bit)浮動小数点値として持ちます。 プログラムで代入することも、オペレーションウィンドウから変更することもできません。

     

  5. 演算子

    (1) 単項演算子

    続く式の内容に演算を施します。以下があります。

    記号意味結果
    -符号反転続く式の値の符号を反転した値 x = y * -z;x は y と -z の積
    !否定続く式が真なら0、偽なら1 if !( x>=3 ) { ... }x が3未満なら...

     

    (2) 2項演算子

    四則演算や不等号など、その前後の式に演算を加えます。以下があります。

    記号意味結果
    +加算2項の和 z = x + y;zはxとyの和
    -減算2項の差 z = x - y;zはxとyの差
    *乗算2項の積 z = x * y;zはxとyの積
    /除算2項の商 z = x / y;zはxとyの商
    %剰余整数部で除算した
    余り
    z = 5.5 % 3.7;z は 5÷3 の余りで 2 になります
    **べき乗x**y で xy の意 z = 3 ** 0.5;z=1.732051 となります
    yが整数でないとき x>0 です。
    > 記述された関係が真なら1、偽なら0 y = x > 0;xが正ならy=1、それ以外ならy=0
    >=非小if x >= 0 { ... }xが負でなければ...
    <if x < 0 { ... }xが負なら...
    <=非大if x <= 0 { ... }xが正でなければ...
    = =等しい if int(x) = = -1 { ... }xが-1以上0未満なら...
    !=等しくない if Bin( ) != 0 { ... }デジタル入力8ビットのうち、ひとつでもHighなら...
    &&論理積 正の値なら真、0または負なら偽として演算し、結果が真なら1、偽なら0 if (x>=0) && (x<=9) { ... }xが0以上9以下なら...
    ||論理和 if (x>0) || (y>0) { ... }x、yのいずれかが正なら...
    &ビット論理積 整数部のビット対応で論理演算します。小数部は無視され、結果は整数値になります。 if Bin( ) & 5 { ... } 5=0000 01012なので、デジタル入力8ビットのうち、ビット0、ビット2 のいずれかが High なら...
    |ビット論理和 Bout( x | 7 ); 7=0000 01112なので、x の整数部の下位0〜2ビットを常時 High として出力します
    ^ビット排他的論理和 x = Bin( ) ^ 128; 128=27なので、デジタル入力8ビットのうち、ビット7だけ論理を反転させて x へ代入します。

    【注意1】この表では、フォントの都合で= =の等号の間にスペースを入れていますが、実際はありません
    【注意2】ある数の整数部とは、その符号によらず、小数点以下を無視した値です。 これに対して整数化関数 int( )はその値以下で最大の整数値を返します。 そのため、負の数について両者は異なります。例えば-2.5の整数部は-2ですが、int(-2.5) は -3 です。
    【注意3】多くの場合、小数点以下を含む数値は見かけの精度が期待できません。 例えば、0.1 という数値は、32bitで正確に表現できないため、近似的に 0.10000000149 として扱われます。 そのため、a=0.1; としても (10*a) <= 1 という式は等号が成立せず 「偽」 となります。 整数値であっても、絶対値が223以上になると精度が劣化します。

     

  6. 関数

    予約された一般の関数とユーザが定義したユーザ関数があります。

     

  7. 制御文

    制御文には、if文、while文 と for文 があります。その構文は以下です。

    1. if 文

        if 式 { 1個以上の文; }
        
        「 elsif 式 { 1個以上の文; }」という文の0回以上の繰り返し
      
          ..........
      
        else { 1個以上の文; }
      

      if に続く式の表す値が正(真)のときそれに続く{ }の処理が実行され、 それ以外のとき次の elsif に続く式が順番に評価されます。 正(真)となる式があったら、それに続く{ }だけが実行され、それ以降は無視されます。 全ての式が「0または負」(偽)なら、最後の else に続く{ }の処理が実行されます。

      elsif 式{ }や else{ }は省略可能です。 else{ }が省略された場合、全ての式が「0または負」(偽)なら何も実行されません。

      【注意】

      • C言語とは異なり、if 式、elsif 式 または else の後に続く文は、1文だけでも{ }に入れなければなりません。
      • elsif はひとつの単語であり、else if ではありません。else の後には { が必要なので、 else if と続けて書くことはできません。

       

    2. while 文

         while  式 { 1個以上の文; }
      

      式の値が正(真)である限り{ }の処理を繰り返します。
      最初から式の値が「0または負」(偽)なら、何も実行されません。

      【注意】

      式の値が真のままだと、永久に{ }を抜けることができません。 式の値を偽とするための処理を{ }に記述することを忘れないでください。 Aporc-1が無限ループに陥った場合は、停止ボタンを押して強制終了してください。 無限ループをシミュレーションするとOSに叱られるので止めましょう。

       

    3. for 文( v1.90 以降で使用可能です )

         for(  文1 ; 式 ; 文2 ){ 1個以上の文; }
      

      この構文は下記と同じですが、文2 が明示的に要求されるので、while 文でよくある 文2 の書き忘れを防止できるという利点があります。

         文1;  while 式 { 1個以上の文;  文2; }
      

     

  8. 出力文

    出力文は代入を伴わない関数です。詳細は 「6.7 関数」 を参照ください

     

  9. 配列

    AprocSバージョン1.4以降では、要素数を宣言した1次元の配列を信号として使うことができます。

    配列は通常の信号と同じように使うことができますが、オペレーションウィンドウには現れません。
    そこで、モニタしたい要素には別名を宣言します。

    以下に例を示します。配列を使って複数の周期信号を生成し、アナログ電圧として出力するプログラムです。

array ax[8];		// 要素数8の配列を定義
alias ax[0]= Sin;	// ax[0]の信号名はSin(小文字のsinは予約語)
alias ax[1-4]= test8;	// ax[1]〜ax[4]の信号名はtest8〜test11
proc 
{  
    ax[0] = w_sin( period, 0, 1 );	// 振幅1の正弦波
    sign = 2 * ( ax[0] > 0 ) - 1;	// ax[0]の符号

    i=1; while i<8
    {
        ax[i] = sign * ax[0] * ax[i-1];	// 信号生成
        Aout( i, 0, 0.2, ax[i] );	// 5V振幅でアナログ出力
        i = i + 1;			// 次のチャンネル
    }
} 

 

【注意】 while文による繰り返しで関数を使う場合、その関数に内部変数(=前回値を保存する信号)が含まれていると、 期待した効果が得られないことがあります。

たとえば、以下のプログラムでは、5つの入力信号を繰り返してフィルタに通過させています。 この場合、フィルタの内部変数が5つの信号に対して共通に使われてしまうので、 独立に5つのフィルタを通した場合と同じ結果にはなりません。

proc 
{  
    for( i=0; i<5; i++ )
    {
        indat[i] = Ain( i, 0, 1 );
        outdat = bqLpf( indat[i], freq, damp );
        Aout( i, 0, 1, outdat );
    }
} 

実際に5つの信号のそれぞれを個別のフィルタに通したければ、5組の内部変数を確保するために、 以下のように5回関数を呼ばなければなりません。

proc 
{  
    for( i=0; i<5; i++ ) { indat[i] = Ain( i, 0, 1 ); }

    outdat[0] = bqLpf( indat[0], freq, damp );
    outdat[1] = bqLpf( indat[1], freq, damp );
    outdat[2] = bqLpf( indat[2], freq, damp );
    outdat[3] = bqLpf( indat[3], freq, damp );
    outdat[4] = bqLpf( indat[4], freq, damp );

    for( i=0; i<5; i++ ) { Aout( i, 0, 1, outdat[i] ); }
} 

つまり、まだ関数を配列として扱えるようになっていません。 ただし、内部変数を含まない入出力関数や算術関数などにはこのような制約はありません。 この例でも関数 Ain, Aout は繰り返して使っていますが問題ありません。

 

 

6.4 宣言部

宣言部はメイン処理部よりも先に記述します。以下の種類があります

種別と書式説明
演算周期

 dtMsec = 数値;

演算周期をミリ秒単位で指定します。この文があると、実行コードを生成したとき オペレーションウィンドウの演算周期の欄に指定した数値が入り、 その値を変更できなくなります。
A/Dレンジ

 adRange = 5;

A/D変換の入力レンジを±5Vに指定します。 5以外の値は無視され、宣言しない場合と同じ(±10V)になります。

入力レンジを±5Vにすると、分解能が向上するかわりに変換値は±5Vで飽和します。 また、チャンネル毎に異なるレンジとすることはできません。

A/D変換平均回数

 adOS = 数値;

AD7606に内蔵されているデジタルフィルタの平均化回数を指定します。 数値として1〜6の整数値を指定しますと以下の設定になります。指定しなければ平均化なしです。
設定値平均化回数所要時間の増分
125μs
2415μs
3835μs
41674μs
532154μs
664311μs
定数宣言

 定数名=数値;

メイン処理部に現れるパラメータ(定数)に予め値を与えます。 ここで宣言したパラメータはオペレーションウィンドウに現れないので、 ソースコードでしか変更できなくなります(変更を有効にするにはコード生成が必要です)。 変更の頻度が低い場合、数値をソースコードで管理したい場合、ユーザ関数と共有したい場合等に使います。
変数宣言

 var 信号名;

 var 信号名=数値;

proc{ } 中に現れる単語がパラメータ(定数)ではなく信号(変数)であることを明示し、 数値が与えられる場合は、それがこの信号の初期値になります。それ以外の信号の初期値は0です。

ユーザ関数の中で記述するとローカルな信号を定義できます。

配列宣言

 array 配列名[数値];

数値(整数)で表される個数の要素をもつ配列を定義します。
配列の別名宣言

 alias 配列名[*] =
 信号名;

配列の要素に別の信号名を与えると、その要素を指定した信号名で扱うことができ、 オペレーションウィンドウからグラフ指定も可能になります。 信号名をコンマで区切ったり、配列番号に範囲を与えることにより、複数の設定を1行で行います。以下に例を示します。
 alias ax[2]=sigA;          // ax[2]=sigA
 alias ax[2]=sigA,sigB;     // ax[2]=sigA,ax[3]=sigB
 alias ax[2]=sigA,,,sigB;   // ax[2]=sigA,ax[5]=sigB
 alias ax=,,sigA,,,sigB;    // 同上
 alias ax[2-5]=sig;         // ax[2]〜[5]=sig0〜3
 alias ax[2-5]=sig19;       // ax[2]〜[5]=sig19〜22
NEW拡張宣言

 xType = 文字列;

使用する拡張インターフェースを指定し、運転に必要なデータを定義します。 Aproc-1 の場合は接続する装置に依存しますので、説明は各インターフェースのデータシートをご覧ください。→ 商品一覧
Aproc-1 Plus の場合は共通で、以下の書式になります。

xType = "XXXX, in=a*b+w, out=c*d, conf=XX-XX-....";

例1  xType= "D023, in=2*16+4, out=3*8, conf=03-C8-F0";
例2  xType= "D024, in=3*4";

XXXX16進数4桁でD000〜D7FFの値をとる識別番号で、装置の識別番号と一致しない場合エラーになります。
省略不可。
in=a*b+w a は入力データ1ワードのバイト数で、1,2,または3。
b はそのワード数。
w はウェイトサイクル数。1サイクルは8×通信クロック周期で最大80サイクル。w=0なら in=a*b も可。
省略時は入力なし。
out=c*d c は出力データ1ワードのバイト数で、1,2,または3。
d はそのワード数。
省略時は出力なし。
conf=XX-XX-... 右辺は、運転開始時に装置へ送信する設定データをハイフンで区切った16進数2桁の数値の並びで表現したもの。最大18バイト
省略時は送信なし。

ワード数 b、d の最大値は、ワード長が1バイトのとき256、
2バイトのとき128、3バイトのとき64

NEWPWM周期

 periodPWM = 数値;

PWM出力の周期をミリ秒単位で与えます。Aproc-1 Plus 専用です。

 

6.5 ユーザ関数

ユーザ関数は、ユーザが定義する関数で、メイン処理部と同じように{ }で囲まれた文の集合です。 定義された関数は、「それ以降の」別のユーザ関数定義部やメイン処理部で使うことができます。

ユーザ関数定義部の書式は以下です。

関数名( 引数1, 引数2, ………… ) 
{ 
    0個以上の文; 
    return 式; 
} 

関数名に続く( )に0個以上の引数をコンマで区切って記し、続く{  }の中に処理内容を記述します。 最後にreturn文を書くと、その式の値が関数の値になります。 定義されたユーザ関数を呼出すとき、引数として信号名やパラメータ名、または数値を与えると、 ユーザ関数はそれらを使って計算された値を返します。

ユーザ関数内部で計算された信号の値は次回のサイクルでも保存されます。 また、同一のユーザ関数の呼び出しををメインソースから複数回記述した場合には、 記述毎に異なる記憶領域を使って信号の値を記憶します。 したがって、ひとつのユーザ関数を使って、性質の異なる複数のフィルタなどを作ることができます。

以下にユーザ関数の制約事項を記します。 AprocS の古い版では制約が増えますので、できるだけ新しいバージョンを使ってください。

  1. ユーザ関数定義部は、呼び出し側のメイン処理やユーザ関数よりも上位に配置する必要があります。
    別のファイルに記述されている場合は、呼び出し側よりも右側のサブソースに配置します。

  2. ユーザ関数定義部で使用するパラメータは、全て引数として与えねばなりません。 定義部で新たな信号をつくることはできますが、新たなパラメータをつくることはできません。 ただし、宣言されたパラメータや信号はGLOBAL扱いとなりますので、引数で与える必要はありません。

    ユーザ関数のLOCALな信号を宣言するために、ユーザ関数定義の中で var 宣言することができます。

  3. 「return 式;」 は関数定義の最後の文でなければなりません。

  4. ユーザ関数定義部で定義された信号はオペレーションウィンドウには現れません。 return で返さない信号をメイン処理部で使ったり、表示、記録するには、 ユーザ補助関数を使います。

  5. ユーザ関数内でメイン処理部や他のユーザ関数定義部で使われている信号と同じスペルの信号を定義しても、 それは別の信号になります。逆に、引数として与えた信号は、綴りが異なっても呼び出し側の信号そのものです。 よって、ユーザ関数内でその値が変更されると、呼び出し側の信号も変化します。

 

ユーザ補助関数

auxfunc(1.92以降は省略形 auxf も可)は、ユーザ関数内で計算された信号の値を得るための関数です。 ユーザ関数を呼び出した後、別のユーザ関数を呼ぶ前に そのユーザ関数内の信号名を引数として与えると、その信号の値を得ることができます。

下に例を示します。関数 mySUM は引数 a、b の和 x と差 y を計算し、 関数 myMAX は a、b の大きい方の値を x、小さい方の値を y とします。 どちらもリターンで返すのは x の値だけですが、auxfunc(y) を使って y の値も得ることができます。

mySUM( a, b )
{
x = a + b;// xはa,bの和
y = a - b;// yはa,bの差
return x;
}

myMAX( a, b )
{
if a > b { x = a; y = b;}// a,bの大きい方がx
else { x = b; y = a; }// 小さい方がy
return x;
}

proc
{
Sin = w_sin( period, 0, amp );
Cos = w_sin( period, 0.25, amp );
sum = mySUM( Sin, Cos );
diff = auxfunc( y );// mySUMのyを得る
max = myMAX( Sin, Cos );
min = auxfunc( y );// myMAXのyを得る
}

このリストのシミュレーション結果です。

 

6.6 一般関数

 →   こちらのページをご覧ください

 


更新:2021年8月28日