前回書いたとおり、磁気コンパスHMC5883L用のI2C通信ラインSCLとSDAを、TM1637の通信ラインCLKとDIOが共有しています。これで問題なく動いている訳をここで簡単に説明したいと思います。
前回の記事:a-tomi.hatenablog.com
回路図を再度見ます。
PICのI2Cモジュール(MSSPで、SPIと共通の回路です)を使う場合、PIC12F1822ではSCLはRA1でSDAはRA2でなければなりません。ここでは、それを使わずに自分ででコーディングすることにより、I2C用のピンが自由に選べるようにしています。同じルーチンは他のPICでもI2C接続用に使えます。
ところでなぜアセンブラーなのかと質問がありましたので、以下脱線気味ですがちょっと追加説明します。
PICを内蔵の16MHzクロックで動かす場合、通常の1マシンステップ実行に1/4µ秒、gotoやbtfscなどのジャンプ命令にその倍の1/2μ秒かかるため、正確なタイミングをプログラムできちんと作るのは簡単ではありません。例えば100KHzの通信プロトコルですとクロックラインはHとLを正確に5μ秒単位で往復しないといけません。その中でアプリケーション処理とデータラインの上げ下げなどを必要とします。
PICに標準装備されているMSSPモジュールを使えば、ライン信号のコントロールなどをハードウェアに任せられますが、ピン番号を自由にするためには、通常のデジタルピンとしての扱いをしなければなりません。C言語ではタイミングを作る上で無理が生じるため、機械語を直接作れるアセンブラーで書いているわけです。
ただしI2CデバイスもTM16xxもクロックに合わせて信号を検出するしかけとなっているので、クロック間隔が多少不揃いでも一応動きます。それで構わなければタイミングはC言語でも大丈夫ですが、小さいPICモデルを使う際はメモリーの制約が厳しくなります。アセンブラーですと上手に書けば資源はごく少しで済みます。
MSSPを使わない勝手な自作プログラム(RYO=ロールユアオウンと呼ばれます)の場合、TM16xxxxでもI2CプロトコルでもデータラインのLOWへの引っ張り合いによる過大電流防止のため、若干の抵抗値挿入が必要なことは前回簡単に説明しました。
それが回路図中のRiとRtです。目的が単にそれだけなら100-300Ωで十分ですが、大きな値ですと別の現象が起きます。データラインだけを見ると次のような接続になるからです。
それぞれのデバイスのプルアップ抵抗(Ri2cとRtm)は、各ICに入っているのではなく、ブレークアウトモジュール上で配線されています。
以下に、これがどのように影響するのか、そしてこの手品のような共有方法のしかけはどうなっているのかを説明します。
Ri2cは次の写真のように4.7KΩ(472)で、VCCとSDAラインの間の抵抗値を測っても同じく4.7KΩです。
それに対しTM1637は10KΩ(103)が付けられています。
ところがVCCとDIOの間の抵抗値を測るとほぼ5KΩです。IC内部の回路が影響しているかと思われます。なのでRtmは5KΩとみなければならないでしょう。(ちなみにVCCとCLKの間を測るとそちらは10KΩですが。)
各デバイスのデータラインが次の表の左の状態欄のようになったとき、上の図中のI,P,T各点の電位がどうなるかを次の表で示します。
そこに先程のプルアップ抵抗値と、Ri=1.2KΩ、Rt=1.5KΩを付けた場合に、左の状態でのI,P,T各電位は次の様に計算されます。その結果各デバイスからのL信号がどう認識されるかは、下表の右欄のようになります。瞬間的な話なので信号の変形も起きるかもしれませんがここでは無視しています。
この実験では比較的ゆっくりにして、I2Cのクロックは50KHz、TM16xxのクロックは25KHzで行っています。もちろんこのアプリケーションの実用上はそれで問題ないですが。
そもそもLやHとみなされる電圧の範囲はデバイスにより少し異なりますが、大まかには次のようになっています。
デバイスの通信に関する受信ピン(つまりRx)はシュミットトリガ入力が普通なので、しきい値外のL値がくるとヒステリシスにより前の値を維持します。つまり前の状態のHとみなされます。
PICではこの場合手作り通信のため、単にデジタル入力ピンとして扱われますので、普通のCMOS入力と同じく閾値外はどう扱われるかは不定です(MSSPでRxとして扱うときはシュミットトリガ入力です)。とはいえPICに到着する電圧が前の表のように閾値内ですから問題なくLに認識される筈です。
つまり、手品の種を明かせば「隣のデバイスは認識するが、さらに隣のデバイスは認識しないようにしている」つもりのわけです。
ロジックアナライザーで見ている限りはそのように動いており、エラーもおきません。コーディングでスイッチ部をバイパスして多数回テストをしても正常です。念のためにデバイスを別の個体と交換してみても大丈夫です。
上はP点のデータですが、PICからI2CへNack(H)を送っている部分でダメ押しの確認をします。もしうまく動いていなければラインを共有しているTM1637がそこへAck(L)を入れてしまいますが、そうはならずNack(H)として記録されています。
そもそもTM1637は何の文字でも8ビットがくれば無条件にAckだけ出してしまいます。随分単純化されたプロトコルです。上に書いた理屈からいって、隣のPICからのデータは必ず受信しているわけなので、そこへはAckを出しているはずですね。
そこでT点で同じ信号を測ってみますと次のようになっています。
やはり、このT点ではロジアナがNackでなくAckと認識しています。ここまでは種明かしの理屈通りのようです。
しかし、この際は念のためにデータラインの電圧がどうなっているのかをオシロで確認してみることにします。
確認に都合のよいのは、PICがI2Cで磁気コンパスとやりとり(50KHz)して6バイトを受け取り、すぐ次にTM1637へ文字を送る(25KHz)箇所でしょう。全部のやりとりが混じっていますから。まずP点を見てみます。
各箇所の電位(右端のスケール)はほぼ想定通りのところに見えます。ただし、この低速なのに信号が変形しているところも見られます。
次にI点を観察します。
左半分は自分とPICのやりとり、右はPICとTM1637のやりとりで、電位は想定通りの3種類を行き来しています。前述のPICからのNack箇所に少し邪魔がはいっているようにもみえます。
さて、最後にT点で確認をします。
これをみると、TM1637は隣のPICからだけではなく、なんと一軒先のI2C磁気コンパスからの信号を検知して、いていちいちAckを送っているではありませんか!これはびっくりで予想外。
ということは、TM1637はLのしきい値が想定より高いようです(シュミット・トリガ―入力を使っていないかも)。このAckがI2C側のプロトコルを邪魔していないのは、タイミングも符号も同じだからでしょうね。また、1か所のNackがもしAckに変っても、毎回シングルショットで測定するこの使い方では大丈夫なのですが、この場合Nackの受け側の磁気コンパスには届いていませんから、何も問題ありませんね。
全体を通してデータの授受は全て正常なのですが、完璧にするには抵抗値をさらにいじるべきかとも考えてしまいます。試しにTM側を2KΩにあげてみるとTM1637の受け取るデータに直ちにエラーが発生してしまいますので、そういう実験はここでやめ。
結論として、この方法で共有してちゃんと動きますがすみずみまで完璧とはいえません。実験や手品としてはとてもよいと思うのですが、表示だけならまだしも、他のデバイスでの大事なところには採用できませんね。
ですのでこの連載の次回からは、I2C用の2つのピンとTM16xx用の2つのピンを元通り分けた形で記述していくことにします。そもそもアセンブラーでの単純でピンが自由なI2C接続をご紹介するのが本当の目的ですので。
ただし、Clockラインのピンを共有するのは何も問題ないですね!そうすれば1ピン減らせます。そちらにしようかな・・。
最後にピンを元通りに分けたプログラムを載せておきます。TM16xxのピンの移動はPORTtmという箇所でのEquation2か所を直すだけで、他はプログラム自体の変更は何もありません。このようにプログラムを作るとピンの移動だけでなくPORTの移動も容易ですね。
;U190829-I2C&TM16-V01s.asm As of Aug. 31, 2019
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; I2C and TM16xx protocol demonstration, using PIC12F1822 - V00 ;
; (c)2010-2019 Akira Tominaga, All rights reserved. ;
; Major changes: ;
; V00: Initial version (Aug. 29, 2019) ;
; V01: Finish I2C & TM16xx line-share ;
; Funtion ;
; 1. Demonstration of I2C and TM16xx protocols ;
; 2. Geomagnet of X,Y,Z axis are shown on 4 digit display ;
; (1) XYZ values are shown sequentially on push of tact-switch ;
; (2) Hexadecimal values are shown, if Long-push after "PUSH" ;
; (3) Magnetic unit is 0.73 milli-Gauss*, i.e. 1370LSb/Gauss ;
; *: mG(milli-Gauss) = 100 nT(nano-Tesla) = 10^(-7)Tesla ;
; 3. Provide PIC Assembler coding source for reuse ;
; (1) I2C interface source, using HMC5883L Geomagnetic Compass ;
; (2) TM163x interface source, for TM1637 Four Digit Display ;
; (3) Device-independent coding techniques and Macro examples ;
; Input/OUtput ;
; 1. RA0 TM16xx-DIO (dio line) Output usually / Input temporarily ;
; 2. RA1 TM16xx-CLK (clk line) Output ;
; 3. RA2 LED Output ;
; 3. RA3 Tact Switch Input pulled-up ;
; 4. RA4 I2C-SDA (data line) Output usually / Input temporarily ;
; 5. RA5 I2C-SCL (clock line) Output ;
; Remarks ;
; 1. Clock = HFINTOSC ( 16MHz) ;
; Hence 1 step = 0.25 micro seconds ;
; 2. Logical PORT name is introduced, for device independence ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
list p=12F1822 ; list directive to define processor
#include ; processor specific variable definitions
__CONFIG _CONFIG1, _FOSC_INTOSC & _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_LO & _LVP_OFF
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macro definitions ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Device dependent Macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
DEVset macro
BANKSEL OSCCON ; Bank=1
movlw B'01111010' ; 16MHz and 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'11001000' ; RA0,1,2,4 and 5 are output
movwf TRISA
;
BANKSEL OPTION_REG ; Bank=1
bcf OPTION_REG,7 ; Enable weak pull-up
BANKSEL WPUA ; Bank=4
movlw B'00001000' ; Weak Pull-up for RA 3
movwf WPUA ;
;
clrf BSR ; Bank=0
InitP ; Initialize ports
endm
;
InitP macro ; Initialize ports
movlw B'11111011' ;
movwf PORTA
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I/O macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; for I2C-Master protocol
I2Csnd macro slave,dataa,datalen
movlw slave
movwf I2Cadr
movlw dataa
movwf FSR0L
movlw datalen
movwf DataLen
call I2Csndr
endm
;
I2Crcv macro slave,dataa,datalen
movlw slave
movwf I2Cadr
movlw dataa
movwf FSR0L
movlw datalen
movwf DataLen
call I2Crcvr
endm
;
I2Cstat macro
call I2Cstar
endm
;
I2Cstop macro
call I2Cstpr
endm
;
; For TM16xx-Master protocol
TMsendL macro tslit ; Send a literal to TM1637
movlw tslit
call TMsndLr
endm
;
TMsendB macro tsbyte ; Send a Byte specified, to TM1637
movf tsbyte,W
movwf Sbyte
call TMsndBr
endm
;
TMstart macro ; Start TM16xx lines
call TMstrtr
endm
;
TMstop macro ; Stop TM16xx lines
call TMstopr
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For general purpose ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LEDon macro ; LED on
goto $+1
bsf PORTA,LED
goto $+1
endm
;
LEDoff macro ; LED off
goto $+1
bcf PORTA,LED
goto $+1
endm
;
WaitSw macro ; Wait for tact Sw pushed
call WaitSwr
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Time cosuming macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic macro ;Consume 1 μS only
goto $+1
goto $+1
endm
;
Mic2 macro mic2p ;Consume 2 μS x n
movlw mic2p
call Mic2r
endm
;
Mic2p5 macro mic25p ; Consume 2.5μS x n
movlw mic25p
call Mic25r
endm
;
Mic5 macro mic5p ; Consume 5μS x n
movlw mic5p
call Mic25r
movlw mic5p
call Mic25r
endm
;
Mic50 macro mic50p ; Consume 50μS x n
movlw mic50p
call Mic50r
endm
;
Milli macro millip ; Consume mS x n
movlw millip
call Millir
endm
;
Mil100 macro mil100p ; Consume 100 mS x n
movlw mil100p
call Mil100r
endm
;
Secs macro secsp ; Consume Second x n
movlw secsp
call Secsr
endm
;
Mins macro minsp ; Consume Minute x n
movlw minsp
call Minsr
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Debug and Abend macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Udebug macro Addr
movf Addr,W
call Udbgr
endm
;
Trigger macro ; DSO external trigger
goto $+1
bsf PORTC,Trig
Mic25
bcf PORTC,Trig
goto $+1
endm
;
Uabend macro abn ; User Abnormal-end number
movlw abn
goto Uabendr
endm
;
Ublink macro bno ; Blink LED for specified times
movlw bno
call Ublinkr
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Logic macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Calculation macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Calculate Literal x Value and add it to answer (HAh&HAl)
LxAadd macro litV,multiA
movf multiA,W ; multiplier byte address in W
movwf Mctr ; and set it to Mctr
movlw litV ; set Literal value into W
call LxAaddr
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Comparison macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Compare A w/ B and branch to Smaller, Equal, or Larger(next statm't line)
CabSEL macro Aadr,Badr,Smladr,Eqladr
movf Badr,W ; W=B
subwf Aadr,W ; W=A-B
btfss STATUS,C ; A≧B? Yes, skip next
goto Smladr ; If A<B goto Smaladr
btfsc STATUS,Z ; A=B? No skip next
goto Eqladr ; If A=B goto Eqladr
; ; If A>B then next (here)
endm
;
; Compare A w/ B and branch to Smaller or Others (Equal or Larger)
CabSO macro Aadr,Badr,Smladr
movf Badr,W ; W=B
subwf Aadr,W ; W=A-B
btfss STATUS,C ; A≧B? Yes, skip next
goto Smladr ; If A<B goto Smaladr
; ; If A≧B then next (here)
endm
;
; Compare A w/ B and branch to Equal, or Other(next statm't line)
CabEO macro Aadr,Badr,Eqladr
movf Badr,W ; W=B
subwf Aadr,W ; W=A-B
btfsc STATUS,Z ; A=B?
goto Eqladr ; If A=B goto Eqljmp
; ; else next (here)
endm
;
; Compare A w/ literal and branch to Smaller, Equal, or Larger(next statm't)
CalSEL macro Aadr,Blit,Smladr,Eqladr
movlw Blit ; W=B
subwf Aadr,W ; W=A-B
btfss STATUS,C ; A≧B? Yes, skip next
goto Smladr ; If A<B goto Smaladr
btfsc STATUS,Z ; A=B? No skip next
goto Eqladr ; If A=B goto Eqladr
; ; If A>B then next (here)
endm
;
; Compare A w/ literal and branch to Smaller, or Others (Equal or Larger)
CalSO macro Aadr,Blit,Smladr
movlw Blit ; W=B
subwf Aadr,W ; W=A-B
btfss STATUS,C ; A≧B? Yes, skip next
goto Smladr ; If A<B goto Smaladr
; ; If A≧B then next (here)
endm
;
; Compare A w/ literal and branch to Equal, or Others
CalEO macro Aadr,Blit,Eqladr
movlw Blit ; W=B
subwf Aadr,W ; W=A-B
btfsc STATUS,Z ; A=B? No skip next
goto Eqladr ; If A=B goto Eqladr
; ; else next (here)
endm
;
; Compare A w/ literal and branch to Large, or Others
CalLO macro Aadr,Blit,Ladr
movlw Blit ; W=B
subwf Aadr,W ; W=A-B
btfss STATUS,C ; A≧B? Yes, skip next
goto $+3 ; If A<B goto Others
btfss STATUS,Z ; A=B? Yes skip next
goto Ladr ; If A>B goto Laddr
; ; If A≦B then next (here)
endm
;
; Compare A with Literal and branch to Un-equal, or Others
CalUO macro Aadr,Blit,Uneqladr
movlw Blit ; W=B literal
subwf Aadr,W ; W=A-B
btfss STATUS,Z ; A=B?
goto Uneqladr ; No, goto unequal
; ; If yes then next
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files and Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cblock H'20'
;
; For application support
; DataA ; Data area : use Xh addr
Xh
Xl
Zh
Zl
Yh
Yl
Bh ; Editing work area
Bl ; Editing work area
;
;Areas for calculation LxA (Literal x byteArea)
Mctr ; Multiplier counter from byteA
Madded ; Multiplied value from Literal
HAh ; Hecto Answer h(Decimal 100-9900)
HAl ; Hecto Answer l(Decimal 0-99)
;
; For I2C protocols
I2Cadr ; Destination I2C address
DataLen ; Number of bytes to be sent/received
Sbyte ; One byte to be sent/received
Bitctr ; Loop counter for bits in a byte
;
; For TM1637 4 digit display
; Sbyte ; Byte to send, shared with I2C
Dig1000 ; Digit 1000
Dig100 ; Digit 100
Dig10 ; Digit 10
Dig1 ; Digit 1
Bytectr ; Loop counter for TM1637-4digits
;
; Areas for time consuming subroutines
; Do not change the sequences from Mic5c to Minsc
; if co-used with calculation parameters
Mic25c
Mic50c
Millic
Mil100c
Secsc
Minsc
;
; Areas for debugging routines
DmpA ; Display byte area
Dmp8C ; Bit counter for loop (Initial Dmp8V =8)
BlinkC ; Counter for blinking (set for Debugb or Abendb)
Abendn ; Abend number
Ucpc ; User Check point chr to trace
Flags
;
endc
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For PORTA ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Dio equ 0 ; TM16xx Data line = DIO
;Clk equ 1 ; TM16xx Clock line =CLK
LED equ 2 ; RA2 = LED
Sw equ 3 ; RA3 = Tact Switch(pulled-up)
;Dl equ 4 ; I2C Data line = SDA
;Cl equ 5 ; I2C Clock line = SCL
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** Logical PORTI2C ; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTI2C equ PORTA ;
Dl equ 4 ; I2C Data line = SDA
Cl equ 5 ; I2C Clock line = SCL
LATI2C equ LATA ; LATch for I2C port
TRISI2C equ TRISA ; TRIS reg for I2C
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** Logical PORTtm ; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTtm equ PORTA ;
Dio equ 0 ; TM16xx Data line = DIO
Clk equ 1 ; TM16xx Clock line = CLK
LATtm equ LATA ; Latch for tm port
TRIStm equ TRISA ; TRIS for tm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Values & Characters ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DataA equ Xh ; share Data address
Compass equ H'1E' ; HMC5883L I2C address
; Flags byte
NegaV equ 1 ; Value is negative
OflowV equ 2 ; Value overflow
HexD equ 3 ; Hexadecimal display requested
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For Debug ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Dmp8V equ D'8' ; Debug display bit counter initial value
Debugb equ D'8' ; number of blinkings to show Debugging
Abendb equ D'25' ; number of blinkings to notify Abend
; Flags byte
LEDsv equ 0 ; LED save bit in Flags byte
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initializing ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 0
goto Startp ; Go to start entry
org 4 ; This is Interrupt entry
retfie ;
;
Startp DEVset ; Define ports
clrf FSR0H ; Clear FSR0H forever
clrf FSR1H ; Clear FSR1H forever
clrf Flags ; Clear all bits of Flags
;
call IniComr ; Set-up Compass HMC5883L
call IniTMr ; Set-up TM1638 display
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main program loop ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp bcf Flags,HexD ; Clear Hex display request
call DspPUSH ; Show PUSH
; Swith handling & selecting Decimal or Hexadecimal format
; ( Short-push for Decimal and Long-push for Hexadecimal)
btfsc PORTA,Sw ; Sw pushed ?
goto $-1 ; No, go back
;
Mil100 5 ; when pushed, wait 0.5 second
btfss PORTA,Sw ; still pushed on (Long Push) ?
bsf Flags,HexD ; Yes, request Hex display
;
btfss PORTA,Sw ; Wait until Sw released
goto $-1 ; If still pushed, go back
;
call RdComr ; Read compass HMC5883L (Single measure.)
call DspXYZr ; Display X,Y,Z values on TM1637
goto Mainp ; Loop for next measurement
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Compass HMC5883L set-up routine ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IniComr equ $
;Conf-regA = B011(#samples=8)110(75Hz@Cont-mode)00(no bias)=0x78
;Conf-regB = B000(±0.88Gauss)00000(must be cleared)=0x00
;Mode-reg = B00000(must be zeros)01(single measurement)=0x01
;
movlw DataA ; Point DataA
movwf FSR0L
movlw H'00' ; Config byte A addres
movwf INDF0
incf FSR0L,F
movlw H'78' ; Config byte A contents
movwf INDF0
incf FSR0L,F
movlw H'00' ; Config byte B contents
movwf INDF0
;
I2Csnd Compass,DataA,3 ; Send 3 bytes to Compass
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 display brightness setting ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IniTMr equ $
; TM brightness initial setting ;
; H'88'+ duty ratio:
; H'00'=1/16, H'01'=2/16, H'02'=4/16, H'03'=10/16
; H'04'=11/16, H'05'=12/16, H'06'=13/16, H'07'=14/16
movlw H'88'+H'02' ; Initial brightness value
movwf Sbyte ; Set to Sbyte
TMstart
TMsendB Sbyte
TMstop
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Read compass HMC5883L into X,Z,Y bytes ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RdComr equ $
; Use single measurement mode 0x01 to Mode Reg (adr 0x02)
; Wait>6mS for data updated
;
; Setting up data
movlw DataA
movwf FSR0L
movlw H'02' ; Mode reg addr of compass
movwf INDF0 ;
incf FSR0L,F ;
movlw H'01' ; Specify Single measurement mode
movwf INDF0
;
I2Csnd Compass,DataA,2 ; Send to compass
Milli D'8' ; Wait ≧ 6mS
;Read compass
I2Crcv Compass,DataA,6 ; Read data X,Z,Y
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Display X,Y,Z with 4 digits x 3 times ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DspXYZr equ $
movlw Xh ; Set addr of X
movwf FSR1L ; and point it by FSR1L
call EdVdspr ; Show X value
;
movlw Yh ; Set addr of Y
movwf FSR1L ; and point it by FSR1L
call EdVdspr ; Show Y value
;
movlw Zh ; Set addr of Z
movwf FSR1L ; and point it by FSR1L
call EdVdspr ; Show Z value
;
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Edit value to 4digit values for display ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EdVdspr movf INDF1,W ; Get high byte
movwf Bh ; Set it to Bh
incf FSR1L,F ; Point low byte
movf INDF1,W ; Get low byte
movwf Bl ; Set it to Bl
;
call Hex2Dr ; Break out to 4 digits
btfss Flags,HexD ; If Hexa disp req'd, skip next
call Hex2Dec ; Hexadecimals to Decimals
;
call Ed2Seg ; Edit them to 7 Segs'
;
btfsc Flags,NegaV ; If value is negative
goto EdVnega ; show negative sign
EdVco btfsc Flags,OflowV ; If value overflow
goto EdVof ; show overflow by LED
EdVd call TMdspr ; and display them
;
WaitSw
LEDoff
return
;
EdVnega btfsc Flags,HexD ; If Hexa disp req'd,
goto EdVco ; then do nothing
;
movlw H'40' ; Minus sign
movwf Dig1000 ; to Dig1000
goto EdVco ; and goto Edv chek overflow
;
EdVof LEDon
goto EdVd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Break-out Hex 2 bytes to 4 Digits ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Hex2Dr movf Bl,W ; Set Bl to W
andlw B'00001111' ; Clear top half of W
movwf Dig1 ; and set it to Dig1
;
swapf Bl,W ; Swap nibbles into W
andlw B'00001111' ; Clear top half of W
movwf Dig10 ; and set it to Dig10
;
movf Bh,W ; Set Bh to W
andlw B'00001111' ; Clear top half of W
movwf Dig100 ; Set Dig100
;
swapf Bh,W ; Swap nibbles into W
andlw B'00001111' ; Clear top half of W
movwf Dig1000 ; Set Dig1000
;
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Hexadecimal to Decimal conversion ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Hex2Dec equ $
bcf Flags,NegaV ; Clear negative Value flag
bcf Flags,OflowV ; Clear overflow Value flag
;
; Check1: Value negative or positive ?
H2Dc1 btfss Dig1000,3 ; Check top bit of Hex V
goto H2Dc2 ; If positive, goto next check
;
; Negative value process
bsf Flags,NegaV ; Show Value is minus
; cgabge Digits positive by complement of H'FFFF'
movlw H'0F'
xorwf Dig1000,F
xorwf Dig100,F
xorwf Dig10,F
xorwf Dig1,F
;
; Check2: Value more than 4095 ?
H2Dc2 CalSO Dig1000,1,H2Dp ; If smaller goto processes
bsf Flags,OflowV ; Show that Value overflow
clrf Dig1000 ; and clear Dig1000
;
; Processes:
; Clear Hecto answer A
H2Dp clrf HAh
clrf HAl
;
; Perform A = A + Dig100x256 (Add 256xDig100 to Hecto A's)
; by A=A+Ax128 + Ax128 in order to avoid byte overflow,
; as Literal≦255 (and A can be max 99 before 2nd adding)
H2Dp100 LxAadd D'128',Dig100 ;
LxAadd D'128',Dig100 ;
;
; Perform A = A + Dig10x16
H2Dp10 LxAadd D'16',Dig10 ; Add 16xDig10 to HAh&l
;
; Perform A = A+ Dig1
H2Dp1 LxAadd D'1',Dig1 ; Add 1xDig1 to HAh&l
;
; Now, calculation Hexa to Hecto done
; Break out HAh to Dig1000 & Dig100,and HAl to Dig10 & Dig1
movf HAh,W ; Set HAh
movwf Dig100 ; to Dig100
;
clrf Dig1000 ; Clear Dig1000 to begin next
H2Dbhlp CalSO Dig100,D'10',H2Dbl ; If Dig100≦10,goto H2Dbl
movlw D'10' ; else Carry-over process
subwf Dig100,F
incf Dig1000,F
goto H2Dbhlp
;
H2Dbl movf HAl,W ; Set HAl
movwf Dig1 ; to Dig1
;
clrf Dig10 ; Clear Dig10 to begin next
H2Dbllp CalSO Dig1,D'10',H2Dend ; If Dig1<10,goto end
movlw D'10' ; else Carry-over process
subwf Dig1,F
incf Dig10,F
goto H2Dbllp
;
H2Dend return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Edit digits to 7 segmeng x 4 ;
; for both Decimals and Hexadecimals ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ed2Seg movlw Dig1000 ; Get top address
movwf FSR0L ; Set address
movlw 4 ; Number of digits
movwf Bytectr ; Set it to Byte counter
;
Ed2Slp movf INDF0,W
call TMser ; Translate to 7 seg
movwf INDF0 ; Replace digit by it
decfsz Bytectr,F ; Done 4 digits?
goto Ed2Snxt ; No, go on
return ; Yes, return
;
Ed2Snxt incf FSR0L,F ; Point next data
goto Ed2Slp ; and loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I2C Send byte-string ;
; when called, ;
; I2C device adr in I2Cadr byte ;
; Data length in DataLen ;
; Data Addr in FSR0L (INDF0) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Csndr movf I2Cadr,W
movwf Sbyte
rlf Sbyte,F ; shift leftt
bcf Sbyte,0 ; indicate write
;
I2Cstat ; Start I2C
call Sendr
Sdata movf INDF0,W ; Get a sending character
movwf Sbyte ; Set it to Sbyte
call Sendr ; Send it to the device
;
incf FSR0L,F ; point next char
decfsz DataLen,F ; Have all chars sent ?
goto Sdata ; No, loop
;
; Stop signal and return
I2Cstop
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I2C Receive byte-string ;
; when called, ;
; I2C device adr in I2Cadr byte ;
; Data length in DataLen ;
; Data Addr in FSR0L (INDF0) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Crcvr equ $
I2Cstat ; Start I2C
movf I2Cadr,W ; Get I2C dev addr
movwf Sbyte ; Set it into Sbyte
rlf Sbyte,F ; Shift left
bsf Sbyte,0 ; indicate read
call Sendr ; Send slave addr to read
;
I2Crbyt equ $
BANKSEL TRISI2C ;
bsf TRISI2C,Dl ; Set Dline input mode
clrf BSR ; Point Bank 0
;
movlw 8 ; Bits in a reciving byte
movwf Bitctr ; into loop counter
I2Crblp Mic5 1 ; Timing before raising clock
bsf PORTI2C,Cl ; Set clock high
Mic2p5 1 ; Timing after raising clock
;
btfsc PORTI2C,Dl
goto Rbith
; goto Rbitl
;
Rbitl bcf Sbyte,0 ; Clear bit 0
goto Rbitnxt ; and goto next
;
Rbith bsf Sbyte,0 ; Set bit 0
Rbitnxt Mic2p5 1 ; Timing after checking
bcf PORTI2C,Cl ; Set clock low
; Mic2p5 1 ; Timing after clock falling
decfsz Bitctr,F ; Still bits?
goto Rbcont ; Yes, continue
goto Rbend ; No, end of one byte
;
Rbcont rlf Sbyte,F ; Shit left
goto I2Crblp ; and goto loop
;
Rbend movf Sbyte,W ; Get received byte
movwf INDF0 ; Set it to INDF0
incf FSR0L,F ; increase index
decfsz DataLen,F ; DataLen-1
goto Sackr ; Send Ack and continue
goto Snackr ; Send Nack and stop
;
;Set Dl output mode and send Ack to conitinue
Sackr equ $
BANKSEL LATI2C ; Data line high when output mode
bsf LATI2C,Dl ; Lat-Dl on
BANKSEL TRISI2C ;
bcf TRISI2C,Dl ; Set Dl output mode
clrf BSR ; Point Bank 0
;
bcf PORTI2C,Dl ; Send Ack
Mic2p5 1 ; Timing after clock falling
bsf PORTI2C,Cl ; Show Ack
Mic2p5 2
bcf PORTI2C,Cl ; Set clock low
Mic2p5 1
bsf PORTI2C,Dl ; Return Dline to high
goto I2Crbyt ; Next byte process
;
;Set Dl output mode and send Nack
Snackr equ $
BANKSEL LATI2C ; Data line high when output mode
bsf LATI2C,Dl ; Lat-Dl on
BANKSEL TRISI2C ;
bcf TRISI2C,Dl ; Set Dl output mode
clrf BSR ; Point Bank 0
;
bsf PORTI2C,Dl ; Send Nack
Mic2p5 1 ; Timing after clock falling
bsf PORTI2C,Cl ; Show Nack
Mic2p5 2
bcf PORTI2C,Cl ; Set clock low
Mic2p5 2
I2Cstop ; and stop I2C once
Mic5 D'10' ; for 50 micro sec
;
I2Cstat ; then start I2C again
movf I2Cadr,W ; Get I2C dev addr
movwf Sbyte ; Set it into Sbyte
rlf Sbyte,F ; Shift left
bcf Sbyte,0 ; indicate write
call Sendr ; Send it
;
I2Cstop
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I2C Start signal routine ;
; when dataline mode is output ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstar bcf PORTI2C,Dl ; set SDA low
Mic2p5 1
bcf PORTI2C,Cl ; set SCL low
Mic2p5 3
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I2C Stop signal routine ;
; when dataline mode is output ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstpr bcf PORTI2C,Cl ; set SCL low
Mic2p5 1
bcf PORTI2C,Dl ; set SDA low
Mic2p5 4
bsf PORTI2C,Cl ; Clock line rasing
Mic2p5 2
bsf PORTI2C,Dl ; Data line rasing
Mic2p5 1
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I2C One-byte sending routine ;
; with data in Sbyte ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Sendr movlw 8 ; Set bit count in a byte
movwf Bitctr ; into loop counter
;
Sloop btfsc Sbyte,7 ; Check top bit of Sbyte
goto Slpdh ;
bcf PORTI2C,Dl ; If bit low then Data L
goto Slpnxt
Slpdh bsf PORTI2C,Dl ; If bit high then Data H
;
Slpnxt Mic2p5 1
bsf PORTI2C,Cl ; Show bit
Mic2p5 2
bcf PORTI2C,Cl ;
Mic2p5 1
;
rlf Sbyte,F ; Shift left
decfsz Bitctr,F ; All bits done?
goto Sloop ; No, loop within a byte
;
;Receive Ack
; set data line input mode
BANKSEL TRISI2C ;
bsf TRISI2C,Dl ; Set Dline input mode
clrf BSR ; Point Bank 0
;
Mic2p5 1 ; wait for Ack timing
bsf PORTI2C,Cl ; Clock H for Acq confirmation
Mic2p5 2 ;
bcf PORTI2C,Cl ; Cl L for Dl release by slave
Mic2p5 2
;
; Set Data line output
BANKSEL LATI2C ; Data line high when output mode
bsf LATI2C,Dl ; Lat-Dl on
BANKSEL TRISI2C ;
bcf TRISI2C,Dl ; Set Dl output mode
clrf BSR ; Point Bank 0
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 support routines ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM 1637 Char to 7 segment editing routine ;
; replaceubg Char in W with 7 seg in W ;
; 7 seg format is B'xgfe-dcba' ;
; if colon required,IOR H'80' to Dig100 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMser andlw H'0F' ;Prevent wild branch
brw
Case0 retlw H'3F'
Case1 retlw H'06'
Case2 retlw H'5B'
Case3 retlw H'4F'
Case4 retlw H'66'
Case5 retlw H'6D'
Case6 retlw H'7D'
Case7 retlw H'07'
Case8 retlw H'7F'
Case9 retlw H'6F'
CaseA retlw H'77' ; A
CaseB retlw H'7C' ; b
CaseC retlw H'39' ; C
CaseD retlw H'5E' ; d
CaseE retlw H'79' ; E
CaseF retlw H'71' ; F
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 displaying routine ;
; using Dig1000 to Dig1 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMdspr movlw Dig1000 ; Point Byte0 address
movwf FSR0L ; set it to use INDF0
movlw 4 ; Set four digits
movwf Bytectr ; to Byte counter
;
TMstart
TMsendL H'40' ;
TMstop ;
;
TMstart
TMsendL H'C0' ; Set addr zero of TM
;
TMdspl movf INDF0,W ; Get byte contents
movwf Sbyte ; Set them to Sbyte
TMsendB Sbyte ;
incf FSR0L,F ; point next byte
decfsz Bytectr,F ; Check if all done
goto TMdspl ; No. loop
;
TMstop ; When all sent, Stop
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Displaying characters directly ;
; as an example "PUSH" ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DspPUSH TMstart ;
TMsendL H'40' ; Set data
TMstop
TMstart ;
TMsendL H'C0' ; Set address zero
TMsendL H'73' ; P
TMsendL H'3E' ; U
TMsendL H'6D' ; S
TMsendL H'76' ; H
TMstop
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 Start sending routine ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMstrtr nop
BANKSEL TRIStm
bsf LATtm,Dio ; Dio high beforhand
bcf TRIStm,Dio ; Set Dio output
clrf BSR ; return to Bank0
;
bsf PORTtm,Dio ; Dio high
Mic5 1
bsf PORTtm,Clk ; Clk high
Mic5 1
bcf PORTtm,Dio ; Dio low
Mic5 1
bcf PORTtm,Clk ; Clk low
Mic5 1
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 Stop sending routine ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMstopr nop
BANKSEL TRIStm
bcf LATtm,Dio ; Dio low beforehand
bcf TRIStm,Dio ; Set Dio output
clrf BSR ; Return to Bank0
;
Mic5 1
bsf PORTtm,Clk ; Clk high
Mic5 1
bsf PORTtm,Dio ; Data high
Mic50 1
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TM1637 Byte sending routine ;
; called by TMsendB with Sbyte or ;
; TMsendL with value in W reg ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMsndLr movwf Sbyte ; Set sending byte
;
TMsndBr movlw 8 ; Set bit count
movwf Bitctr ; into loop counter
;
Tloop btfsc Sbyte,0 ; Check top bit
goto Tlpdh ;
bcf PORTtm,Dio ; If bit low then Data L
goto Tlpnxt
;
Tlpdh bsf PORTtm,Dio ; If bit high then Data H
Tlpnxt Mic5 1 ;
bsf PORTtm,Clk ; Clock high
Mic2p5 4 ; 10 micro sec
bcf PORTtm,Clk ; Clock low
Mic5 1
rrf Sbyte,F ; Shift right
decfsz Bitctr,F
goto Tloop
;
; Receiving Ack ;
BANKSEL TRIStm
bsf TRIStm,Dio ; Set Dio input mode
clrf BSR ; return to Bank0
Mic2p5 4 ; Wait for Ack=low
bsf PORTtm,Clk ; Clk high for Ack confirmation
Mic2p5 4 ; 10 micro sec
bcf PORTtm,Clk ; Clk L for Data release to H by Slave
Mic2p5 4 ; Wait for Dio set H
;
BANKSEL TRIStm
bsf LATtm,Dio ; Dio high beforhand
bcf TRIStm,Dio ; Set Dio output
clrf BSR ; return to Bank0
Mic50 1 ; Enough time for TM1637 after Ack
return ;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Waiting for Sw pushed and released ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WaitSwr goto $+1 ; Timing delay for PORTupadate
btfsc PORTA,Sw ; Wait until Sw on
goto $-1 ; If off, go back
btfss PORTA,Sw ; Wait until released
goto $-1 ; If still on, go back
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiply and add result to HAh and HAl ;
; called by LxAadd macro and ;
; LitVsv x Mctr result to be added to HAh&l ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LxAaddr movwf Madded ; Set Literal as multiplied
CalEO Mctr,0,LxAend ; If Mctr=0, return
;
LxAlp movf Madded,W ; Multiplied into W
addwf HAl,F ; add it to HAl
CalSO HAl,D'100',LxAnxt ; If HAl<100 then goto nxt
movlw D'100' ; Else, carry-over process
subwf HAl,F
incf HAh,F
;
LxAnxt decfsz Mctr,F ; If still Mctr,
goto LxAlp ; then loop
;
LxAend return ; else return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Timing subrooutines for general purposes ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Make 2.0 micro S x n (Mic2) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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 (Mic2p5) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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 Mic50 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r movwf Mic50c ; set how many 50 microsec (1 micro sec to here)
nop ; 1.25 micro sec up to here
;
Mic50l Mic2p5 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 (Milli) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir movwf Millic ; set how many 1 mil sec (1 mic S up to here)
nop ; 1.25 micro sec
;
Millil Mic50 D'19' ; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25)
Mic2p5 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 (Mil100);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r movwf Mil100c ;set how many 100 ms(1 micr sec up to here)
nop ; 1.25 micro sec
;
Milhl Milli D'99' ;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
Mic50 D'19' ; + 950 mic = 99951.25 micS(2nd.199951.25mic)
Mic2p5 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 (Secs) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secsr movwf Secsc ; set how many sec ( 1 mic sec up to here)
nop ; 1.25 micro sec
;
Secsl Mil100 D'9' ;
Milli D'99' ; + 999 milli sec = 999001.25 micro sec
;
Mic50 D'19' ; + 950 mic = 999951.25 micro sec
Mic2p5 D'19' ; + 47.5 mic = 999998.75 micro sec
nop ; + 0.25 mic = 999999 micro sec
;
decfsz Secsc,F ; If exhausted then 1 micro sec hereafter
goto Secsli ; else, go out
return
;
Secsli Mic
goto Secsl ; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Minutes x n (Mins) ;
; Overhead ignored, that is only ;
; 751.25 Mic S even when 100 Min ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minsr movwf Minsc ;set how many minutes from parameter
;
Minsl Secs D'60' ; 1 Seconds x 60
decfsz Minsc,F
goto Minsl
return
;
space
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; User debug subroutine ;
; Show bit 7 to 0 ;
; of specified byte ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Udbgr clrf BSR ; Set Bank=0
movwf DmpA ; move data to Dmpa
;
btfss PORTA,LED ; Check if LED=on (on=High)
goto UdbLoff ; if LED=off(Low), skip saving process
bsf Flags,LEDsv ; Save LEDon status
LEDoff ; and off LED
Mil100 D'10' ; wait for a second in case LED has been on
;
UdbLoff movlw Dmp8V ; set counter 8
movwf Dmp8C ; to Dmp8C
;
Udblp Ublink Debugb ; Blink for Debug = 8 times
btfsc DmpA,7 ; check top bit 7
goto UdbOn ; if on then to UdbOn
goto UdbOff ; if off then to UdbOff
;
UdbOn LEDon
Mil100 D'30' ;
goto Udbeck
;
UdbOff LEDoff
Mil100 D'30' ;
; goto Udbeck
;
Udbeck decfsz Dmp8C,F
goto Udbnext
goto Udbend
;
Udbnext rlf DmpA,F
goto Udblp
;
Udbend Ublink Debugb ; end blinking and
Mil100 D'100' ; blank for 10 seconds to write down
;
btfss Flags,LEDsv ; Check if LED was on
goto Udbret ; no, goto return
LEDon ; if it was on, then on again
bcf Flags,LEDsv ; Clear LED save flag
;
Udbret return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Blinking to show debug or abend ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ublinkr movwf BlinkC
Ublinkl LEDon ; LED on
Milli D'30' ; for 30ms
LEDoff ; LED off
Milli D'200' ; for 200ms
;
decfsz BlinkC,F
goto Ublinkl
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Abend routine ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Uabendr clrf BSR
movwf Abendn ; Set Uabend number
;
Ublink Abendb ; Blinking 25 times
Udebug Abendn ; Show Abend number
goto $
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; End of program ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end
次回にプログラム内容を説明するとして、今回はこのへんで。
©2019 Akira Tominaga, All rights reserved.