(メニューへもどる)

NADVコントロールプログラム作成の解説


目次

1.最も基本的なプログラム
2.一定の時間間隔でデータを取り込む
3.音声の取り込みと発声(BASIC+マシン語プログラムの例)
4.8255の空きポートからLow・Highのデータを取り込む
5.データを取り込み、テキストファイルを作成する(C言語での例)
6.NADVブロック図


1.最も基本的なプログラム

 チャンネル4からデータを取り込み、それを画面に表示する最も基本的なBASICのプログラム例を次に示す。

--- プログラム1 ---
10 OUT &HD6,&H98   : '汎用入出力ポート8255のモード設定
20 OUT &HD4,&H3    : '入力先をチャンネル4に設定
30 A=INP(&HD0)    : 'データの取り込み
40 PRINT A      : 'データの表示
50 GOTO 30      : '繰り返し

《入出力LSI8255のコントロール》

 NADVでは、ADコンバータAD7824やDAコンバータDAC0808とのインターフェースに8255というLSIを使用している。8255はポートA(PA),ポートB(PB),ポートC(PC)と呼ばれる8ビットのパラレル入出力ポートを3つ持っている。この3つのポートはプログラムによってそれぞれ入力・出力を設定できるが、各ポートの機能を設定したり制御するために8ビットのコントロールワードレジスタという内部レジスタが設けられており、このレジスタにデータを書き込むことによりPA、PB、PCの各入出力ポートの働きが決まる。したがって、8255は4つのI/Oアドレスを持つLSIである。NADVのブロック図からもわかるように各ポートは次のように使用されている。

  PA0〜7 ・・・・・ A/Dコンバータからのデータ入力
  PB0〜7 ・・・・・ D/Aコンバータにデータを出力
  PC0・1 ・・・・・ A/Dコンバータのチャンネル選択のためのデータを出力
  PC2  ・・・・・ 8253にデータを出力
  PC3   ・・・・・ 空き(出力に設定)
  PC4・5 ・・・・・ 8253からデータを入力
  PC6・7 ・・・・・ 空き(入力に設定)

 NADVでは、8255と8253のアドレスの上位8ビットはディップスイッチによって任意に設定できるようになっているが、ここでは上位8ビットはすべて0に設定してあるものとする。各ポートとコントロールワードレジスターの使用アドレスと入出力の設定は次の通りである。

  00D0H ・・・・・ 8255 Aポート(入力)
  00D2H ・・・・・ 8255 Bポート(出力)
  00D4H ・・・・・ 8255 Cポート(上位は入力、下位は出力)
  00D6H ・・・・・ 8255 コントロールワードレジスタ

 8255はモード0、モード1、モード2の3つのモードでの使用法があるが、ここでは最も単純なモード0で使用する。モード0のときのコントロールワードレジスタの各ビットの意味を次に示す。

PAを入力、PBを出力、PC上位を入力、PC下位を出力とするには

  D7 D6 D5 D4 D3 D2 D1 D0
  1  0  0  1  1  0  0  0 →  16進表示では 98H

とすればよい。したがって、NADVでの8255のモード設定は

OUT &HD6,&H98 (00D6H番地の出力装置に98Hを書き込む)となる。

《入力チャンネルの設定》

 8255のPC0とPC1でAD7824の入力チャンネルを設定する。

   チャンネル1の設定  OUT &HD4,&H00
   チャンネル2     OUT &HD4,&H01
   チャンネル3     OUT &HD4,&H02
   チャンネル4     OUT &HD4,&H03

《データの取り込み》

 A/DコンバータAD7824は変換スタートや変換終了等の処理が必要ないため、いきなり読み込み命令のみでよい。8255のAポートから取り込むから、

  A=INP(&HD0)  (00D0H番地の入力装置からデータを読み込んで、変数Aに入力する)

となる。ここで変数Aに入力される値は8ビットのデータであるから、16進表示で00H〜FFH、10進表示で0〜255の値である。アナログの入力電圧が0〜5Vであるならば、デジタル値1に対応する入力電圧は5V/255=0.0196Vであるので、電圧値で表示させる場合はこの値とAとの積をとる必要がある。

