Renesas Synergy™

FAQ 1006570 : ソフトウェアでI2Cバスのスレーブ機能の実現について2(78K0S/Kx1+)

ソフトウェアでI2Cバスのスレーブ機能の検討」の結果の

・標準モード(クロックが100kHz以下)

・シングル・マスタ

・シングル・スレーブ(通信中以外に不要な信号変化がない)

・通信途中(8ビット目まで)でスタート・コンディションやストップ・コンディションが発行されない(通信前か9クロック目が完了した後のみで発行可能)

・他の割り込みは使用しない(割り込み応答の余裕が1μSしかないため)

の条件でのI2Cバスのスレーブ機能をソフトウェアによるポート制御で実現してみます。
基本的な処理は「ソフトウェアでI2Cバスのスレーブ機能の実現について」の内容を参照してください。

(1)システム概要
ここで対象にする例は、アナログ入力をA/D変換器でデジタル・データに変換して取り込み、その変換結果をマスタにI2Cバスを介して転送するものです。
マスタからは変換したいアナログ入力チャネルをI2Cバスのマスタ送信で指定します。スレーブ・マイコンはマスタからのマスタ受信指示で変換結果を転送します。
このときのシステム構成例を示します。



この例では、78K0S/KA1+のポート3(ビット0とビット4)を利用してI2Cバスの通信を行います。同じポートの2ビットが使用でき、SDAで使用する端子にエッジ検出割り込み機能があれば、他の端子に変更しても構いません。

(2)処理概要
以下に実際のプログラム例を示しながら、説明します。ここで対象にするプログラムは、SDAの立下りで発生した割り込みをスタート・コンディション検出に使用します。割り込みが発生し、処理プログラムの先頭で、ソフトウェアによりSCLの状態を確認し、スタート・コンディションであれば処理を開始します。処理を開始すると、通信完了するまではスタート・コンディションを検出した割り込みの中で処理を行います。スレーブ送信の場合にはマスタからのNACK応答で、スレーブ受信の場合にはデータ受信後のストップ・コンディション検出で通信を完了して割り込み処理から抜け出します。
データ転送の方向(受信か送信か)はI2Cバスの規格に従い、アドレスのLSB(ビット0)で判断しています。I2Cバスに関しては、FAQの「I2Cバスについての概要」を参照してください。LSBの値により、以下のような動作を行います。

LSBが0 : A/D変換するチャネルの指定(初期値はチャネル0)
LSBが1 : 指定されたチャネルの変換結果を上位バイト・下位バイトの順で送信


ここで使用するA/Dはメイン処理の中で前もって起動しておきます。常時、変換動作を実行し、マスタからの送信要求で最新の変換結果を送信します。

このプログラムで使用する変数は以下のようになります。このプログラムを使用する場合には、これらを前もって設定しておく必要があります。

SAV0 : スレーブとしてのアドレスを保持しています。マスタからのアドレス(上位7ビット)がこの値と一致すると、実際の通信を行います。ビット0は必ず0にします。
IIC0 : 受信データを構成するために使用する。初期値として通常は00をセットしておきます。
IICC0 : ビット2がACK応答するかどうかのフラグ(ACKE)です。このビットがセットされていると、マスタからのアドレスがSAV0の値と一致したらACK応答します。マスタから応答したくないとき、フラグ(ACKE)をクリアします。マスタからのアドレスが一致しなかったときにはクリアされるので、通信を許可するにはフラグ(ACKE)をセットする必要があります。


(3)全体の処理
ここで考えている通信処理全体の概略状態遷移を以下に示します。



