PICをアセンブリ言語のプログラムで使う、は新記事の公開を終了します。
アセンブリ言語で、LCD表示器を使う、ハードウエア編。
今回は、LCD表示器に文字を表示します。
まずは回路ですが、下の通りです。
使用する、LCD表示器は、秋月電子で売っている超小型LCDキャラクタディスプレイモジュール(16×2行 白抜き)型番SD1602VBWB-XA-G-G(下写真)です。
LCDキャラクタディスプレイモジュール 表(文字表示面)
文字表示状況(写真は、違う型番のものですが、表示は同じです)右から光っているのがバックライトです。
LCDキャラクタディスプレイモジュール 裏
この表示器には、バックライト(裏面照明)がついており、15(+)・16(-)番ピンに電源を接続(電流制限抵抗が必要)するか、裏面のJ3パッドを短絡し、R9に100Ωの電流制限抵抗を接続すると点灯することができます。
なお、ピンの並びが、端から順番になっていないので、注意が必要です、また、このLCD表示器には、姉妹品があるのですが、物によってピン配置が異なるので、差し替える場合は注意が必要です。
さて、このLCD表示器は、データーラインが8ビットと4ビットのどちらかを選択して使用しなければなりません、ここでは、配線が少なくて済む4ビットモードで使います、したがって、回路図のLCD表示器のD0~D3端子(7~10番端子)は無接続になっています。
(メーカーのデータシートに、使わない端子は解放(無接続)にするよう書かれています、また、4ビットモードで使うとPICのピンが4つで済むので、空いた4つのピンを他に使えます)
ハードウエアの構成は決まったので、ブレッドボードに組んでおきます。
回路を組んだブレッドボード(もう、プログラムが走ってます)
次回から、LCD表示器のプログラムでの制御方法を勉強します。
アセンブリ言語で、LEDチカチカをやってみた。
アセンブリ言語でプログラムを書いて、LEDチカチカをやってみた。
下が、そのプログラム、40行まで、初期設定である。
29、30行で変数のラベルを設定。
34行からがメインプログラム、35行でメモリのバンクを1に変更。
(TRISレジスタがバンク1にあるから)
36,37行でPORTAおよびBを全部出力に設定。
38でメモリのバンクを0に戻す。
39、40行で、コンパレータをOFFにし、1、2、17、18ピンをデジタル入出力に設定。
上の続き。
42行はLIGHTというラベルを設定。
43行でLED点灯用データをWレジスタに入れる。
44行でWレジスタのデータをPORTBにいれて、LEDを点灯させる。
45行は、DELAYサブルーチン(待ち時間作成サブルーチン)に飛ぶ。
46行でPORTBをクリア(0にする)して、LEDを消す。
47行は、DELAYサブルーチンに飛ぶ。
48行で、LIGHT(ラベル)に飛ぶ。
以上で、42行から、48行までを永久に繰り返すことにより、LEDが点滅し続ける。
以下、サブルーチンの説明。
50行がDELAYサブルーチンの始まり、DELAYというラベルにした。
51行で、繰り返し回数データ(0FFh、10進数で255)をWレジスタに入れる。
52行で、Wレジスタのデータを変数COUNT1に入れる。
54行が繰り返しの始まり、LOOP1というラベルにした。
55行は、DELAYSサブルーチン(待ち時間作成サブルーチン)に飛ぶ。
56行は、COUNT1から1を引き、COUNT1が0でない時次の行に行き、0の時は、次の行をNOP命令にして実行後、その次(58行)の行に行く。
57行は、LOOP1に飛ぶ。
(54行から、57行までが255回繰り返されるとCOUNT1が0になり、58行が実行され、CALL命令の次の行に戻る。)
58行は、CALL命令の次の行に飛ぶ。
60行から、68行までは、54行から、57行までとほぼ同じ内容で、65行のみNOP命令になっているだけである。
CALL命令で、DELAYサブルーチンが呼び出されると、LOOP1を255回実行する内にLOOP2が255回呼び出され実行される、この実行時間をLEDの点灯および消灯時間にしている。
その時間は、アセンブリ言語ではほぼ正確に算出できる。
まず1命令の実行時間は、クロックが4MHzだから、1μSとなる。
では、命令の数を計算してみよう、命令の数が算出できれば、命令数✖1μSで、計算できる。
まず、50行から、DELAYはラベルであり命令ではないので、数えない。
51行と52行で、2命令。
55行はCALL命令で、2サイクル命令なので、2命令。
ここで60行に飛んで、61行と62行で2命令。
65,66,67行は、3命令で、254回繰り返すので、3✖254=762命令。
65,66,67行の最後の1回は、65.66,67(NOP命令になる)の3命令とリターン命令(2サイクル命令)で5命令。
つまり、DELAYSサブルーチンの命令数は、769命令。
56行にサブルーチンから戻ってくると、56、57行で2命令。
55行から、57行までは254回繰り返されるので、(2+769+2)✖254=196,342命令。
55行から、57行までの最後は、55行の762命令と56、57行の2命令とリターン命令の2命令で、766命令。
従って、全体の命令数は、51行と52行で、2命令と55~57行の196,342命令と55行から、57行までの最後の766命令で、合計197,110命令です。
時間は、197,110命令✖1μS=197.110mS=0.19711Sと言う事で、約0.2秒と言う事になります、したがって、LEDは0.2秒点灯し0.2秒消灯するを繰り返すことになります。
上のプログラムを実行させてみました。
PICの動作はいかにして開始されるか。
PICの動作開始は、どの様になっているのか。
1.PICが適正な回路で使用され、電源が投入される。
2.電源電圧が決まった値を超えると、リセット信号が出て、PICは動作停止状態になる。
3.その後、決まった時間待機してから、クロック信号をカウント開始。
4.クロックが正常に1024カウント出来たら、0x00から、プログラムを開始。
のようになります。
PICのプログラムメモリーは下のようになっています。
PICは0x00から動作を始めますが、上のように、割込み発生時には0x04から処理が開始されるようになっています。
何もしないと、命令は0x00から0x01へ、そして。0x02と順番に実行されるので、0x04から始まる割込み処理も次々と実行してしまいます。
そこで、それを回避するために、0x00にGOTO 0x08(0x04を回避すればよいので0x08でなくとも良い)を書き、ジャンプして避けています。
また、割込み発生時には、0x04から処理が開始されるので、そのままだと、メインルーチンの処理に入ってしまうので、ここでも、GOTO INTERRUPTとしてジャンプし、割込みルーチンに処理が行くようにプログラムします。
例; 下のプログラムは、時計用プログラムの一部です。
;******************************** ;以降はコメント文
; Jumping Vector
;********************************
ORG 0 ;ORG 0 は、次の命令は0x00に置くという命令です、したがって、0x00に、GOTO INIT が置かれます。
GOTO INIT
ORG 4 ;ORG 4 は、次の命令を0x04に置くという命令です、したがって、0x04に、GOTO INTRPT が置かれます。
GOTO INTRPT
ORG 08H ;ORG 08Hは、次の命令を0x08に置くという命令です、したがって、0x08に、INIT が置かれますので、0x08のラベルはINITです。
(すぐ下からコメント文が始まりますが、コメント文は無視されるので、INITになる。)
ここで、ORG 08H 命令が必要なのは、メインルーチンがどのアドレスから始まるか指定するためです、
これが決まると、これを基準に他のラベルや命令のアドレスは計算できるのです。
;************************************
; Initialize routine
; PORT A & B Initialize
; PORTA
; RA3,4 :AC SWITCH control output
; RA0,1,2:LCD control output
; PORTB
; lower:SWITCH input
; upper:LCD data output
;
; Timer initilize
;
;************************************
INIT ;ここから、メインルーチン
;**** CMCON mode set *****
MOVLW 07H ;degital mode
MOVWF CMCON ;CMCON set
;**** PORT mode set *****
BCF INTCON,GIE ;Interrupt Disable
BSF STATUS,RP0 ;Set page 1
中略
;*************************************************
; Timer interrupt routine
; This interrupt occur every 3.125KHz
; So count this interrupt until 3125 times,
; then second count +1.
;*************************************************
INTRPT ;ここから、割込みルーチン
;**** save each register *******
MOVWF WR_SV ;save wreg
SWAPF STATUS,W ;save status
MOVWF STA_SV
;**** last pulse check ****
BCF INTCON,T0IF ;int flag reset
以下省略。
のように、プログラムを作ります。