《チャンネル4で0〜5Vの電圧を取り込む》

 NADVのチャンネル4は、OPアンプによるボルテージフォロア回路が組まれた0〜5Vの電圧取り込み用のチャンネルであるが、これを用いて、画面中央に測定電圧値を表示するプログラム例を次に示す。

--- プログラム2 ---
 10 OUT &HD6,&H98             : '8255のモード設定
 20 OUT &HD4,&H03             : '入力先をチャンネル3に設定
 30 CLS
 40 A=INP(&HD0)              : 'データ(0〜255)の取り込み
 50 A=5/255*A               : '生データを電圧値に変換
 60 LOCATE 35,12:PRINT USING "##.# V";A  : 'データの表示
 70 GOTO 40                 : '繰り返し

(目次へ)

2.一定の時間間隔でデータを取り込む

 プログラム1やプログラム2では取り込みの時間間隔は考慮されていないが、実際の測定では一定の時間間隔での計測が必要とされることが多い。1秒以上の間隔でよければ、BASICのTIMER$という関数でパソコン本体に内蔵されたタイマーによる時刻を読み込むことができる。プログラム上のダミーのむだループを利用して1秒以下のソフト的タイマーをBASICで作ることもできるが、パソコンの機種に依存してしまう。NADVではProgrammable Interval Timer(PIT)と呼ばれる汎用のプログラマブルタイマーLSIの8253を積んでいるので、これをもちいて正確な時間間隔でデータの取り込みを行うことができる。すなわち、パソコン本体からの307.2kHzのクロックパルスを8253で分周し必要な周波数のパルスを作りだし、これをもとに一定の時間ごとにデータの取り込みを行うことができる。0.5秒ごとにチャンネル4から20個のデータを取り込み、配列に格納するプログラム例を次に示す。

--- プログラム3 ---
10 '
20 DIM  DT(20)        : 'データ格納配列
30 '----- 8255 初期設定 -----
40 OUT &HD6,&H98        : '汎用入出力ポート8255のモード設定
50 OUT &HD4,&H3        : '入力先をチャンネル4に設定
60 '----- 8253 初期設定 -----
70 '8253 モード設定
80 OUT &HDE,&H34       : 'カウンタ0 モード2
90 OUT &HDE,&H76       : 'カウンタ1 モード3
100 '
110 '8253 各カウンタ初期値設定
120 OUT &HD8,&H0       : 'カウンタ0の設定(下位8ビット)
130 OUT &HD8,&H8       : 'カウンタ0の設定(上位8ビット)
140 OUT &HDA,&H4B       : 'カウンタ1の設定(下位8ビット)
150 OUT &HDA,&H0       : 'カウンタ1の設定(上位8ビット)
160 '
170 OUT &HD4,&H4+3      : '8253カウンタ1起動(入力をチャンネル4にしたまま)
180 '----- データの取り込み -----
190 FOR I=1 TO 20
200 WHILE (INP(&HD4) AND &H10) <> &H10 : WEND    : ' PC4に入るパルスの
210 WHILE (INP(&HD4) AND &H10) = &H10 : WEND     : ' 立ち上がりで
220 DT(I)=INP(&HD0)                 : ' データを取り込む
230 NEXT I
240 '----- データの表示 -----
250 FOR I=1 TO 20
260 PRINT DT(I)
270 NEXT I
280 END

《タイマーLSI8253のコントロール》

 8253は16ビットのカウンタを3つもっている。それらはカウンタ0、カウンタ1、カウンタ2と呼ばれ、基本的にパルスが入ってくるとカウント値が減るダウンカウンタとなっている。各カウンタはそれぞれCLK、GATE、OUTと呼ばれる3つの端子を持っているが、その働きは次の通りである。

CLK ・・・・・ カウンタにカウントさせるパルスを入力する端子
GATE ・・・ カウンタの制御入力で、カウンタの停止や初期化するのに使う
OUT ・・・・・ カウント終了時にモードに応じた変化をする出力端子