処理の開始はSDA信号の立ち下がり(INTP0)とします。最初にSCL信号のとの関係をチェックしてスレーブ・アドレス受信に移ります。受信したスレーブ・アドレスが一致して応答許可状態のときにACK応答を行います。何か内部処理を実行中で通信したくないときには応答禁止状態にしておき、アドレスが一致してもACK応答しないようにできます。このようにACK応答をしないことで、マスタに処理中であることを知らせることができます。(ただし、実際にはこの機能は使用していません。)
スレーブ受信の場合には、受信準備をして、「バイト切れ目での処理」になります。データが送信されてきたら、(上位6ビットをマスクして)アナログ入力チャネルの指定を行います。複数のデータが送られてきた場合には最後のデータが有効になります。ここで、スタート・コンディションが検出された場合には、リスタート処理として、アドレス受信か、ストップ・コンディション検出を待ちます。ここで、ストップ・コンディションを検出すると、通信処理を完了します。
スレーブ送信の場合には、A/D変換結果を読み出し、上位バイトから順に送信します。マスタからACK応答があれば次のデータを送信し、NACK応答の場合(ACK応答がなければ)通信を完了します。ACK応答が続くと、新しい変換結果を順次送信していきます。
以下では詳細な処理について説明します。

(4)通信の起動(スタート・コンディション検出)
通信を開始するタイミング(スタート・コンディション)はSDA信号の立下りをエッジ検出したベクタ割り込みで検出するものとします。このとき、以下に示すプログラム例では、SCL信号がハイでなければ処理は行わないようにしています。これでも十分にスタート・コンディション検出が可能です。スタート・コンディションを検出したら、SCL信号が一旦立ち下がったことを確認してから、SCL信号の立ち上がり(アドレス受信)を待ちます

__INTP0:
BF      P3.4,$NOTSTART ;SCLがハイか確認
PUSH    AX                      ;AXレジスタをセーブ
MOV     IIC0,#00000000B ;データ初期値を設定
LOOP0:

MOV     A,P3 ;SDAとSCL読み込み
BF      A.4,$ADDRESS0 ;SCLの立下りで分岐
BF      A.0,$LOOP0 ;SDAがロウなら継続
NOTACK:
POP     AX                      ;AXレジスタを復帰
NOTSTART:
RETI                            ;ストップコンディション検出

(5)アドレスの受信
SCL信号がロウになったことを確認してから、アドレス受信のためにSCL信号の立ち上がりを待ちます
このときの処理プログラムは以下の例のようになります。SCL信号がハイのときにSDA信号が有効として、そのデータがハイの場合には変数IIC0の該当するビットを1にします。この処理を以下のようなマクロsin1を定義しておくことでプログラムを読みやすくします。

sin1 macro   bitno
LOCAL   DATAis0,LOOP
LOOP:
MOV     A,P3
;SCLとSDAを読み込む
BF      A.4,$LOOP ;SCL立ち上がり待ち
BF      A.0,$DATAis0 ;SDAを確認
SET1    IIC0.bitno ;1ならビットをセット
DATAis0:
BT      P3.4,$$
;SCLの立下り待ち
endm

これで、アドレスの受信処理は、マクロ名とビット番号(マクロの引数)を組み合わせて以下のように記述することができます。

ADDRESS:
sin1    7 ;ビット7受信
sin1    6 ;ビット6受信
sin1    5 ;ビット5受信
sin1    4 ;ビット4受信
sin1    3 ;ビット3受信
sin1    2 ;ビット2受信

これで、ビット7~ビット2までの受信処理を行います。ビット1(アドレスの最後のビット)についてはアドレスの比較が必要なためにできるだけ無駄な待ちループが発生しないよう最後のSCL信号の立ち下がり待ちの前にアドレス比較を行います。以下の処理を実行しても、ウェイトをかけることなくSCL信号のロウ期間に処理を完了して最後の転送方向受信処理に間に合います。

LOOP1:
MOV     A,P3 ;SCLとSDAを読み込む
BF      A.4,$LOOP1 ;SCL立ち上がり待ち
BF      A.0,$bit1is0 ;SDAを確認
SET1    IIC0.1 ;1ならビット1をセット
bit1is0:
MOV     A,SVA0                  ;アドレスを確認
SUB     A,IIC0                  ;結果をゼロ・フラグに
BZ      $RESACK ;アドレスが一致しないと
CLR1    ACKE ;ACK応答禁止に設定
RESACK:
BT      P3.4,$$ ;SCL立下り待ち

