PICアセンブラ#01-タイミング
別の記事にタイミング用(時間消耗用)のルーチンを載せましたが、一部でなく全体のコーディングが知りたい方がおられますので、この際きちんと書いて、測定についても載せておきます。前の記事はこれです。
プレゼンタイマー(PICアセンブラー版) - 勝手な電子工作・・
測定のための回路ですから簡単です。しかしタイミングのテストですのでオシレータは内部オシレータではなく外部のクリスタルを使ってみます。
上の図でクリスタルに16MHzを使います。一般的にその先は22pFを介してグラウンドに落としますが、+側につないでも同じことですね。配線の都合の良い方で大丈夫。
そして、例えば次のコーディングをします。ここでは、タイミング用のルーチンはいつも同じなので、自分で作ったマクロ、Cblock(ファイル)、サブルーチンを.incファイルとしてIncludeしていますが、そこに直接中身を書いても同じことです。後ろにそれぞれのincファイル内容も示します。
ところで、このコーディングの中のinclude文の後ろには<>でファイル名が書かれていますが、それが表示されないようです。やむを得ず{}を書いておきますから、そこを<>に置き換えてください。すみません。
;Utime-test-V00-01.asm As of Sept.24, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Testing time-consuming routines ;
; All rights reserved. 2018(C) Akira Tominaga ;
; ;
; Function ;
; Timing measurement with logic analyzer ;
; ;
; Input/Output for 12F1822 or 16F1823 ;
; RA0 LED output (on =H) ;
; RA1 Timing signals ;
; RA4 and RA5 for Xtal Oscillator (HS:High speed) ;
; ;
; Remarks ;
; 1. Clock = High speed Xtal (16MHz) ;
; Hence 1 step = 0.250 micro seconds ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
list p=12F1822 ; list directive to define processor
#include {p12F1822.inc}; processor specific variable definitions
__CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macro definitions ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Device dependent Macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DEVset macro
BANKSEL OSCCON ; Bank=1
movlw B'00000000' ; HS 16MHz Xtal oscillator
; movlw B'01111010' ; Comment for 16MHz internal oscillator
movwf OSCCON
;
; BANKSEL INTCON ; Interrupt Con (in all banks hence comment)
clrf INTCON ; Disable all interrupts
;
; PORTA initialization
BANKSEL PORTA ; Bank=0
clrf PORTA
BANKSEL LATA ; Bank=2
clrf LATA
BANKSEL ANSELA ; Bank=3
clrf ANSELA ; No use of ADC
BANKSEL ADCON0 ; Bank=1
clrf ADCON0 ; No use of ADC
;
BANKSEL TRISA ; Bank=1
movlw B'11111100' ; RA0 and RA1 are output
movwf TRISA
;
; BANKSEL OPTION_REG ; Bank=1
bcf OPTION_REG,7 ; Enable weak pull-up
BANKSEL WPUA ; Bank=4
movlw B'00001100' ; Weak Pull-up for RA2 and 3
movwf WPUA ;
;
clrf BSR ; Bank=0
movlw B'11111100' ; Initialize PORT
movwf PORTA
goto $+1
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; General purpose macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include {at-Mtime.inc}
#include {at-Mdebug.inc}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files and Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cblock H'20' ; H'20' to H'6F', 80bytes for 12F1822,etc.
; For application
LoopC ; Loop counter
endc
;
; For utilities
#include {at-Ctime.inc}
#include {at-Cdebug.inc}
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;******************************** ** Comments for real connections
; For PORTA * ** to secure device independence
;******************************** ** Change when PORTs changed **
;LED equ 0
;Tsig equ 1 ; Test signal
;
;********************************
; For logical PORTled * ** Change when PORTled changed **
;********************************
PORTled equ PORTA ; PORT for LED
LED equ 0 ; LED bit
;
;;********************************
; For logical PORTtst * ** Change when PORTtst changed **
;********************************
PORTtst equ PORTA ; PORT for test
Tsig equ 1 ; Test signal bit for measurement
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Values ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ten equ D'10'
Five equ 5
Three equ 3
Two equ 2
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Flags Byte ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Equ's for utilities ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include {at-Edebug.inc}
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initializing ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 0
goto Startp ; Go to start entry
org 4 ; This is Interrupt entry
retfie ; If here, then return
;
Startp clrf Flags ; Clear debugging flags
DEVset ; Define ports and set initial values
;
LEDon ; Show that I am awake
Millin D'100' ;
LEDoff ;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main program ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp equ $
;
; 1 micro sec x 3
movlw Three
movwf LoopC
Mic1x3 bsf PORTtst,Tsig
goto $+1 ; 0.5 micro sec
nop ; 0.25/0.75 micro sec
bcf PORTtst,Tsig
decfsz LoopC,F ; 0.25 micro sec
goto Mic1x3 ; 0.75 micro sec
;
; 3 micro sec x 1 (test Mic2n 1)
Mic3t bsf PORTtst,Tsig
Mic2n 1 ; 2.0
goto $+1 ; /2.5 micro sec
nop ; /2.75 micro sec
bcf PORTtst,Tsig
Mic2n 1 ; 2.0
goto $+1 ; /2.5 micro sec
nop ; /2.75 micro sec
;
; 5 micro sec x 1 (test Mic2n 2)
Mic5t bsf PORTtst,Tsig
Mic2n 2 ; 4.0
goto $+1 ; /4.5 micro sec
nop ; /4.75 micro sec
bcf PORTtst,Tsig
Mic2n 2 ; 4.0
goto $+1 ; /4.5 micro sec
nop ; /4.75 micro sec
;
; 10 micro sec x 1 (test Mic2p5n x 3)
Mic10t bsf PORTtst,Tsig
Mic2p5n 3 ; 7.5
Mic2n 1 ; 9.5
nop ; 9.75
bcf PORTtst,Tsig
Mic2p5n 3 ; 7.5
Mic2n 1 ; 9.5
nop ; 9.75
;
; 11 micro sec x 1 (test Mic5n x 2)
Mic11t bsf PORTtst,Tsig
Mic5n 2 ; 10
goto $+1 ; /10.5
nop ; /10.75
bcf PORTtst,Tsig
Mic5n 2 ; 10
goto $+1 ; /10.5
nop ; /10.75
;
; 51 micro sec x 1 (test Mic50n x 1)
Mic51t bsf PORTtst,Tsig
Mic50n 1 ; 50
goto $+1 ; /50.5
nop ; /50.75
bcf PORTtst,Tsig
Mic50n 1 ; 50
goto $+1 ; /50.5
nop ; /50.75
;
; 101 micro sec x 1 (test Mic50n x 2)
Mic101t bsf PORTtst,Tsig
Mic50n 2 ; 100
goto $+1 ; /100.5
nop ; /100.75
bcf PORTtst,Tsig
Mic50n 2 ; 100
goto $+1 ; /100.5
nop ; /100.75
;
; End of timing test
Secn 1 ; wait for 1 sec
goto Mainp ; and loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Subroutines ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Utility subroutines ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include {at-Rtime.inc}
#include {at-Rdebug.inc}
;
end
Include命令にはタグと同じ<>が入りますから、ここへコードを載せるのに少し苦労してしまいました^^;それでもわかりません。しかたがないので、<>をすべて{}で置き換えて入れてありますので、ご注意ください。
このプログラムを実行して、ロジックアナライザーで測定をすると、タイミングはぴったりになっていることがわかります。最初のアウトプットの箇所です。
次に各ファイル(マクロat-Mtime.inc, Cブロックat-Ctime.inc, サブルーチンat-Rtime.inc)を示します。
まずマクロです。
;at-Mtime.inc - Time macros by Akira Tominaga V08.01
; Mic,Mic2n,Mic2p5n,Mic5n,Mic50n,Millin,Mill100n,Secn,Minn
; As of Sept.16, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Constant time consuming ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic macro ; Consume 1 μS only
goto $+1
goto $+1
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Time macros with number to multiply ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2n macro mic2p ; Consume 2μS x n
movlw mic2p
call Mic2r
endm
;
Mic2p5n macro mic25p ; Consume 2.5μS x n
movlw mic25p
call Mic25r
endm
;
Mic5n macro mic5p ; Consume 5μS x n
movlw mic5p
call Mic25r
movlw mic5p
call Mic25r
endm
;
Mic50n macro mic50p ; Consume 50μS x n
movlw mic50p
call Mic50r
endm
;
Millin macro millip ; Consume 1mS x n
movlw millip
call Millir
endm
;
Mil100n macro mil100p ; Consume 100mS x n
movlw mil100p
call Mil100r
endm
;
Secn macro secp ; Consume Second x n
movlw secp
call Secr
endm
;
Minn macro minp ; Consume Minute x n
movlw minp
call Minr
endm
;
次にCブロックです。endcが済んだ後にcblockを書くと、前のcblockで使われた
次のデータアドレスから始まります。cblockとendcの間には余計なことを書けませんから、書きたいときはそのようにするわけです。つまりincludeの場合だけではなくいつでもそれができます。
;Ctime.inc - Constants for Time macros V08.01 Sept 17, 2018
cblock
Mic25c
Mic50c
Millic
Mil100c
Secc
Minc
endc
; Remarks: Do not change the sequences from Mic25c to Minc,
; to share the bytes with other sequential-usage purposes.
;
次にサブルーチンです。
;Rtime - Time consuming routines by Akira Toninaga V08-01
; As of Sept. 16, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Timing subrooutines for general purposes;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Make 2.0 micro S x n (Mic2n) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2r movwf Mic25c ; + Wset + call = 1 micro sec
;
Mic2l decfsz Mic25c,F ; If exhausted, 1 micro S hereafter
goto Mic2li ; else go out (2nd time 1.75 mic sec)
return
;
Mic2li goto $+1 ; (2nd time 2.25 mic sec)
nop ; (2nd time 2.5 mic sec)
goto Mic2l ; go back (2nd time 3 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Make 2.5 micro S x n (Mic2p5n) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic25r movwf Mic25c ; + Wset + call = 1 micro sec
nop ; 1.25 micro sec
;
Mic25l nop ; 1.5 micro sec (2nd time 4 mic sec)
decfsz Mic25c,F ; If exhausted, 1 micro S hereafter
goto Mic25li ; else go out (2nd time 2.25 mic sec)
return
;
Mic25li Mic ; (2nd time 3.25 mic sec)
goto Mic25l ; go back (2nd time 3.75 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 50 Microseconds x n Mic50n ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r movwf Mic50c ; set # of 50 microsecs (1 micro sec to here)
nop ; 1.25 micro sec up to here
;
Mic50l Mic2p5n D'19' ; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
nop ; + 0.25 = 49 micro sec (2nd time 99 mic sec)
;
decfsz Mic50c,F ; If exhausted then 1 mic S hereafter
goto Mic50li ; else go out (2nd time 49.75 mic sec)
return
;
;
Mic50li Mic ; (2nd time 50.75 mic sec)
goto Mic50l ; go back (2nd time 51.25 mic sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Milliseconds x n Millin ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir movwf Millic ; set # of 1 mil secs (1 mic S up to here)
nop ; 1.25 micro sec
;
Millil Mic50n D'19' ; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25)
Mic2p5n D'19' ; + 47.5 mic = 998.75 micro S (2nd, 1998.75)
nop ; +0.25 mic = 999 micro sec (2nd, 1999)
;
decfsz Millic,F ; If exhausted then 1 micro sec hereafter
goto Millili ; else go out (2nd, 999.75 mic S)
return
;
Millili Mic ; (2nd time 1000.75 mic S)
goto Millil ; go back (2nd time 1001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 100 Milliseconds x n Mil100n ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r movwf Mil100c ;set # of 100 ms(1 micr sec up to here)
nop ; 1.25 micro sec
;
Milhl Millin D'99' ;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
Mic50n D'19' ; + 950 mic = 99951.25 micS(2nd.199951.25mic)
Mic2p5n D'19' ; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
nop ; + 0.25 mic = 99999 mic S (2nd,199999 micS)
;
decfsz Mil100c,F ; If exhausted then 1 micro sec hereafter
goto Milhli ; else go out (2nd time, 99999.75 mic S)
return
;
Milhli Mic ; (2nd time, 100000.75 mic S)
goto Milhl ; (2nd time, 100001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Seconds x n Secn ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secr movwf Secc ; set # of seconds ( 1 mic sec up to here)
nop ; 1.25 micro sec
;
Secl Mil100n D'9' ;
Millin D'99' ; + 999 milli sec = 999001.25 micro sec
;
Mic50n D'19' ; + 950 mic = 999951.25 micro sec
Mic2p5n D'19' ; + 47.5 mic = 999998.75 micro sec
nop ; + 0.25 mic = 999999 micro sec
;
decfsz Secc,F ; If exhausted then 1 micro sec hereafter
goto Secli ; else, go out
return
;
Secli Mic
goto Secl ; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Minutes x n Minn ;
; Overhead ignored, that is only ;
; 751.25 Mic S even when 100 Min ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minr movwf Minc ;set # of minutes from parameter
;
Minl Secn D'60' ; 1 Seconds x 60
decfsz Minc,F
goto Minl
return
;
内部にタグのマークがあるコーディングでしたため、うまく表示するのがたいへんで結局あきらめて別文字を入れました。すみません。何かやりかたがあるのでしょうね、その知識がなくてすみません。後で調べてみます。
それはそうと、コーディング中にあるLEDonとLEDoffのマクロ命令ですが、これらはデバッグ用マクロの塊にしている、at-Mdebug.incの中で定義しています。これを開くと、読み手は混乱するでしょうから、該当のマクロだけをここに書いておきます。
LEDon macro
goto $+1
bsf PORTled,LED
goto $+1
endm
;
LEDoff macro
goto $+1
bcf PORTled,LED
goto $+1
endm
;
なぜgoto $+1があるかというと、ここでクロック2サイクルを消耗させるためです。PICでは同一ポートへのアクセスの間で2サイクルの間をとらないとIOが正しく動きません。このマクロの直前に何が書かれるかわからないわけで、同じPORTへの更新がないとは限りません。それでも大丈夫なように、PORT更新の前と後にそれぞれCPUクロック2サイクルを消耗させるのです。nop命令2個でもよいですが、そうすると全体でプログラムメモリーを4つ使うため、この命令で2つに減らすものです。
また、なぜPORT名を直接指定しないかといえば、このマクロはどのPICモデルでも共通に使いたいわけですし、そもそも、どのポートにLEDをつけるかというのも、配線の都合などで自由にしておきたいものです。ですから、論理的なポート名PORTledを定義し、プログラムの本体では PORTled equ PORTAとするもの。つまり「デバイスインデペンス」を確保するためです。このようなアセンブラーの組み方は、保守や変更を極めて容易にします。どのコンピュータでもプロのコーディングでは定石となっている、数あるテクニックの1つといえます。
(c)2018 Akira Tominaga, All rights reserved.