« なんとなくPICらしくなってきた(追記あり) | トップページ | やっと時刻が表示できたけれど.... »

2013年11月15日 (金)

ソース付き・ゴールが見えてきたGPSタイムの表示

GPS受信モジュールの測位情報の中にあるGPS時刻を目に見えるようにしようという試みです。

前回の記事に書いたように数値を7セグメントLEDで表示することはできるようになりました。あとはGPS受信モジュールから送られてくる測位情報(緯度経度などの位置情報と時刻情報他)を取得することが必要です。

測位情報はRS232Cのようなシリアル通信で送られてきます。一方PIC16F648Aにはシリアル通信機能(USART)がありますからGPS受信モジュールが垂れ流しで送信している測位情報を受信できるはずです。

もうめちゃくちゃたいへんだった(といって袋小路に陥って堂々巡りをしていたという意味ですが)のでその苦労話を書きたくてしようがないのですがひとまず結論だけ。

GPS受信モジュールの測位情報


これはGPS受信モジュールGM-316からデータを受信したら16進数にして右の二桁に表示しています。次のデータが来たら右の二桁を左の二桁に移動し新たに受信したデータを右に表示する、という操作を繰り返しています。

1秒間に500文字近いデータが送信されていますから7セグメントLEDは激しく点滅を繰り返していますがデータの送信が一段落すると表示は「0d/0A」で一時停止します。これはGM-316から送られてくるデータ(NMEA)の最後が必ずCR/LF復帰・改行)で終わっていることに対応しています。

他にも“$”の次は必ず“G”であることとか送信データの特徴も確認できました。
ここまでくれば測位情報から時刻を得て表示することはさほど難しくなさそうです。

