Renesas Synergy™

FAQ 1007820 : 8ビット・タイマ・カウンタHのパルス発生への応用プログラム例[小ピンマイコン共通]

ここでは、「8ビット・タイマ・カウンタHのパルス発生への応用」で説明した応用の具体的なプログラム例について説明します。

[Ⅰ 概要]
指定された周期のパルスを出力するだけの単純な機能なので、できるだけ小さなマイコンで実現することを考えます。具体的なターゲットとして、10ピンで内 蔵ROMが1kバイトのμPD78F9200での実現を例として取り上げます。電源電圧は5V(4V以上)として、高速内蔵発振器の8MHzでの動作とし ます。出力の範囲は以下の8つのレンジで1μ秒~100秒をカバーします。






[Ⅱ プログラム概要]
プログラムは大きく10個の部分で構成されます。プログラムの容量が設定データの保存用に1ブロックを使用し、合計でも1kバイトに収めるために全てアセ ンブラ記述とします。また、ベクタ・テーブル領域とオプション・バイトの間にもプログラムを配置してできるだけメモリに無駄が発生しないようにします。

(1)オプション・バイト部
動作クロックとして高速内蔵発振クロックを使用し、P34端子はリセットではなくポートとして使用するように指定します。また、ウォッチドッグ・タイマは 使用しないので、低速内蔵発振器を停止可能に指定します。また、プロテクト・バイトは全て書き込み/消去許可に設定しておきます。

(2)初期化部
低電圧検出回路を用いて、電源電圧が所定の電圧(4V)以上になるのを待ち、内蔵フラッシュのデータ領域に記録されている最新の設定データに基づいて、出力パルスの指定を行います。

(3)パルス出力部
指定された条件から出力パルスの周期に応じた出力処理を行います。出力処理は大きく2つの処理に分けられます。
1つは1m秒以下の出力に対応するためにタイマHの出力を直接使用する(ハードウェア出力)ものです。プログラムとしては、タイマの設定を行った後は設定変更の確認タイミングを待つためのカウント処理を行います。この間、タイマHは指定された方形波出力/PWM出力で動作し、タイマ割り込みを発生しますが、タイマ割り込みマスクしておき、使用しません。
もう一つの処理は、タイマHをインターバル・タイマとして使用し、その割り込み回数をカウントして、出力を変化させるタイミングを得る(ソフトウェア出力) ものです。割り込み回数のカウントは2段階で処理します。これは、時間のカウントをレンジごとの刻み(レンジの最小時間の1/10)を作る部分と、レンジ の中での設定値を指定する部分に分けて処理するためです。これにより、1m秒~100秒までの広い周期に対応できるようにします。出力を反転させた後で は、設定変更を確認するためのタイミングをカウントします。

(4)設定変更確認部
あるタイミングで、P3.4に接続されたスイッチの状態を確認して、変数に取り込んでいきます。このプログラムでは、2回連続してロウ・レベルと確認したら設定の変更が有効と判断します(レベル検出)。また、ロウ・レベルの後2回連続したハイ・レベルを検出すると、設定変更結果のフラッシュ書き込み処理と判断します(エッジ検出)。

(5)設定確認部
設定確認はA/Dコンバータを用いて、半固定抵抗により入力される電圧値を読み込むことで、処理します。A/D変換処理は割り込みで処理します。このと き、ノイズの影響を少なくするために4回の変換を行い、その合計した結果を1/8にします。こうして得られた0~127の値を周期指定に使用します。同時 にレンジを指定するスイッチの内容も読み込みます。このようにして得られた結果は従来の設定と比較して、変化がなければ、ゼロ・フラグで確認できるように します。なお、この処理の期間だけベクタ割り込みを使用します。

(6)設定の解析部
変更された新しい設定から、具体的なタイマHの設定やソフトウェア出力のパラメータ設定を行います。ソフトウェア出力では、レンジが同じであれば、次の出 力反転以降から新しい設定が反映されます。それ以外の変更では、一旦タイマHを停止して、新しい設定に変更して動作を開始します。このため、切り替え時に出力パルスの乱れが発生してしまいます。

(7)フラッシュへ書き込み処理部
P3.4に 接続されたスイッチがオフになると、変更内容のフラッシュへの書き込みを行います。従来の設定値と新しい指定値を比較して、変化がなければ、何もしないで 戻ります。このように、フラッシュへの不要な書き込みを行わないことで、フラッシュの書き換え回数をできるだけ少なくします。フラッシュへ書き込み内容はレンジ情報(0000xxx0の3ビット分)とレンジ内での指定値の合計2バイトです。
書き込みはフラッシュに対するセルフ・プログラミングを用いた、簡易的なEEPROMのエミュレーションです。簡単化のために、エラー処理は一切行いません。

(8)セルフ・プログラミング・ライブラリ部
小ピン・マイコンの内蔵フラッシュへの書き込みを行うためのライブラリで、基本的にユーザーズ・マニュアルに記載されたプログラムそのものです。

(9)タイマH割り込み処理部
設定確認処理の期間のみで有効になり、ソフトウェア出力処理のタイミングカウントだけを行います。出力の直接の操作には使用しません。

(10)A/D変換割り込み処理部
設定確認処理で半固定抵抗を介して入力される電圧値を変換します。変換結果は作業用の変数に積算していきます。


以下に概略の状態遷移を示します。



[Ⅲ オプション・バイト]
ここで使用するオプション・バイトは以下のように設定します。

@@OPTB  CSEG    AT      0080H
DB              10010100b       ; オプション・バイト
DB              11111111b       ; プロテクト・バイト

[Ⅳ 初期化処理]
POC解除により起動して、パルス出力の準備を行います。

①動作準備部
スタック・ポインタ設定、ポート設定、ウォッチドッグ・タイマ停止、アナログ入力の設定を行い、低電圧検出機能を用いて電源電圧が4V以上になるのを待ちます。

CSEG
;****************************************************************
;
;       ハードウェアの初期化
;
;  ポートやアナログ入力の設定、電源電圧を4V以上に設定する
;
;****************************************************************