3つのカウンタは、独立にモード0からモード5までの6つのモードを設定することができるが、その指定は8255と同様にコントロールワードレジスタにデータを書き込むことによって行う。3つのカウンタとコントロールワードレジスタのアドレスはNADVでは次の通りである。ここでも上位アドレスはすべて0に設定してあるものとする。

  00D8H ・・・・・ 8253 カウンタ0
  00DAH ・・・・・ 8253 カウンタ1
  00DCH ・・・・・ 8253 カウンタ2
  00DEH ・・・・・ 8253 コントロールワードレジスタ

コントロールワードレジスタの各ビットの意味を次に示す。

 ここで使用するモード2は分周器として動作する。たとえば初期値に100を設定すると、クロックがCLKに入るごとに100から1ずつカウントダウンし、カウンタの値が1になったときOUTが1クロック分だけLになる。カウンタの値は再び100となり、以後同じ動作を繰り返す。GATEがLのときはカウントを停止する。たとえば、GATEをHにしておいて、CLKに300kHzのクロックパルスを入力すると、OUTから3kHzのクロックパルスが出力されることになる。つまり100分の1の分周器として働くわけである。詳細は他の資料を参考にしてもらいたいがモード3もほぼ同様の働きをする。プログラム3ではカウンタ0をモード2、カウンタ1をモード3で使っている。カウンタ2は使用していない。

 8255と8253の接続は図の通りである。パソコン本体の307.2kHzのパルスは8253のカウンタ0とカウンタ1で2Hzにされ8255のPC4に送り込まれている。この2Hzのパルスの監視により8255は1秒間に2回すなわち0.5秒ごとのデータの取り込みを行うことができる。各カウンタに設定される初期値は次の通りである。

307.2k=307200=16・16・16・(16・4+11)=1000H・004BH より
307200/2=0800H・004BH
よって、初期値はカウンタ0が0800H、カウンタ1が004BH

各カウンタへの初期値の書き込みは、下位8ビット・上位8ビットの順に行わなくてはならない。

(目次へ)

3.音声の取り込みと発声(BASIC+マシン語プログラムの例)

 音を取り込んだり(ディジタル録音)、発声(再生)する場合もプログラミング上の基本的な考え方はプログラム3の場合と同じである。すなわち決められた一定の時間間隔でA/Dコンバータを通してデータを取り込んだり(録音)、D/Aコンバータにデータを出力(再生)してやればよい。データを取り込む時間的タイミングを周波数で表したものをサンプリング周波数と呼ぶが、プログラム3の場合は0.5秒ごとの取り込みであったので、サンプリング周波数は2Hzである。データが音である場合、たとえば人の声を取り込み、それを意味のある言葉として再生するためには少なくとも数kHzのサンプリング周波数が必要である。これくらいのサンプリング周波数でデータを取り込むためには、BASICのみのプログラムでは対応できず、機械語のプログラムが必要である。次のプログラム4は、サンプリング周波数が10kHzで、データ格納のためのメモリを16KB(したがって録音時間は1.6秒)としたプログラム例である。「取り込みを開始します。リターンキーを押して下さい」という表示に対してリターンキーを押すと、すぐにデータの取り込みを開始し、その終了後引き続いて「発声を開始します。リターンキーを押して下さい」という表示に対してリターンキーを押すと、すぐに取り込んだ音が再生される。プログラムは取り込みと再生の部分を機械語のサブルーチンとしてある。8255と8253の初期設定の部分もサブルーチンとしてあるが、ここの設定はサンプリング周波数の変更点を除けばプログラム3とまったく同じである。機械語を表すDATA文の部分にアセンブラでの記述と簡単な解説をREM文で埋め込んであるので参考にして頂きたい。