(2013-11-15 21:42:42)
-------
ボーレートの設定でだいぶ手間取ったりしたので参考までにソースを添付しておきます。
間違っているとかこうした方がいいというコメントは大歓迎ですが、ダサいとか目が回るというコメントは勘弁してください (^^;;


LIST P=pic16f648a
#include <p16f648a.inc>

; シリアル受信データを四桁7セグメントLEDに垂れ流し表示

; ピンアサイン - 括弧内はDIPのピン番号
; LEDはアノードコモンを使っています。
; オープンドレインのピンがあるのでカソードコモンを使うときは注意してください。
; PGC、PGD、VppはPICKit3をはずさないでテストできるように使っていません。

; RA0(17) 7seg.LED - A
; RA1(18) 7seg.LED - B
; RA2(01) 7seg.LED - C
; RA3(02) 7seg.LED - D
; RA4(03) 7seg.LED - E
; RA5(04) - Vpp/MCLR
; RA6(15) 7seg.LED - F
; RA7(16) 7seg.LED - G
; RB0(06) 7seg.LED - Digit1(いちばん右)
; RB1(07) - RX
; RB2(08) - TX
; RB3(09) 7seg.LED - Digit2
; RB4(10) 7seg.LED - Digit3
; RB5(11) 7seg.LED - Digit4
; RB6(12) - PGC
; RB7(13) - PGD
; VSS(05)
; VDD(14)

; _INTOSC_OSC_NOCLKOUT と _MCLRE_OFF を同時にしてすると警告されます (^^;;
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _CP_OFF

; アセンブルのときMessageが出るのが嫌いなのでBank1のレジスタは再定義してあります。
; 再定義してあるレジスタをバンク切り替えなしにつ使っていたらどこか間違ってます。
_OPTION EQU H'01'
_TRISA EQU H'05'
_TRISB EQU H'06'
_PIE1 EQU H'0C'
_TXSTA EQU H'18'
_SPBRG EQU H'19'

CBLOCK 20h
DG1 ; 表示データ下位バイト(7セグメントLEDのDigit1、Digit2)
DG2 ; 表示データ上位バイト(7セグメントLEDのDigit3、Digit4)
PON ; 表示データ制御用(表示スべき桁-1)
SAVE_W ; 割り込みルーチンのレジスタ退避用
SAVE_S ; 〃 ほんとはスタックにすべきだと思います。
TMP ; 表示用データの変換用作業領域
BUF ; 受信データのバッファ
ENDC

ORG H'0000'
GOTO INIT

; 割り込みルーチン(タイマー割り込み用)
ORG H'0004'
; レジスタの退避
; 割り込みの使い方 http://www.picfun.com/pic08.html を参考にさせていただきました。
; 二種類以上の割り込みがあるときこれでいいのか?スタックを使うべき?
MOVWF SAVE_W
SWAPF STATUS,W
MOVWF SAVE_S
; LED消灯
MOVLW 0x00
MOVWF PORTB
; PONがNのとき右からN+1桁目の表示
DECFSZ PON,F
GOTO NEXT1
; 一桁目の表示(DG1の下位4ビット)
MOVF DG1,W
CALL SETP
MOVWF PORTA

MOVLW b'00000001'
MOVWF PORTB

MOVLW 4
MOVWF PON
GOTO PEND

; 二桁目の表示(DG1の上位4ビット)
NEXT1 BTFSC PON,1
GOTO NEXT2
MOVF DG1,W
MOVWF TMP
SWAPF TMP,W
CALL SETP
MOVWF PORTA
MOVLW b'00001000'
MOVWF PORTB
GOTO PEND

; 三桁目の表示(DG2の下位4ビット)
NEXT2 BTFSC PON,0
GOTO NEXT3
MOVF DG2,W
CALL SETP
MOVWF PORTA

MOVLW b'00010000'
MOVWF PORTB
GOTO PEND

; 四桁目の表示(DG2の上位4ビット)
NEXT3 MOVF DG2,W
MOVWF TMP
SWAPF TMP,W
CALL SETP
MOVWF PORTA

MOVLW b'00100000'
MOVWF PORTB

PEND
; 本処理に戻る前にタイマー割り込みを有効にします
; なおUSARTのときはこういう操作は不要です。
BCF INTCON,T0IF

; 最初USARTも割り込みで処理していたのでエントリーが作ってあります。
; 退避していたレジスタを戻します。
: 割り込みの使い方 http://www.picfun.com/pic08.html を参考にさせていただきました。
ENDI SWAPF SAVE_S,W
MOVWF STATUS
SWAPF SAVE_W,F
SWAPF SAVE_W,W
RETFIE

; 16進一桁のデータをLEDの表示セグメントに変換します。
; 上位桁(上位4ビット)はマスクします。
SETP ANDLW 0x0F
ADDWF PCL,F
RETLW b'10000000' ; '0'
RETLW b'11011001' ; '1'
RETLW b'01000100' ; '2'
RETLW b'01010000' ; '3'
RETLW b'00011001' ; '4'
RETLW b'00010010' ; '5'
RETLW b'00000010' ; '6'
RETLW b'11011000' ; '7'
RETLW b'00000000' ; '8'
RETLW b'00011000' ; '9'
RETLW b'00001000' ; 'A'
RETLW b'00000011' ; 'B'
RETLW b'01000111' ; 'C'
RETLW b'01000001' ; 'D'
RETLW b'00000110' ; 'E'
RETLW b'00001110' ; 'F'

; 電源投入後の実行ポイント
; CLRWDT はタイマー割り込みを行うための準備です
; (データシートにこうしろと書いてありました)
INIT CLRWDT

; Bank1
BSF STATUS,RP0

; タイマーの分周比はLED表示の見栄えを考えながらお好みで.... 
MOVLW b'00000010'
MOVWF _OPTION

MOVLW B'00100000'
MOVWF _TRISA

; USARTを使うために<2:1>をセットします。
MOVLW B'11000110'
MOVWF _TRISB

; Bank0
BCF STATUS,RP0

MOVLW B'00000111'
MOVWF CMCON

; LED消灯
MOVLW 0x00
MOVWF PORTB
MOVLW 0xFF
CLRF PORTA

; タイマー割り込みの周期の設定(プリスケーラ-はOPTIONにあります)
; LED表示の見栄えを考えながらお好みで.... 
MOVLW 0x00
MOVWF TMR0
; 全般的な割り込み許可
BSF INTCON,GIE
; タイマー割り込み許可
BSF INTCON,T0IE
; ペリフェラルの割り込み許可(USARTの割り込みを許可する場合にセットします)
; さらに_PIE1<RCIE>のセットも必要です。
BSF INTCON,PEIE

; Bank1
BSF STATUS,RP0

; USARTも割り込みで処理するときは_PIE1<RCIE>をセットします。
; BSF _PIE1,RCIE

; USART非同期通信
BCF _TXSTA,SYNC
; USARTボーレートジュネレーターをHighスピード設定にします。
; Lowスピード設定よりボーレートの誤差が出にくいはずです。
BSF _TXSTA,BRGH
; ボーレートジュネレータの設定です
; USARTボーレートHighスピード設定で4MHzクロック、4800bpsの場合です
; (データシートの計算式と表参照)
MOVLW 0x33
MOVWF _SPBRG

; Bank0
BCF STATUS,RP0

; USARTパリティーなし
; (パリティーありにしてもパリティーは自分で作る必要があったような....)
BCF RCSTA,RX9
; USART・受信の使用を可能にします。
BSF RCSTA,SPEN
; USART連続受信可(意味はよくわからないがデータシートにはこうしろと書いてあったような....)
BSF RCSTA,CREN

; 表示桁位置の制御用
MOVLW 4
MOVWF PON

; 受信データがあるかチェックします。
MAIN BTFSS PIR1,RCIF
GOTO MAIN

; フレームエラーがあるかチェックします。
BTFSC RCSTA,FERR
GOTO M_FERR
; オーバーランエラーがあるかチェックします。
BTFSC RCSTA,OERR
GOTO M_OERR

; DG1のデータをDG2に移動し受信データをDG1にコピーします。
; 受信データを取得することによてPIR1<RCIF>はクリアされます。
; 割り込み中の処理であればこれによって割り込みが可能になります。
; PIR1<RCIF>はRead Onlyなのでこれをクリアするのは無意味です。
MOVF DG1,W
MOVWF DG2
MOVF RCREG,W
MOVWF DG1
GOTO MAIN

; フレームエラー
; ボーレートが間違っているかシリアルデータの品質に問題があります。
; データを読み込むことによってRCSTA<FERR>はクリアされます。
; エラー処理は適当です。
M_FERR MOVLW 0xFF
MOVWF DG1
MOVF RCREG,W
GOTO MAIN

; オーバーランエラー
; 処理が間に合っていない?
; RCSTA<CREN>をクリアして再度セットします。
; エラー処理は適当です。
M_OERR BCF RCSTA,CREN
BSF RCSTA,CREN
MOVLW 0xFE
MOVWF DG1
GOTO MAIN

END



(2013-11-16 00:50:11, 2013-11-16 07:23:18)
------
ほよほよさんのコメントを参考にRRFを四回使っているところをSWAPFを使う方法に変えました。
割り込み処理時のレジスタの退避について参考にしたサイトを追記しました。

(2013-11-16 10:39:57)
------

関連記事

  「時刻標準のまとめと関連記事一覧編集

« なんとなくPICらしくなってきた(追記あり) | トップページ | やっと時刻が表示できたけれど.... »

編集用」カテゴリの記事

コメント

この記事へのコメントは終了しました。

フォト

サイト内検索

  • 記事を探されるんでしたらこれがいちばん早くて確実です。私も使ってます (^^;; 検索窓が表示されるのにちょっと時間がかかるのはどうにかしてほしいです。

新着記事

リンク元別アクセス数

  • (アクセス元≒リンク元、原則PCのみ・ドメイン別、サイト内等除く)

人気記事ランキング

  • (原則PCのみ、直近2週間)
無料ブログはココログ