START:
MOVW    AX,#STACKTOP
MOVW    SP,AX                   ; スタックの設定
MOV     PMC2,#0001000b          ; ANI3のみアナログに設定
CLR1    PM2.0                   ; タイマ出力用端子を出力に設定
MOV     PU2,#00000110b          ; 入力ポートはプルアップを設定
MOV     PU3,#00000100b          ;
MOV     PU4,#00001001b          ; プルアップを設定
MOV     LVIS,#00000000b         ; LVI=4.0V
MOV     LVIM,#10000000b         ; 低電圧検出開始
MOV     PCC,#00                 ; クロックを1/4分周に設定
MOV     WDTM,#01110111b         ; ウォッチドッグ・タイマ停止
SET1    LSRSTOP                 ; 低速発振器停止
MOV     ADS,#00000011b          ; アナログ入力にANI3を選択
MOV     A,#50
PONLOOP:
DEC     A
BNZ     $PONLOOP                ; 0.2ms待つ

PONLOOP2:
BT      LVIF,$PONLOOP2          ; 電圧が4.1V以上まで待つ
MOV     PPCC,#00                ; クロックをfXに設定

②パルス出力設定部
フラッシュに格納されている最新の設定値から動作条件を確認し、対応したモードでの設定を行い、パルス出力動作を開始します。

MOV     COUNTCHK,#00001110b     ; 変更タイミング初期化

;
;       ブロック3の有効データスキャン
;
MOV     H,#EEPROM_BLOCK+1
MOV     L,#0                    ; HLにスキャン用ポインタ設定
SCANLOOP:
DECW    HL
DECW    HL
MOV     A,[HL]                  ; レンジを読み出し
CMP     A,#0FFH                 ; 未書き込みかをチェック
BZ      $SCANLOOP               ; 次のアドレスを確認
AND     A,#00001110b            ; 未使用ビットのマスク
XCH     A,X                     ; レンジをXレジスタにセーブ
MOV     A,[HL+1]                ; レンジ内での値を読み出し
AND     A,#01111111b            ; 未使用ビットをマスク
MOVW    FREQ,AX                 ; 設定値を作業領域にコピー
XCHW    AX,HL                   ; 最新データのアドレスを
MOVW    _Rd_Address,AX          ; 作業領域に保存
;
;  新しい設定でのタイマ起動
;
RESTART:
MOV     A,FREQ+1                ; 出力のパルス周波数データ読み出し
ADD     A,#10                   ; 設定値に10のオフセットを付けて、
MOV     COUNTH,A                ; カウント値に設定する
MOV     B,A
;
;  動作パラメータ(レンジや設定値)を読み出して、その値に応じた
;動作パラメータで処理ルーチンに分岐する
;

CALL    !SETTMH1MODE            ; 設定値から設定用パラメータに変換
BC      $SOFTTIME               ; ソフトウェア処理なら分岐

[Ⅴ ソフトウェア出力処理]
1m秒以上の周期のパルスに対してはソフトウェア出力処理(前出の状態遷移で青い破線で囲まれた部分)を行います。ソフトウェア出力処理では、タイマHで 基本となるインターバルで割り込みを発生させ、その割り込みをHALT状態の解除に使用することで、時間測定を行います。タイマHのインターバル時間は以 下のようになります。

レンジ カウント・
クロック
タイマHインターバル時間
1m秒 fXP/4(2MHz) 50μ秒
10m秒 fXP/16(500kHz) 0.5m秒
100m秒 fXP/64(125kHz) 1m秒
1秒 fXP/4096(2kHz) 50m秒
10秒 fXP/4096(2kHz) 0.1秒


出力パルスは指定された時間の1/2の時間でハイ・レベルとロウ・レベルを切り替える必要があります。また、各レンジで示された時間の1/10の時間の刻 み(分解能)を確保することを考慮すると、タイマHで発生するインターバルはレンジの値の1/20に設定する必要があります。100m秒や10秒のレンジ では1/100の時間しか生成できないので、5カウントして分解能に相当する時間をえます。そのために以下の2つのソフトウェアによるカウンタを使用しま す。

  メインカウンタ カウント値保持レジスタ
プリ・カウンタ PRECOUNT PRECOUNTH
指定時間(周期)カウンタ Bレジスタ COUNTH


また、設定変更の確認のためのタイミング計測用に出力を反転させた回数をCレジスタでカウントします。これにより、設定変更スイッチのチャタリングの影響をなくします。

実際のプログラム例を以下に示します。

①ソフト・カウンタ設定
まず、カウント値保持レジスタから実際にカウントを行うレジスタに値をコピーします。その後、タイマHを起動して割込みマスクを解除します(割り込みは禁止状態です)。

SOFTTIME:
MOV     A,COUNT2H               ; チェック回数を読み出し
MOV     C,A                     ; カウントレジスタに設定
MOV     A,PRECOUNTH             ; 設定値を読み出す
MOV     PRECOUNT,A              ; 作業用にコピー
MOV     A,COUNTH                ; 周期データ読み出し
MOV     B,A                     ; カウンタにセット
SET1    TMHE1                   ; タイマの起動
CLR1    TMIFH1                  ; 割り込みフラグをクリア
CLR1    TMMKH1                  ; タイマ割り込みのマスク解除
BR      $SOFTTIME2              ; 出力を反転しないでスタートする

②出力反転
タイマHからの割込みをHALT状態で待ち、割り込み発生によりHALT状態が解除されると、直ちに出力を反転します。その後、設定変更の確認のカウンタを更新し、確認タイミングであれば、設定モードの確認(CHKDATAINをサブルーチン・コール)します。そこでは、A/D変換を4回行って平均化処理を行いますが、次の出力反転タイミングまでは最低でも500マイクロ秒弱あるので、この処理で出力に影響を与えません。
スイッチの状態が変更なしなら、WAITLOOPに分岐して処理を継続します。変更モードであれば、設定内容の確認(SETMAIN)に分岐します。変更モードの完了ならば、変更内容を確認して、設定値が変更されていれば、フラッシュに新しい設定値を書きこみ(サブルーチンCHANGEEXITで処理)処理を継続します。
フラッシュ書き込みでは割り込みを全てマスクするので、書き込みから戻ってきたら、タイマHの割り込みマスクを解除します。なお、フラッシュ書き込みの最中にはパルス出力処理は実行できないので、パルスの周期が延びることがあります