(6)アドレスの受信完了からACK応答
アドレスの8ビット目(転送方向)を受信したら、アドレスが一致してなおかつACK応答可能なときにSCL信号の9クロック目でACK応答を行います。アドレスの一致は最初の7ビットでチェックが完了しているので、ここではその結果のACKEフラグを参照して応答するかどうかを判定します。アドレスが一致していても、ACKEフラグがクリアされている場合(別の処理を行っていて、応答できない場合)にはACK応答しません。従って、スレーブからACK応答がなかったときには、マスタはある程度時間を置いて再度スタート・コンディションから開始する必要があります。ACK応答しないときにはスレーブの処理はこれで完了となります。
転送方向を受信したSCL信号の立ち上がりから約7μSでACK応答を戻すことができます。これは次のSCL信号の立ち上がりに対して十分なマージンを確保できています。

sin1    0                       ;ビット0受信
BF      ACKE,$NOTACK0 ;ACK応答しないなら抜ける
CLR1    PM3.0 ;ACK応答

(7)ACK応答完了
ACK応答が完了したら、ACKの転送完了(SCL信号の立ち上がりと立ち下がり)を待ち、ACK応答を切ります。これでアドレス受信処理は完了したので、後は転送方向に応じた処理となります。SCL信号の変化待ちでは処理に余裕があるので、前もって転送方向で処理を分けておきます。

MOV     A,IIC0                  ;アドレスをAレジスタに
ROR     A,1                     ;CY=0:受信、1:送信
BNC     $RXDATA ;受信なら分岐

(8)スレーブ送信でのアドレス9クロック目以降の処理(送信準備)
スレーブ送信では、A/D変換結果(既に変換は完了している)を読み出し、2回に分けて送信します。ここで、ループを回すと処理が複雑になり、時間がかかることが考えられるので、ここでは、8ビットの送信処理を2つ並べておきます。

TXDATA:
MOVW    AX,ADCR ;変換結果を読み出し
BF      P3.4,$$ ;SCL立ち上がり確認
TXLOOP:
MOV     TXCOUNT,#8              ;ビット数をセット

(9)データ送信処理~ACK確認
スレーブ送信処理では、SCL信号の変化を待つだけなので、ループで処理しても十分に処理可能です。そこで、ループ・カウンタ(変数TXCOUNT)を用いて制御します。8ビットの送信が完了すると、SDA信号を開放してACK応答を待ちます。マスタからACK応答があった場合には次のデータに進みます。ACK応答がなかった場合には処理を終了します。

;
;  上位バイト送信
;
TXBLOOP1:
ROL     A,1 ;MSBをキャリーへ
BT      P3.4,$$ ;SCL立ち下がり待ち
SET1    PM3.0 ;ACK応答解除
BC      TXBIT1 ;データが1なら分岐
CLR1    PM3.0 ;SDAをロウに
TXBIT1:
BF      P3.4,$$ ;SCL立ち上がり待ち
DBNZ    TXCOUNT,$TXBLOOP1 ;8ビット分繰り返し
BT      P3.4,$$ ;SCL立ち下がり待ち
SET1    PM3.0 ;SDA開放
MOV     A,X ;下位データ準備
;
;  ACK応答確認
;
BF      P3.4,$$ ;SCL立ち上がり待ち
BT      P3.0,$NOTACK ;NACKなら抜ける
MOV     TXCOUNT,#8              ;ビット数をセット
;
;  下位バイト送信
;
TXBLOOP2:
ROL     A,1 ;MSBをキャリーへ
BT      P3.4,$$ ;SCL立ち下がり待ち
SET1    PM3.0 ;ACK応答解除
BC      TXBIT2 ;データが1なら分岐
CLR1    PM3.0 ;SDAをロウに
TXBIT2:
BF      P3.4,$$ ;SCL立ち上がり待ち
DBNZ    TXCOUNT,$TXBLOOP2 ;8ビット分繰り返し
MOVW    AX,ADCR ;次の変換結果を読み出し
BT      P3.4,$$ ;SCL立ち下がり待ち
SET1    PM3.0 ;SDA開放
;
;  ACK応答確認
;
NOTACK0:
BF      P3.4,$$ ;SCL立ち上がり待ち
BF      P3.0,$TXLOOP ;ACKなら次データへ
NOTACK:
;
;  9クロック目完了待ち
;
BT      P3.4,$$ ;SCL立ち下がり待ち
POP     AX                      ;AXレジスタ復帰
CLR1    PIF3                    ;割り込み要求をクリア
RETI                            ;処理完了

