マイコンでいろいろな処理を同時に進めるときには、リアルタイムOSを使うことが多くなってきています。 但し、リアルタイムOSがない環境や、リアルタイムOSを使用するほどでもない状況では、それぞれの処理を時分割処理に刻んで並行処理する手法が使用される場合があります。
例えば、一定の周期で処理したい処理が3つあったとします。それらを仮にタスクA,B,Cとします。そうすると、以下のように一定の周期でタスクを実行できます。タスクそれぞれを別な処理のステートマシンにする事で、外部からは3つの異なる処理が同時に処理できます。
処理周期に対して一回あたりの全処理処理時間が終わった後の待機中の期間をアイドルタスクと呼び、この部分の割合をCPU処理余裕度と考えることができると思います。以下の図は、それを模式的にあらわしたもので時間軸は横方向、左から右に流れているつもりで書いています。
この処理を実現する場合、以下のアクティビティ図のような状態遷移で実現できると思います。
いろいろな実現方法があるかと思いますが、私はCounter8を使用しました。まずは、Device EditorからCounter8を導入し、モジュール名は「Counter8_1」としました。
Selected User ModulesにCounter8のアイコンが出ていると思いますので、右クリックして「Place」を選択しましょう。これで配置されます。
Counter8のパラメータは以下のように設定してみました。
| User Module Parameters | Value |
| Clock | VC3 |
| ClockSync | Sync to SysClk |
| Enable | High |
| CompareOut | None |
| TerminalCountOut | None |
| Period | 0 |
| CompareValue | 0 |
| CompareType | Less Than Or Equal |
| InterruptType | Compare True |
| InterruptAPI | Enable |
| IntDispatchMode | ActiveStatus |
| InvertEnable | Normal |
ClockはVC3にしました。VC3の設定については後述します。
次に、ツールバーのProject→Settingsタブ→Enable Interrupt generation controlのチェックを入れてください。
Counterなどの周辺回路では、クロック源としてSysClkをはじめとして各種使用可能です。PSoCでは、VC1〜VC3というクロック源があり、SysClkを接続して、分周したものを周辺回路に供給する事が可能です。
今回は、十分遅いタイミングを生成してテストしたかったのでSysClkをVC1、VC2、VC3を使用して分周しました。 とりあえず、以下のように設定してみました。
この設定では、元々のSysClk(24MHz)が分周器VC1〜3に接続されています。
したがって、Counter8には、366.2[Hz]が供給されることになります。
Config→Generate Applicationを選択して、Counter8のAPIを生成します。 次に、Counter8割り込みの割り込み処理を作成しましょう。割り込み処理はC言語で記載します。
static B Cyclic_WaitFlag;
#pragma interrupt_handler Counter8_1_INT
void Counter8_1_INT(void){
Cyclic_WaitFlag = 0;
}
割り込み処理で、スタティック変数Cyclic_WaitFlagを0にするよう記述します。また、コンパイラに割り込み処理である事を通知するため、#pragma interrupt_handlerで関数を登録します。
libフォルダに「Counter8_1INT.asm」というファイルが生成されていると思います(モジュール名の設定によってはプリフィックス部の名称が変わります)。 これをエディタで開き、先ほどのC言語による割り込み処理ルーチンがコールされるよう変更します。
_Counter8_1_ISR: ;@PSoC_UserCode_BODY@ (Do not change this line.) ;--------------------------------------------------- ; Insert your custom code below this banner ;--------------------------------------------------- ; NOTE: interrupt service routines must preserve ; the values of the A and X CPU registers. ljmp _Counter8_1_INT ; ここを追加する!!! ;--------------------------------------------------- ; Insert your custom code above this banner ;--------------------------------------------------- ;@PSoC_UserCode_END@ (Do not change this line.) reti
PSoCの自動生成ファイルは、PSoC Designerで勝手に書き換えられてしまいますが、上記の
;--------------------------------------------------- ; Insert your custom code below this banner ;---------------------------------------------------
から
;--------------------------------------------------- ; Insert your custom code above this banner ;---------------------------------------------------
のバナーの間はユーザーが変更しても変更内容は保持されるようです。 ここでは、C言語の割り込み処理ルーチンは、Counter8_1_INT()でしたので、上記のように追加して下さい。C言語関数はアセンブラ展開された時先頭に「_」(アンダーバー)が付くようですのでアンダーバー付きで指定します。
処理の追加・削除が行いやすいよう、関数テーブルに関数を追加すると、その関数全てがテーブルの定義順にシーケンシャルに実行できるようにしてみます。今回は全て同じ周期でコールされますが、処理によってスケジューリングできるように工夫しても面白そうですね。
また、このスタイルでプログラムを作成する時には、絶対処理中で長い待ち処理(例えばfor文ループなど)を入れてはいけません。待ちもひとつの状態として処理し、他の処理の実行を阻害しないようにします。
// void function(void)関数型
typedef void (*VFP)(void);
void DEBUG_MessageOutput(void);
void DEBUG_EchoBack(void);
const VFP Task_FuncTable[] = {
DEBUG_MessageOutput,
DEBUG_EchoBack
};
/** タスクを実行する
* @note この関数を実行する度にスケジューリングしている全関数をシーケンシャルにコールする
*/
void TASK_Execute(void){
int i;
for(i=0;i<ARRAY_LEN(Task_FuncTable);i++){
(*(Task_FuncTable[i]))();
}
}
この例では周期処理として、DEBUG_MessageOutput関数とDEBUG_EchoBackという関数を登録しています。次は、これらの関数を一定周期でコールする処理を作ります。
では、メイン処理から定期的に各処理の呼び元をコールするようループを作成し、ループの最後で次の処理周期フラグが立つのを待ちます。
// 周期処理開始
while(1){
// 周期タスクの実行
TASK_Execute();
// 次の周期タスク実行タイミングまでの待ち処理
{
B wait_flag;
while(1){
Counter8_1_DisableInt();
wait_flag = Cyclic_WaitFlag;
Counter8_1_EnableInt();
if(wait_flag == 0){
Counter8_1_DisableInt();
Cyclic_WaitFlag = 1;
Counter8_1_EnableInt();
break;
}
}
}
}
Cyclic_WaitFlag変数は割り込み内部でセットされる変数ですので、変数へのアクセス時はCounter8割り込みを停止させています。
上記の例では、Debug用のふたつの関数を登録しました。それらの関数の役割は以下のようになっています。
| DEBUG_MessageOutput()関数 | デバッグメッセージをUSBUARTから出力 |
| DEBUG_EchoBack()関数 | USBUARTからデータを入力したらメッセージを出力 |
したがって実行し、適当にTeraTermでキーインすると以下のような表示が出ます。
Count : 206(Hello)[RAM:R A M!]123
Count : 207(Hello)[RAM:R A M!]123
Count : 208(Hello)[RAM:R A M!]123
Input messageDUMP{0D 00 00 00 00 00 00 00 00 00 }
Count : 209(Hello)[RAM:R A M!]123
Count : 210(Hello)[RAM:R A M!]123
Count : 211(Hello)[RAM:R A M!]123
Count : 212(Hello)[RAM:R A M!]123
Input messageDUMP{0D 00 00 00 00 00 00 00 00 00 }
Count : 213(Hello)[RAM:R A M!]123
Count : 214(Hello)[RAM:R A M!]123
Input messageDUMP{0D 00 00 00 00 00 00 00 00 00 }
Count : 215(Hello)[RAM:R A M!]123
ソースコード一式はこちらでダウンロードして下さい。 なお、CY8C24794-24LFXI(PastelMagicさんのところのボード等)用です。 vcフォルダは、そーすをVisualStudio2005の開発環境で編集する目的で作成したソリューションファイルです。
Access count : - Today's access count : -