;
;  前処理が完了して、パルス出力開始
;

SOFTTIME1:
HALT                            ; タイマ割り込み待ち
XOR     P2,#00000001b           ; 出力の反転
SOFTTIME2:
DBNZ    C,$WAITLOOP             ; チェックタイミング以外なら継続
MOV     A,COUNT2H               ; チェック回数を読み出し
MOV     C,A                     ; 再設定
CALL    !CHKDATAIN              ; 設定モードか確認
BNZ     $WAITLOOP               ; 変更なければ分岐
BC      $SETMAIN                ; 変更モードなら分岐

;****************************************************************
;
;       変更データのフラッシュへの書き込み
;
;  設定変更モードで設定された内容がフラッシュの最新のデータと
;同じかを確認して、変更されていれば、新しい設定値をフラッシュに
;書きこむ
;
;****************************************************************

CALL    !CHANGEEXIT             ; 変更したデータの書き込み処理
CLR1    TMMKH1                  ; タイマ割り込みのマスク解除
;
;  ここから下に抜ける場合には、次のHALTは直ぐに解除される。

③インターバル時間の計測
ここでは、タイマHからの割り込みをカウントして必要な時間を待ちます。割り込みの回数は一旦PRECOUNTでカウントして必要な分解能分のタイミングを生成します。分解能のタイミングをBレジスタでカウントすることで、出力するパルスの周期の半分の時間間隔(ロウ・レベルの期間/ハイ・レベルの期間)を知ることができます。②で割り込み要求フラグ(TMIFH1)をクリアしないので、出力を反転する間隔はPRECOUNTH×COUNTHとなります。

;
;  ここで、インターバル・タイマ割り込みの回数をカウントして
;次に割り込みで出力を反転するまで待ち、次で反転するときは
;上の処理に分岐する
;
WAITLOOP:
HALT                            ; タイマ割り込み待ち
CLR1    TMIFH1                  ; 割り込み要求フラグをクリア
DBNZ    PRECOUNT,$WAITLOOP      ; プリ・カウント
MOV     A,PRECOUNTH             ; 設定値を読み出す
MOV     PRECOUNT,A              ; 作業用にコピー
DBNZ    B,$WAITLOOP             ; タイム・アップしなければループ
MOV     A,COUNTH                ; 周期データ読み出し
MOV     B,A                     ; カウンタにセット
BR      $SOFTTIME1              ; 次の割り込みで出力反転へ

[Ⅵ ハードウェア出力処理]
1m秒未満のレンジではソフトウェア処理では処理時間が間に合わないので、タイマHの出力機能を利用してパルスを出力します。この場合には、カウント・ク ロックは2のべき乗で分周されるので、分解能はレンジの1/10にはできません。できるだけ分解能を近づけるためにタイマHの動作モードをPWM出力と方 形波出力を使い分けしています。

①タイマHの設定処理
各レンジに対するタイマHの設定は以下のプログラムのようになります。ここで、変数FREQ及びFREQ+1はレンジ情報とそのレンジでの周期指定データ(0~127の7ビットのデータ)が入っています。レンジ毎に設定プログラムは分かれていますが、これはできるだけ処理時間を短くするためです。それでも、タイマHを停止してモード設定(下記のプログラムでは赤で示す命令)から再起動(青で示す命令)までは12クロックはかかります。そのため、同じレンジで設定値(周期)を変更するだけでも出力が乱れます。

;****************************************************************
;
;       ハードウェア処理の場合のタイマHの設定
;  TMH1のモード設定(動作は停止)して、コンペアレジスタに周期に
;応じた値を設定する。キャリー・フラグをクリアして戻るので、ソフト
;処理と区別することができる。
;
;  CASE1(1μレンジ:0.125μ分解能)
;
;  8MHzクロックのPWMモードで使用するので、分解能は1/8μsとなる
;
;****************************************************************

CASE1:
MOV     A,FREQ+1                ; 新しい設定値を読み出す
ADD     A,#7                    ; 7(1μ)~134(17μ)
MOV TMHMD1,#00001001b ; fXP動作、PWMモード
MOV     CMP01,A                 ; 周期の設定
RORC    A,1                     ; デューティを約1/2に
MOV     CMP11,A
SET1 TMHE1 ; 新しい設定値でタイマ起動
CLR1    CY
RET
;
;  CASE2(10μレンジ:1μ分解能)
;
;  2MHzクロックのインタイバル・タイマで使用するので、インターバルは
;1μsとなる(タイマはハイ、ローの期間を示すので、周期としては倍)
;

CASE2:
MOV     A,FREQ+1                ; 新しい設定値を読み出す
ADD     A,#9                    ; 9(10μ)~136(137μ)
MOV     TMHMD1,#00010001b       ; fXP/4動作、インターバル・タイマ
MOV     CMP01,A
SET1    TMHE1                   ; 新しい設定値でタイマ起動
RET

;
;  CASE3(100μレンジ:8μ分解能)
;
;  125kHzクロックのPWMモードで使用するので、分解能は8μs
;

CASE3:
MOV     A,FREQ+1                ; 新しい設定値を読み出す
ADD     A,#11                   ; 11(96μ)~138(1112μ)
MOV     TMHMD1,#00111001b       ; fXP/64動作、PWMモード
MOV     CMP01,A                 ; 周期の設定
RORC    A,1                     ; デューティを約1/2に
MOV     CMP11,A
SET1    TMHE1                   ; 新しい設定値でタイマ起動
CLR1    CY
RET

②出力中のソフトウェア処理
この動作でのパルス出力中のソフトウェアは単に設定変更の確認タイミングを待つだけの処理です。割り込みはマスク状態で動作し、確認タイミングはHLレジスタでのソフトウェア・タイマを使用して待ちます。確認タイミングになるとサブルーチン(CHKDATAIN) をコールして設定スイッチの状態を確認します。パルス出力はタイマHがハードウェア機能として実行しているので、ソフトウェアの実行時間の制限はありませ ん。スイッチの状態が設定変更でなければ処理を継続します。変更完了であれば、変更内容をフラッシュに書き込みます。設定変更ならそのための処理(HWTIMERCHANGE)に分岐します。

