Pi:Co Classic Ver3 改造例(3)で7セグの点灯の確認をしました。今回は、UARTからのデータを7セグに点灯させます。
まず、仕様を見直すと
・UARTは割り込みを使用し、割り込みが入ったらデータを更新をする。
・7セグのデータはシフトレジスタ形式にする。
・7セグの繰り替えは、3msごとに切り替える。main文の中でwhileでまわす。
としか書いていません。つまり、UARTのデータはバイナリなのかアスキーなのかわからない仕様になります。つまり、その仕様ではプログラムが書けないことに気づきます。仕様がないなら、仕様を作ればよいので、改めて仕様を更新します。
・UARTは割り込みを使用し、割り込みが入ったらデータを更新をする。
・UARTの通信は38400bps、8bit、パリティ無し、stop 1bit、調歩同期、受信のみとする。
・UARTのデータ形式は、アスキーとする。
・7セグのデータはシフトレジスタ形式にする。
・7セグの繰り替えは、3msごとに切り替える。main文の中でwhileでまわす。
ここまでUARTの仕様が具体的になると仕様通りにプログラミングするだけなので何をすればわからないということがなくなります。
データの形式をアスキーにしたのは、TeraTermなどのターミナルに送るデータと同じにした方が、PiCo側のデータ送信のプログラムが簡単になります。PiCo側の送信はPrintf(“123”)と送れば、PIC側に”123″の文字を送ることができます。
以下がPICのUARTの設定プログラムです。
BRG16=1;//16bit RX9=0;//8bit //Fosc/[4(n+1)] SPBRG=51;//38400 error rate0.16% BRGH=1;//High speed SYNC=0; SPEN=1;//Serial Port enable CREN=1; RCIE=1;//RX Enable INTCONbits.GIE=1;//enable INTCONbits.PEIE=1;//enable
PIC16F687のマニュアルをみると、調歩同期(Asynchronous)で設定する場合、FOSC=8MHzでは、SYNC=0、BRG16=1、BRGH=1でないとエラー率が高く使えないようです。ここから、1行目のBRG16が”1″、5行目のBRGHが”1″、6行目のSYNCが”0″である理由です。これと、38400bpsからSPBRGの値を決定することができます。
Baud Rate= FOSC/(4×(n+1))からn=8000000/38400/4-1=50.81となりSPBRGは51となります。これが4行目の値の理由です。あとは、仕様からデータは8bitなので、8bitデータフォーマットに設定するのがRX9レジスタです。8bitにするには”0″を設定します。これが、2行目の値の理由です。
調歩同期で受信(Asynchronous Receiver)をコントロールするには、
・CREN=1
・SYNC=0
・SPEN=1
を設定するようにと記載されています。これが6~8行目の値の理由です。これでUARTの受信の設定は終わりです。残りはUARTの割り込みの設定になります(9~11行目)。UARTの割り込みに関してもマニュアルに記載されており、
・PIE1レジスタのRCIE割り込みをイネーブルにする
・INTCONレジスタのPEIE周辺割り込みをイネーブルにする。
・INTCONレジスタのGIE汎用割り込みをイネーブルにする。
となっています。
UARTの割り込み内の処理は、データのシフトをするだけです。
void interrupt Inter(void) { if(RCIF == 1){ data[2]=data[1]; data[1]=data[0]; data[0]=RCREG; } }
使用したソフトでは、interruptという関数名の前に付けると割り込み関数になります。Inter(void)の関数名はなんでもよいです。PICの割り込みは割り込みの種類ごとに割り込み関数がなく、一つの割り込み関数内でフラグを見て割り込み処理をする仕様のようです。2行目のようにUARTの受信割り込みフラグを確認して、割り込み処理をしています。今回の割り込み処理はデータのシフトのみです。3行目から5行目がそれに当たります。シフトするデータが多い場合、for文でまわした方が記述量が少なく間違いが少なくなります。3個場合は、for文で書くよりベタ書きの方がすっきりします。以下がfor文のサンプル例です。
for(i=2;i>0;i--){ data[i] = data[i-1]; } data[0]=RCREG;
PIC16F687の受信フラグRCIFはソフトウェアから書き込みができない仕様になっています。すべてハードウェア側で管理されていて、RCIFのフラグをクリアするには、RCREGを読み込む必要があります。
最後に、受信データを7セグに送るデータの作成です。受信データはアスキー形式で送られてきます。そのデータを7セグのカソード制御に使用すると思いもよらない表示になります。つまり、アスキーデータを7セグのカソード制御データに変換する必要があります。簡単に計算式でかけるなら苦労はしないのですが、簡単に計算式が作れないため、if文または、swith文で記述します。
void seg(unsigned char data) { if(data=='0'){ PORTC = 0x28; }else if(data=='1'){ PORTC = 0xeb; }else if(data=='2'){ PORTC = 0x1a; }else if(data=='3'){ PORTC = 0x8a; }else if(data=='4'){ PORTC = 0xc9; }else if(data=='5'){ PORTC = 0x8c; }else if(data=='6'){ PORTC = 0x0c; }else if(data=='7'){ PORTC = 0xe8; }else if(data=='8'){ PORTC = 0x08; }else if(data=='9'){ PORTC = 0x88; }else if(data==' '){ PORTC = 0xff; } }
このままでも使える状態なのですか、上記のプログラムに0~9以外に” “(スペース)が入っています。これは、PDCAのCheckのところで、3桁の数字を表示することができるようになったが、一つ前のデータが残像として表示されることが分かり、改善として一度クリアしてからデータを書き込むようにしました。これがPDCAのActionです。
while(1){ seg(' ');//追加した個所 PORTA = 0xfb; seg(data[0]); __delay_ms(3); seg(' ');//追加した個所 PORTA = 0xef; seg(data[1]); __delay_ms(3); seg(' ');//追加した個所 PORTA = 0xdf; seg(data[2]); __delay_ms(3); }
これでPi:Co Classic Ver3 改造例 7セグ編は終了になります。