--- プログラム4 ---
1000 'SAVE"NADVP4.BAS",A
1010 '
1020 '   NADV 録音・再生サンプルプログラム  NADVP4.BAS
1030 '             1991.10.26 By N.Egawa
1040 '
1050 '
1060 '----------------------------------------初期設定
1070 '
1080 CLEAR &H500       :'機械語プログラム領域の大きさ &H5000
1090 '                &H0000-&H0FFF 機械語領域
1100 '                &H1000-&H4FFF データ格納領域(16KB)
1110 DEF SEG=SEGPTR(2)    :'機械語領域のセグメントベースを宣言
1120 ADR.AD=&H0        :'&H0000  A/D開始アドレス
1130 ADR.DA=&H100       :'&H0100  D/A開始アドレス
1140 '
1150 GOSUB *SET.MACHINE    :'機械語読み込み
1160 GOSUB *SET8255      :'8255初期設定
1170 GOSUB *SET8253      :'8253初期設定
1180 '
1190 '---------------------------------------- MAIN
1200 '
1210 CLS
1220 PRINT "NADV 音声の取り込みと発声 サンプルプログラム"
1230 PRINT
1240 INPUT "取り込みを開始します。リターンキーを押して下さい",KBUF$
1250 PRINT
1260 PRINT " A/D 変換中 "
1270 '
1280 CALL ADR.AD        : '取り込み(A/D変換) 機械語サブルーチン実行
1290 '
1300 PRINT
1310 INPUT "発声を開始します。リターンキーを押して下さい",KBUF$
1320 PRINT
1330 PRINT " D/A 変換中 "
1340 '
1350 CALL ADR.DA        : '発声(D/A変換) 機械語サブルーチン実行
1360 '
1370 PRINT
1380 END
1390 '
1400 '--------------------------------------- 8255 初期設定
1410 '
1420 *SET8255
1430 OUT &HD6,&H98       :'PA入力 PB出力 PCH入力 PCL出力
1440 OUT &HD4,&H0        :'チャンネル1選択
1450 RETURN
1460 '
1470 '--------------------------------------- 8253 初期設定
1480 '
1490 *SET8253
1500 '8253モード設定
1510 OUT &HDE,&H34   :'&H34=&B 00 11 010 0 カウンタ0 LSB,MSB順W/R モード2
1520 OUT &HDE,&H76   :'&H76=&B 01 11 011 0 カウンタ1 LSB,MSB順W/R モード3
1530 'カウンタ初期値設定
1540 OUT &HD8,2   : OUT &HD8,0    :'サンプリング周波数 307,2/(2・15)kHz=10kHz
1550 OUT &HDA,15  : OUT &HDA,0    :'
1560 RETURN
1570 '
1580 '-------------------------------------------- 機械語書き込み
1590 '
1600 *SET.MACHINE
1610 ADR=0 : ML$=""
1620 RESTORE *MLDATA.AD
1630 WHILE ML$<>"**"
1640    READ ML$
1650    IF ML$<>"**" THEN POKE ADR,VAL("&H"+ML$)
1660    ADR=ADR+1
1670 WEND
1680 '
1690 ADR=&H100 : ML$=""
1700 RESTORE *MLDATA.DA
1710 WHILE ML$<>"**"
1720    READ ML$
1730    IF ML$<>"**" THEN POKE ADR,VAL("&H"+ML$)
1740    ADR=ADR+1
1750 WEND
1760 RETURN
1770 '
1780 'A/D変換
1790 *MLDATA.AD
1800 DATA 50     :'0000 ADSTR:PUSH AX    ;レジスタ退避
1810 DATA 53     :'0001    PUSH BX    ;
1820 DATA 51     :'0002    PUSH CX    ;
1830 DATA 52     :'0003    PUSH DX    ;
1840 DATA 1E     :'0004    PUSH DS    ;
1850 DATA 06     :'0005    PUSH ES    ;
1860 DATA 57     :'0006    PUSH DI    ;
1870 DATA 8C,C8    :'0007    MOV AX,CS   ;データセグメントを
1880 DATA 8E,D8    :'0009    MOV DS,AX   ; コードセグメントに一致
1890 DATA 8C,C8    :'000B    MOV AX,CS   ;
1900 DATA 8E,C0    :'000D    MOV ES,AX   ;
1910 DATA BB,00,40  :'000F    MOV BX,4000H ;データ個数
1920 DATA BF,00,10  :'0012    MOV DI,1000H ;データ格納先頭番地
1930 DATA BA,D4,00  :'0015    MOV DX,00D4H ;・D4Hは8255 PCのアドレス
1940 DATA B0,04    :'0018    MOV AL,04H   ;・PC2に"H"を出力して
1950 DATA EE     :'001A    OUT DX,AL   ;・8253のカウンタ1を起動
1960 DATA EC     :'001B LOOP1:IN AL,DX    ;・PC4が ・クロックパルス
1970 DATA 24,10    :'001C    AND AL,10H   ;・"H"になる・の立ち下
1980 DATA 74,FB    :'001E    JE LOOP1    ;・のを待つ ・がりで
1990 DATA EC     :'0020 LOOP2:IN AL,DX    ;・PC4が ・データを
2000 DATA 24,10    :'0021    AND AL,10H   ;・"L"になる・読むため
2010 DATA 75,FB    :'0023    JNE LOOP2   ;・のを待つ ・
2020 DATA BA,D0,00  :'0025    MOV DX,00D0H ;8255 PA(AD7824)から
2030 DATA EC     :'0028    IN AL,DX    ;データを読み込み,
2040 DATA AA     :'0029    STOSB     ;メモリに格納し,格納番地+1
2050 DATA 4B     :'002A    DEC BX     ;データ個数ー1
2060 DATA BA,D4,00  :'002B    MOV DX,00D4H ;DXにPCのアドレスをセット
2070 DATA 75,EB    :'002E    JNE LOOP1   ;BXが0でなければジャンプ
2080 DATA 5F     :'0030    POP DI     ;レジスタ復帰
2090 DATA 07     :'0031    POP ES     ;
2100 DATA 1F     :'0032    POP DS     ;
2110 DATA 5A     :'0033    POP DX     ;
2120 DATA 59     :'0034    POP CX     ;
2130 DATA 5B     :'0035    POP BX     ;
2140 DATA 58     :'0036    POP AX     ;
2150 DATA CF     :'0037    IRET      ;BASICへ戻る
2160 DATA **
2170 '
2180 'D/A変換
2190 *MLDATA.DA
2200 DATA 50     :'0100 DASTR:PUSH AX    ;レジスタ退避
2210 DATA 53     :'0101    PUSH BX    ;
2220 DATA 51     :'0102    PUSH CX    ;
2230 DATA 52     :'0103    PUSH DX    ;
2240 DATA 1E     :'0104    PUSH DS    ;
2250 DATA 8C,C8    :'0105    MOV AX,CS   ;データセグメントを
2260 DATA 8E,D8    :'0107    MOV DS,AX   ; コードセグメントに一致
2270 DATA BB,00,40  :'0109    MOV BX,4000H ;データ個数
2280 DATA BF,00,10  :'010C    MOV DI,1000H ;データ格納先頭番地
2290 DATA BA,D4,00  :'010F    MOV DX,00D4H ;・D4Hは8255 PCのアドレス
2300 DATA B0,04    :'0112    MOV AL,04H   ;・PC2に"H"を出力して
2310 DATA EE     :'0114    OUT DX,AL   ;・8253のカウンタ1を起動
2320 DATA EC     :'0115 LOOP1:IN AL,DX    ;・PC4が ・クロックパルス
2330 DATA 24,10    :'0116    AND AL,10H   ;・"H"になる・の立ち下
2340 DATA 74,FB    :'0118    JE LOOP1    ;・のを待つ ・がりで
2350 DATA EC     :'011A LOOP2:IN AL,DX    ;・PC4が ・データを
2360 DATA 24,10    :'011B    AND AL,10H   ;・"L"になる・読むため
2370 DATA 75,FB    :'011D    JNE LOOP2   ;・のを待つ ・
2380 DATA BA,D2,00  :'011F    MOV DX,00D2H ;8255 PB(DAC0808)に
2390 DATA 8A,05    :'0122    MOV AL,[DI]  ;メモリ中のデータを
2400 DATA EE     :'0124    OUT DX,AL   ;出力する
2410 DATA 47     :'0125    INC DI     ;メモリ格納番地+1
2420 DATA 4B     :'0126    DEC BX     ;データ個数ー1
2430 DATA BA,D4,00  :'0127    MOV DX,00D4H ;DXにPCのアドレスをセット
2440 DATA 75,E9    :'012A    JNE LOOP1   ;BXが0でなければジャンプ
2450 DATA 1F     :'012C    POP DS     ;レジスタ復帰
2460 DATA 5A     :'012D    POP DX     ;
2470 DATA 59     :'012E    POP CX     ;
2480 DATA 5B     :'012F    POP BX     ;
2490 DATA 58     :'0130    POP AX     ;
2500 DATA CF     :'0131    IRET      ;BASICへ戻る
2510 DATA **
2520 '