;****************************************************************
;
;  タイマHの出力を直接使用する
;
;****************************************************************
CASE1to3:
CLR1    P2.0                    ; 兼用ポートをクリア
SET1    TMHE1                   ; タイマの起動
SET1    TMMKH1                  ; タイマH割り込みはマスクしておく
;
;       パルス出力
;
HWTIMERLOOP0:
MOVW    HL,#0
HWTIMERLOOP1:
DECW    HL                      ; 更新周期のカウント
MOV     A,H
OR      A,L
BNZ     $HWTIMERLOOP1           ; 更新周期でなければ継続
CALL    !CHKDATAIN              ; 通常動作かの確認
BNZ     $HWTIMERLOOP0           ; 変更なければ処理継続
BC      $HWTIMERCHANGE          ; 設定変更なら分岐
;****************************************************************
;
;       変更データのフラッシュへの書き込み
;
;  設定変更モードで設定された内容がフラッシュの最新のデータと
;同じかを確認して、変更されていれば、新しい設定値をフラッシュに
;書きこむ
;
;****************************************************************

CALL    !CHANGEEXIT             ; 変更したデータの書き込み処理
BR      $HWTIMERLOOP0           ; 処理継続へ

③設定の変更処理
設定変更の場合にはサブルーチン(SETMAINSUB)で指定内容を確認します。指定内容に変更がなければ、処理を継続します。変更があった場合には、指定内容を反映させるために、動作条件確認処理(RESTART)に分岐します。

HWTIMERCHANGE:
;
;       変更の確認処理
;
CALL    !SETMAINSUB             ; 変更の確認
BZ      $HWTIMERLOOP0
;
;       レンジ変更処理/ハードウェア変更処理
;

BR      $RESTART

[Ⅶ 設定変更確認処理]
動作条件の設定変更はP34に接続されたスイッチがオン(P34がロウ・レベル)の場合に処理します。そのために、ある間隔でP34を確認し、その変化を 検出します。スイッチのチャタリング対策のために、同じ状態が2回連続したことを確認したら有効な指定とします。そのため、P34の状態を保持しておき、 以下の3つ状態を判定します。

・2回連続でロウ・レベル   :新しい条件の指定
・ロウ・レベルの後、2回連続ハイ・レベル   :指定完了
・それ以外   :通常動作


新しい条件の指定では指定内容を確認するためにA/Dコンバートを起動して半固定抵抗器で設定された電圧を4回分読み出し、平均します。同時にレンジを指定するスイッチの状態も読み出してレンジの確認をします。

①設定変更指示の確認処理
P34の状態を確認するプログラムを以下に示します。P34の状態を変数COUNTCHKに保存しておき、新たな状態をビット4に付け加えていきます。
P34が押されたときの変数COUNTCHKの変化は以下のようになります。ここで、ビット3,2が00なら新しい条件の指定として条件の読み出しを行います。



P34が放されたときの変数COUNTCHKの変化は以下のようになります。この場合には、ビット3~1が110のときに条件の指定の完了と判断します。このように3ビットのビット・パターンで判断することで、エッジ検出を行います。



このようにして最新の3回分を判定して、結果をキャリー・フラグ及びゼロ・フラグでもどします。

;****************************************************************
;  P3.4が設定モードの指定に使用されており、これが2回以上0を検出
;している状態が設定変更モードとなる。また、0の後で1が2回続くと、
;設定モードから抜けたとして、設定が変更されていた場合には
;フラッシュへの書き込みを行う。
;  このためにここでは、P3.4の過去2回の履歴をCOUNTCHKに保持して、
;P3.4の変化を確認する。
;
;  CY  ZERO
;   0     1             :設定完了で書き込みへ
;   1     0             :設定変更しない
;   1     1             :設定変更の確認
;
;****************************************************************

CHKDATAIN:
MOV     A,P3
AND     A,#00010000b            ; 更新スイッチ(P3.4)をチェック
OR      A,COUNTCHK              ; 履歴に追加
AND     A,#00011100b            ; 3回目以前をマスク
ROR     A,1                     ; P3.4がビット3に
MOV     COUNTCHK,A              ; 履歴を更新
CMP     A,#00001100b            ; 1が2回続いたかチェック
BZ      $CHKDATAEND             ; 設定完了でデータを書きこむ
AND     A,#00001100b            ; 2回0で設定と判断
SET1    CY                      ; チェック完了
CHKDATAEND:
RET

②指示内容の取り込み処理
新しい条件の指示の場合には具体的な指示内容の確認を行います。そのために、A/Dコンバータを起動し8ビットのデータを得ます。A/D変換処理はベクタ 割り込みで処理します。タイマH割り込みもマスクされていない場合(ソフトウェア出力の場合マスクされていない)にはベクタ割り込みが発生します。ベクタ 割り込みはここでのみ使用します。
4回(変数ADENDで指定)のA/D変換が完了すると、割り込み処理では変数ADENDを0にし、A/D変換を停止するので、それを待ちます。

;****************************************************************
;
;       変更の確認処理
;  A/Dを起動して、ノイズ対策で4回分を蓄積する。その値とスイッチ
;設定の状態を元に新しい設定値を求めるとともに、変化があったかを
;フラグで戻す。
;
;****************************************************************
SETMAINSUB:
MOV     ADM,#00110001b          ; A/Dのモードを設定
MOVW    AX,#0
MOVW    ADDATASUM,AX            ; A/D結果領域をクリア
SET1    ADCS                    ; 1μ秒待ってA/D変換開始
CLR1    ADIF                    ; A/D割り込みクリア
MOV     ADEND,#4                ; A/D変換は4回行う
CLR1    ADMK                    ; A/Dの割り込み許可
CLR1    TMIFH1                  ; タイマ割り込み要求クリア
EI
;
;       ソフト処理の時間計測は継続しながら、A/D完了待ち
;ここでの処理の期間の時間計測は割り込み処理で行う。
;(出力制御のタイミングまではかからないのでカウントのみ)
;
SETLOOP1:
MOV     A,ADEND                 ; 残りA/D回数を読み出し
AND     A,A                     ; 完了をチェック
BNZ     $SETLOOP1               ; 完了してなければループ

