送信部、受信部の機能が確認出来たところでソフトウェアに挑む。
これまでPICやハードウェアの機能確認のために簡単なソフトを組んだが、次はPICの性能を引き出すべく割り込みで処理を行う。次図はPIC16F18326の割り込みロジック。
最初に作るのは送信部だ。送信部は外部条件に左右されずひたすらデータを送るだけのタスクなので敢えて割り込みを使わなくても作る事が出来る。つまりEUARTの送信バッファが空になるまで待って次のデータを書き込む、ひたすらこれを繰り返せばよい。それだけである。これを割り込みを使うようにするには(PIC16F18326の初期化部分を除いて)次の3つのプロルラムに分ける。
1)起動処理 - 送信データが発生すれば割り込みを起動する。
2)割り込み処理 - 今回使うPIC16デバイスはベクター割り込みが使えないので、割り込みが発生したら先ずその要因を調べ、それがUARTの送信だった場合は 2.5)へ進む。
2.5)データ送信 - データを1バイト送信バッファに書き込む。
3)完了処理 - 送信すべきデータが無くなれば割り込みを停止させ完了をデータ送信を依頼したプログラムに知らせる。
0)作業用データ
typedef enum{TRUE=1, FALSE=0} boolean; //真理値型の定義
char *bufp; //送信データポインタ
boolean cmplt = TRUE; //完了フラグ
1)起動処理
void sendUART(char *buf){
bufp = buf; // バッファポインタをセット
cmplt = FALSE; // 完了フラグをOFF
PIE1bits.TXIE = ON; // TX割り込みON
}
2)割り込み処理
void __interrupt() isr(){
if(PIR1bits.TXIF) sendISR(); //UART送信可なら送信処理
}
この割り込み処理ルーチンに入る時にGIEはOFFにされ多重の割り込みは起こらない。また割り込み処理ルーチンからリターンするときGIEは自動的にONにされる。この処理時間を調べたが2.5)3)を含めて15~18μs程度であった。
2.5) データ送信 & 3)完了処理
void sendISR(){
TX1REG = *bufp++; // データ1文字送信
if(*bufp == 0){ // もし最終文字なら
PIE1bits.TXIE = OFF; // TX割り込みOFF
cmplt = TRUE; // 完了フラグをON
}
}
これを呼び出すメインルーチン側は次の様に記述する。
INTCONbits.PEIE = 1; // ペリフェラル割り込み可
INTCONbits.GIE = 1; // グローバル割り込み可
while(1){
sendUART("Test Data"); // 送信要求(起動)
while(!cmplt){}; // 完了待ち
__delay_ms(33); // 33ms(=25+8)の休止が必要
}
受信モジュールの規格上、sendUART()に渡す文字列(一度に送信できる量)は18文字以下に収め、そして送信完了後は25ms以上の休止時間を設ける必要がある(直後に次の送信がある場合)。ここで注意が必要なのは、ソフトウェア上で送信が完了しても送信バッファには最大2文字分の未送信データが残っており、それらの送出にはその後約8ms必要なので、足して33msの休止時間の確保が必要な事である。
以上ページを間延びさせたくなかったので細かい部分は省いて骨格だけを書いた。
プログラムを作っている時気付いたが、何故か次の割り込み処理ルーチンのプロトタイプ宣言がコンパイルエラーとなる。
void interrupt isr(void);
xc8コンパイラはvoidやinterruptに文句を言ってくる。まさか文法がANSIからK&Rに戻った訳でもあるまいに。色々調べると、xc8コンパイラのあるバージョン以降は次の書き方をするよう変更になったようで、これに書き換える事でコンパイルはできるようになった。
void __interrupt() isr(void);
しかしこれは、これまで見た事も無い訳の分からない文法だ。
0 件のコメント:
コメントを投稿