PIC18F14K50は16ビットアーキテクチャを
持った次世代PICである。
メモリが大きいので C言語に向いている
今回はアセンブラで組んでみよう
回路は下記である (別紙参照)
PIC18は本も掲載記事も少ないので、苦労する
難解なマニュアルを片手に試行錯誤してみた
PIC16と同じようにプログラムを組んだが、動かないのである、
PIC18は機能が増えて、I/Oがアナログとデジタル設定がるのである。
そのまま使うと、出力はできるが、KEYのON-OFF入力はできないのである
CLRF ANSEL
CLRF ANSELH
この命令で I/Oポートをデジタル設定にしておく。下記はポートの入出力設定である
内部クロックは表を参考に設定するとよい
movlw B'01100010' ;内部8Mクロック
movwf OSCCON ;w---> OSCCON
movlw B'10000000' ;0= 出力
movwf TRISC
movlw B'00110000' ;1= 入力
movwf TRISB
movlw B'11111111' ;1= 入力
movwf TRISA
さて、プログラムの全体像である
LCDにキャラクタを表示させ、テーブルの文字を表示させる
次に
LEDを点滅させる。 KEYスイッチを押すと、LEDのオレンジと緑の点滅が切り替わる
crt_lcd:
TBLRD*+
movF TABLAT,w ;TABLAT---->w
call wordcp
btfss endflg,0 ;0bit=0 次命令スキップ
goto crt_lcd1
return
crt_lcd1:
movF TABLAT,w ;TABLAT---->w
call cara_one
goto crt_lcd
;return
LCD SC2004は 4行表示できるので 行を設定
Yloca0 macro 1行目
movlw 1
movwf Yziku
call zahyou
endm
Yloca1 macro 2行目
movlw 2
movwf Yziku
call zahyou
endm
Yloca2 macro 3行目
movlw 4
movwf Yziku
call zahyou
endm
Yloca3 macro 4行目
movlw 8
movwf Yziku
call zahyou
endm
データを保管する場所をレジスタに割り当てる
CBLOCK 020h
tim1
tim2
mem1
mem2
lcddat
Xziku
Yziku
endflg
ENDC
CONFIGで内部クロックを使う設定をしておこう
PIC16F84は古いマイコンなので、内部クロックが無いが、最近のPICは殆どが内部クロック
を持っている
CONFIG FOSC = IRC ;内部クロック設定
ーーーーーーーーーーーーーーーーーーーーーー
下記は 定型文と思っていた方がよいだろう
LIST P=PIC18F14K50
INCLUDE "P18F14K50.INC"
; TODO INSERT CONFIG CODE HERE USING CONFIG BITS GENERATOR
CONFIG USBDIV = OFF ;USB CLOCK SELECTION BIT
CONFIG MCLRE = OFF ;MCLR PIN ENABLE BIT
CONFIG IESO = OFF ;Internal/External Oscillator Switchover bit
CONFIG FCMEN = OFF ;Fail-Safe Clock Monitor Enable bit
CONFIG FOSC = IRC ;OSCILLATOR SELECTION BITS
CONFIG PWRTEN = ON ;Power-up Timer Enable bit
CONFIG PLLEN = OFF ;X PLL ENABLE BIT(OSCILLATOR MULTIPLIED BY 4)
CONFIG PCLKEN = OFF ;PRIMARY CLOCK ENABLE BIT
CONFIG BOREN = OFF ;Brown-out Reset Enable bits
CONFIG LVP = OFF ;Single-Supply ICSP Enable bit
CONFIG CPUDIV=NOCLKDIV ;CPU SYSTEM CLOCK SELECTION BIT
CONFIG CP0 = OFF ;Code Protection bit
CONFIG CP1 = OFF ;Code Protection bit
CONFIG CPD = OFF ;Data EEPROM Code Protection bit
CONFIG CPB = OFF ;Boot Block Code Protection bit
CONFIG WDTEN = OFF ;Watchdog Timer Enable bit
CONFIG HFOFST = OFF,STVREN = OFF,BBSIZ = OFF,XINST = OFF
CONFIG EBTR0 = OFF,EBTR1 = OFF,EBTRB = OFF
ポート出力をわかりやすく 疑似表示させるため、#define を使う
#define LCD_RS PORTC,5
#define LCD_E PORTC,4
#define LED_G LATB,6
#define LED_R LATB,7
#define KEY1 PORTB,4
#define KEY2 PORTB,5
タイマーのルーチンである。
PIC16は 8ビットなので
goto $+1 でよいが、 PIC18は goto $+2 にする必要がある
----------タイマー 8MHZの時---(10us)-------------------
t10us:
goto $+2
goto $+2
goto $+2
goto $+2
nop
return
PICで1cara を表示させるのに、いちいちLCDへキャラを送るのは、現実的ではない
ここは DB テーブルを使いたい
例えば DBテーブルに表示させたい文面を記載して
CALL することで、一気に表示させたい
C言語の場合は簡単だが、アセンブラはちょっと工夫が必要である。
moji2 DB "Prog by Majima$"
テーブル moji2 を$まで、表示させてしまうプログラムである。
--------------------------------
movlw HIGH moji2
movwf TBLPTRH ;w-->TBLTRH
movlw LOW moji2
movwf TBLPTRL
call crt_lcd
--------------------------------
テーブルアドレスは16BITなので HIGHとLOW を設定して moji2 の先頭アドレス
から TBLPTRL で 文字をwへ取得している
連続して取り出し
「$」が来ると終了するのである
LCDの1行目に 「A] と言う文字を表示させるには 下記の表記になる
Yloca0
movlw 041H
call cara_one
--------------------------------------------------
サブルーチン cara_one は 1文字をLCDに表示させるプログラムである
cara_one:
movwf lcddat
bsf LCD_RS
movlw 0F0h
andwf PORTC,F
swapf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
movlw 0F0h
andwf PORTC,F
movf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
call t1ms
return
ーーーーーーーーーーーーーーーーーーーーーー
下記は LCDで命令(コマンド)を1byte 送り込むプログラムである
LCD_command:
movwf lcddat
bcf LCD_RS ;0=制御
movlw 0F0h
andwf PORTC,F
swapf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
movlw 0F0h
andwf PORTC,F
movf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
call t1ms
return
;-------------------------------------------
wordcp:
btfsc TABLAT,0 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,1 ;0bit=0 次命令スキップ
goto wordcp_e
btfss TABLAT,2 ;0bit=1 次命令スキップ
goto wordcp_e
btfsc TABLAT,3 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,4 ;0bit=0 次命令スキップ
goto wordcp_e
btfss TABLAT,5 ;0bit=1 次命令スキップ
goto wordcp_e
btfsc TABLAT,6 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,7 ;0bit=0 次命令スキップ
goto wordcp_e
movlw 1
movwf endflg
return
wordcp_e:
movlw 0
movwf endflg
return
;
LIST P=PIC18F14K50
INCLUDE "P18F14K50.INC"
; TODO INSERT CONFIG CODE HERE USING CONFIG BITS GENERATOR
CONFIG USBDIV = OFF ;USB CLOCK SELECTION BIT
CONFIG MCLRE = OFF ;MCLR PIN ENABLE BIT
CONFIG IESO = OFF ;Internal/External Oscillator Switchover bit
CONFIG FCMEN = OFF ;Fail-Safe Clock Monitor Enable bit
CONFIG FOSC = IRC ;OSCILLATOR SELECTION BITS
CONFIG PWRTEN = ON ;Power-up Timer Enable bit
CONFIG PLLEN = OFF ;X PLL ENABLE BIT(OSCILLATOR MULTIPLIED BY 4)
CONFIG PCLKEN = OFF ;PRIMARY CLOCK ENABLE BIT
CONFIG BOREN = OFF ;Brown-out Reset Enable bits
CONFIG LVP = OFF ;Single-Supply ICSP Enable bit
CONFIG CPUDIV=NOCLKDIV ;CPU SYSTEM CLOCK SELECTION BIT
CONFIG CP0 = OFF ;Code Protection bit
CONFIG CP1 = OFF ;Code Protection bit
CONFIG CPD = OFF ;Data EEPROM Code Protection bit
CONFIG CPB = OFF ;Boot Block Code Protection bit
CONFIG WDTEN = OFF ;Watchdog Timer Enable bit
CONFIG HFOFST = OFF,STVREN = OFF,BBSIZ = OFF,XINST = OFF
CONFIG EBTR0 = OFF,EBTR1 = OFF,EBTRB = OFF
CBLOCK 020h
tim1
tim2
mem1
mem2
lcddat
Xziku
Yziku
endflg
ENDC
; 行
Yloca0 macro
movlw 1
movwf Yziku
call zahyou
endm
Yloca1 macro
movlw 2
movwf Yziku
call zahyou
endm
Yloca2 macro
movlw 4
movwf Yziku
call zahyou
endm
Yloca3 macro
movlw 8
movwf Yziku
call zahyou
endm
#define LCD_RS PORTC,5
#define LCD_E PORTC,4
#define LED_G LATB,6
#define LED_R LATB,7
#define KEY1 PORTB,4
#define KEY2 PORTB,5
;-----------------------------------------
RES_VECT CODE 0x0000 ; processor reset vector
GOTO START ; go to beginning of program
; TODO ADD INTERRUPTS HERE IF USED
MAIN_PROG CODE ; let linker place main program
START
CLRF ANSEL
CLRF ANSELH
movlw B'01100010' ;内部8Mクロック
movwf OSCCON ;w---> OSCCON
movlw B'10000000' ;0= 出力
movwf TRISC
movlw B'00110000' ;1= 入力
movwf TRISB
movlw B'11111111' ;1= 入力
movwf TRISA
MAIN
bsf LED_G ;緑
bsf LED_R ;オレンジ
call t1s
bcf LED_G
bcf LED_R
call t1s
call lcd_init
Yloca0
movlw B'00110001'
call cara_one
Yloca1
movlw 041h
call cara_one
movlw 042h
call cara_one
Yloca2
movlw HIGH moji2
movwf TBLPTRH ;w-->TBLTRH
movlw LOW moji2
movwf TBLPTRL
call crt_lcd
LOOP:
bsf LED_G
call t500ms
bcf LED_G
call t500ms
btfss KEY2 ;1ならば JMP次行?
goto LOOP11
nop
GOTO LOOP
LOOP11:
bsf LED_R
call t500ms
bcf LED_R
call t500ms
btfss KEY1
goto LOOP
nop
goto LOOP11
GOTO MAIN ; loop forever
;-------------------------------------------
wordcp:
btfsc TABLAT,0 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,1 ;0bit=0 次命令スキップ
goto wordcp_e
btfss TABLAT,2 ;0bit=1 次命令スキップ
goto wordcp_e
btfsc TABLAT,3 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,4 ;0bit=0 次命令スキップ
goto wordcp_e
btfss TABLAT,5 ;0bit=1 次命令スキップ
goto wordcp_e
btfsc TABLAT,6 ;0bit=0 次命令スキップ
goto wordcp_e
btfsc TABLAT,7 ;0bit=0 次命令スキップ
goto wordcp_e
movlw 1
movwf endflg
return
wordcp_e:
movlw 0
movwf endflg
return
crt_lcd:
TBLRD*+
movF TABLAT,w ;TABLAT---->w
call wordcp
btfss endflg,0 ;0bit=0 次命令スキップ
goto crt_lcd1
return
crt_lcd1:
movF TABLAT,w ;TABLAT---->w
call cara_one
goto crt_lcd
;return
;--------------------------
cara_one:
movwf lcddat
bsf LCD_RS
movlw 0F0h
andwf PORTC,F
swapf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
movlw 0F0h
andwf PORTC,F
movf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
call t1ms
return
LCD_command:
movwf lcddat
bcf LCD_RS ;0=制御
movlw 0F0h
andwf PORTC,F
swapf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
movlw 0F0h
andwf PORTC,F
movf lcddat,w
andlw 0Fh
iorwf PORTC,F
bsf LCD_E
nop
bcf LCD_E
call t1ms
return
lcd_init:
call t100ms
bcf LCD_RS ;0=制御モード 1=データモード
bcf LCD_E ;E=0-->1で書き込み
call t10ms
;1) 0011-0000
movlw 0F0h
andwf PORTC,w
iorlw 03h ;1
movwf PORTC ;w--->LCD_DATへ格納
bsf LCD_E
nop
bcf LCD_E
call t10ms
movlw 0F0h
andwf PORTC,w
iorlw 03h ;2
movwf PORTC ;w--->LCD_DATへ格納
bsf LCD_E
nop
bcf LCD_E
call t10ms
movlw 0F0h
andwf PORTC,w
iorlw 03h ;3
movwf PORTC ;w--->LCD_DATへ格納
bsf LCD_E
nop
bcf LCD_E
call t10ms
movlw 0F0h
andwf PORTC,w
iorlw 02h
movwf PORTC ;w--->LCD_DATへ格納
bsf LCD_E
nop
bcf LCD_E
call t1ms
movlw 028h
call LCD_command
call LCD_off
call LCD_cls
movlw 06h
call LCD_command
call LCD_on
bsf LCD_RS ;1=データモード
return
LCD_home:
movlw 02h
call LCD_command
return
LCD_cls:
movlw 01h
call LCD_command
return
LCD_off:
movlw 08h
call LCD_command
return
LCD_on:
movlw 0Ch
call LCD_command
return
LCD_2line:
movlw 0C0h
call LCD_command
return
LCD_3line:
movlw 094h
call LCD_command
return
LCD_4line:
movlw 0D4h
call LCD_command
return
zahyou:
btfss Yziku,0 ;0bit=1 次命令スキップ
goto zahyou_1
movlw 080h
goto zahyou_e
zahyou_1:
btfss Yziku,1 ;1bit=1 次命令skip
goto zahyou_2
movlw 0C0h
goto zahyou_e
zahyou_2:
btfss Yziku,2 ;2bit=1 次命令skip
goto zahyou_3
movlw 094h
goto zahyou_e
zahyou_3:
movlw 0D4h
zahyou_e:
;addwf Xziku
call LCD_command
return
;----------タイマー 8MHZの時---(10us)-------------------
t10us:
goto $+2
goto $+2
goto $+2
goto $+2
nop
return
t500us:
movlw D'50' ;w <---89
movwf tim1 ;レジスタを使用する
t500us_1:
call t10us
decfsz tim1,f ;0でなければ次の行、違えば 次は飛ばす
goto t500us_1
nop
return
t1ms:
movlw D'100' ;
movwf tim1 ;レジスタを使用する
t1ms_1:
call t10us
decfsz tim1,f ;0でなければ次の行、違えば 次は飛ばす
goto t1ms_1
nop
goto $+2
return
;-------- 25000サイクル--------------
t10ms:
movlw D'10'
movwf tim2
t10ms_1:
call t1ms
decfsz tim2,f
goto t10ms_1
nop
return
;-------- 250000サイクル--------------
t100ms:
movlw D'10'
movwf tim2
t100ms_1:
call t1ms
call t1ms
decfsz tim2,f
goto t100ms_1
nop
return
;-------- 1250000サイクル--------------
t500ms:
movlw D'250'
movwf tim2
t500ms_1:
call t1ms
call t1ms
decfsz tim2,f
goto t500ms_1
nop
return
;----------------------
t1s:
movlw D'250'
movwf tim2
t1s_1:
call t1ms
call t1ms
call t1ms
call t1ms
decfsz tim2,f
goto t1s_1
nop
return
moji1 DB 045H
moji2 DB "Prog by Majima$"
END
工事中ーー