③取り込み内容の加工と確認処理
4回のA/D変換結果は累積されて2バイトの変数ADDATASUMに格納されているので、それを1/4にして平均を得ます。ここでは、結果は7ビットで十分なので、さらに1/2にします。このようにして得られた0~127のデータは16ビット変数FREQの 上位8ビット(FREQ+1)に格納します。このとき、従来の設定値との差をとっておきます。続いて、レンジ指定用スイッチの値も確認して変更があったか を確認します。全く変更がなければゼロ・フラグがセットされます(レンジの変更がなければXレジスタは0となります)。
処理が完了したら、割り込みを禁止にして戻ります。

;
;  A/D変換が完了したので、変更内容の確認を行う。
;

;****************************************************************
;
;       新しい設定結果の確認
;新しい設定データは変数FREQに設定される。
;       FREQ    :スイッチの設定値(レンジ指定用)
;       FREQ+1  :A/D変換結果(値指定用)
;
;  全く変更がなければ、ZEROフラグがセットされて戻る。
;スイッチ入力の端子構成
;       P40             :スイッチの上位ビット
;       P22             :スイッチの中位ビット
;       P21             :スイッチの下位ビット
;
;****************************************************************
CHKDATA:
MOV     A,ADDATASUM             ; A/D結果の下位桁を読み出し
ROR     A,1                     ; 1/2
ROR     A,1                     ; 1/4
ROR     A,1                     ; 1/8
AND     A,#00011111b            ; 上位ビットをマスク
XCH     A,ADDATASUM+1           ; 上位桁読み出し
ROR     A,1                     ; 1/2
ROR     A,1                     ; 1/4
ROR     A,1                     ; 1/8
ADD     A,ADDATASUM+1           ; 下位桁とマージする
;
;       これで、変換結果は0~127の値になる
;
XCH     A,FREQ+1                ; 新しいデータを保存
SUB     A,FREQ+1                ; データの変化は?
XCH     A,X
MOV     A,P2                    ; レンジの読み出し
AND     A,#00000110b            ; 未使用ビットのマスク
XOR     A,#00000110b            ; スイッチONを1に反転
BT      P3.2,$P32is0            ; 上位桁を確認
SET1    A.3
P32is0:
XCH     A,FREQ                  ; レンジを格納
SUB     A,FREQ                  ; レンジの変更分
XCH     A,X                     ; レンジ変更をXに保存
OR      A,X                     ; 変更はあったか?
DI                              ; 割り込み許可はここまで
RET

[Ⅷ A/D変換割り込み処理]
半固定抵抗器による設定を読み出すためにA/D変換結果を8ビット精度で読み出します。A/D変換は変数ADENDで指定された回数実行します。変換結果は16ビットの変数ADDATASUMに積算していきます。指定された回数の変換・累積が完了したら、A/Dコンバータを停止します。

;****************************************************************
;
;       interrupt for A/D
;
;  半固定抵抗での設定値をA/Dコンバータで読み出して、その結果
;を4回分加算する。4回の変換が完了したら変換を停止して処理を
;終了する。
;  変換結果は変数ADDATASUMに格納され、変換完了でADENDは00になる。
;
;****************************************************************
ADINT:
PUSH    AX
MOV     A,ADCRH                 ; アナログ入力の変換結果読み出し
ADD     A,ADDATASUM             ; 変換結果を積算
MOV     ADDATASUM,A             ; 結果を保存
ADDC    ADDATASUM+1,#0          ; 上位への桁上がり
DBNZ    ADEND,$NOTEND           ; 変換回数をカウントダウン
MOV     ADM,#00110000b          ; A/D変換を終了
CLR1    ADIF                    ; 要求フラグをクリア
NOTEND:
POP     AX
DUMMY:
RETI

[Ⅸ タイマH割り込み処理]
指定内容の変更を行っている最中にもパルス出力を正常に継続するためにソフトウェア・タイマのカウントを継続します。指定内容の変更処理で必要な時間は次に出力を反転する時間よりも短い時間なので、単にカウントを継続するだけです。

;****************************************************************
;
;       interrupt for TMH1
;
;  設定変更の確認処理の期間の時間を計測するためだけに使用する
;
;****************************************************************
TMH1INT:
DBNZ    PRECOUNT,$TMH1EXIT      ; プリ・カウント完了なら、
PUSH    AX
MOV     A,PRECOUNTH             ; 設定値を読み出す
MOV     PRECOUNT,A              ; 作業用にコピー
POP     AX
DEC     B                       ; 周期をカウント・ダウン
TMH1EXIT:
RETI

[Ⅹ 動作条件確認及び設定処理]
フラッシュに格納された初期データや設定変更結果から実際の処理で必要な設定を行います。
ハードウェア出力とソフトウェア出力では設定すべき内容が異なるためにレンジにより処理方法を変更しています。

①レンジによる振り分け処理
ハードウェア出力の場合には、基本的にタイマHの設定だけですむので、レンジごとの設定処理ルーチンのアドレス・テーブルを準備し、テーブル参照により[ハードウェア出力処理]で説明したCASE1CASE3の 各サブルーチンへ分岐して処理します(各設定処理での処理時間をできるだけ短くするためにレンジ毎に処理を分割しています)。ソフトウェア出力の場合に は、処理時間よりプログラムの大きさを考慮してレンジ毎に設定するパラメータをテーブルで準備し、共通の設定ルーチンで処理しています。

;****************************************************************
;                                                               *
;       動作条件に応じた初期設定                                *
;                                                               *
;ハードウェア(タイマH)でパルス出力する場合には設定プログラムの*
;アドレスをテーブル参照して、BR  AX命令で処理部に分岐する。 *
;ソフトウェア処理の場合には、設定するパラメータ・テーブルから読み*
;出して、その値を設定する。                                     *
;                                                               *
;****************************************************************

SETTMH1MODE:
MOV     A,FREQ                  ; 新しいレンジ設定値を読み出す
MOV     X,#0
SUB     A,#3*2
BNC     $SETTMH1MODE2           ; ソフトウェア処理なら分岐
XCH     A,X                     ; AXにオフセット
ADDW    AX,#SETTABLE+3*2+0FF00H ; アドレス・テーブルを参照
MOVW    HL,AX
MOV     A,[HL]                  ; 処理アドレスの下位を読み出し
MOV     X,A                     ; Xにプログラム・アドレス下位
MOV     A,[HL+1]                ; AXに処理プログラム・アドレス
BR      AX                      ; CASE1~3処理プログラムに分岐
;
;       ハードウェア処理用のパラメータ・テーブル
;  初期設定サブルーチンのアドレスを示す。
;