スレーブ送信処理では、マスタからのNACK応答を確認した段階(9クロック目)で処理を完了しています。この後、マスタはストップ・コンディションかスタート・コンディションを発行することになります。ここで抜けてしまうと、ストップ・コンディションを発行するときには、以下のような信号の動きとなり、SDAを立ち下がりだけを見ているので、スタート・コンディションを誤検出します。しかし、INTP0割り込み処理の中でSCLがロウなら何もしないで抜けるようになっていることと、SCLがハイならSDAの立ち上がり(ストップ・コンディション)で抜けるので、問題はありません。



(10)スレーブ受信での9クロック目以降の処理

RXDATA:
;
;  9クロック目(ACK応答完了)待ち
;
BF      P3.4,$$ ;SCL立ち上がり待ち
BT      P3.4,$$ ;SCL立ち下がり待ち
SET1    PM3.0 ;ACK応答解除
MOV     IIC0,#00000000B ;データ初期値を設定

9クロック目のSCL信号が立ち下がったら、ACK応答を解除してSDA信号を解放します。引き続いて、データの受信処理に移ると以降は繰り返し処理となります。繰り返しで処理する場合には、スレーブ受信として次のデータが送られてくる以外に、以下の3つの場合が考えられます。これらをポートを用いて確認する必要があるため、処理が複雑になり、タイミング的に苦しくなることが考えられます。

①次のデータを受信する
②スタート・コンディション(リスタート)を受け付ける
③ストップ・コンディションを受け付ける

①の場合にはSCL信号がロウの状態でSDA信号が変化して、SCL信号が立ち上がります。その後SDA信号は保持したままでSCL信号が立ち下がります。SCL信号が立ち下がって始めてデータだと分かります。この場合にはSCL信号のハイ幅が4μS以上で、SDA信号は250nSのセット・アップ時間と0nSのホールド時間で変化する可能性があります。この時間は判別できる時間間隔よりはるかに小さいので、単独または、SDA信号立ち下がりと同時にSCL信号の立ち下がりが検出できたらデータ受信と判断することになります。



②の場合にはSCL信号がロウの状態でSDA信号が立ち上がり、SCL信号がハイの状態でSDA信号が立ち下がります。SDA信号の立ち下がりでスタート・コンディションであることは分かりますが、SCL信号が立ち下がるまでは次には移れません。



③の場合にはSDA信号をどのタイミングで立ち下げるかで、さらに2つの場合が考えられます。SCL信号がロウの状態で立ち下がれば、単純にストップ・コンディションの発行だけとなります。SCL信号の立ち上げと同時またはその後でSDA信号が立ち下がった場合には、そこがスタート・コンディションと同じになります。その後でストップ・コンディションが発行されることになります。つまり、スタート・コンディションを検出した場合にはSCL信号が立ち下がるか、SDA信号が立ち上がるかを待つ必要があります。



この部分を処理するための状態遷移図を以下に示します。



この処理のプログラム例を示します。

①SDA信号がハイであったときの処理
まず、SCL信号が立ち上がったときに、SDA信号がハイの場合の処理を行います。SCL信号の立ち上がりとSDA信号の組み合わせでの場合分け(下記プログラムのLOOP21以降の3命令)は、SCL信号の立ち上がりから30クロック(3.7μs)以内に処理できるので、SCL信号の周期が短い(4μs)データ転送の場合でも、タイミングに問題はありません。STCLOOP以降の3命令で、データ受信開始かスタート・コンディション(リスタート)を待っています。データ受信では、SCL信号の立ち下がりから30クロック(3.7μs)以内に検出できるので、SCL信号がロウの期間(4.7μs)に処理可能です(以降の処理は)。