(目次へ)

4.8255の空きポートからLow・Highのデータを取り込む例

 これまでの例は、いずれもアナログデータをA/Dコンバータを通して取り込む例であったが、ここでは8255の空き入力ポートを直接利用し、Low・Highのデータでタイマーをスタートし、次のLow・Highでタイマーをストップさせ、その時間間隔を測定するプログラム例を示す。必要な回路は図の通りである。

 共通インターフェースボードNADVは、200台目以降のNADV3から8255のPC3、PC6、PC7は図の通り5 Vでプルアップされているので、スイッチ部分だけを付加すればよい。PC6はスイッチSWがONのときLow、OFFのときHighとなる。次のプログラム5では、PC6がLow→High、すなわちSWをONにして次にOFFにした瞬間にタイマーをスタートさせ、再びLow→Highのときタイマーをストップさせている。これは、図のようにSWの部分をフォトトランジスタを組み込んだ回路で置き換え、フォトトランジスタに光が照射されているときPC6がHigh、光が照射され ていないときPC6はLowとなるようにして、物体が光をさえぎることによりタイマーをスタートさせたり、ストップさせたりすることにより、その物体の通過時間を測定することを目的としたプログラムである。プログラム例はBASICのみの記述であるので、PC6にON・OFFが入力されてからタイマーをスタート・ストップさせるまで時間のずれが生じてしまうため、実際には機械語プログラムにしなければならない。しかし、ここではプログラムの流れを示すことが目的であるので、BASICのみを用いた。落下運動は難しいが、力学台車の運動などのゆっくりした運動であれば、この程度のプログラムでも対応できるはずである。