SETTABLE:
DW      CASE1
DW      CASE2
DW      CASE3

②パラメータ設定処理
ソフトウェア出力の場合のパラメータを設定します。設定するパラメータはタイマHの動作モード(各レンジでカウント・クロックが異なる)、インターバル・ タイマの周期、プリ・カウント値、及び設定変更指示の確認周期の4つです。1m秒レンジではタイマHで50μ秒のインターバル時間を得るためにfXP/4(2MHz)のカウント・クロックを100カウントさせます。これだけで100μ秒の分解能が得られるので、プリ・カウント値は1となります。設定変更指示の確認周期出力反転100回毎に行う設定です。

;
;       ソフトウェア処理用のパラメータ・テーブル
;  各レンジに対して、以下の4バイトのパラメータを定義
;・TMH1のモード(カウント・クロックを指定、出力は禁止)
;・CMP01への設定値
;・プリ・カウンタ(割り込み回数をカウント)
;・設定変更確認周期
;
;  TMH1は指定されたクロックでCMP01への設定値カウント毎に割り込みを
;発生する。それをPRECOUNTHで指定した回数カウントすることで分解能分
;の時間(レンジの1/20の時間)を得る。分解能できまる時間をA/D
;変換で得られた値(0~127になる)に10を加算した回数カウント
;することでレンジ/2~レンジ×13.7/2の時間を得る。
;(1/2にするのは必要な周期の半分の時間で出力を反転させるため)
;
SETTABLE2:
DB      00010000b,      99,1,100        ; 1msレンジ(タイマは50us)
DB      00100000b,      249,1,10        ; 10msレンジ(タイマは0.5ms)
DB      00110000b,      124,5,1         ; 100msレンジ(タイマは1ms)
DB      01000000b,      97,1,1          ; 1sレンジ(タイマは50ms)
DB      01000000b,      194,5,1         ; 10sレンジ(タイマは100ms)

上記のパラメータを設定するプログラムは以下のようになります。設定が完了すると、キャリー・フラグを設定して戻るので、戻り先ではハードウェア出力かソフトウェア出力かを簡単に判定できます。

;
;       ソフトウェアによる処理の場合
;
SETTMH1MODE2:
ADD     A,A                     ; テーブルのオフセットを計算
XCH     A,X                     ; AXにオフセット
ADDW    AX,#SETTABLE2           ; パラメータのアドレスを計算
MOVW    HL,AX
MOV     A,[HL]                  ; TMHのモードを読み出し
MOV     TMHMD1,A                ; モードをセット(タイマは停止)
MOV     A,[HL+1]                ; CMP01への設定値を読み出し
MOV     CMP01,A                 ; カウント値の設定
MOV     A,[HL+2]                ; ソフトカウント値の読み出し
MOV     PRECOUNTH,A             ; データ保持レジスタへの設定
MOV     A,[HL+3]                ; 設定変更確認周期の読み出し
MOV     COUNT2H,A               ; データ保持レジスタへの設定
SET1    CY                      ; CY=1でソフト処理を示す
RET

[ⅩⅠ フラッシュ書き込み処理]
フラッシュをEEPROMの代わりに利用して、出力パルスの条件指定が完了したときに設定内容がフラッシュに格納されている最新の値と異なっていた場合に新しい設定内容をフラッシュに保存します。

①書き込み制御処理部
新しい設定値をフラッシュに格納されている最新の値と比較して、異なる場合にはフラッシュに新しい値を追記します。

;
;       更新完了
;
CHANGEEXIT:
PUSH    HL
MOVW    AX,_Rd_Address          ; EEPROMの最新データ・アドレス
MOVW    HL,AX
MOV     A,[HL]                  ; 現在のEEPROMデータを読み出し
SUB     A,FREQ                  ; 新しい設定値と比較
XCH     A,X
INC     L
MOV     A,[HL]                  ; 2つ目のパラメータも比較
SUB     A,FREQ+1
OR      A,X
BZ      $END_ADINT              ; 変更になければ割り込み終了
CALL    !WRITEDATA              ; 変更分をフラッシュに書き込み
END_ADINT:
POP     HL
RET

②書き込み処理部
フラッシュのセルフ・プログラミングを利用して、簡易的なEEPROM機能を実現します。このために使用しているフラッシュは1ブロックのみなので、ここ では、フラッシュへの書き込みをできるだけ行わないようにしています。また、1kバイトで全て処理するためにエラー処理は省略しています。

;
;       Data Write to Flash
;
WRITEDATA:
CALL    !SelfFlashModeOn        ; セルフ書き込みモードに
INCW    HL                      ; 最新データの次アドレスへ
MOVW    AX,HL
CMP     A,#EEPROM_BLOCK
BZ      $WRIREDATA2             ; 書き込み可能なら分岐
;
;       ブロックがいっぱいなので消去する
;
CALL    !BlockErase             ; ブロックを消去する
;
;       BC      $ERROR
;  エラーが起こるほど書き込みは行なわないのでエラーは無視する
;
MOVW    AX,#BROCK3              ; ブロックの先頭アドレス設定

WRIREDATA2:
MOVW    _Wr_Address,AX          ; 新しいアドレスを設定
MOVW    _Rd_Address,AX          ; 読み出し用にも設定
MOVW    AX,FREQ                 ; 書き込みデータをセット
CALL    !EEPROMWrite            ; 1バイト目書き込み
XCH     A,X
INC     _Wr_Address             ; 書き込みアドレス更新
CALL    !EEPROMWrite            ; 書き込み
CALL    !SelfFlashModeOff       ; セルフ書き込み終了
RET

③データ部
データ部分の例を示します。2FE番地と2FF番地が初期値となるデータです。この直後の300番地からの1ブロックが新しい設定内容を書き込むために使用されます。この部分はプログラムと分離してデータ部分だけの別ファイルとして準備しています。