;
;       アドレス受信、データ受信した後の処理の判断を行う。
;
LOOP21:
MOV     A,P3 ;SCLとSDAを読み込む
BF      A.4,$LOOP21 ;SCL立ち上がり待ち
BF      A.0,$SDALOW ;SDAがロウなら分岐
;
;       スタート・コンディションかデータ待ち
;  SCLが立ち下がれば通常データ受信(⑤)
;  SDAが立ち下がればスタート・コンディション(②)
;  ここは必ずSCLの確認してからSDAを確認する必要がある。
;
STCLOOP:
MOV     A,P3 ;SCLとSDAを読み込む
BF      A.4,$DATAREAD ;SCLが立ち下がれば受信へ
BT      A.0,$STCLOOP ;変化なければループ

②リスタート
リスタートの場合、信号の読み取りが20クロックのループになり、1回は確実に確認できますが、確認処理完了に最大38クロックかかります。このとき、次データのためにSCL信号が立ち下がっている可能性があります。その後、4クロックで信号を確認します(次図の)が、このときの状態で、次が何かを判断する必要があります。
SCL信号が立ち下がれば(実線)、リスタート後のアドレス受信()の開始です。SCL信号がハイのままSDA信号が立ち上がれば(破線)、ストップ・コンディション()です。ここでは、どちらかの信号が変化するまで待ちます。



;
;       スタート・コンディション検出
;  スタート・コンディションを検出したらSCLの立下り(通信開始)か
;SDAの立ち上がりを待つ
;
STCLOOP2:
MOV     A,P3 ;SCLとSDAを読み込む
BF      A.4,$ADDRESS2 ;SCLの立下りでアドレス受信
BF      A.0,$STCLOOP2 ;ストップ・コンディション以外

③アドレス受信
アドレス受信時の分岐先のADDRESS2は、本来ADDRESSですが、ここからの条件分岐では直接飛べず、また、いくつかの処理が必要なためのクッションです。RXDATAの直前に配置しておく必要があります。

;
;       リスタート時にアドレス受信へ戻る処理
;
ADDRESS2:
MOV     IIC0,#0 ;受信データをクリア
BR      ADDRESS

④ストップ・コンディション
受信を完了して、ストップ・コンディションを検出したら、処理を完了します。これまでのSDAの変化で、PIF0がセットされているので、クリアしてから割り込み処理を抜けます。

;
;       ストップ・コンディション検出
;  通信完了フラグをセット、ACK応答禁止にして処理を完了します。
;
STPCND:
POP     AX                      ;AXレジスタ復帰
CLR1    PIF0                    ;割り込み要求をクリア
RETI                            ;処理完了

⑤データ受信処理(SDA=Hのとき)
次データ受信の処理です。最初のビットは受信完了済みなので、残り7ビットの受信でACK応答し、受信データをバッファに書き込みます。その後、(9)スレーブ受信での9クロック目以降の処理の最初に戻ります。

;
;       データ受信処理
;  最上位ビットは既に受信済みのため、残り7ビット分を受信する。
;受信が完了して、ACK応答後9クロック目でウェイトして処理を抜ける。
;
DATAREAD:
MOV     IIC0,#10000000B ;ビット7は1であった
DATAREAD2:
sin1    6                       ;ビット6を受信
sin1    5                       ;ビット5を受信
sin1    4                       ;ビット4を受信
sin1    3                       ;ビット3を受信
sin1    2                       ;ビット2を受信
sin1    1                       ;ビット1を受信
sin1    0                       ;ビット0を受信
CLR1    PM3.0 ;ACK応答
MOV     A,IIC0 ;受信データ読み出し
BF      P3.4,$$ ;SCL立ち上がり待ち
AND     A,#00000011b            ;受信フラグをセット
MOV     ADS,A                   ;アナログ入力選択
BT      P3.4,$$ ;SCL立下り待ち
SET1    PM3.0 ;ACK解除
BR      !LOOP21                 ;継続処理へ

⑥SDA信号がロウであったときの処理
ここでは、SCL信号が立ち上がったときに、SDA信号がロウの場合の処理を行います。このときの次の状態は、データ受信()かストップ・コンディション()かのどちらかです。

