ikkei blog

電子工作やパズルのブログです。主にLEDを使った電子工作をやっています。

PICのparity generator はこうだ!

2013年06月19日 00時51分17秒 | PIC
先のサムチェック同様、なんとかして欲しいのがパリティジェネレータです。
大抵のマイコンのシリアルIFにはパリティビットを設定でき、
ハードで、パリティの計算もやってくれます。

ところが、ハードが貧弱なPICにはパリティビットは有っても
パリティジェネレータは有りません。
それは、ソフトでやってね。ってことだと思うのですが、
だったら、ソース付けとけって言いたいですね。

と言うのも、前任者はわざわざ4ビットのパリティ表を作って
2回参照して作っていたからです。

ググっても、1ビットずつ8回ループを回すと言った研修の演習のようなソースが。
もちろん、海外ならすごいコードが出てきます。
でも、アセンブラなので、SWAPとかCでは書けないコードを使っています。

で、私のコードはずばりこれです。
unsigned char get_parity(unsigned char w){
	w ^= w >> 4;
	w ^= w >> 2;
	w ^= w >> 1;
	return( w & 0x01 );
}
これは、偶数パリティの場合。
奇数の場合は、returnのところを
return( w & 0x01 ^ 0x01 );
に変えます。

トリッキーではないでしょ。

さらに、もう一つ言いたいことは、パリティって、
8ビットのパリティと 1ビットのパリティビット 
ではなく、9ビットのパリティだと言うことです。

9ビット分のパリティを計算して、それが0(偶数)なのか、1(奇数)なのか
と言うことなのです。

だから、送信時は8ビット分のパリティの結果を9ビット目に代入し、
void tx_byte(unsigned char data){
TX9D = get_parity(data);
TXREG = data;
txptr++;
}
受信時は8ビット分のパリティの結果と9ビット目をEXORして、0になるかチェックします。
ついでに、他のエラービットもチェック出来ます。
奇数パリティの場合、結果は1になるので、上記のように1を追加して、結果が0になるようにします。
void serial_rx(void){
unsigned char work;
if (rxptr < RXMAX){
work = RCREG;
if (((get_parity(work) ^ RCSTA) & 0x07) == 0){ // error check
if (rxptr <RXSIZE){
rxbuf[rxptr] = work;
}
rxptr++;
sum += work;
..........
ところで、組み込みでシリアルを使おうとすると、
当然、割り込みを使わざるを得ません。

でも、PICの本では、受信は割り込み処理で書かれていても、
送信はTXIFをポーリングするだけの処理が多いようです。
これでは、実際には使い物になりません。

9600ボーなら、10バイト程度でも10ms以上かかってしまうので、
待ってられないからです。

だから、送信も割り込みを使わざるを得ません。
でも、そう言う例はPIC本では見られません。

私のコードはこれです。
// シリアル出力開始 1バイト目出力と2バイト目セット
void serial_tx1(unsigned char num){
tx_num = num;
txptr = 0;
while(TXIF == 0); // ***
tx_byte(txbuf[txptr]);
if (tx_num > 1){
while(TXIF == 0);
tx_byte(txbuf[txptr]);
TXIE = 1; // serial tx interrupt enable
}
}


// シリアル割り込みで3バイト目以降セット
void serial_tx2(void){
tx_byte(txbuf[txptr]);
if (txptr >= tx_num){
TXIE = 0; // serial tx interrupt disable
}
}

txbuf[]に送信データをセットして、送信バイト数をパラメータにセットしてserial_tx1をコールします。
通常、送信したあと返事を待って送信するので、***の行は無くても構いません。

割り込み部分はこんな感じです。
//  interrupt
void interrupt ISP(void){
// serial rx interrupt
if (RCIF && RCIE){
serial_rx();
// serial tx interrupt
} else if (TXIF && TXIE){
serial_tx2();
// timer interrupt
} else if (T0IF){
TMR0 = T_STEP;
T0IF = 0;
timer0();
}
}
TXIF && TXIE の部分は TXIF & TXIE でも、良さそうですが、3バイト多くなってしまいます。
しかし、PICの場合、割り込みのエントリーが1つしかないので、
イネーブルフラグも見ないといけないのは、なんだかなぁ。って感じです。

多くのベクター方式の割り込みなら、こんな面倒なことはありません。
このあたりも、PIC本には受信割り込みだけの例しか無く、
イネーブルフラグも見ないといけないなんて、書いてません。

私が、学校でPICのアセンブラを教えるのはダメだと言う理由の一つに
このような、PIC固有の付帯事項(他のマイコンではほとんど出てこないので、知っていても応用できない)
が多すぎることなのです。

ほとんどの学生はこれら付帯事項を理解するのにおなか一杯になってしまい、
肝心のアセンブラコーディングの本質にたどり着かないのです。
結果、習ったはずなのに応用課程で何も出来ない人続出ってことに。

しかし、PICに使われている記号やニーモニックはなぜにこんなに不統一なのでしょうか?
送信がTXIF なのに、受信はRXIFではなくRCIF
タイマ0は、T0IEなのに、タイマ1は、TM1IEだったり、
こんな行き当たりばったりをユーザに押しつけないで欲しいものです。



最新の画像もっと見る

コメントを投稿