[ⅩⅡ セルフ・プログラミング処理部]
この部分は独立したプログラムとして、別に準備します。そのため、パルス出力プログラムの先頭で、以下のように外部のサブルーチンとして宣言しておきます。

①外部参照の宣言
EXTRN   SelfFlashModeOn
EXTRN   SelfFlashModeOff
EXTRN   BlockErase
EXTRN   EEPROMWrite
EXTRN   _Wr_Address
EXTRN   _Rd_Address
EXTRN   EEPROM_BLOCK
EXTRN   BROCK3

②セルフ・プログラミング処理本体(別ファイル)
実際にμPD78F9200でセルフ・プログラムを行うためのプログラム本体です。基本的な処理はマニュアルに記載された内容をプログラムに展開しただけなので、説明は省きます。

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; システム : 78K/0S EEPROMエミュレーション・プログラム(簡易版)
; ファイル名 : selfP.asm
; バージョン名 : 1.00
; ターゲットCPU : uPD78F9200
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PUBLIC SelfFlashModeOn
PUBLIC SelfFlashModeOff
PUBLIC __SelfFlashBlockErase
PUBLIC BlockErase
PUBLIC __FlashEEPROMWrite
PUBLIC EEPROMWrite
PUBLIC _Wr_Address
PUBLIC _Rd_Address
EXTRN EEPROM_BLOCK

;---------------------------------------------------------------------
; フラッシュ制御用定数のEQU定義
;---------------------------------------------------------------------
CMD_INTERNAL_VERIFY     EQU     (00000001B)     ;内部ベリファイ
CMD_INTERNAL_VERIFY2    EQU     (00000010B)     ;内部ベリファイ2
CMD_BLOCK_ERASE         EQU     (00000011B)     ;ブロック消去
CMD_BLANK_CHECK         EQU     (00000100B)     ;ブランク・チェック
CMD_BYTE_WRITE          EQU     (00000101B)     ;1バイト書き込み
NO_ERR                  EQU     (00000000B)     ;エラーなし
ERR_FPRERR              EQU     (00000001B)     ;PFCMD書き込みエラー
ERR_VCERR               EQU     (00000010B)     ;消去/書き込み/内部ベリファイ
;・エラー
ERR_WEPRERR             EQU     (00000100B)     ;プロテクト・エラー
FALSE                   EQU     (0FFH)          ;異常
TRUE                    EQU     (00H)           ;正常
WRITE_RETRY             EQU     (10)            ;書き込み時のリトライ回数
ERASE_RETRY             EQU     (20)            ;消去時のリトライ回数
;---------------------------------------------------------------------
; RAM設定
;---------------------------------------------------------------------
EP_RAM1         DSEG    saddrp
_Wr_Address:    DS      2               ; EEPROM書き込みアドレス設定用
_Rd_Address:    DS      2               ; EEPROM読み出しアドレス設定用


EEPROM_PROG     CSEG

;-------------------------------------------------------------------
; 関数名 :__SelfFlashBlockErase
; 入力  :なし
; 出力  :CY = 0(正常終了) / CY = 1(異常終了)
; 概要 :ブロック3の消去およびブランク・チェックを行う。
;-------------------------------------------------------------------
;bool   _SelfFlashBlockErase(void)

__SelfFlashBlockErase:
BlockErase:
PUSH    BC
PUSH    AX
MOV     B,#ERASE_RETRY          ; 消去時のリトライ回数設定
BR      $SF_BKER_ST             ; ブランクチェックから開始

SF_BKER_RE:
CALL    !FlashBlockErase        ; 消去処理
BC      $SF_BKER_01             ; 異常終了
SF_BKER_ST:
CALL    !BlankCheck             ;ブランク・チェック処理
BNC     $SF_BKER_TR             ;ブランク・チェック正常終了
SF_BKER_01:
DBNZ    B,$SF_BKER_RE           ;リトライ回数のチェックを行う
SF_BKER_FL:
SET1    CY                      ;戻り値 = 異常終了

SF_BKER_TR:
POP     AX
POP             BC
RET

;-------------------------------------------------------------------
; 関数名 :SelfFlashModeOff
; Input :なし
; Output :なし
; 使用レジスタ:なし
; 概要 :セルフ・プログラミング・モードを解除する。
;-------------------------------------------------------------------
SelfFlashModeOff:
MOV     FLCMD,#0
SF_MDOF_LP:
MOV     PFS,#NO_ERR
MOV     PFCMD,#0A5H             ; PFCMDレジスタ制御
MOV     FLPMC,#00H              ; FLPMCレジスタ制御(設定値)
MOV     FLPMC,#0FFH             ; FLPMCレジスタ制御(設定値の反転)
MOV     FLPMC,#00H              ; 通常モード設定
BT      PFS.0,$SF_MDOF_LP       ; 特定レジスタへの書き込み完了確認
RET

;-------------------------------------------------------------------
; 関数名 :SelfFlashModeOn
; Input :なし
; OutPut :なし
; 使用レジスタ:なし
; 概要 :セルフ・プログラミング・モードに設定する。
;-------------------------------------------------------------------
SelfFlashModeOn:
MOV     MK0,#11111111B
DI
MOV     FLCMD,#0
SF_MDON_LP:
MOV     PFS,#NO_ERR
MOV     PFCMD,#0A5H             ; PFCMDレジスタ制御
MOV     FLPMC,#01H              ; FLPMCレジスタ制御(設定値)
MOV     FLPMC,#0FEH             ; FLPMCレジスタ制御(設定値の反転)
MOV     FLPMC,#01H              ; セルフ・プログラミング・モード設定
NOP                             ; 
HALT                            ; 
BT      PFS.0,$SF_MDON_LP       ; 特定レジスタへの書き込み完了確認
RET