;
;       ストップ・コンディションかデータ待ち
;  SCLが立ち下がれば通常データ受信(⑦)
;  SDAが立ち上がればストップ・コンディション(④)
;  ここは必ずSCLを確認してからSDAを確認する必要がある。
;
SDALOW:
STCLOOP3:
MOV     A,P3 ;SCLとSDAを読み込む
BF      A.4,$DATAREAD3 ;SCLが立ち下がれば受信へ
BF      A.0,$STCLOOP3 ;変化なければループ
BR      $STPCND                 ;ストップ・コンディションへ

⑦データ受信処理(SDA=Lのとき)
次データ受信の処理です。最初のビットは受信完了済みなので、残り7ビットの受信でACK応答し、受信データをバッファに書きこみます。この例では、最初のビットを0にし、のビット6受信に分岐させています(共通の処理)。

DATAREAD3:
MOV     IIC0,#00000000B ;ビット7は0であった
BR      $DATAREAD2              ;受信処理継続

(11)各種の宣言
このプログラムを使用する上で使用する変数や定数は以下のように定義しています。

;************************************************************************
;                                                                          *
;               データ領域(変数やフラグ)の定義                            *
;                                                                          *
;                                                                          *
;************************************************************************
PUBLIC          SVA0                            ;アドレス
PUBLIC          _SVA0                           ;アドレス(C言語用)
PUBLIC          IICC0                           ;動作指定
PUBLIC          _IICC0                          ;動作指定(C言語用)
PUBLIC          __INTP0                         ;割り込み処理部

;
;  作業用のフラグ、変数
;
DSEG            saddr
IIC0:
DS      1                       ;受信データ作業用
SVA0:
DS      1                       ;スレーブ・アドレス保持用
IICC0:
DS      1                       ;動作指定用
ACKE            EQU     IICC0.2                 ;ACK応答制御用
_ACKE           EQU     IICC0.2                 ;ACK応答制御用(C言語用)
;  1:ACK応答許可、0:ACK応答禁止
PUBLIC          ACKE
PUBLIC          _ACKE                           ;C言語用

TXCOUNT:
DS      1                       ;送信のビット・カウント用

(12)このプログラム例を使う方法(アセンブラ)

このプログラムを使用するにはオプション・バイトで高速内蔵クロックの使用、RESET端子のP34での使用、ウォッチドッグ・タイマを使わなくするために低速内蔵発振器の停止可能を設定します。オプション・バイトの設定例を以下に示します。

@@OPTB  CSEG    AT      0080H
DB      10010100b
DB      11111111b
END

その上で、使用する内蔵周辺機能等の初期設定を行うためのメイン処理を作成する必要があります。以下の例は、そのための初期化を行う例で、初期化完了後にはループしているだけです。実際の使用に当たっては、MLOOP以降に実際に処理させたいプログラムを記述してください。この例では、A/D4チャネルを使用可能にして、チャネル0をA/D変換する状態で通信待ちを行っています。
なお、送信するか、受信するかはマスタから送られてくるアドレスのLSBで指定されるので、通信が始まるまではわかりません。

EXTRN           SVA0                            ;アドレス
EXTRN           IICC0                           ;動作指定
EXTRN           __INTP0                         ;割り込み処理部
EXTBIT          ACKE                            ;ACK応答許可

RSTVECT CSEG    AT 0
DW              START
ORG     18H
DW              __INTP0                 ;割り込みベクタの設定

STKADR  DSEG    IHRAM
DS              32                      ;スタック領域(32バイト)
STACK:

