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

PIC1814K50でLCDを表示させる

さて、プログラムの全体像である
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

$がきたら、終了するプログラムである
$=24Hを比較するが、AVRのような CP 命令が見当たらないので、
bitfsc ,を用いて作ってみた

;-------------------------------------------
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

工事中ーー