-
Notifications
You must be signed in to change notification settings - Fork 0
/
Divergence.asm
1830 lines (1691 loc) · 80.3 KB
/
Divergence.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;**********************************************************************
; This file is a basic code template for assembly code generation *
; on the PIC16F628A. This file contains the basic code *
; building blocks to build upon. *
; Refer to the MPASM User's Guide for additional information on *
; features of the assembler (Document DS33014). *
; Refer to the respective PIC data sheet for additional *
; information on the instruction set. *
; *
;**********************************************************************
; *
; Filename: DivergenceMeter.asm *
; Date: 5-12-2012 *
; File Version: 1.05 (REMEMBER to update number in code!) *
; *
; Author: Tom Titor *
; Company: /a/ *
; *
;**********************************************************************
; Files Required: P16F628A.INC *
;**********************************************************************
; *
; Notes:Had to take out "& _DATA_CP_OFF " from template __CONFIG *
; line because it resulted in error. Why? The line was *
;__CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT *
; *
; Using internal oscillator 4 MHz (default) *
; *
; *
; 0.00 Had to set MCLRE_OFF in config since that pin floats *
; unconnected on my board. *
; 0.01 Had to turn comparators off to get PORTA to work as *
; inputs, and then stupid typo in doing so wasted hours. *
; 0.1 (1/31) Able to display a digit on the tubes. *
; 0.2 (2/1) Able to display worldline number to all 8 tubes. *
; 0.3 (2/1) Testing animation of number. *
; 0.37(2/2) More animation messin' *
; 0.4 (2/6) Worldline number random rolls work! *
; 0.43(2/7) Adjustable brightness with fading pulse at end *
; 0.44(2/13) Worked on long/short button pushes. *
; 0.45(2/15) Adding I2C to talk to DS1307 Real-time Clock chip *
; using Andrew D. Vassallo's bit banging from piclist.com *
; (2/17) Works. Long time debugging since it apparently *
; MUST have the backup battery in there to work reliably. *
; 0.5 (2/17) Working on the Clock display and interface. *
; 0.6 (2/19) Clock works. Working on settings interface. *
; 0.7 (2/21) Basic settings done: Time / Date / Brightness. *
; 0.75(2/22) Added preset world lines from anime/visual novel. *
; 0.8 (2/25) Added manual world line entry. Added random beta *
; and neg. world lines. Put useful things in subroutines. *
; 0.85(2/27) Date format pref (MM DD YY or DD MM YY) done. *
; 0.90(2/28) Tube blanking hours. Fun2 roll at top of hour. *
; 1.0 (3/3) Time adjustment implemented and tested. *
; All originally planned features have been implemented. *
; 1.01 (3/22) Fixed bug in setting 12/24-hour format from *
; the value stored in EEPROM location 7F. *
; 1.02 (3/30) Changed so the device starts up in clock mode. *
; Mainly because if there is a power outage, you don't *
; want the device to wake up and stay with one number on *
; the nixie tubes for an extended period. *
; 1.03 (4/20) Fixed error in Year-setting routine. *
; 1.04 (5/11) Fixed error in error routine that reports "666" *
; if the clock chip does not respond. This did not work *
; right at power-up because the tube power was still off, *
; so I added lines to turn tubes on to the error handler. *
; ALSO added version number display. The version number *
; will be displayed as long as switch 2 is held on the way *
; into the Settings menu. *
; 1.05 (5/12) Works for either DS1307 or DS3232 clock chips. *
; 1.06 7/2019 MKM Modified for special ZM 2040 Nixies *
;**********************************************************************
list p=16f628A ; list directive to define processor
#include "C:\Program Files (x86)\Microchip\xc8\v2.05\mpasmx\P16F628A.INC" ; processor specific variable definitions
errorlevel -302 ; suppress message 302 from list file
__CONFIG _CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT
; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.
;***** VARIABLE DEFINITIONS
wTmp EQU 0x7E ; variable used for context saving
statusTmp EQU 0x7F ; variable used for context saving
ShadowA equ 20 ; shadow register for PORTA
ShadowB equ 21 ; shadow register for PORTB
Delay1 equ 22 ; for delay
Delay2 equ 23 ; for delay
Counter equ 24 ; counter
; NOTE! The following 26 registers must be in the order below!
LeftDP equ 25 ; Flags for left decimal places
RightDP equ 26 ; Flags for right decimal places
T0 equ 27 ; Number for Tube 0 (rightmost). An 11(base 10) in these means no digit in that tube.
T1 equ 28 ; etc.
T2 equ 29 ; .
T3 equ 2A ; .
T4 equ 2B ; .
T5 equ 2C ; .
T6 equ 2D ; .
T7 equ 2E ; Number for Tube 7 (leftmost)
TR0 equ 2F ; Run length for Tube 0 (rightmost) (i.e., cycles to run until digits halt)
TR1 equ 30 ; etc.
TR2 equ 31 ; .
TR3 equ 32 ; .
TR4 equ 33 ; .
TR5 equ 34 ; .
TR6 equ 35 ; .
TR7 equ 36 ; Run length for Tube 7 (leftmost)
V0 equ 37 ; Values for tubes to stop at (using alternate animation method)
V1 equ 38 ; .
V2 equ 39 ; .
V3 equ 3A ; .
V4 equ 3B ; .
V5 equ 3C ; .
V6 equ 3D ; .
V7 equ 3E ; .
Flag equ 3F ; Flag register
n equ 40 ; Work register used by Loader
m equ 41 ; Work register used by Loader
LDP equ 42 ; Work register used by Loader
RDP equ 43 ; Work register used by Loader
random equ 44 ; random number
work equ 45 ; Work register for use inside any subroutine
bright equ 46 ; Brightness value 0 (dimmest) to 7 (brightest) currently in use.
incMin equ 47 ; Register to hold Minimum while incrementing settings
incMax equ 48 ; Register to hold Maximum while incrementing settings
oldMin equ 49 ; Register to hold old minutes (so we can tell if they were changed)
blankStart equ 4A ; Register to hold starting hour of tube blanking
blankEnd equ 4B ; Register to hold ending hour of tube blanking
hourCount equ 4C ; Register to count down hours until time adjustment
oldHour equ 4D ; Register to track start of hour
LED equ 0 ; LED is bit 0 in PORTB
HVE equ 1 ; High Voltage Enable is bit 1 in PORTB
CLK equ 2 ; Clock line for serial-to-parallel drivers is bit 2 in PORTB
NBL equ 3 ; NOT Blank for serial-to-parallel drivers is bit 3 in PORTB
DAT equ 4 ; Data line for serial-to-parallel drivers is bit 4 in PORTB
NLE equ 5 ; NOT Latch Enable for serial-to-parallel drivers is bit 5 in PORTB
SW1 equ 2 ; Switch 1 is bit 2 in PORTA
SW2 equ 3 ; Switch 2 is bit 3 in PORTA
short1 equ 0 ; Short press of Button 1 was made
long1 equ 1 ; Long press of Button 1 was made
short2 equ 2 ; Short press of Button 2 was made (or any press...not tracking long)
long2 equ 3 ; (reserved in case I want to track long pressed of Button 2)
Done equ 4 ; Flag Bit 4 used to see if world line animation is done
Slide equ 5 ; Flag Bit 5 used for 'slide loading' in Loader (1=slide)
APnow equ 6 ; Flag Bit 6 keeps track of whether current time is AM or PM (1=PM)
Clk12 equ 7 ; Flag Bit 7 is 12/24 hour preference flag (1=12 hour clock)
negWL equ 7 ; Bit 7 of Eflag is for negative world lines.
toggl equ 6 ; Bit 6 of Eflag is for toggling
beta equ 5 ; Bit 5 of Eflag is for beta world line
deBounceDly equ d'30' ; Set the constant for the deBounce delay time
; Variables for I2C routines need to be accessable in Bank1, so I'll start them at 70h (where there are registers availble to both Banks 0 and 1).
GenCount equ 70 ; General-purpose counter/scratch register
Mem_Loc equ 71 ; Memory address within DS1307 chip to access
Data_Buf equ 72 ; Byte read from DS1307 gets stored here
Out_Byte equ 73 ; Used to hold byte to be written to DS1307
Eflag equ 74 ; Flag bit register
brightSet equ 75 ; Clock Brightness preference by user (also here so it can be loaded from EEPROM 7Eh while we are in Bank 1)
dateDMY equ 76 ; Date setting peference by user 1= prefers DD MM YY 0= prefers MM DD YY (read from in EEPROM 7Dh)
pointer equ 77 ; Pointer to track EEPROM address (accessible from both Banks)
timeAdj equ 78 ; Time adjustment register (number of hours between time adjustments)
timeFast equ 79 ; Time adjustment for Fast or Slow clock (1=fast 0=slow)
; Define port pins for I2C access of DS1307: SCL clock line is RA0. SDA data line is RA1.
; The lines have 10K pullup resistors and will be used in passive control mode where the outputs
; are set to zero, and then controlled by setting and clearing TRISA,0 and TRISA,1. Setting TRIS
; bit high will make pin an input, and the resistor will pull the line connected to that high-Z
; pin high (1). Clearing TRIS bit makes pin an output, and the zero will be output to make the
; line low (0). This must be done in Bank1 where the TRIS register can be accessed. Why all this?
; Because this way the I2C slave (DS1307) can pull the high line low in response.
; Where the assembler sees the symbols defined below, they are the same as the "TRISA,n" stuff
; (or as "PORTA,n" in Bank0).
#define SCL TRISA,0
#define SDA TRISA,1
;**********************************************************************
ORG 0x000 ; processor reset vector
goto Main ; go to beginning of program
;======================
;Interrupt routines
ORG 0x004 ; interrupt vector location
movwf wTmp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf statusTmp ; save off contents of STATUS register
; isr code can go here or be located as a call subroutine elsewhere
movf statusTmp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf wTmp,f
swapf wTmp,w ; restore pre-isr W register contents
retfie ; return from interrupt
;======================
;Subroutines
RunLength addwf PCL,f ; Lookup Table for run lengths (appropriate random number in W... 0-7, 0-15, 0-63)
retlw d'20' ; The first 8 are multiples of 10, for use when tube 7 returns to starting digit.
retlw d'30' ; The first 16 are multiples of 5, for use when two cycles return digits to same.
retlw d'40' ; The rest of the 64 are spaced to give good stopping distribution.
retlw d'50' ;
retlw d'50' ;
retlw d'60' ;
retlw d'60' ;
retlw d'70' ; Last of the first 8
retlw d'15' ;
retlw d'25' ;
retlw d'35' ;
retlw d'45' ;
retlw d'55' ;
retlw d'55' ;
retlw d'55' ;
retlw d'65' ; Last of the first 16
retlw d'18' ;
retlw d'19' ;
retlw d'22' ;
retlw d'23' ;
retlw d'24' ;
retlw d'26' ;
retlw d'27' ;
retlw d'28' ;
retlw d'29' ;
retlw d'31' ;
retlw d'32' ;
retlw d'33' ;
retlw d'34' ;
retlw d'36' ;
retlw d'37' ;
retlw d'38' ;
retlw d'39' ;
retlw d'41' ;
retlw d'42' ;
retlw d'43' ;
retlw d'44' ;
retlw d'46' ;
retlw d'47' ;
retlw d'48' ;
retlw d'49' ;
retlw d'16' ;
retlw d'51' ;
retlw d'17' ;
retlw d'52' ;
retlw d'68' ;
retlw d'53' ;
retlw d'67' ;
retlw d'21' ;
retlw d'69' ;
retlw d'54' ;
retlw d'56' ;
retlw d'56' ;
retlw d'64' ;
retlw d'57' ;
retlw d'57' ;
retlw d'66' ;
retlw d'58' ;
retlw d'58' ;
retlw d'63' ;
retlw d'59' ;
retlw d'59' ;
retlw d'61' ;
retlw d'62' ; Last of 64
;--------
deBounce ; Debounce delay with brightness control
bsf ShadowB,NBL ; Set bit for tubes NOT Blanked
movfw Delay2 ; Get current Delay2 value
andlw b'00000111' ; Keep only 3 rightmost digits (0 to 7)
subwf bright,w ; See if result is greater than brightness number
btfss STATUS,C ; If Y<w, C=0
bcf ShadowB,NBL ; So if Y<w, Clear bit for tubes Blanked
movfw ShadowB ; Move tube blanking result to PORTB
movwf PORTB ;
deBounce1 decfsz Delay1,f ; Runs through 256 loopings of Delay1
goto deBounce1 ;
decfsz Delay2,f ; Decrements Delay2
goto deBounce ; If Delay2 not over, wait more.
movlw deBounceDly ; Delay2 ran out, so reload it for next time
movwf Delay2
return
;-------
delay movwf Counter ; Delay with brightness control. Time in W when called.
delay1 bsf ShadowB,NBL ; Set bit for tubes NOT Blanked
movfw Counter ; Get current Counter value
andlw b'00000111' ; Keep only 3 rightmost digits (0 to 7)
subwf bright,w ; See if result is greater than brightness number
btfss STATUS,C ; If Y<w, C=0
bcf ShadowB,NBL ; So if Y<w, Clear bit for tubes Blanked
movfw ShadowB ; Move tube blanking result to PORTB
movwf PORTB ;
delay2 decfsz Delay1,f ; Inner loop...
goto delay2 ; runs through 256 loopings decrementing Delay1
decfsz Counter,f ; Decrement Counter.
goto delay1 ; and do more loops until Counter is zero
return
;-------
delay100 movwf Counter ; Delay 100% brightness. Time in W when called.
delay3 decfsz Delay1,f ; Inner loop...
goto delay3 ; runs through 256 loopings decrementing Delay1
decfsz Counter,f ; Decrement Counter.
goto delay3 ; and do more loops until Counter is zero
return ; Retuns with W intact to call again if desired
;-------
FillBlanks movlw d'8' ; Going to blank 8 tubes
movwf Counter ; with this counter
movlw T0 ; ADDRESS of T0
movwf FSR ; for indirect addressing
movlw d'10' ; 10 will display blank in tube
nextBlank movwf INDF ; Put it in a tube register
incf FSR,f ; Increment for next tube
decfsz Counter,f ; See if I'm done
goto nextBlank ; Not yet
return ;
;-------
; This routine gets the contents of a register from DS1307 and puts the ones digit in T0 and
; the tens digit in T1.
; Call with memory location value in W, *or* call GetT1T0b if location is already in Mem_Loc
GetT1T0 movwf Mem_Loc
GetT1T0b call ReadDS1307 ; Get the contents from the clock register with location already in Mem_Loc
FillT1T0 movfw Data_Buf ; (for calls that jump in here, bring Data_Buf into W)
andlw b'00001111' ;
movwf T0 ; Put ones digit into T0
swapf Data_Buf,w ;
andlw b'00001111' ;
movwf T1 ; Put tens digit into T
return
;-------
Buttons movlw b'11110000' ; Clear the Button flag return bits (bits 0-3)
andwf Flag,f ;
call deBounce ; Call deBounce to give the tubes some properly dimmed display time
btfsc PORTA,SW1 ; Button 1 pressed?
goto length ; ...yes, go see if it's long or short
btfsc PORTA,SW2 ; Button 2 pressed?
goto any2press ; ...yes, go handle button 2 press
goto Buttons ; Neither button pressed. Wait more.
length movlw d'40' ; This many deBounce times is a long push
movwf Counter ; (With deBounce Delay2=30 and Counter=40, about 1 second)
watch btfss PORTA,SW1 ; Button 1 released?
goto short1press ; ...yes. Go handle short push of Button 1.
call deBounce ; Wait some (tubes get displayed with dimming during deBounce)
decfsz Counter,f ; Done counting?
goto watch ; ...still counting. Go wait more.
; Fallen out of long delay...
long1press btfsc PORTA,SW1 ; Handle long press of button 1
goto long1press ; ...after first waiting for release.
call deBounce ; deBounce after relase.
bsf Flag,long1 ; Flag long press of Button 1
return
short1press call deBounce ;
bsf Flag,short1 ;
return
any2press btfsc PORTA,SW2 ; Handle press of button 2
goto any2press ; ...after first waiting for release.
call deBounce ; deBounce after relase.
bsf Flag,short2 ;
return
;--------
Increment call deBounce ; This routine increment/decrements settings values
call Buttons
btfsc Flag,short2 ; If Button 2 press, done adjusting
return
btfsc Flag,short1 ; If Button 1 short press...
goto incValue ; ...go increment value
decValue movfw incMin ; ...otherwise, decrement value. First we see if it already at Min...
subwf Data_Buf,w ; ...by subtracting (packed BCD numbers). Result will be Zero if they are the same.
btfsc STATUS,Z ;
goto setToMax ; If Z=1, they were the same, so go set Data_Buf to incMax.
; If Z=0, decrement the packed BCD.
decBCD movlw b'00001111' ; First check to see if the right digit is 0000...
andwf Data_Buf,w ; ...by grabbing the right digit into W
btfss STATUS,Z ; If the result in W was Zero, the Z bit will be set
goto decNow ; ...If Z=0, go decrement directly
movlw b'00001001' ; ...If Z=1, the right digit was zero, and we must set it to 9 and borrow
addwf Data_Buf,f ; Here is the setting the right digit to 9 instead of zer0
movlw b'00010000' ; And then...
subwf Data_Buf,f ; ...here is the subtracting 1 from the left digit (borrow).
goto valueOK
decNow decf Data_Buf,f ; If the right digit is not zero, we can just decrement the packed BCD directly.
goto valueOK ; and be done.
setToMax movfw incMax ; Take the packed BCD pattern of incMax...
movwf Data_Buf ; ...and put it into Data_Buf.
goto valueOK ;
incValue movfw incMax ; Move incMac (packed BCD) into W for compare
subwf Data_Buf,w ; If Data_Buf is >= max, result will Carry flag will be set
btfsc STATUS,C ; If C clear, go increment.
goto setToMin ; If C set, go put incMin in.
incBCD incf Data_Buf,f ; Increment the packed BCD. This might cause right digit to go to hex A...
movlw b'00001111' ; so let's get that digit...
andwf Data_Buf,w ; by doing this...
sublw b'00001010' ; so we can compare to hex A
btfss STATUS,Z ; Is that digit hex A? If it is, Z=1
goto valueOK ; If Z is not set, we are fine and quit
movlw b'11110000' ; If Z is set...
andwf Data_Buf,f ; ...do this AND to zero out the right digit...
movlw b'00010000' ; ...and add one to the left digit...
addwf Data_Buf,f ; ...and done!
goto valueOK ;
setToMin movfw incMin ; Take the packed BCD pattern of incMin...
movwf Data_Buf ; ...and put it into Data_Buf.
goto valueOK ;
valueOK call FillT1T0 ; Fill new value into tubes
call Loader ;
goto Increment ;
;--------
; Routine to send a 1 to the serial-to-parallel drivers.
send1 bsf ShadowB,DAT ; Set Data line high for one
bsf ShadowB,CLK ; Set clock high
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB
bcf ShadowB,CLK ; Set clock low
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB
return
;-------
; Routine to send a 0 to the serial-to-parallel drivers.
send0 bcf ShadowB,DAT ; Set Data line high for one
bsf ShadowB,CLK ; Set clock high
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB
bcf ShadowB,CLK ; Set clock low
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB
return
;-------
RandomNum movlw d'63' ; Pseudo-random number generator
addwf random,w ; newRandom = 3 x oldRandom + 63
addwf random,w ;
addwf random,f ;
movfw random ;
return ;
;-------
; Call with: DS1307 register address in Mem_Loc
; Returns with: byte in Data_Buf
ReadDS1307 bcf STATUS,RP0 ; Bank0
movfw ShadowA ; Clear bits RA0 and RA1 in shadowA and PORTA...
andlw b'11111100' ; ...for passive control of the I2C lines (if one of those pins gets
movwf ShadowA ; ...set as output, these zeros will make the line low, and if the
movwf PORTA ; ...pin is set as (Hi-Z) inputs, a resistor pulls the line high.
bsf STATUS,RP0 ; Select Bank 1 for TRISA access (passive SCL/SDA control)
bsf SDA ; Let SDA line get pulled high (by setting it as a input)
bsf SCL ; Let SCL line get pulled high (by setting it as a input)
bcf SDA ; START condition = data line going low while clock line is high
movlw b'11010000' ; Send Write (to set address before reading)
call Byte_Out ;
btfsc Eflag,0 ; Eflag bit0 will be set if no ACK received from DS1307
goto Err_Routine ; NOTE: MUST USE "RETURN" FROM THAT ROUTINE
movfw Mem_Loc ; Memory location we want to read is in Mem_Loc
call Byte_Out ; ...and needs to be in W when Byte_Out is called
btfsc Eflag,0 ;
goto Err_Routine ;
bcf SCL ; Pull clock line low in preparation for 2nd START bit
nop ;
bsf SDA ; Data line gets pulled high - data transition during clock low
bsf SCL ; Clock line gets pulled high to begin generating START
bcf SDA ; 2nd START condition as data line goes low
movlw b'11010001' ; Request data read from DS1307 register
call Byte_Out ;
btfsc Eflag,0 ;
goto Err_Routine ;
; Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master.
call Byte_In ;
movfw Data_Buf ; put result into W register for returning from CALL
bcf SCL ; extra cycle for SDA line to be freed from DS1307
nop ;
bcf SDA ; ensure SDA line low before generating STOP
bsf SCL ; pull clock high for STOP
bsf SDA ; STOP condition = data line goes high while clock line is high
bcf STATUS,RP0 ; leave with Bank 0 active as default
return
;-------
; Save each byte as it's written
; Call with: a DS1307 resister address in Mem_Loc, byte to be sent in Data_Buf
; Returns with: nothing returned
WriteDS1307 bcf STATUS,RP0 ; Bank0
movfw ShadowA ; Clear bits RA0 and RA1 in shadowA and PORTA
andlw b'11111100' ; ...for passive control of the I2C lines (if one of those pins gets
movwf ShadowA ; ...set as output, these zeros will make the line low, and if the
movwf PORTA ; ...pin is set as (Hi-Z) inputs, a resistor pulls the line high.
bsf STATUS,RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control)
bsf SDA ; ensure SDA line is high
bsf SCL ; clock high gets pulled high
bcf SDA ; START condition = data line going low while clock is high
movlw b'11010000' ; Send Write code (to set address first)
call Byte_Out ;
btfsc Eflag,0 ; Eflag bit0 gets set of not ACK received from DS1307
goto Err_Routine ; NOTE: MUST USE "RETURN" FROM THAT ROUTINE
movfw Mem_Loc ; Send the memory location to wite to...
call Byte_Out ; ...now
btfsc Eflag,0 ;
goto Err_Routine ;
movfw Data_Buf ; move data byte to be sent to W
call Byte_Out ;
btfsc Eflag,0 ;
goto Err_Routine ;
bcf SCL ; extra cycle for SDA line to be freed from DS1307
nop ;
bcf SDA ; Ensure SDA line low before generating STOP...
bsf SCL ; pull clock high for STOP..
bsf SDA ; STOP condition = data line goes high.
bcf STATUS,RP0 ; Leave with Bank 0 active by default
return
;-------
; This routine reads one byte of data from the DS307 real-time Clock chip into Data_Buf
Byte_In clrf Data_Buf ;
movlw 0x08 ; 8 bits to receive
movwf GenCount ;
ControlIn rlf Data_Buf,f ; Shift bits into buffer
bcf SCL ; Pull clock line low
nop ;
bsf SCL ; Clock line gets pulled high to read bit
bcf STATUS,RP0 ; Select Bank 0 to read PORTA bits directly!
btfss SDA ; Test bit from DS1307 (if bit=clear, skip because Data_Buf is clear)
goto $+3 ; Jump ahead 3 instructions
bsf STATUS,RP0 ; Select Bank 1 to access variables (Don't think I need this [could nop], but I'll leave it.)
bsf Data_Buf,0 ; Read bit into 0 first, then eventually shift to 7
bsf STATUS,RP0 ; Select Bank 1 to access variables (Don't think I need this [could nop], but I'll leave it.)
decfsz GenCount,f ;
goto ControlIn ;
return
;-------
; This routine sends out the byte in the W register and then waits for ACK from DS1307 (256us timeout period)
Byte_Out movwf Out_Byte ; Byte to send was in W...now also in Out_Byte
movlw 0x08 ; 8 bits to send
movwf GenCount ;
rrf Out_Byte,f ; shift right in preparation for next loop
ControlOut rlf Out_Byte,f ; shift bits out of buffer
bcf SCL ; pull clock line low
nop ;
btfsc Out_Byte,7 ; send current "bit 7"
goto BitHigh ;
bcf SDA ;
goto ClockOut ;
BitHigh bsf SDA ;
ClockOut bsf SCL ; pull clock high after sending bit
decfsz GenCount,f ;
goto ControlOut ;
bcf SCL ; pull clock low for ACK change
bsf SDA ; free up SDA line for slave to generate ACK
nop ; wait for slave to pull down ACK
nop
nop
bsf SCL ; pull clock high for ACK read
clrf GenCount ; reuse this register as a timeout counter (to 256us) to test for ACK
WaitForACK bsf STATUS,RP0 ; select Bank1 for GenCount access (Don't think I need this [could nop], but I'll leave it.)
incf GenCount,f ; increase timeout counter each time ACK is not received
btfsc STATUS,Z ; Z will be clear until we increment GenCount all the way up to zero (after 256 times)
goto No_ACK_Rec ;
bcf STATUS,RP0 ; select Bank0 to test SDA PORTA input directly!
btfsc SDA ; test pin. If clear, EEPROM is pulling SDA low for ACK
goto WaitForACK ; ...otherwise, continue to wait
bsf STATUS,RP0 ; select Bank1 as default during these routines
bcf Eflag,0 ; clear flag bit (ACK received)
return
;-------
; No ACK received from DS1307 (must use "return" from here)
; Set a flag bit to indicate failed write and check for it upon return.
No_ACK_Rec bsf Eflag,0 ; set flag bit
return ; returns to Byte_Out routine (Bank 1 selected)
;-------
; No ACK received from slave. This is the error handler.
Err_Routine
bcf STATUS,RP0 ; make sure I'm in Bank0 to flash LED
call FillBlanks ; fill tubes with blanks
movlw d'6' ; Put error code "666" in tubes 0-2
movwf T2
movwf T1
movwf T0
clrf LeftDP ; Clear the decimal points
clrf RightDP
call Loader ; Load the display
bsf ShadowB,NBL ; set NOT Blanking high (tubes no longer blanked),
bsf ShadowB,HVE ; and Set High Voltage Enable ON to display the tubes now, too.
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB
Crash666 goto Crash666 ; Infinite loop crash.
; And unused below, just for the look of things:
return ; returns to INITIAL calling routine
;------
Fun clrf T7 ; Zero out the leftmost tube for most random world lines
bcf Eflag,beta ; Clear the beta world line flag.
bcf Eflag,negWL ; Clear negative world line flag.
movfw TMR0 ; Seed 0-255 randomly by switch release that got us here
movwf random ; Store the random number.
; Other worldline branchings will go here:
call RandomNum ; Gets 0-255 in W
andlw b'11111100' ; This will clear the right two bits of W and leave the rest unaltered. If W is now zero, it
; must have been 0 to 3 before the AND.
btfsc STATUS,Z ; See if the random number is now zero (4 out of 256 chance)
bsf Eflag,negWL ; If so, make this a negative world line (first tube will show up blank).
andlw b'11110000' ; This will clear the right three bits of W and leave the rest unaltered. If W is now zero, it
; must have been 0 to 15 before the AND.
btfsc STATUS,Z ; See if W is now zero (16 out of 256 chance it is)
bsf Eflag,beta ; Display a beta world line number (1.xxxxxx)
; (Of course, it was 0, we already flagged it as negative WL)
call RandomNum ; Gets 0-255 in W
andlw b'00000111' ; 0-7 in W
call RunLength ; Gets runlength that's a multiple of 10 for tube 7
movwf TR7 ; so leftmost tube will return to 0.
btfsc Eflag,beta ; But if we got a beta world line...
incf TR7,f ; increment the run length so it will stop at one.
clrf TR6 ; Decimal point tube does no incrementing.
FillRunLens movlw TR5 ; ADDRESS of TR5
movwf FSR ; for indirect addressing.
nextRL call RandomNum ; Gets 0-255 in W
andlw b'00111111' ; 0-63 in W
call RunLength ; Gets tube's run length
movwf INDF ; and puts it in TRn
decf FSR,f ; Decrement for next tube
movlw T7 ; ADDRESS of T7 register (below the TRn registers)
subwf FSR,w ; Does FSR minus T7;s address
btfss STATUS,Z ; see if result is zero
goto nextRL ; no...go get runlength for next tube
; yes...all TRn filled
call animate ;
return ;
;-------
animate bcf Flag,Done ; Clear bit Done of Flag for tracking if animation is done.
movfw TR7 ; Load TR7 runlength into W
btfsc STATUS,Z ; and see if it's zero.
goto chkNeg ; If zero, skip to tubes 5 thru 0 (7 has already stopped)
decf TR7,f ; If not zero, do tube 7. Decrement runlength.
bsf Flag,Done ; Set bit so we know we haven't finished aniation.
incf T7,f ; Increment T7 value
movlw d'10' ; See if it went over 9...
subwf T7,w ;
btfsc STATUS,C ; If new T7 < 10, C=0
clrf T7 ; so clear T7 to zero if it reached 10.
goto IncTubes ; On to tubes 5-0
chkNeg movlw d'10' ; Before we go one to tubes 5-0, check to see if this is a negative world line...
btfsc Eflag,negWL ;
movwf T7 ; ...If it is, we blank tube 7.
IncTubes movlw TR5 ; ADDRESS of TR5
movwf FSR ; for indirect addressing
nextTube movfw INDF ; Put TRn runlength into W
btfsc STATUS,Z ; and see if it's zero.
goto notthis ; If zero, don't do this tube (done animating it), and go to next one.
decf INDF,f ; If not zero, do this tube. Decrement runlength.
bsf Flag,Done ; Set bit so we know we haven't finished aniation.
movlw d'8' ; Subtract 8 from FSR so it points
subwf FSR,f ; to Tn instead of TRn
incf INDF,f ; Increment Tn
movlw d'10' ; See if it went over 9...
subwf INDF,w ;
btfsc STATUS,C ; If new Tn < 10, C=0
clrf INDF ; so clear Tn to zero if it reached 10.
movlw d'8' ; Add 8 back into FSR to
addwf FSR,f ; put it back to TRn
notthis decf FSR,f ; Decrement to do next tube
movlw T7 ; ADDRESS of T7 register (below the TRn registers)
subwf FSR,w ; Does FSR minus T7's address
btfss STATUS,Z ; If we have done all the tubes, Zero flag will be clear.
goto nextTube ; if Zero not clear, go do next tube
; We get here if all tubes done.
btfss Flag,Done ; See if no tubes were changed (Flag,Done would be clear).
goto alldone ; No tubes changed...we are finished
call Loader ; Display the new number in the tubes
movlw d'30' ; Delay to see the number
call delay ;
goto animate ; And go to the next animation step.
alldone call Pulse ; Animation done. Do flash at end of animation
return ;
;------
Pulse movlw d'7' ; Flash full brightness
movwf bright ;
movlw d'200' ; Flash at end of animation
call delay ;
movlw d'6' ; Fade to level 6 brightness
movwf bright ;
movlw d'50' ;
call delay ;
movlw d'5' ; Fade to level 5 brightness
movwf bright ;
movlw d'40' ;
call delay ;
movlw d'4' ; Fade to level 4 brightness
movwf bright ;
movlw d'30' ;
call delay ;
movlw d'3' ; Fade to level 3 brightness
movwf bright ;
return ;
;------
Fun2 movfw TMR0 ; Seed 0-255 randomly by switch release that got us here
movwf random ; Store the random number.
FillRuns movlw TR7 ; ADDRESS of TR7
movwf FSR ; for indirect addressing.
nextRLen call RandomNum ; Gets 0-255 in W
andlw b'00111111' ; 0-63 in W
call RunLength ; Gets tube's run length
movwf INDF ; and puts it in TRn
decf FSR,f ; Decrement for next tube
movlw T7 ; ADDRESS of T7 register (below the TRn registers)
subwf FSR,w ; Does FSR minus T7's address
btfss STATUS,Z ; see if result is zero
goto nextRLen ; no...go get runlength for next tube
; yes...all TRn filled
clrf TR6 ; Decimal point tube does no incrementing. I could have not filled it, but it seems simpler to just clear it now.
call animate2 ;
return
;------
; animate2 is different from animate in that when it stops it will be displaying V7-V0 values.
animate2 bcf Flag,Done ; Clear bit Done of Flag, for tracking if animation is done.
IncTubes2 movlw TR7 ; ADDRESS of TR7
movwf FSR ; for indirect addressing
nextTube2 movfw INDF ; Bring TRn runlength into W
btfsc STATUS,Z ; and see if it's zero.
goto notthis2 ; If zero, this tube's run length has run out (done animating it), and go to next one.
decf INDF,f ; If not zero, do this tube. Decrement runlength.
movfw INDF ; Let's see if it just got to zero after the decrement above
btfss STATUS,Z ;
goto keepon ; If it was decremented to zero, we go on as before
movlw d'8' ; But if the runtime just decremented to zero, let's make sure it has it's final value in it:
addwf FSR,f ; Add 8 to FSR to get the corresponding Vn register
movfw INDF ; and take the value from that register
movwf work ; hold it here for a while
movlw d'16' ; then point tho the corresponding Tn tube
subwf FSR,f ; by adjusting FSR 16 registers down
movfw work ; grabbing the value
movwf INDF ; and putting it into Tn
movlw d'8' ; Then let's bring FSR back to the TRn registers, but one register lower than before
addwf FSR,f ; so we can do the next tube.
goto notthis2 ;
keepon bsf Flag,Done ; Set bit so we know we haven't finished aniation.
movlw d'8' ; Subtract 8 from FSR so it points
subwf FSR,f ; to Tn instead of TRn
incf INDF,f ; Increment Tn
movlw d'10' ; See if it went over 9...
subwf INDF,w ;
btfsc STATUS,C ; If new Tn < 10, C=0
clrf INDF ; so clear Tn to zero if it reached 10.
movlw d'8' ; Add 8 back into FSR to
addwf FSR,f ; put it back to TRn
notthis2 decf FSR,f ; Decrement for next tube.
movlw T7 ; ADDRESS of T7 register (below the TRn registers)
subwf FSR,w ; This does FSR minus T7's address
btfss STATUS,Z ; If we have gone through all the tubes another time, Zero flag will be clear.
goto nextTube2 ; if Zero not clear, go do next tube
; We get here if all tubes done.
btfss Flag,Done ; See if no tubes were changed (Flag,Done would be clear).
goto alldone2 ; No tubes changed...we are finished
call Loader ; Display the new number in the tubes
movlw d'30' ; Delay to see the number
call delay ;
goto animate2 ; And go to the next animation step.
alldone2 call Loader ; Final load
call Pulse ; Animation done. Do flash at end of animation
return ;
;------
; Routin copies T0-T7 into V0-V7
moveNumber movlw T0 ; ADDRESS of T0
movwf FSR ; for indirect addressing.
nextMove movfw INDF ; Get Tn
movwf work ; put it in work
movlw d'16' ; Change the FSR pointer by +16 to point
addwf FSR,f ; to the corresponding Vn register
movfw work ; Get the value
movwf INDF ; and put it where it Vn
movlw d'15' ; Change the FSR pointer by -15 to point
subwf FSR,f ; to the T(n+1) register
movlw TR0 ; ADDRESS of TR0 (which is right above T7)
subwf FSR,w ; Test to see if FSR is pointing to TR0
btfss STATUS,Z ; which will be true if the Zero bit is set;
goto nextMove ; If it's not true, we go do the next tube's values
return ; And if it is true, we are all done moving and get here, so Return.
;------
Loader movfw LeftDP ; Routine to load a number into all 8 tubes. Values are in T0-T7, LeftDP, and RightDP.
movwf LDP ; Make copies of LeftDP and RightDP so contents are not destroyed.
movfw RightDP ;
movwf RDP ;
movlw T7 ; Put the *ADDRESS* of T7 register into W ("T7" is equated to that address)
movwf FSR ; ...and then into the File Select Register. We can now access the number we want displayed on a tube using INDF.
loopLoad rlf LDP,f ; Rotate a dp flag into the Carry bit
btfsc STATUS,C ; Is the dp flag set?
goto dpset ; ...yes, jump to dpset.
call send0 ; ...no, so send 0 to the shift registers.
goto digi ; and then jump to continue with the digit.
dpset call send1 ; dp flag was set, so send 1 to shift registers
digi movlw d'9' ; Put 9 into m. This will decrement as we go through loopdigi.
movwf m
clrf n ; Start with n=0. This will increment as we go through loopdigi.
loopdigi incf n,f ; Increment n (n is the number we compare against the digit we want to show).
movfw n ; Get the current n...
subwf INDF,w ; See if the digit we want to display equals n by subtract n from that digit (via INDF) and leave result in W
btfsc STATUS,Z ; If that digit=n (Zero flag will be set from subtraction), then...
goto yesdigi ; ...goto yesdigi
call send0 ; ...otherwise send a 0 to the shift registers.
goto nextshift ; and check the next bit to shift
yesdigi call send1 ; Digit=n, so send a 1 to the shift registers.
nextshift decfsz m,f ; Decrement m and see if we are done.
goto loopdigi ; ...if not done go back to loopdigi
movfw INDF ; When we get here we still need to see if the digit is a zero
btfsc STATUS,Z ; If that digit=0 (Zero flag will be set from moving it into W), then...
goto yeszero ; ...goto yeszero
call send0 ; ...otherwise send a 0 to the shift registers.
goto checkRDP ; and check the next bit to shift
yeszero call send1 ; Digit=n, so send a 1 to the shift registers.
checkRDP rlf RDP,f ; Digit is done, so check for right decimal point
btfsc STATUS,C ; Is the dp flag set?
goto dpset2 ; ...yes, jump.
call send0 ; ...no, so send 0 to the shift registers.
goto tubeDone ; and then jump to continue
dpset2 call send1 ; dp flag was set, so send 1 to shift registers
tubeDone decf FSR,f ; Decrement File Select Register to do next tube.
btfss Flag,Slide ; "Slide Loading" flag
goto noSlide ; If Flag,Slide is clear, normal load (skip this next stuff)
LatchSlide bsf ShadowB,NLE ; Latch the result sf current tubes:
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB (Latches load when NLE is high)
bcf ShadowB,NLE ; Get ready to lock the latches.
bsf ShadowB,NBL ; Set NOT Blanking high (tubes no longer blanked) while I'm at it
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB (Latches lock when NLE is low)
movlw d'80' ; Pause for display
call delay
noSlide movlw RightDP ; Put the *ADDRESS* of the RightDP register into W ("RightDP" is equated to that address)
subwf FSR,w ; ...and subtract it from FSR to see if we did all the tubes.
btfss STATUS,Z ; If we haven't done all the tubes, Zero flag will be clear
goto loopLoad ; so go back and do the next tube.
Latch bsf ShadowB,NLE ; Latch the result:
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB (Latches load when NLE is high)
bcf ShadowB,NLE ; Get ready to lock the latches.
bsf ShadowB,NBL ; Set NOT Blanking high (tubes no longer blanked) while I'm at it
movfw ShadowB ; Copy ShadowB...
movwf PORTB ; ...to PORTB (Latches lock when NLE is low)
return
;======================================================================
;Program Start
Main ; Main routine
Init clrf PORTA ; Clear Port A
clrf ShadowA ; Clear ShadowA
movlw 0x07 ; Turn comparators off and
movwf CMCON ; enable pins for I/O functions
clrf PORTB ; Clear Port B
clrf ShadowB ; Clear ShadowB
bcf STATUS,RP1 ; First time, make sure this is also clear so the next command...
bsf STATUS,RP0 ; Goes to Bank 1
movlw b'00101111' ; Set input/output pins in PORTA
movwf TRISA ; RA0 is SCL (clock) to clock chip
; RA1 is SDA (data) to clock chip
; RA2 is button 1
; RA3 is button 2
; RA4-RA7 are not used (except RA5 is for programmer)
movlw b'00000000' ; Set all pins as outputs
movwf TRISB ; RB0 is LED output for testing
; RB1 is High Voltage Enable
; RB2 is Clock line to serial chips
; RB3 is NOT Blank line to serial chips
; RB4 is Data line to serial chips
; RB5 is NOT Latch Enable to serial chips
; RB6-RB7 are for programmer
movlw b'11011111' ; Set TMR0 to clock off the internal clock, no prescaler (prescaler assigned to WDT)
movwf 0x81 ; Huh... "OPTION" was not recognized here. Why?
; Read timeFast setting from EEPROM
movlw 0x7B ; Address to read...
movwf EEADR ; ...gets put here.
bsf EECON1,RD ; EE Read
movfw EEDATA ; W = EEDATA
movwf timeFast ; Put it in its place (which is a register also available in Bank 1)
; Read timeAdj setting from EEPROM
movlw 0x7C ; Address to read...
movwf EEADR ; ...gets put here.
bsf EECON1,RD ; EE Read
movfw EEDATA ; W = EEDATA
movwf timeAdj ; Put it in its place (which is a register also available in Bank 1)
; Read date format setting from EEPROM
movlw 0x7D ; Address to read...
movwf EEADR ; ...gets put here.
bsf EECON1,RD ; EE Read
movfw EEDATA ; W = EEDATA
movwf dateDMY ; Put it in its place (which is a register also available in Bank 1)
; Read brightness setting from EEPROM
movlw 0x7E ; Address to read...
movwf EEADR ; ...gets put here.
bsf EECON1,RD ; EE Read
movfw EEDATA ; W = EEDATA
movwf brightSet ; Put it in its place (which is a register also available in Bank 1)
; Read 12/24 clock setting from EEPROM
movlw 0x7F ; Address to read...
movwf EEADR ; ...gets put here.
bsf EECON1,RD ; EE Read
movfw EEDATA ; W = EEDATA (W will now have the 12/24 setting, either 00000001 for 12-hour, or 00000000 for 24-hour)
bcf STATUS,RP0 ; Back to Bank 0
clrf Flag ; Clear the Flag register
; btfsc W,0 ; Clock preference setting from EEPROM is in W from before <-- ERROR HERE. Can't test bits in W like this!
movwf work ; Move W to register "work"...
btfsc work,0 ; ...and do the test there.
bsf Flag,Clk12 ; Set the 12/24 flag based upon it. (1 = 12 hour)
; I am handling 12/24 setting myself and leaving DS1307 in 24 hour mode.
movfw timeAdj ; Copy the timeAdj value into the
movwf hourCount ; hour counter to track when time adjustments need to be made.
; Note that this will get reset if you unplug/replug the device, since it may have been previously partway
; through a count...so don't unplug for maximum accuracy (or reset time after unplug). But it will be close.
; Also, the hour counter won't count if you are playing in D.M. mode at the top of the hour.
clrf Delay1 ; Will be used to loop 256 times
movlw deBounceDly ; Will loop deBounce this many times (constant deifned in equates)
movwf Delay2 ; Will be used to loop n times
bcf ShadowB,LED ; Set bit for LED OFF in ShadowB
bcf ShadowB,NBL ; Set Not Blanking low (this will blank the tubes)
bcf ShadowB,HVE ; Set bit for High Voltage Enable OFF
bcf ShadowB,NLE ; Set NOT Latch Enable low (transfer of bits from shift registers to latches is OFF)
bcf ShadowB,CLK ; Set Clock line low (setting it high and back low will clock the serial chips...62 ns minimum pulse width)
movfw ShadowB ; copy ShadowB to PORTB
movwf PORTB ;
clrf Eflag ; Clear the error flag register
; See if the Real Time Clock is running (or if loss of backup battery power has stopped it).
clrf Mem_Loc ; First check CH (Clock Halt) bit in the seconds register (00h) to see if DS1307 is halted
call ReadDS1307 ; Read the seconds register (Mem_Loc = 00h) from DS1307
btfsc Data_Buf,7 ; Test CH bit (bit 7)
goto Start1307 ; ...if CH is set, DS1307 is stopped and needs startup
; ...if CH is clear, either DS1307 is running, or this may be a DS3232 (running or stopped).
movlw 0x0F ; See if the DS3232 Clock is running by checking bit 7 of 0Fh in the clock chip
movwf Mem_Loc ;
call ReadDS1307 ; Read the 0Fh register (a control/status register in the DS3232; a RAM register in the DS1307)
btfss Data_Buf,7 ; Oscillator Stopped Flag is bit 7
goto ClockON ; ...if OSF is clear, Clock was running (with battery backup)
; ...if we get here, this is either a stopped DS3232, or a running DS1307 that just
; happens to have RAM 0Fh bit 7 set. To test this, we will try writing a 1 to 0Fh Bit 0
; which is a flag bit in the DS3232 that CAN'T have a 1 written to it.
bcf Data_Buf,0 ; First we clear bit 0
call WriteDS1307 ; ...and write a zero to that bit in 0Fh (just in case there was a 1 there to bein with)
bsf Data_Buf,0 ; ...then we SET bit 0 to 1 in Data_Buf