--- プログラム5 ---
100 'SAVE"NADVP5.BAS",A
110 '
120 '       NADV 時間計測サンプルプログラム  NADVP5.BAS
130 '                1994.1.28 By N.Egawa
140 '
150 '----- 8255 初期設定 -----
160 OUT &HD6,&H98     : '汎用入出力ポート8255のモード設定
170 '
180 '----- 8253 初期設定 -----
190 '8253 モード設定
200 OUT &HDE,&H34     : 'カウンタ0 モード2
210 OUT &HDE,&H70     : 'カウンタ1 モード0
220 '8253 カウンタ0初期値設定
230 OUT &HD8,&H0     : '307200/100=3072=16・16・12=0C00H
240 OUT &HD8,&HC     : '
250 '
260 '----- スタート・ストップ -----
270 OUT &HD4,&H4 : '8253カウンタ1起動
280 WHILE(INP(&HD4) AND &H40)= &H40 : WEND :'PC6がLow-Highのとき
290 WHILE(INP(&HD4) AND &H40)<>&H40 : WEND :'カウンタ1に初期値をセットしてカウント開始
300 OUT &HDA,&HFF : 'カウンタ1に初期値FFFFHをセット
310 OUT &HDA,&HFF : '
320 PRINT "START"
330 WHILE (INP(&HD4) AND &H40) = &H40 : WEND : 'PC6がLow-Highのとき
340 WHILE (INP(&HD4) AND &H40) <>&H40 : WEND : 'カウンタ1をラッチしてカウント停止
350 OUT &HDE,&H40 : 'カウンタ1 ラッチ
360 PRINT "STOP"
370 '
380 '----- 時間の表示 -----
390 T=(65535!-(INP(&HDA)+256*INP(&HDA)))/100 :'カウンタ1の値を読み取り,秒に換算
400 PRINT "T= ";T;"[s]"
410 '
420 END