CSEG
START:
MOVW            AX,#STACK
MOVW            SP,AX
MOV             PCC,#00000000B
MOV             WDTM,#01110000b         ;ウォッチドッグ・タイマ停止
SET1            LSRSTOP                 ;低速クロック停止
SET1            LVIMK
MOV             LVIM,#00000000b
MOV             LVIS,#00000000b         ;電圧を4V以上に設定
SET1            LVION                   ;低電圧検出回路起動
MOV             B,#0
DBNZ            B,$$
BT              LVIF,$$                 ;電源立ち上がり待ち
MOV             PPCC,#00000000b         ;8MHz動作に
MOV             SVA0,#10100000b         ;スレーブのアドレス設定
SET1            ACKE                    ;ACKEをセット
;
;  A/D変換起動
;
MOV             ADM,#00100001b          ;A/D変換は28μS
MOV             PMC2,#00001111b         ;4チャネル使用可能に
MOV             PM2,#11111111b
MOV             ADS,#00                 ;初期値はチャネル0
SET1            ADCS                    ;A/D変換開始
;
;  ポート、割り込み初期化
;
MOV             PM3,#11111111b          ;使用ポートを入力に
MOV             P3,#00000000b           ;ポートデータをクリア
MOV             INTM0,#00000000b        ;INTP0を立ち下がりエッジ検出に
CLR1            PIF0
CLR1            PMK0
EI
;
;  初期設定を完了して、通信可能に
;

MLOOP:                                          ;SDA立下りの割り込み待ち
NOP
;
;  ここに必要な処理が入るが、この例では何も行わずループさせている。
;
BR              $MLOOP

END

(13)このプログラム例を使う方法(C言語)
このプログラムを使用するにはオプション・バイトで高速内蔵クロックの使用、RESET端子のP34での使用、ウォッチドッグ・タイマを使わなくするために低速内蔵発振器の停止可能を設定します。さらに、INTP0の割り込みベクタの設定を含めたオプション・バイトの設定例を以下に示します。

EXTRN   __INTP0
RSTVECT CSEG    AT 8H
DW              __INTP0
@@OPTB  CSEG    AT      0080H
DB      10010100b
DB      11111111b
END

この機能(割り込み処理)を使用するための初期化を行なうC言語でのメイン処理は以下のようになります。hdwinit関数で必要な初期化処理を行います。その後のmain関数ではA/Dコンバータを起動し、割り込み許可にしてINTP0割り込みを待つだけです。この例ではNOP命令でループしているだけですが、必要に応じて処理を追加してください。

#pragma SFR
#pragma EI
#pragma DI
#pragma NOP

extern  unsigned char SVA0;
extern bit ACKE;

/*--------------------------------------------------------------*/
/*                                                                */
/*                                                                */
/*      Function Body                                            */
/*                                                                */
/*                                                                */
/*--------------------------------------------------------------*/
/****************************************************************/
/*                                                                */
/*                                                                */
/*      Hardware initialize                                      */
/*                              (call by start up routine)       */
/*                                                                */
/****************************************************************/
void hdwinit(void)
{
unsigned char   work1;

DI();
WDTM = 0b01110000;              /* stop WDT             */
LVIMK = 1;
LVIS = 0x00;                    /* select VLI=4V        */
LVIM = 0b10000000;              /* Start VLI detection  */
PCC = 0x00;                     /* CPU clock is fx/4    */
/*
wait for 0.17ms(=0.2ms-(32+30)*52/1000)
*/
for (work1 = 0; work1 < 10; work1++){
NOP();
}

while ( LVIF ){
NOP();
}       /* wait VDD > 4V */

PPCC = 0;                       /* CPU clock is fx=fR   */

ADM = 0b00100001;               /* set A/D mode         */
PMC2 = 0b00001111;              /* use 4-ch for A/D     */
ADS = 0b00000000;               /* initial channel is 0 */

PM3 = 0b11111111;               /* set port to input    */
P3 = 0b00000000;                /* clear port data to 0 */
INTM0 = 0b00000000;             /* detect falling edge  */
PIF0 = 0;
PMK0 = 0;

SVA0 = 0b10100000;              /* set slave address    */
ACKE = 1;                       /* enable ACK           */
}

/****************************************************************/
/*                                                                */
/*                                                                */
/*      Main                                                      */
/*                                                                */
/*                                                                */
/****************************************************************/
void main(void)
{
ADCS = 1;                       /* start A/D            */
EI();

while(1){

NOP();                  /* wait interrupt       */
NOP();

}

}

 

適用製品

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