;-------------------------------------------------------------------
; 関数名 :FlashBlockErase
; Input :なし
; OutPut :CY(CarryFlag) = 正常終了(0) / 異常終了(1)
; 使用レジスタ:なし
; 概要 :ブロック3を消去する。
;-------------------------------------------------------------------
FlashBlockErase:
MOV     FLCMD,#CMD_BLOCK_ERASE  ;フラッシュ制御コマンド設定(ブロック消去)
MOV     FLAPH,#EEPROM_BLOCK     ;ブランク・チェック・ブロック番号設定
MOV     FLAPL,#00H
MOV     FLAPHC,#EEPROM_BLOCK
MOV     FLAPLC,#00H
;
;  引き続き実際のフラッシュ・セルフ・プログラミング処理へ
;
;--------------------------------------------------------------------
; 関数名 :SubFlashSelfPrg
; Input :なし
; Output :CY(CarryFlag) = 正常終了(0) / 異常終了(1)
; 使用レジスタ:なし
; 処理 :フラッシュ・セルフ・プログラミング機能呼び出し
;--------------------------------------------------------------------
SubFlashSelfPrg:
SubSelfPrg:
PUSH    AX
MOV     PFS,#NO_ERR             ;フラッシュ・ステータス・レジスタのクリア
HALT                            ;セルフ・プログラミング開始
MOV     A,PFS
SUB     A,#NO_ERR
ADD     A,#0FFH
POP     AX
RET

;-------------------------------------------------------------------
; 関数名 :__FlashBlockBlankCheck
; Input :なし
; OutPut :CY(CarryFlag) = 正常終了(0) / 異常終了(1)
; 使用レジスタ:なし
; 概要 :指定ブロックのブランク・チェックを行う。
;-------------------------------------------------------------------
__FlashBlockBlankCheck:
BlankCheck:
MOV     FLCMD,#CMD_BLANK_CHECK  ;フラッシュ制御コマンド設定
;(ブロック・ブランク・チェック)
MOV     FLAPH,#EEPROM_BLOCK     ;ブランク・チェック・ブロック番号設定
MOV     FLAPL,#00H
MOV     FLAPHC,#EEPROM_BLOCK
MOV     FLAPLC,#0FFH
BR      $SubSelfPrg

;-------------------------------------------------------------------
; 関数名 :__FlashEEPROMWrite
; Input :
; :_Wr_Address = 書き込み開始アドレス
; :X = 書き込みデータ(8bit)
; 使用レジスタ  : なし
; OutPut :CY(CarryFlag) = 正常終了(0) / 異常終了(1)
; 概要 :EEPROMでの書き込みおよび内部ベリファイを行う。
;-------------------------------------------------------------------
;bool   _FlashEEPROMWrite(unsigned int)

__FlashEEPROMWrite:
EEPROMWrite:
PUSH    BC
PUSH    AX
MOV     A,_Wr_Address           ; 書き込みアドレスの読み出し
MOV     C,A                     ; 作業用レジスタにセット
MOV     FLCMD,#CMD_BYTE_WRITE   ;フラッシュ制御コマンド設定
;(バイト書き込み)
FL_WR_W1:
MOV     B,#WRITE_RETRY
MOV     FLAPH,#EEPROM_BLOCK     ; 書き込みブロックの設定
MOV     A,C
MOV     FLAPL,A                 ; 書き込み/ベリファイ・アドレス設定
MOV     A,X
MOV     FLW,A                   ; 書き込みデータ設定
FL_WR_W2:
CALL    !SubSelfPrg
BNC     $FL_WR_W3               ; 正常完了なら抜ける
DBNZ    B,$FL_WR_W2             ; リトライ・カウンタ判定(リトライ10回)
BR      FL_WR_E
FL_WR_W3:
;
; 書き込み完了してベリファイする
;
MOV     FLCMD,#CMD_INTERNAL_VERIFY2 ;フラッシュ制御コマンド設定
;(内部ベリファイ2)
MOV     FLAPH,#EEPROM_BLOCK
MOV     A,C                     ; 書き込みアドレスの読み出し
MOV     FLAPL,A                 ; ベリファイ開始アドレス設定
MOV     FLAPHC,#EEPROM_BLOCK
MOV     FLAPLC,A                ; ベリファイ終了アドレス設定
CALL    !SubSelfPrg
FL_WR_E:
POP     AX
POP     BC
RET
END

[ⅩⅢ プログラムの配置、データ領域]
①プログラムの配置
このプログラムはサイズに余裕が少ないため、割り込み処理部[Ⅶ 設定変更確認処理]②指示内容の取り込み処理③取り込み内容の加工と確認処理をベクタ・テーブルに続けて記述します。

RSTVECT CSEG    AT      0
DW      START                   ;00:リセットスタート処理のベクタ
DW      DUMMY                   ;02:
DW      DUMMY                   ;04:
DW      DUMMY                   ;06:LVI
DW      DUMMY                   ;08:INTP0
DW      DUMMY                   ;0A:INTP1
DW      TMH1INT                 ;0C:INTTMH1
DW      DUMMY                   ;0E:INTTM000
DW      DUMMY                   ;10:INTTM010
DW      ADINT                   ;12:INTAD

ここに2つの割り込み処理部を記述する


さらに続けて、

②指示内容の取り込み処理③取り込み内容の加工と
確認処理を記述する


と記述することで、0~7EH番地に配置されることになります。
その後に残りのプログラムを新たなセグメントとして"CSEG"を宣言して以下のように記述していきます。この部分はオプション・バイトやプロテクト・バイトの後(82H番地)に配置されます。

CSEG
;****************************************************************
;
;       ハードウェアの初期化
;
;  ポートやアナログ入力の設定、電源電圧を4V以上に設定する
;
;****************************************************************

START:

②データ領域
セルフ・プログラミングを除いたこのプログラムで使用するデータ(変数)領域は以下の通りです。

;
;       データ領域
;
DSEG
DS              20H
STACKTOP:
DSEG    saddrp
ADDATASUM:
DS      2                       ; 4回分のA/D加算用
FREQ:
DS      1                       ; レンジ指定用
DS      1                       ; 値設定用
PRECOUNT:
DS      1                       ; プリ・カウント作業用
PRECOUNTH:
DS      1                       ; プリ・カウント用設定値
COUNT:
DS      1                       ; カウント指定値用
COUNTH:
DS      1                       ; カウント指定値設定値
COUNTCHK:
DS      1                       ; 設定変更タイミング用
COUNT2H:
DS      1                       ; 設定変更確認用カウンタ設定値
ADEND:
DS      1                       ; A/D変換カウント用

 

他にご質問がございましたら、リクエストを送信してください