《8253のモード0とカウンタラッチ》

 プログラム5において、8255のモード設定はこれまでと同じである。8253のカウンタ0もこれまで同様モード2に設定し、3072分の1の分周器として用い、PC9801本体からの307.2kHzのクロックを100Hzにしてカウンタ1に送り込んでいる。カウンタ1はモード0に設定している。モード0での動作はおよそ次の通りである。

 ・初期値に設定した値から0になるまでのダウンカウント動作を1回だけ行う。
 ・CLK端子にパルスが1個入るごとにカウント値が1ずつ減り、0になると、  OUT端子がLowからHighになる。
 ・初期値設定直後の次のCLK入力パルスの立ち下がりでカウントダウンを開始  する。
 ・カウント中はGATEをHighにしておく。GATEをLowにするとカウ  ントを中断する。
すなわち、カウンタ0から出力される100Hzのクロックパルスを、カウンタ1はPC6に入力される信号によりカウンタをスタート・ストップさせ、その個数をかぞえている。1パルスがO.O1秒なので、パルスの個数が 2OO(ダウンカウンタなので、初期値−カウント値= 2OO)ならば、O.O1×2OO= 2.OO秒となり、100分の1秒のタイマーとして機能している。

 カウンタの値を読み出すにはカウンタラッチという機能を用いる。8253のコントロールワードレジスタのD5・D4に0、D7・D6にカウンタ番号を書き込むことによりカウント途中のデータのラッチ(記憶)が行われる。カウンタラッチを行った後に下位・上位の順で8ビットずつカウンタの内容を読み出す。

(目次へ)

5.データを取り込み、テキストファイルを作成する

 ここでは、A/Dコンバータを通して一定の時間間隔で決められた個数だけデータを取り込み、そのデータをテキストファイルにするプログラム例を示す。作表、グラフ化等の実験データの加工は、場合によってはそれ専用のソフトを作成するよりは一般の表計算ソフトで行った方が容易であるが、プログラム6(プログラム名NAD)はそのためのソフトである。プログラムはCで記述した(用いたCコンパイラはQuickCであるが、このままでMS−Cでのコンパイルも可能である)。

ソフトの概要と使用法はプログラムリストの最後にある関数type_help()にある通りである。8255及び8253の使用モードはプログラム4と同じである。プログラムの詳細はプログラムリスト中のコメントを参考にしてもらいたい。表計算でのマクロプログラムでこのソフトを利用し、データの取り込み・加工を行う場合は次の様な流れになる。

    表計算ソフト起動・ワークシート読み込み・マクロ実行
        ↓
    外部コマンドとしてNADを実行
      (データの取り込み・データファイルNAD.TXT作成)
        ↓
    表計算ソフトに戻る
        ↓
    データファイルNAD.TXT(テキストファイル)を読み込む
        ↓
    データの処理(作表・グラフ化等)

--- プログラム6 ---
/*-----------------------------------------------------------------------
*     NAD.C Ver.1.0  NADV用データ取り込みテキストファイル作成ソフト
*                   1993.9.16 By N.Egawa
*-----------------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

void type_help();

FILE *fp;
int ch,ndt,max;
unsigned int i;
unsigned int par=0x00d0, pbr=0x00d2, pcr=0x00d4,cwr55=0x00d6;/*8255アドレス*/
unsigned int ctr0=0x00d8,ctr1=0x00da,ctr2=0x00dc,cwr53=0x00de;/*8253アドレス*/

unsigned char dat[200];
char buf[5];

