前の記事s.h.log: PSoC Designer – CY8C29466でスイッチ入力と同じ動作を、割り込みでやってみた。
基盤も同じくCY3210-MiniEvalを使った。
動き方もまったく同じのを作っちゃったのでビデオは省略。ただスイッチの扱い方が違うだけ。
SourceCode (PSoC Designer 4.3 + C Compiler)
■動作設定
Device EditorのInterconnect Viewで
基本的にs.h.log: PSoC Designer – CY8C29466でスイッチ入力と同じだが、
タクトスイッチの接続されているPORT2-4のInterruptをFailingEdgeにする。
割り込みの仕方は3種類あり、
・FailingEdge → 立下り割り込み
・RisingEdge → 立ち上がり割り込み
・ChangeFromRead → 両エッジ変化割り込み
から選ぶ。
AVRのSIG_INTERRUPT0、SIG_INTERRUPT1はそれぞれINT0, INT1ピンの状態が変化を監視する外部入力割り込みだが、
PSoCの外部入力割込みはAVRのSIG_PIN_CHANGEの方と同じく、どのピンに変化があっても割り込みが発生してしまう。
だから、複数のピンの割り込みを有効にする場合は実際にどのピンの変化が割り込みを発生させたのか?をいちいち確認しなければならない。今回はマスクレジスタで1つのピン(PORT2-4)だけをenableにしているので必要ないけど。
軽くまとめると、PSoCの割り込みの設定は
・マスクレジスタで「どのピンの変化を監視するか」を指定
・ピン毎に「立ち上がり/下がり/両方の、どの条件で割り込むか」を指定
できる。でもこれはPSoC Designerが自動生成してくれるので下手に触る必要は無い。
マスクで複数enableに指定した場合は、実際にどのピンが反応したか?はプログラミングでなんとかする。(1回前のPRTnDRの状態をglobal変数に保存しておいて比較するとか)
この辺ははじめてのPSoCマイコンの「入出力&割り込みのしくみとスイッチ&LEDを使った実験」p.67に詳しく書かれている。
■割り込みの記述
Generate Applicationしても、割り込みをアセンブラではなくC言語で書くにはまだ足りない。
Source Files/boot.asmを見てみると、PSOC_GPIO_ISRというサブルーチンが呼ばれている
boot.asm
org1Ch;GPIOInterruptVectorこのPSOC_GPIO_ISRはLibrary Source/psocgpioint.asmの中に記述されている。
ljmpPSoC_GPIO_ISR
reti
で、boot.asmを書き直してmain.c内のC言語の関数を呼び出しても良いんだけど、boot.asmはDeviceEditorでGenerate Applicationする毎に書き換えられてしまうので、psocgpioint.asmの中からさらにljmpで関数を呼び出す方が良い。
boot.asm→psocgpioint.asm→main.c という流れ。
psocgpioint.asm
PSoC_GPIO_ISR:_INT_GPIOという関数を呼び出す様にした。
;@PSoC_UserCode_BODY@(Donotchangethisline.)
;---------------------------------------------------
;Insertyourcustomcodebelowthisbanner
;---------------------------------------------------
ljmp_INT_GPIO
;---------------------------------------------------
;Insertyourcustomcodeabovethisbanner
;---------------------------------------------------
;@PSoC_UserCode_END@(Donotchangethisline.)
reti
■mainプログラム
ようやく今回のコード。アセンブラから_INT_GPIOを登録したので、INT_GPIO()という関数で外部入力割り込みが受け取れる。
main.c
#include<m8c.h>//partspecificconstantsandmacros■main.cの解説
#include&qute;PSoCAPI.h&qute;//PSoCAPIdefinitionsforallUserModules
#define_BV(BIT)(1<<BIT)
#definesbi(BYTE,BIT)(BYTE|=_BV(BIT))
#definecbi(BYTE,BIT)(BYTE&=~_BV(BIT))
volatilecharled;
voidmain()
{
M8C_EnableGInt;
M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
for(;;){
PRT2DR=led;
}
}
#pragmainterrupt_handlerINT_GPIO
voidINT_GPIO(void){
led++;
}
まず割り込みを許可し、GPIOの割り込みも許可する。External Headers/m8c.incに定義されている。
M8C_EnableGInt;INT_GPIO()関数を登録。これが無いと割り込みから呼ばれない。
M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
#pragmainterrupt_handlerINT_GPIOavr-gccではグローバル変数を割り込み/mainの両側から読み書きする時はvolatileつけないとおかしくなってたので、volatile付けてCPU最適化を防ぐ。
volatilecharled;でもさっき無しで試しても動いた。まあとりあえず付けよう。
割り込み。グローバル変数の値を増やすだけ。
voidINT_GPIO(void){「涙のfor」って萩野先生が言ってた。while(1)って書くより文字数が少ない。
led++;
}
for(;;){PRT2DRに直接8bit変数を代入すると、こんな風にバイナリでLEDが点くわけですよ。
PRT2DR=led;
}
■参考サイト
・法政大学工学部システム制御小林研究室 – CY3210 MiniEval によるスイッチの利用(2005.11.29)
boot.asmにljmp _関数名を加えるとC言語でも割り込みが書ける
・PSoCをはじめよう I/Oの割り込みで動かす
・PSOC関連② I/Oポート割り込みについて