-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathkeyer-3.0.12.asm
4591 lines (3833 loc) · 112 KB
/
keyer-3.0.12.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
; Keyer 3.0.12
; Goody K3NG
;
; 2004.11.25
; This is a PIC based keyer. Currently supported devices are the 16F84A, 16F628, and 16F628A although memory limits on
; 16F84 make this a bit tough
;
; http://www.qrpis.org
; goody @ qrpis . org
; TODO - code practice, random callsigns
; TODO - turn off startup HI
; TODO - configurable memory repeat delay and store in eeprom
; TODO - RX mute line (use TX wake line)
; TODO - LCD Support
; TODO - DDS Support
; TODO - Configurable beacon sleep time
; TODO - include_beacon_fox_message
errorlevel -302 ; turn off bank 0 / bank 1 warnings
; ************************************** user configurable stuff **********************************************
; processor definition - uncomment one and be sure to set your compiler for the right proc
;#define processor_16f84
#define processor_16f628
;#define processor_16f628a
; ***************************
; * code inclusion *
; ***************************
; comment out these to reduce the code size or change features
; note that some modules of code depend on others; read the notes
; bytes last updated 2004-09-18
#define include_iambic_b_code ; cost: 16 bytes - support for iambic b mode
#define include_wavesidetone_code ; cost: ? bytes - additional support of wavesidetone
#define include_needless_feature_code ; cost: 31 bytes - unimportant stuff (power up "HI")
#define include_function_button_code ; cost: 160 bytes (includes some dependent code); support for buttons other than mode
#define include_toggle_sidetone_on_off_code ; cost: 18 bytes - code to turn off sidetone during TX
#define include_weighting_code ; cost: 77 bytes - command mode W: dah weighting
#define include_paddle_reverse_code ; cost: 39 bytes - command mode R: reverse paddles
#define include_mode_button_hold_code ; cost: 43 bytes - code for mode button hold shortcuts (programming memories, quick speed adj)
#define include_funky_beeps_code ; cost: 17 bytes - code for high and low beeps using wave sidetone; not applicable if using externally keyed sidetone oscillator (requires wavesidetone_code)
#define include_freq_counter_code ; cost: 502 bytes - base frequency counter code
#define include_freq_counter_button_code ; cost: 24 bytes - support for frequency counter button (requires freq_counter_code, function_button_code)
#define include_freq_counter_calib_code ; cost: 56 bytes - code for frequency calibration mode, command L (reqs freq_counter_code, function_button_code)
;#define include_bug_code ; cost: 33 bytes - bug paddle mode
;#define include_call_cq_code ; cost: 55 bytes - call cq mode
;#define include_9850_dds_code ; experimental / under construction
;#define include_calibration_code ; cost: 34 bytes - this adds another command mode for calibrating the speed counters
;#define include_cw_rx_practice_code ; cost: 113 bytes - command mode P: random five letter group code practice
;#define include_cw_tx_practice_code ; cost: 25 bytes - command mode Q: send code without transmitting
#define include_m_and_h_cmd_code ; cost: 86 bytes - command modes M and H: program and playback memories in command mode
;#define include_beacon_code ; cost: 60 bytes - beacon mode support
;#define include_fox_code ; under construction
;#define include_nnnnn_code ; cost: 23 bytes - this code allows you to go into command mode after five consecutive Ns are sent
;#define include_txwake_line_code ; cost: ? bytes - code for TX_WAKE line
;#define include_debug_code ; misc debug code - comment out for production chips
; ***************************
; * options *
; ***************************
#define _4_mhz_clock
; aliases for pins
#define mode_switch PORTB,0x00 ; momentary switch
; PORTB,0x01
#define dit PORTB,0x02 ; dit of paddle
#define dah PORTB,0x03 ; dah of paddle
ifndef include_wavesidetone_code
#define sidetone PORTB,0x04 ; keys external sidetone oscillator
else
#define wavesidetone PORTB,0x04 ; square wave sidetone output
endif
#define key PORTB,0x05 ; transmitter cw key
ifdef include_txwake_line_code
#define txwake PORTB,0x06 ; goes high to turn on TX if used as FM CW unit, or T/R relay
endif
ifdef include_function_button_code
#define switch0 PORTA,0x00
#define switch1 PORTA,0x01
#define switch2 PORTA,0x02
endif
#define initial_speed_wpm d'20' ; this is the default wpm speed when the cw_unit it first powered up
#define initial_memory_repeat_delay d'35' ; this time in between repeating a memory in units of 100mS
; *************** don't adjust anything below this line unless you know what the hell you are doing *************
; eeprom addresses - this defines eeprom memory locations
#define eeprom_addr_speed_wpm 0x00 ; CW speed in binary format
#define eeprom_wavesidetone_setting 0x01 ; sidetone frequency setting
#define eeprom_settings1_location 0x02 ; various user settings, register eeprom_settings1
#define eeprom_freq_calib_high 0x03 ; frequency counter calibration, high byte
#define eeprom_freq_calib_low 0x04 ; frequency counter calibration, low byte
#define eeprom_freq_offset_high 0x05 ; frequency counter offset, lower nibble is BCD2
#define eeprom_freq_offset_low 0x06 ; frequency counter offset, upper nibble is BCD1, lower nibble is BCD0
#define eeprom_memory_location_0 0x07 ; cw memory 0 ( callsign )
#define eeprom_memory_loc_0_cw_units d'28'
; first byte in memory location is a count of cw units stored in that memory
; the remaining bytes are the stored cw units
; a cw unit is two bits and is read MSB to LSB
ifdef processor_16f84
#define eeprom_memory_location_1 0x0F ; cw memory 1
#define eeprom_memory_location_2 0x28 ; cw memory 2
#define eeprom_memory_loc_1_cw_units d'96' ; four cw units can be stored per byte
#define eeprom_memory_loc_2_cw_units d'92'
endif ;processor_16f84
ifdef processor_16f628
#define eeprom_memory_location_1 0x0F ; cw memory 1
#define eeprom_memory_location_2 0x48 ; cw memory 2
#define eeprom_memory_loc_1_cw_units d'224'
#define eeprom_memory_loc_2_cw_units d'220'
endif ;processor_16f628
ifdef processor_16f628a
#define eeprom_memory_location_1 0x0F ; cw memory 1
#define eeprom_memory_location_2 0x48 ; cw memory 2
#define eeprom_memory_loc_1_cw_units d'224'
#define eeprom_memory_loc_2_cw_units d'220'
endif ;processor_16f628a
; timing calibrations - these must be adjusted for clock speed
ifdef _4_mhz_clock
#define _100ms_counter1_calibration 0xff
#define _100ms_counter2_calibration 0x78
#define _100ms_counter3_calibration 0x01
#define _cw_unit_wpm_factor d'20000' ; this adjustment control the time length of one CW unit ( a dit )
#define _beep_length d'20'
#define _high_beep_tone d'20'
#define _low_beep_tone d'55'
#define _initial_wavesidetone_setting d'34' ; this is the default wavesidetone frequency (600Hz)
#define _frequency_counter_calib d'48900' ; higher = shorter sampling duration (1/4 second)
; delay = 15 * 1uS * (65535 - _frequency_counter_calib)
#define _txwake_delay_time d'30000'
#define _txwake_delay_time_straight_key d'400'
endif ;_4_mhz_clock
; processor declarations
ifdef processor_16f84
processor 16f84
include <p16f84.inc>
__config _HS_OSC & _WDT_OFF
#define cblock_start 0x0c
endif ;processor_16f84
ifdef processor_16f628
processor 16f628
include <p16f628.inc>
__config _HS_OSC & _WDT_OFF & _LVP_OFF & _BODEN_OFF
#define cblock_start 0x20
endif ;processor_16f628
ifdef processor_16f628a
processor 16f628a
include <p16f628a.inc>
__config _HS_OSC & _WDT_OFF & _LVP_OFF & _BODEN_OFF
#define cblock_start 0x20
endif ;processor_16f628a
; define registers
cblock cblock_start
speed_wpm:1 ;global
bit_stuff1:1 ;global
bit_stuff2:1 ;global
bit_stuff3:1 ;global
cw_unit_counter:2 ;loop_cw_unit
counter1:1 ;pause_100_ms, loop_cw_unit
counter2:1 ;pause_100_ms, loop_cw_unit
counter3:1 ;pause_100_ms, send_cw
cw_char_to_send:2 ;send_cw(parm)
temp:1 ;send_cw
dividend:2 ;divideby16bit
divisor:2 ;divideby16bit
quotient:2 ;divideby16bit
remainder:2 ;divideby16bit
count:1 ;divideby16bit
binary2bcd_binary_in:2 ;binary2bcd
BCD0:1 ;binary2bcd
BCD1:1 ;binary2bcd
BCD2:1 ;binary2bcd
bcd_low_nibble:1 ;speed_mode
bcd_high_nibble:1 ;speed_mode
write_verify_data:1 ;write_eeprom
write_verify_addr:1 ;write_eeprom
command_mode_loop_count1:1 ; check_mode_button (enhanced)
command_mode_loop_count2:1 ; check_mode_button (enhanced)
command_mode_loop_count3:1 ; check_mode_button (enhanced)
command_mode_buffer1:1 ; check_mode_button (enhanced)
command_mode_buffer2:1 ; check_mode_button (enhanced)
recording_loop_counter1:1 ; program_memory
recording_loop_counter2:1 ; program_memory
cw_unit_count:1 ; program_memory
temp_memory:1 ; program_memory
temp_memory_eeprom_pointer:1 ;program_memory
temp_memory_mask:1 ; program_memory
temp_w:1 ; program_memory.store_temp_memory_to_eeprom
send_cw_temp:1 ; send_cw
memory_number:1 ; program_memory, play_memory
eeprom_memory_locations:3 ; program_memory, play_memory
eeprom_memory_loc_limits:3 ; program_memory
start_of_memory_location:1 ; program_memory, play_memory
porta_temp:1 ; check_function_buttons
eeprom_settings1:1
wavesidetone_counter
wavesidetone_counter_setting
endc
ifdef include_txwake_line_code
cblock
txwakecounter:2
endc
endif ;include_txwake_line_code
ifdef include_nnnnn_code
cblock
ditdah_history1:1 ; global - include_nnnnn_code
ditdah_history2:1 ; global - include_nnnnn_code
ditdah_history_timer1:1 ; global - include_nnnnn_code
endc
endif
ifdef include_weighting_code
cblock
cw_unit_counter_dah:2
cw_unit_counter_dit:2
speed_wpm_dah
endc
endif
ifdef include_cw_rx_practice_code
cblock
randomnum:2
endc
endif
ifdef include_freq_counter_code
cblock
freqcount:3
BCD3:1
frequency_counter_calib:2
freq_offset_binary:2
L_temp:1
H_temp:1
endc
bcd2binary_binary_out equ binary2bcd_binary_in
ifdef include_debug_code
bcd2binary_binary_out_2 equ binary2bcd_binary_in+1 ; for debugger work
freq_offset_binary_2 equ freq_offset_binary+1 ; for debugger work
endif ;include_debug_code
endif ;include_freq_counter_code
#define dit_buffer bit_stuff1,0x00 ; used to store a dit in iambic operation
#define dah_buffer bit_stuff1,0x01 ; used to store a dah
#define key_tx_active bit_stuff1,0x02 ; 0 = do not turn on key_tx line when sending cw
#define sending_dit bit_stuff1,0x03 ; 1 = send dit in send_dit_or_dah
#define tune_latch_mode bit_stuff1,0x04 ; 1 = tx is latched on
#define temp_memory_dirty bit_stuff1,0x05 ; used by memory record functions
#define paddle_was_hit bit_stuff1,0x06
ifdef include_function_button_code
#define memory_playback_manual_exit bit_stuff1,0x07
endif
#define send_cw_preemptible bit_stuff2,0x00 ; send_cw routine can be interrupted by user when this flag is set
ifndef include_wavesidetone_code
#define wavesidetone bit_stuff2,0x01
else
#define sidetone bit_stuff2,0x01
endif
#define expert_commands_on bit_stuff2,0x02 ; 1 = expert commands have been activated in command mode
#define bit_temp bit_stuff2,0x03
ifdef include_freq_counter_code
#define command_mode_v_cmd bit_stuff2,0x04
#define command_mode_k_cmd bit_stuff2,0x05
endif
ifdef include_call_cq_code
#define dit_hit bit_stuff2,0x06
endif ;include_call_cq_code
ifdef include_m_and_h_cmd_code
#define command_mode_m_cmd bit_stuff2,0x07
#define command_mode_h_cmd bit_stuff3,0x00
endif ;include_m_and_h_cmd_code
;eeprom_settings1 is used for settings that need to be stored in nonvolatile memory
;they are written to eeprom using call write_eeprom_settings1
#define sidetone_off_during_tx eeprom_settings1,0x00 ; 1 = no sidetone during TX (for internal use in rigs that alread have sidetone)
ifdef include_iambic_b_code
#define iambic_b_mode eeprom_settings1,0x01 ; 1 = iambic b mode activated
endif
ifdef include_paddle_reverse_code
#define paddle_reverse eeprom_settings1,0x02 ; 1 = paddle reverse mode activated
endif
ifdef include_freq_counter_code
#define eight_digit_mode eeprom_settings1,0x03 ; 1 = 8 digit frequency counter mode
#define offset0 eeprom_settings1,0x04 ; offset0 and 1 stores frequency counter offset mode (table below)
#define offset1 eeprom_settings1,0x05
endif
ifdef include_bug_code
#define bug_mode_on eeprom_settings1,0x06 ; 1 = bug mode activated
endif
; frequency counter offset table
; offset0 offset1
; 0 0 no offset
; 0 1 reading = offset - measurement
; 1 0 reading = measurement - offset
; 1 1 reading = measurement + offset
org 0x00
goto main_program_start
; Subroutines -------------------------------------------------------------
cw_table
; this is a lookup table for sending numbers in CW using send_cw routine
; 00 = termination
; 01 = dit
; 11 = dah
; stream goes MSB -> LSB (MSB first)
; two bytes long
addwf PCL, F
retlw b'11111111' ;0 0
retlw b'11000000'
retlw b'01111111' ;1 1
retlw b'11000000'
retlw b'01011111' ;2 2
retlw b'11000000'
retlw b'01010111' ;3 3
retlw b'11000000'
retlw b'01010101' ;4 4
retlw b'11000000'
retlw b'01010101' ;5 5
retlw b'01000000'
retlw b'11010101' ;6 6
retlw b'01000000'
retlw b'11110101' ;7 7
retlw b'01000000'
retlw b'11111101' ;8 8
retlw b'01000000'
retlw b'11111111' ;9 9
retlw b'01000000'
ifdef include_cw_rx_practice_code
retlw b'01110000' ;A 10
retlw b'00000000'
retlw b'11010101' ;B 11
retlw b'00000000'
retlw b'11011101' ;C 12
retlw b'00000000'
retlw b'11010100' ;D 13
retlw b'00000000'
retlw b'01000000' ;E 14
retlw b'00000000'
retlw b'01011101' ;F 15
retlw b'00000000'
retlw b'11110100' ;G 16
retlw b'00000000'
retlw b'01010101' ;H 17
retlw b'00000000'
retlw b'01010000' ;I 18
retlw b'00000000'
retlw b'01111111' ;J 19
retlw b'00000000'
retlw b'11011100' ;K 20
retlw b'00000000'
retlw b'01110101' ;L 21
retlw b'00000000'
retlw b'11110000' ;M 22
retlw b'00000000'
retlw b'11010000' ;N 23
retlw b'00000000'
retlw b'01111101' ;P 24
retlw b'00000000'
retlw b'11110111' ;Q 25
retlw b'00000000'
retlw b'01110100' ;R 26
retlw b'00000000'
retlw b'01010100' ;S 27
retlw b'00000000'
retlw b'11000000' ;T 28
retlw b'00000000'
retlw b'01011100' ;U 29
retlw b'00000000'
retlw b'01010111' ;V 30
retlw b'00000000'
retlw b'01111100' ;W 31
retlw b'00000000'
retlw b'11010111' ;X 32
retlw b'00000000'
retlw b'11011111' ;Y 33
retlw b'00000000'
retlw b'11110101' ;Z 34
retlw b'00000000'
endif
; ------------------
ifdef include_freq_counter_code
; 1. Read the frequency on pin RA4 for 250 mS. The signal goes through the prescaler /32
; 2. Multiply measurement by 128 [ /32 (prescaler) + /4 (250 mS sample time) ]
; 3. Convert the three byte binary reading to eight BCD digits
; 4. Calculate the reading by applying the offset if applicable
; 5. Readout the frequency in CW either in eight or three digit mode, with leading zero suppression
count_frequency
bsf STATUS,RP0 ; bank 1
movlw b'00110100'
; bit 5 : 1 = RA4 input
; bit 4 : 0 = low to high transistion
; bit 3 : 0 = prescaler assigned to TIMER0
; bit 2-0 : set prescaler to 100 (/32)
movwf OPTION_REG
bcf STATUS,RP0 ; bank 0
movfw frequency_counter_calib+1
movwf counter1
movfw frequency_counter_calib+0
movwf counter2
clrf freqcount+0
clrf freqcount+1
clrf freqcount+2
bcf INTCON,T0IF
clrf TMR0 ; clear TIMER0 and prescaler
loop_250_ms
movfw TMR0
btfss INTCON,T0IF ; did TIMER0 overflow?
goto no_timer0_overflow
bcf INTCON,T0IF
incfsz freqcount+1, F
goto no_overflow_freqcount_1
incf freqcount+0, F
goto overflow_freqcount_1
no_timer0_overflow
nop
nop
nop
no_overflow_freqcount_1
nop
nop
overflow_freqcount_1
incf counter1, F
btfsc STATUS,Z
incf counter2, F
btfss STATUS,Z
goto loop_250_ms
loop_250_ms_done
;movfw TMR0 ; get timer0 as least significant byte
movwf freqcount+2
;multiple by 128 by rotating everything right 7 times
movlw d'7'
movwf count
multiply_loop
bcf STATUS,C
rlf freqcount+2, F
rlf freqcount+1, F
rlf freqcount+0, F
decfsz count,F
goto multiply_loop
;convert 24 bit freqcount to 8 digit BCD
bcf STATUS,C ; clear the carry bit
movlw d'24'
movwf count
clrf BCD0 ; most significant
clrf BCD1
clrf BCD2
clrf BCD3 ; least significant
loop24
rlf freqcount+2, F
rlf freqcount+1, F
rlf freqcount+0, F
rlf BCD3,F
rlf BCD2,F
rlf BCD1,F
rlf BCD0,F
decfsz count, F
goto adjDEC24
goto calculate_the_reading
; goto send_the_digits_in_cw
adjDEC24
movlw BCD3
movwf FSR
call adjBCD24
movlw BCD2
movwf FSR
call adjBCD24
movlw BCD1
movwf FSR
call adjBCD24
movlw BCD0
movwf FSR
call adjBCD24
goto loop24
adjBCD24
movlw 0x03
addwf INDF,W
movwf temp_memory
btfsc temp_memory,3 ; test if result > 7
movwf INDF
movlw 0x30
addwf INDF,W
movwf temp_memory
btfsc temp_memory,7 ; test if result > 7
movwf INDF ; save as MSD
return
calculate_the_reading
; calculate the reading using the offset
btfsc eight_digit_mode ; if we are in eight digit mode, there is no offset applied
goto send_the_digits_in_cw
btfsc offset0
goto offset0_is_1
btfss offset1
goto send_the_digits_in_cw ; there is no offset activated, skip over
goto calc_offset_minus_measurement
offset0_is_1
btfsc offset1
goto calc_measurement_plus_offset
goto calc_measurement_minus_offset
send_the_digits_in_cw
btfss eight_digit_mode ; are we in eight digit mode ?
goto skip_BCD0 ; no, skip over BCD0
;send BCD0 H
swapf BCD0,F
movfw BCD0
andlw b'00001111'
btfsc STATUS,Z
goto skip_BCD0H
call send_w_BCD_in_cw
skip_BCD0H
;send BCD0 L
swapf BCD0,F
movfw BCD0
andlw b'00001111'
call send_w_BCD_in_cw
skip_BCD0
btfsc eight_digit_mode
goto no_BCD1H_zero_suppress
movfw BCD1
btfsc STATUS,Z
goto BCD1_is_zeros
no_BCD1H_zero_suppress
;send BCD1 H
swapf BCD1,F
movfw BCD1
andlw b'00001111'
btfss eight_digit_mode ; skip over zero suppresion if we're in 8 digit mode
btfss STATUS,Z ; zero suppression
call send_w_BCD_in_cw
skip_BCD1H
;send BCD1 L
swapf BCD1,F
movfw BCD1
andlw b'00001111'
call send_w_BCD_in_cw
BCD1_is_zeros
swapf BCD2,F
movfw BCD2
andlw b'00001111'
call send_w_BCD_in_cw
btfss eight_digit_mode
return ; if we are in three digit mode, blow out of here
swapf BCD2,F
movfw BCD2
andlw b'00001111'
call send_w_BCD_in_cw
swapf BCD3,F
movfw BCD3
andlw b'00001111'
call send_w_BCD_in_cw
swapf BCD3,F
movfw BCD3
andlw b'00001111'
call send_w_BCD_in_cw
return
; these routines calculate the frequency readout when the offset is configured
; 0 7 , 0 4 0 , 0 0 0 hertz
;+-----+-----+-----+-----+-----+-----+-----+-----+
;|BCD0H|BCD0L|BCD1H|BCD1L|BCD2H|BCD2L|BCD3H|BCD3L|
;+-----+-----+-----+-----+-----+-----+-----+-----+
; | | |
; +-----+-----+-----+
; | freq_offset |
; +-----+-----+-----+
calc_offset_minus_measurement
clrf BCD0 ; in this offset mode we the 10 Mhz and 1 Mhz digits
call rotate_BCD012_right ; rotate the BCD digits one position to the right
clrf BCD0
call bcd2binary ; convert the BCD measurement to binary
movfw freq_offset_binary+1 ; store offset in temp registers
movwf L_temp
movfw freq_offset_binary+0
movwf H_temp
movfw bcd2binary_binary_out+1
subwf L_temp,F
btfss STATUS,C
decf H_temp,F
movfw binary2bcd_binary_in+0
subwf H_temp,F
movfw L_temp
movwf binary2bcd_binary_in+1
movfw H_temp
movwf binary2bcd_binary_in+0
call binary2bcd
call rotate_BCD012_left
goto send_the_digits_in_cw
calc_measurement_minus_offset
call rotate_BCD012_right ; rotate the BCD digits one position to the right
call bcd2binary ; convert the BCD measurement to binary
movfw freq_offset_binary+1
subwf bcd2binary_binary_out+1,F
btfss STATUS,C
decf bcd2binary_binary_out+0,F
movfw freq_offset_binary+0
subwf bcd2binary_binary_out+0,F ;bcd2binary_binary_out becomes input parameters for binary2bcd routine
call binary2bcd
call rotate_BCD012_left
goto send_the_digits_in_cw
calc_measurement_plus_offset
call rotate_BCD012_right ; rotate the BCD digits one position to the right
call bcd2binary ; convert the BCD measurement to binary
movfw freq_offset_binary+1
addwf bcd2binary_binary_out+1,F
btfsc STATUS,C
incf bcd2binary_binary_out+0,F
movfw freq_offset_binary+0
addwf bcd2binary_binary_out+0,F ;bcd2binary_binary_out becomes input parameters for binary2bcd routine
call binary2bcd
call rotate_BCD012_left
goto send_the_digits_in_cw
endif ;include_freq_counter_code
; ------------------
ifdef include_freq_counter_code
rotate_BCD012_right
clrf temp_w
movlw d'4'
movwf count
rotate_BCD012_right_loop
bcf STATUS,C
rrf BCD0,F
rrf BCD1,F
rrf BCD2,F
rrf temp_w,F
decf count,F
btfss STATUS,Z
goto rotate_BCD012_right_loop
movfw temp_w ; store the original lower nibble of BCD2 in upper nibble of BCD0
addwf BCD0,F
return
endif ;include_freq_counter_code
; ------------------
ifdef include_freq_counter_code
rotate_BCD012_left
clrf temp_w
movlw d'4'
movwf count
rotate_BCD012_left_loop
bcf STATUS,C
rlf BCD2,F
rlf BCD1,F
rlf BCD0,F
rlf temp_w,F
decf count,F
btfss STATUS,Z
goto rotate_BCD012_left_loop
movfw temp_w ; store the upper nibble of BCD0 in lower nibble of BCD2
addwf BCD2,F
return
endif ;include_freq_counter_code
; ------------------
send_w_BCD_in_cw
movwf temp_memory
addwf temp_memory, F ; double it so we're in the right spot in cw_table
movfw temp_memory ; put it in W for lookup table
call cw_table
movwf cw_char_to_send+0
movfw temp_memory
addlw 0x01 ; add 1 to get next byte in table
call cw_table
movwf cw_char_to_send+1
call send_cw
return
; ------------------
ifdef include_funky_beeps_code
beep
movwf temp_w ; store w temporarily
movfw wavesidetone_counter_setting ; store real wavesidetone setting in temp_memory
movwf temp_memory
movfw temp_w ; get temp_w and put in for wavesidetone setting
movwf wavesidetone_counter_setting
movlw _beep_length
movwf counter1
movwf counter2
bsf sidetone
beep_loop
call produce_wavesidetone
decfsz counter1, F
goto beep_loop
decfsz counter2, F
goto beep_loop
bcf sidetone
movfw temp_memory ; restore real wavesidetone setting
movwf wavesidetone_counter_setting
return
; ------------------
high_beep
movlw _high_beep_tone
call beep
return
; ------------------
low_beep
movlw _low_beep_tone
call beep
return
; ------------------
beep_boop
call high_beep
call low_beep
return
; ------------------
boop_beep
call low_beep
call high_beep
return
endif ;include_funky_beeps_code
; ------------------
divide16bit
; dividend / divisor = quotient
; this code from Mark Sullivan www.markworld.com (thanks for saving me hours of work ! :-)
movlw d'16'
movwf count
clrf quotient+0 ;quotient
clrf quotient+1
clrf remainder+0 ;remainder
clrf remainder+1
udiv1
bcf STATUS,C
rlf dividend+1,F
rlf dividend+0,F
rlf remainder+1,F
rlf remainder+0,F
movf divisor+0,W
subwf remainder+0,W
btfss STATUS,Z
goto udiv2
movf divisor+1,W
subwf remainder+1,W
btfss STATUS,C
goto udiv4
movwf remainder+1
movf divisor+0,W
subwf remainder+0,F
goto udiv3
udiv2
btfss STATUS,C
goto udiv4
movf divisor+1,W
subwf remainder+1,F
btfss STATUS,C
decf remainder+0,F
movf divisor+0,W
subwf remainder+0,F
udiv3
bsf STATUS,C
udiv4
rlf quotient+1,F
rlf quotient+0,F
decfsz count,F
goto udiv1
retlw 0
; ------------------
ifdef include_freq_counter_code
bcd2binary
; BCD to 16 bit binary converter
; adapted from Microchip AN526
; http://www.microchip.com
; thanks, Microchip !
;BCD0 = most significant digits
;BCD1
;BCD2 = least significant digits
clrf bcd2binary_binary_out+0
movf BCD0,W
andlw 0x0F
movwf bcd2binary_binary_out+1
call mpy10a ; result = 10a+b
swapf BCD1,W
call mpy10b ; result = 10[10a+b]
movf BCD1,W
call mpy10b ; result = 10[10[10a+b]+c]
swapf BCD2,W
call mpy10b ; result = 10[10[10[10a+b]+c]+d]
movf BCD2,W
andlw 0x0F
addwf bcd2binary_binary_out+1, F
btfsc STATUS,C
incf bcd2binary_binary_out+0, F ; result = 10[10[10[10a+b]+c]+d]+e
return ; BCD to binary conversion done
; subroutines
mpy10b
andlw 0x0F
addwf bcd2binary_binary_out+1, F
btfsc STATUS,C
incf bcd2binary_binary_out+0, F
mpy10a
bcf STATUS,C ; multiply by 2
rlf bcd2binary_binary_out+1,W
movwf L_temp
rlf bcd2binary_binary_out+0,W ; (H_temp,L_temp) = 2*N
movwf H_temp
bcf STATUS,C ; multiply by 2
rlf bcd2binary_binary_out+1, F
rlf bcd2binary_binary_out+0, F
bcf STATUS,C ; multiply by 2
rlf bcd2binary_binary_out+1, F
rlf bcd2binary_binary_out+0, F
bcf STATUS,C ; multiply by 2
rlf bcd2binary_binary_out+1, F
rlf bcd2binary_binary_out+0, F ; (bcd2binary_binary_out+0,bcd2binary_binary_out+1) = 8*N
movf L_temp,W
addwf bcd2binary_binary_out+1, F
btfsc STATUS,C
incf bcd2binary_binary_out+0, F
movf H_temp,W
addwf bcd2binary_binary_out+0, F
return ; (bcd2binary_binary_out+0,bcd2binary_binary_out+1) = 10*N
endif ;include_freq_counter_code
; ------------------
binary2bcd
; 16 bit binary to bcd converter
; adapted from Microchip AN526
; http://www.microchip.com
; thanks, Microchip !
bcf STATUS, C ; clear the carry bit
movlw .16
movwf count
clrf BCD0 ; most significant digit
clrf BCD1
clrf BCD2 ; least significant digit
loop16
rlf binary2bcd_binary_in+1, F ; LSB
rlf binary2bcd_binary_in+0, F ; MSB
rlf BCD2, F
rlf BCD1, F
rlf BCD0, F
decfsz count, F
goto adjDEC
retlw 0
adjDEC
movlw BCD2
movwf FSR
call adjBCD
movlw BCD1
movwf FSR
call adjBCD
movlw BCD0
movwf FSR
call adjBCD
goto loop16
adjBCD
movlw 3
addwf INDF, W
movwf temp
btfsc temp,3 ; test if result > 7
movwf INDF
movlw 30
addwf INDF, W
movwf temp
btfsc temp,7 ; test if result > 7
movwf INDF ; save as MSD
retlw 0
; ------------------
write_eeprom
; save EEDATA and EEADR for write verify
ifdef processor_16f628
bsf STATUS, RP0 ; select bank 1
endif
movfw EEDATA
ifdef processor_16f628
bcf STATUS, RP0 ; select bank 0
endif
movwf write_verify_data
ifdef processor_16f628
bsf STATUS, RP0 ; select bank 1
endif
movfw EEADR
ifdef processor_16f628
bcf STATUS, RP0 ; select bank 0
endif
movwf write_verify_addr
start_write
bsf STATUS, RP0 ; select bank 1
bcf INTCON, GIE ; disable interrupts