void main(int argc,char *argv[])
{

  if(argc != 4){ type_help(); return; }
  ch =atoi(strcat(argv[1],""));
  ndt=atoi(strcat(argv[2],""));
  max=atoi(strcat(argv[3],""));
  if(ch != 1 && ch != 2 && ch != 3 && ch != 4){ type_help(); return;}
  if(ndt != 1 && ndt != 2 && ndt != 5 && ndt != 10 ){
    type_help();
    return;
  }
  if(max > 200){ type_help(); return;}

  /* 8255 初期設定 */
  outp(cwr55,0x98);     /*PA-in PB-out PCH-in PCL-out */
  outp(pcr,0x0000+ch-1);  /* ADC7824 チャンネル設定 */
  /* 8253 初期設定 */
  outp(cwr53,0x34); /* 0x34=00 11 010 0 : counter0 LSB-MSB-W/R mode2 */
  outp(cwr53,0x76); /* 0x76=01 11 011 0 : counter1 LSB-MSB-W/R mode3 */
  outp(cwr53,0xb6); /* 0xb6=10 11 011 0 : counter2 LSB-MSB-W/R mode3 */
  switch(ndt){
    case 1: outp(ctr0, 0); outp(ctr0,0x10); /*307200=16・16・16・75 */
        outp(ctr1,0x4b); outp(ctr1, 0); /*=16・16・16・(16・4+11)*/
                        /* =0x1000・0x004b */
        outp(pcr,0x04+ch-1);       /* 8253タイマ1起動 */
        break;
    case 2: outp(ctr0, 0); outp(ctr0,0x08); /*307200/2 */
        outp(ctr1,0x4b); outp(ctr1, 0); /* =0x0800・0x004b */
        outp(pcr,0x04+ch-1);       /* 8253タイマ1起動 */
        break;
    case 5: outp(ctr0, 0); outp(ctr0,0x10); /*307200/5 */
        outp(ctr1,0x0f); outp(ctr1, 0); / *=0x1000・0x000f */
        outp(pcr,0x04+ch-1);       /* 8253タイマ1起動 */
        break;
    case 10:outp(ctr0, 0); outp(ctr0,0x08); /*307200/10 */
        outp(ctr1,0x0f); outp(ctr1, 0); /* =0x0800・0x000f */
        outp(pcr,0x04+ch-1);       /* 8253タイマ1起動 */
        break;
  }

  printf("\x01b[2J"); /*テキスト画面クリア*/
  putchar(0x1e);    /*カーソルホーム*/
  printf("\n Hit <RETURN> key to start. ");
  gets(buf);
  printf("\n Working !!! ... NAD By N.E ...");

  for(i=0;i<max;i++){
    while(!(inp(pcr) & 0x10)){ ;}
    while( inp(pcr) & 0x10) { ;}
    dat[i]=inp(par);
  }
  if((fp=fopen("NAD.TXT","wt"))==NULL){
    printf("\n");
    printf(" エラー : ファイルがオープンできませんでした.\n");
    return;
  }
  for(i=0;i<max;i++){
    itoa(dat[i],buf,10);
    fputs(buf,fp);
    fputc('\n',fp);
  }
  fclose(fp);

  printf("\x01b[2J"); /*テキスト画面クリア*/
  putchar(0x1e);    /*カーソルホーム*/

  printf("\n");
  printf(" テキストファイル NAD.TXT を作成しました.\n");
  printf("\n");
  return;
}

void type_help()
{
  printf("\n");
  printf(" NAD.EXE は NADV用のデータ取り込みソフトです.      \n");
  printf(" 取り込みのチャンネル番号,時間間隔,データ個数をコマンドラインから\n");
  printf(" 指定して実行すると,カレントディレクトリに NAD.TXT のファイル名で \n");
  printf(" 取り込んだデータのテキストファイルを作成します.        \n");
  printf(" \n");
  printf(" 使用法 NAD c t n                   \n");
  printf("       c:取り込みチャンネル番号1〜4          \n");
  printf("       t:取り込み時間間隔 1/2秒なら2と入力    \n");
  printf("         (1,2,5,10 のどれかを指定のこと)    \n");
  printf("       n:取り込むデータの個数(最大200個まで)    \n");
  printf("\n");
  printf("             NAD Ver.1.0 By N.Egawa 1993.9 \n");
  printf("\n");
}

(目次へ)

6.NADVブロック図

(目次へ)

(メニューへもどる)