-
Notifications
You must be signed in to change notification settings - Fork 22
/
SP_VFO_Controller_Keyer.ino
3297 lines (2768 loc) · 105 KB
/
SP_VFO_Controller_Keyer.ino
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
/*
Arduino Nano script for homebrew multiband SSB/CW transceivers.
Written by Paul Taylor, VK3HN (https://vk3hn.wordpress.com/) standing on the shoulders of:
- Przemek Sadowski, SQ9NJE (basic controller script)
- Jason Mildrum NT7S (si5351 library)
- too many others to mention (ideas, code snippets).
Targets Ashar Farhan VU2ESE's Arduino Nano/si5351 module (Raduino).
V1.0, 20 Jun 2017 - first version for homebrew Arduino/si5351 VFO
V1.4, 27 Nov 2018 - revised version with CW keyer for homebrew SP_IV transceiver
V1.5, 3 Dec 2018 - Refactored #define's and code blocks for project labels
V1.6 6 Jun 2019 - Added MCP9808 temp sensor (Adafruit)
V1.7 2 Mar 2020 - Added code for AM transmitters that use one clock only as transmitter VFO at signal frequency
V1.8 2 Mar 2020 - Code for VFO / BFO reversing.
V1.9 25 Sep 2021 - general update.
Labels that need to be #define'd for your target radio/rig/project:
Rotary encoder {ENCODER_OPTICAL_360, ENCODER_MECHANICAL}
Display technology {DISPLAY_LCD, DISPLAY_OLED}
Display type {LCD_20X4, LCD_16X2, LCD_8X2, OLED_128X64}
Project name {SP_IV, SP_11, SP_V, SS_EI9GQ, SP_6, SP_7, etc }
BFO enable {BFO_ENABLED}
VSWR meter {VSWR_METER}
CW keyer {CW_KEYER}
Tune mS {TUNE_MS} Typical value: 3000mS
Held button mS {BUTTON_HELD_MS} Typical value: 700mS
Diagnostics on display {DIAGNOSTIC_DISPLAY}
VFO/BFO swap between transmit and receive {VFO_BFO_SWAP}
*/
// common libraries
#include <Rotary.h>
#include <si5351.h> // Etherkit si3531 library from NT7S, V2.1.4 https://github.com/etherkit/Si5351Arduino
#include <PCF8574.h> // pcf8574 library by Rob Tillaart 0.3.2
#include <Wire.h>
#include <EEPROM.h>
// ------------------------------------------------------------------------------------------------------------------
// #define one (and only one) label to pull in the right code for the specific project
// [ Summit Prowlers ]
//#define SP_IV // for code specific to Summit Prowler IV (6 band MST) (16x2 LCD, optical encoder)
// #define SP_V // for code specific to Summit Prowler V rig (2 band G6LBQ BiTx) (8x2 LCD, mechanical encoder)
// #define SP_6 // for code specific to DK7IH Compact Multibander (128x64 OLED with SSD1308, mechanical encoder)
// #define SP_7 // for code specific to VK3WAC SSDRA four-bander (LCD, optical encoder)
// #define SP_8 // 28MHz SSB transceiver
// #define SP_9 // 5-band compact SSB/CW transceiver (5/2020)
// #define SP_X // 4-band hand held channelised CW 'appliance' transceiver (1/2021)
// #define SP_11 // 3-band QRO SOTA CW rig (4/2021)
#define UNIVERSAL_VFO_CONTROLLER // Universal VFO Controller (22/9/2021)
// [ Shack projects ]
// #define SS_EI9GQ // for code specific to Shack Sloth base station transceiver by Eamon EI9GQ) (20x4 LCD, mechanical encoder)
// [ AM transmitters ]
// #define SS_FAT5_160AM_TX // for code specific to the GW8LLJ (FAT5) 160 AM/CW transmitter/receiver (16x2 LCD, optical encoder)
// #define SS_VK3SJ_160AM_TX // for code specific to the Laurie VK3SJ's PWM AM transmitter (16x2 LCD, optical encoder)
// #define SS_VK3SJ_160AM_PORTABLE_TX // for code specific to the Laurie VK3SJ's portable PWM AM transmitter (16x2 LCD, optical encoder)
// #define SS_AM_TX_TEST_VFO // for code specific to a bench VFO for testing AM transmitters (11/2019)
// #define SS_VK3SJ_40AM_TX // for code specific to the VK3SJ 40m AM transmitter (16x2 LCD, optical encoder)
// ------------------------------------------------------------------------------------------------------------------
// common #define's that precede other declarations
#define LCD_RS 8 // Register Select is LCD pin 4
#define LCD_E 9 // Enable/clock LCD pin 6
#define LCD_D4 10 // LCD D4
#define LCD_D5 11 // LCD D5
#define LCD_D6 12 // LCD D6
#define LCD_D7 13 // LCD D7
#define BUTTON_HELD_MS 700 // button down period in mS required to activate 2nd pushbutton function
#define TUNE_MS 5000 // tune (key down) period (mS)
//#define TUNE_MS 30000 // tune (key down) period (mS) 30 for testing
#define LPF_DROPOUT_DELAY 8000 // period of inactivity before the LPF drops out to save battery (mS)
#define FAN_DROPOUT_DELAY 5000 // period of inactivity before the fan drops out to save battery (mS)
#define VFO_DRIVE_THRESHOLD 18000000 // threshold freq above which a higher si5351 clock output level on the VFO clock is used
#define CO_DRIVE_THRESHOLD 18000000 // threshold freq above which a higher si5351 clock output level on the carrier oscillator (CW) clock is used
//#define CO_DRIVE_THRESHOLD 18000 // threshold freq above which a higher si5351 clock output level on the carrier oscillator (CW) clock is used
#define RX_MUTE_DELAY_MS 10 // mS delay after muting receiver and before unmuting receiver
#define BREAK_IN_DELAY 800 // break-in hang time (mS) (may be overridden in the project sections)
// ------------------------------------------------------------------------------------------------------------------
// Arduino Nano digital pin assignments (aligns with Raduino)
// 0 Serial
// 1 Serial
#define ENCODER_B 2 // Encoder pin B
#define ENCODER_A 3 // Encoder pin A
#define PTT_SENSE 4 // sense the PTT button being pressed (low == transmit)
#define RX_MUTE_LINE 5 // receiver mute
#define RX_MUTE_OFF_VALUE 0 // default value for an un-muted receiver (low), can be inverted in a project block
#define RX_MUTE_ON_VALUE 1 // default value for a muted receiver (high), can be inverted in a project block
// 6 keyer sidetone, declared below
#define TRANSMIT_LINE 7 // controls the T/R relay (high == transmit)
// Arduino Nano analogue pins
#define SWITCH_BANK A0 // front panel push buttons
//#ifdef CW_KEYER
#define PIN_PADDLE A1 // paddle on analog pin 1
#define PIN_PUSHBTTN_REAR A2 // keyer memory pushbuttons on analog pin 2
#define PIN_KEYER_SPEED A3 // speed potentiometer wiper
//#endif
#define PIN_S_METER A3 // s-meter TBA (alternately, use A7)
// A4 SDA
// A5 SCL
#define PIN_PWR_METER A6 // analogue pin for relative RF sensing circuit
int pwr_val = 0; // stores the last reading of the RF power sensing input (on pin PIN_PWR_METER)
#ifdef VSWR_METER
#define PIN_SWR_FWD A6 // analogue pin for SWR bridge forward
#define PIN_SWR_REV A7 // analogue pin for SWR bridge reverse
#endif
// specific declarations and #define's for each project -------------------------------------------------
// 'Summit Prowlers' - - -
#ifdef SP_IV // 6-band OzQRP-based MST SSB/CW transceiver
#define ENCODER_OPTICAL_360
#define BFO_ENABLED
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency
volatile uint32_t USB = 11998500ULL; // the reference BFO freq for LSB, may be tuned, put in EEPROM once
volatile uint32_t LSB = 11995500ULL; // the reference BFO freq for USB, may be tuned, put in EEPROM once
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 10 // number of selectable VFOs
// #define VSWR_METER // uncomment to compile VSWR meter code
#define CW_KEYER // include the CW keyer code
#endif
#ifdef SP_V // Two-band G6LBQ 'walkie talkie' SSB/CW transceiver
#define ENCODER_MECHANICAL
#define BFO_ENABLED
#define BFO_TUNE_LO 8990000ULL // lowest BFO frequency
#define BFO_TUNE_HI 9010000ULL // highest BFO frequency
volatile uint32_t USB = 9002200ULL; // USB on 20m
// was volatile uint32_t LSB = 8999800ULL; // LSB on 40m (too much bass)
// volatile uint32_t LSB = 8999450ULL; // LSB on 40m (upper limit for treble)
volatile uint32_t LSB = 8999300ULL; // LSB on 40m (reset June 2020)
#define DISPLAY_LCD
#define LCD_8X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 4 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#endif
#ifdef SP_6 // Compact mono-band DK7IH SSB/CW transceiver
#define ENCODER_MECHANICAL
#define BFO_ENABLED
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency
volatile uint32_t USB = 11998500ULL; // the reference BFO freq for LSB, may be tuned, put in EEPROM once
volatile uint32_t LSB = 11996000ULL; // the reference BFO freq for USB, may be tuned, put in EEPROM once
// original -- 11,995,500ULL;
#define DISPLAY_OLED
#define OLED_128X64
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_OLED_ADDRESS 0x3C // correct!
//#define I2C_OLED_ADDRESS 0x3D // test for dead display
#define RST_PIN -1 // Define proper RST_PIN if required
SSD1306AsciiAvrI2c oled;
#define NBR_VFOS 10 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
// #define DIAGNOSTIC_DISPLAY // allow use of the OLED for tracing simple values (eg button values)
#define TX_SSB_MUTE_LINE 9 // D9 is used to mute the mic amp to silence a T/R squeal in SP_6
// normally high, this line goes low TX_SSB_MUTE_DELAY mS after PTT when transmitting SSB
#define TX_SSB_MUTE_DELAY 350 // delay (mS) before the mic amp is unmuted after SSB PTT
#define CO_DC_SUPPLY 8 // this pin controls a high side DC switch to enable the carrier oscillator when keyed
#endif
#ifdef SP_7 // VK3WAC SSDRA Mono-band SSB/CW transceiver
#define ENCODER_OPTICAL_360
#define BFO_ENABLED
#define BFO_TUNE_LO 5100000ULL // lowest BFO frequency
#define BFO_TUNE_HI 5130000ULL // highest BFO frequency
volatile uint32_t USB = 5120000ULL; // the reference BFO freq for USB, may be tuned, put in EEPROM once
//volatile uint32_t LSB = 5121500ULL; // the reference BFO freq for LSB, may be tuned, put in EEPROM once
volatile uint32_t LSB = 5116000ULL; // the reference BFO freq for LSB, may be tuned, put in EEPROM once
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 4 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define CO_DC_SUPPLY A7 // this pin controls a high side DC switch to enable the carrier oscillator when keyed
#endif
#ifdef SP_8 // Compact 4-band CW-only transceiver
#define ENCODER_MECHANICAL
#define BFO_ENABLED
#define BFO_TUNE_LO 8998000ULL // lowest BFO frequency
#define BFO_TUNE_HI 9002000ULL // highest BFO frequency
volatile uint32_t USB = 8989000ULL; // selected sideband at 28MHz
volatile uint32_t LSB = 8986100ULL;
#define DISPLAY_OLED
#define OLED_128X64
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_OLED_ADDRESS 0x3C // correct!
#define RST_PIN -1 // Define proper RST_PIN if required
SSD1306AsciiAvrI2c oled;
#define NBR_VFOS 5 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define CO_DC_SUPPLY 11 // this pin controls a high side DC switch to enable the carrier oscillator when keyed
#define ENCODER_BUTTON 12 // the digital input used to read the mech encoder's pushbutton
#define BAND_SENSE_2M 10 // this pin senses when the 2m transverter is selected and powered on
bool sp8_band_2m; // true if band selected is 2m
#define SP_8_DIAL_OFFSET -1700 // offset to be applied to the displayed frequency to correct for transverter crystal frequency error
#endif
#ifdef SP_9 // Compact 5-band SSB/CW transceiver
#define ENCODER_MECHANICAL
#define ENCODER_BUTTON 12 // the digital input used to read the mech encoder's pushbutton
#define BFO_ENABLED
#define BFO_TUNE_LO 8998500ULL // lowest BFO frequency
#define BFO_TUNE_HI 9001500ULL // highest BFO frequency
volatile uint32_t USB = 9001500ULL; // selected sideband
volatile uint32_t LSB = 8998500ULL;
#define DISPLAY_OLED
#define OLED_128X64
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_OLED_ADDRESS 0x3C // correct!
#define RST_PIN -1 // Define proper RST_PIN if required
SSD1306AsciiAvrI2c oled;
#define NBR_VFOS 5 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define CO_DC_SUPPLY 11 // this pin controls a high side DC switch to enable the carrier oscillator when keyed
// #define DIAGNOSTIC_DISPLAY // FOR TESTING THOSE PESKY PUSHBUTTONS!!
#define RX_MUTE_DELAY_MS 20 // override the mS delay after muting receiver and before unmuting receiver
#endif
#ifdef SP_X // Compact 4-band channelised CW transceiver
#define ENCODER_MECHANICAL // not used
#define ENCODER_BUTTON 12 // digital input used to read the mech encoder's pushbutton (not used)
#define BFO_ENABLED
#define BFO_TUNE_LO 3998500ULL // lowest BFO frequency
#define BFO_TUNE_HI 4001200ULL // highest BFO frequency
volatile uint32_t USB = 4000700ULL;
volatile uint32_t LSB = 3998900ULL;
// default channel frequencies
#define SP_X_CH0_FREQ_DEFAULT 7025700 // 7,025 CW calling channel in VK
#define SP_X_CH1_FREQ_DEFAULT 7032700 // 7,032 CW SOTA channel - primary
#define SP_X_CH2_FREQ_DEFAULT 10110930 // 10,110 CW SOTA channel - primary TBC
#define SP_X_CH3_FREQ_DEFAULT 14059300 // 14,060 CW SOTA channel - secondary
#define SP_X_CH4_FREQ_DEFAULT 14061300 // 14,062 CW SOTA channel - primary
#define SP_X_CH5_FREQ_DEFAULT 18094300 // 18,095 CW SOTA channel - primary TBC
// display declarations are not used, but left in to avoid compiler errors (!)
#define DISPLAY_OLED
#define OLED_128X64
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_OLED_ADDRESS 0x3C // correct!
#define RST_PIN -1 // Define proper RST_PIN if required
SSD1306AsciiAvrI2c oled;
#define NBR_VFOS 6 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
// #define CO_DC_SUPPLY 11 // this pin controls a high side DC switch to enable the carrier oscillator when keyed (not used)
// #define DIAGNOSTIC_DISPLAY // FOR TESTING THOSE PESKY PUSHBUTTONS!!
#define RX_MUTE_OFF_VALUE 1 // value for an un-muted receiver (high)
#define RX_MUTE_ON_VALUE 0 // value for a muted receiver (low)
#define RX_MUTE_DELAY_MS 10 // override the mS delay after muting receiver and before unmuting receiver
#define BREAK_IN_DELAY 500 // override the default break-in hang time (mS)
#define SP_X_MUTE_SPKR 2 // D2 is used as a digital line to control a mute relay in series with the speaker
bool SP_X_init = true;
unsigned int SP_X_counter = 0;
#endif
#ifdef SP_11 // 3-band QRO SOTA CW rig
#define ENCODER_OPTICAL_360
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency
volatile uint32_t USB = 3999700ULL;
volatile uint32_t LSB = 3999700ULL;
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 3 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#endif
#ifdef UNIVERSAL_VFO_CONTROLLER // Universal VFO Controller 23/9/2021
#define ENCODER_MECHANICAL
#define BFO_ENABLED
#define BFO_TUNE_LO 5100000ULL // lowest BFO frequency
#define BFO_TUNE_HI 5130000ULL // highest BFO frequency
volatile uint32_t USB = 5120000ULL; // the reference BFO freq for USB, may be tuned, put in EEPROM once
volatile uint32_t LSB = 5116000ULL; // the reference BFO freq for LSB, may be tuned, put in EEPROM once
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 4 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
// #define CO_DC_SUPPLY A7 // this pin controls a high side DC switch to enable the carrier oscillator when keyed
#endif
// ------------------------------------------------------------------------------------------------------------------
#ifdef SS_EI9GQ // 8-band EI9GQ base SSB/CW transceiver
#define ENCODER_OPTICAL_360
#define BFO_TUNE_LO 8990000ULL // lowest BFO frequency
#define BFO_TUNE_HI 9010000ULL // highest BFO frequency
volatile uint32_t USB = 9002200ULL;
volatile uint32_t LSB = 8998500ULL;
#define DISPLAY_LCD
#define LCD_20X4
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#include "RTClib.h"
RTC_PCF8523 rtc; // declare a RTC (on I2C address 0x68)
#define NBR_VFOS 10 // number of selectable VFOs
// #define VSWR_METER // uncomment to compile VSWR meter code
#define CW_KEYER // include the CW keyer code
#endif
// ------------------------------------------------------------------------------------------------------------------
#ifdef SS_FAT5_160AM_TX // GW8LJJ FAT5 160m 100W Class E AM transmitter
#define ENCODER_OPTICAL_360
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency (not currently used)
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency (not currently used)
volatile uint32_t USB = 0ULL; // BFO not used in this Tx
volatile uint32_t LSB = 0ULL;
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 4 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define PWM_ENABLE_LINE 6 // normally low, take high to enable PWM (used in T/R sequencing)
#endif
#ifdef SS_VK3SJ_160AM_TX // VK3SJ Laurie's 160m Class D AM PWM transmitter
#define ENCODER_OPTICAL_360
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency (not used)
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency (not used)
volatile uint32_t USB = 0ULL; // BFO not used
volatile uint32_t LSB = 0ULL;
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 3 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define PWM_ENABLE_LINE 6 // normally low, take high to enable PWM (used in T/R sequencing)
#include <Adafruit_MCP9808.h>
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808(); // I2C address defaults to ...
byte loop_cntr=0;
#endif
#ifdef SS_VK3SJ_160AM_PORTABLE_TX // VK3SJ 160m Class D AM PWM PORTABLE transmitter / receiver
#define ENCODER_MECHANICAL
#define BFO_TUNE_LO 455000ULL // lowest BFO frequency (not currently used)
#define BFO_TUNE_HI 455000ULL // highest BFO frequency (not currently used)
volatile uint32_t USB = 456000ULL; // the reference BFO freq for LSB, may be tuned
volatile uint32_t LSB = 454000ULL; // the reference BFO freq for USB, may be tuned
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 2 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define PWM_ENABLE_LINE 6 // normally low, take high to enable PWM (used in T/R sequencing)
#define PIN_VOLTMETER A6 // analogue pin for HT voltage sensor (0..5v)
unsigned int HT_v = 0;
#define PIN_AMMETER A7 // analogue pin for HT current sensor (via INA169), amps
unsigned int HT_a = 0;
float HT_a_f = 0.0;
#endif
#ifdef SS_VK3SJ_40AM_TX // VK3SJ Laurie's 40m Class D AM PWM transmitter
#define ENCODER_OPTICAL_360
#define BFO_TUNE_LO 11990000ULL // lowest BFO frequency (not used)
#define BFO_TUNE_HI 12005000ULL // highest BFO frequency (not used)
volatile uint32_t USB = 0ULL; // BFO not used
volatile uint32_t LSB = 0ULL;
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 2 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#define PWM_ENABLE_LINE 6 // normally low, take high to enable PWM (used in T/R sequencing)
byte loop_cntr=0;
#endif
#ifdef SS_AM_TX_TEST_VFO // Test/bench VFO for Class D/E AM transmitters
#define ENCODER_MECHANICAL
#define BFO_TUNE_LO 455000ULL // lowest BFO frequency (not currently used)
#define BFO_TUNE_HI 455000ULL // highest BFO frequency (not currently used)
volatile uint32_t USB = 455000ULL; // the reference BFO freq for LSB, may be tuned
volatile uint32_t LSB = 455000ULL; // the reference BFO freq for USB, may be tuned
#define DISPLAY_LCD
#define LCD_16X2
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#define NBR_VFOS 8 // number of selectable VFOs
#define CW_KEYER // include the CW keyer code
#endif
#ifdef DIAGNOSTIC_DISPLAY
// flags and variables to trace values to the display, for temporary diagnostics
bool diagnostic_flag = false; // trace on the display as a diagnostic
int diagnostic_int = 0; // trace an integer value
// String diagnostic_string(""); // trace a String
#endif
// frequency ranges for automatic band pass and low pass filter switching
#define FILTER_630_LB 200000ULL // Filter set lower bound (MHz)
#define FILTER_630_UB 500000ULL // Filter set upper bound (MHz)
#define FILTER_MW_LB 500100ULL // Filter set lower bound (MHz)
#define FILTER_MW_UB 1750000ULL // Filter set upper bound (MHz)
#define FILTER_160_LB 1750100ULL // Filter set lower bound (MHz)
#define FILTER_160_UB 2500000ULL // Filter set upper bound (MHz)
#define FILTER_80_LB 2501000ULL // Filter set lower bound (MHz)
#define FILTER_80_UB 4000000ULL // Filter set upper bound (MHz)
#define FILTER_60_LB 4001000ULL // Filter set lower bound (MHz)
#define FILTER_60_UB 6500000ULL // Filter set upper bound (MHz)
#define FILTER_40_LB 6501000ULL // Filter set lower bound (MHz)
#define FILTER_40_UB 8000000ULL // Filter set upper bound (MHz)
#define FILTER_30_LB 8001000ULL // Filter set lower bound (MHz)
#define FILTER_30_UB 12000000ULL // Filter set upper bound (MHz)
#define FILTER_20_LB 12001000ULL // Filter set lower bound (MHz)
#define FILTER_20_UB 16000000ULL // Filter set upper bound (MHz)
#define FILTER_17_LB 16001000ULL // Filter set lower bound (MHz)
#define FILTER_17_UB 18500000ULL // Filter set upper bound (MHz)
#define FILTER_15_LB 19000000ULL // Filter set lower bound (MHz)
#define FILTER_15_UB 21500000ULL // Filter set upper bound (MHz)
// ------------------------------------------------------------------------------------------------------------------
// i2c devices and addresses:
// si5351 x60
// BPF selector PCF8574 x20 .. x38
// LPF selector PCF8574 x40
#define I2C_BPF_DEMUX 0x20 // default I2C address of the BPF PCF8574
#define I2C_LPF_DEMUX 0x24 // default I2C address of the LPF PCF8574
#ifdef SS_EI9GQ
#define I2C_BPF_DEMUX 0x38 // I2C address of the BPF PCF8574 in this rig
#endif
#ifdef SP_6
#define I2C_BPF_DEMUX 0x20 // I2C address of the BPF PCF8574 in this rig
#define I2C_LPF_DEMUX 0x3E // I2C address of the LPF PCF8574 in this rig
#endif
#ifdef SP_7
#define I2C_BPF_DEMUX 0x20 // I2C address of the BPF PCF8574 in this rig
#define I2C_LPF_DEMUX 0x38 // I2C address of the LPF PCF8574 in this rig
#endif
#ifdef SP_8
#define I2C_BPF_DEMUX 0x20 // I2C address of the BPF PCF8574 in this rig
#define I2C_LPF_DEMUX 0x38 // (there is no LPF PCF8574 in this rig)
#endif
#ifdef SP_9
#define I2C_BPF_DEMUX 0x20 // I2C address of the BPF PCF8574 in this rig
#endif
#ifdef SP_11
#define I2C_BPF_DEMUX 0x20 // I2C address of the BPF PCF8574 in this rig
#endif
PCF8574 PCF_BPF(I2C_BPF_DEMUX);
PCF8574 PCF_LPF(I2C_LPF_DEMUX);
// ------------------------------------------------------------------------------------------------------------------
bool message_playing = false; // true when the keyer is playing a CW message
#define CW_TONE_HZ 700 // CW tone frequency (Hz)
unsigned int dot_dash_counter = 0; // total nbr CW chars sent since power-up
unsigned int dot_dash_sent = 0; // nbr CW chars sent this transmit period, used for timing a refresh to the (interleaved) RF relative power meter
#define PIN_TONE_OUT 6 // digital pin with keyed audio tone on it
bool key_down = false;
unsigned long char_sent_ms, curr_ms;
bool space_inserted;
#define KEYER_MSG_SPEED 50
#ifdef CW_KEYER
// start of CW Keyer block -------------------------------------------------------------
#define PADDLE_R 1 // value representing analog value for paddle left (dot)
#define PADDLE_L 2 // value representing analog value for paddle right (dash)
#define CW_DASH_LEN 5 // length of dash (in dots)
#define SERIAL_LINE_WIDTH 80 // number of morse chars on Serial after which we newline
// set the CW keyer speed and canned messages for each project
// for the keyer speed, lower is faster, 60 is 10 w.p.m.
#ifdef SS_EI9GQ
String morse_msg[] = {"CQ CQ VK3HN VK3HN K", "DE VK3HN ", "VK3HN ", "73 TU . ." };
#endif
#ifdef SP_IV
byte dot_length_ms = 55;
#define KEYER_MSG_SPEED 42 // make the keyer play out canned messages faster
String morse_msg[] = {"CQ SOTA VK3HN/P K", "VK3HN ", "73 TU . ."};
#endif
#ifdef SP_V
byte dot_length_ms = 60; // make the CW slower, for pushbutton CW
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
String morse_msg[] = {"CQ SOTA VK3HN/P K", "CQ VK3HN/P K", "VK3HN/P K" };
//String morse_msg[] = {"CQ SOTA VK3HN/P K", "VK3HN ", " RST 599 5NN BK" };
#endif
#ifdef SP_6
byte dot_length_ms = 56; //
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
String morse_msg[] = {"CQ SOTA VK3HN/P K", "DE VK3HN" };
//String morse_msg[] = {"1", "2" }; // for testing
#endif
#ifdef SP_7
byte dot_length_ms = 56; //
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
String morse_msg[] = {"CQ SOTA VK3HN/P K", "CQ CQ VK3HN K" };
//String morse_msg[] = {"1", "2" }; // for testing
#endif
#ifdef SP_8
byte dot_length_ms = 60;
#define KEYER_MSG_SPEED 45
String morse_msg[] = {"NOT USED"};
#endif
#ifdef SP_9
byte dot_length_ms = 65; //
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
String morse_msg[] = {"CQ SOTA VK3HN/P K"};
//String morse_msg[] = {"1" }; // for testing
#endif
#ifdef SP_X
byte dot_length_ms = 57; //
#define KEYER_MSG_SPEED 50 // make the keyer play out canned messages faster
// String morse_msg[] = {"V V V DE VK3HN ."};
String morse_msg[] = {"CQ SOTA VK3HN/P K"};
#define CW_DASH_LEN 4 // re-define the length of dash (in dots), this is personal preference!
#endif
#ifdef SP_11
byte dot_length_ms = 60; //
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
//String morse_msg[] = {"CQ SOTA VK3HN/P K", "CQ CQ VK3HN K", "CQ TEST VK3HN K" };
String morse_msg[] = {"1", "2", "3" }; // for testing
#endif
#ifdef SS_EI9GQ
byte dot_length_ms = 56;
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
#endif
#if defined(SS_FAT5_160AM_TX) || defined(SS_VK3SJ_160AM_TX) || defined(SS_AM_TX_TEST_VFO) || defined(SS_VK3SJ_40AM_TX) || defined(SS_VK3SJ_160AM_PORTABLE_TX)
byte dot_length_ms = 56;
String morse_msg[] = {"CQ CQ DE VK3HN VK3HN K", "DE VK3HN" };
#endif
#ifdef UNIVERSAL_VFO_CONTROLLER
byte dot_length_ms = 56; //
#define KEYER_MSG_SPEED 45 // make the keyer play out canned messages faster
String morse_msg[] = {"MSG 1", "MSG 2", "MSG 3" };
#endif
// morse reference table
struct morse_char_t {
char ch[7];
};
morse_char_t MorseCode[] = {
{'A', '.', '-', 0, 0, 0, 0},
{'B', '-', '.', '.', '.', 0, 0},
{'C', '-', '.', '-', '.', 0, 0},
{'D', '-', '.', '.', 0, 0, 0},
{'E', '.', 0, 0, 0, 0, 0},
{'F', '.', '.', '-', '.', 0, 0},
{'G', '-', '-', '.', 0, 0, 0},
{'H', '.', '.', '.', '.', 0, 0},
{'I', '.', '.', 0, 0, 0, 0},
{'J', '.', '-', '-', '-', 0, 0},
{'K', '-', '.', '-', 0, 0, 0},
{'L', '.', '-', '.', '.', 0, 0},
{'M', '-', '-', 0, 0, 0, 0},
{'N', '-', '.', 0, 0, 0, 0},
{'O', '-', '-', '-', 0, 0, 0},
{'P', '.', '-', '-', '.', 0, 0},
{'Q', '-', '-', '.', '-', 0, 0},
{'R', '.', '-', '.', 0, 0, 0},
{'S', '.', '.', '.', 0, 0, 0},
{'T', '-', 0, 0, 0, 0, 0},
{'U', '.', '.', '-', 0, 0, 0},
{'V', '.', '.', '.', '-', 0, 0},
{'W', '.', '-', '-', 0, 0, 0},
{'X', '-', '.', '.', '-', 0, 0},
{'Y', '-', '.', '-', '-', 0, 0},
{'Z', '-', '-', '.', '.', 0, 0},
{'0', '-', '-', '-', '-', '-', 0},
{'1', '.', '-', '-', '-', '-', 0},
{'2', '.', '.', '-', '-', '-', 0},
{'3', '.', '.', '.', '-', '-', 0},
{'4', '.', '.', '.', '.', '-', 0},
{'5', '.', '.', '.', '.', '.', 0},
{'6', '-', '.', '.', '.', '.', 0},
{'7', '-', '-', '.', '.', '.', 0},
{'8', '-', '-', '-', '.', '.', 0},
{'9', '-', '-', '-', '-', '.', 0},
{'/', '-', '.', '.', '-', '.', 0},
{'?', '.', '.', '-', '-', '.', '.'},
{'.', '.', '-', '.', '-', '.', '-'},
{',', '-', '-', '.', '.', '-', '-'}
};
byte curr_msg_nbr; // index into morse_msg[] array
byte cw_msg_index; // index into morse_msg[cw_msg_index] array
#endif
// end CW Keyer block -------------------------------------------------------------
byte curr_line = 0; // the currently selected filter control line
// struct for 'VFO parameter set' records -- the parameters that will change with each VFO
typedef struct {
boolean active;
uint32_t vfo;
uint32_t radix;
} VFOset_type;
VFOset_type VFOSet[NBR_VFOS]; // array of band parameter sets
byte v; // index into VFOSet array (representing the current VFO)
byte v_prev;
Si5351 si5351; // I2C address defaults to x60 in the NT7S lib
Rotary r = Rotary(ENCODER_A, ENCODER_B);
// USB/LSB initialisation
#define SIDEBAND_THRESHOLD 10000000ULL // threshold VFO freq for auto sideband selection: above use USB, below use LSB
volatile uint32_t bfo = LSB; // the actual BFO freq for si5351 CLK2, arbitrary set to LSB, reset in main loop
// ------------------------------------------------------------------------------------------------------------------
// variables for transmit-receive control
bool mode_tx = false;
bool mode_cw = false;
bool mode_tune = false;
// LPF control variables
byte LPF_line=0; // current LPF line (0..5), set in set_filters()
bool LPF_engaged = false; // to allow the LPF to be engaged just in time
unsigned long last_T_R_ms = 0; // time of last Transmit to receive change
// button variables used in main loop for sensing the multiplexed buttons
byte button_nbr;
byte old_button_nbr = 0;
// S meter reading
String S_meter;
int s_meter_reading=100;
int s_meter_update_cnt = 0;
int last_s_meter_val = 0;
// ------------------------------------------------------------------------------------------------------------------
//-- VSWR meter code begins ---// Note: left without #defines purposely
int fwd_max=0, rev_max=0;
//-- VSWR meter code ends ---------------------------------------------
bool func_button_pressed = false; // if true, the next button pressed is interpreted as a Function
bool BFO_tune_flg = false; // BFO Tune feature
byte dial_tick=0;
#ifdef SP_7
byte dial_speed=6; // slightly different value for this particular rig and encoder
#else
byte dial_speed=8; // control rotary encoder /dial speed
#endif
// ------------------------------------------------------------------------------------------------------------------
// variables for controlling EEPROM writes
unsigned long last_freq_change_ms;
bool eeprom_written_since_last_freq_change;
bool changed_f = false;
/**************************************/
/* Interrupt service routine for encoder frequency change */
/**************************************/
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_CW)
set_frequency(1);
else if (result == DIR_CCW)
set_frequency(-1);
}
/**************************************/
/* Change frequency; dir=1 Increment; dir=-1 Decrement
/**************************************/
void set_frequency(short dir)
{
#ifdef ENCODER_OPTICAL_360
if(++dial_tick%dial_speed != 0) return; // damp the (very fast) 360PPM optical encoder
#endif
if(mode_tx) return; // dial locks in transmit
if (dir == 1)
{
if(!BFO_tune_flg)
VFOSet[v].vfo += VFOSet[v].radix;
else
if(bfo < BFO_TUNE_HI) bfo += 100;
}
else
{
if (dir == -1)
if(!BFO_tune_flg)
VFOSet[v].vfo -= VFOSet[v].radix;
else
if(bfo > BFO_TUNE_LO) bfo -= 100;
};
if(BFO_tune_flg)
{
if(VFOSet[v].vfo >= SIDEBAND_THRESHOLD)
{
USB = bfo;
}
else
{
LSB = bfo;
}
}
changed_f = 1;
};
int read_analogue_pin(byte p)
{
// Take an averaged reading of analogue pin 'p'
int i, val=0, nbr_reads=2;
for (i=0; i<nbr_reads; i++)
{
val += analogRead(p);
delay(1);
}
return val/nbr_reads;
};
#ifdef CW_KEYER
int read_keyer_speed()
{
int n = read_analogue_pin((byte)PIN_KEYER_SPEED);
//Serial.print("Speed returned=");
//Serial.println(n);
dot_length_ms = 60 + (n-183)/5; // scale to wpm (10 wpm == 60mS dot length)
// '511' should be mid point of returned range
// change '5' to widen/narrow speed range...
// smaller number -> greater range
return n;
};
#endif
byte get_front_panel_button()
// Take a reading of the front panel buttons and map it to a button number (0..4)
// Take multiple readings and average them
{
byte b=0;
int z;
z = read_analogue_pin((byte)SWITCH_BANK);
// Serial.print("Frnt bttn="); Serial.println(z);
#ifdef SP_V
if(z > 450 && z < 600) b = 4; // 524
else if(z > 650 && z < 900) b = 6; // 717
#endif
#ifdef SS_EI9GQ
if (z > 1021) b = 0; // 1023
else if(z >= 1000 && z <= 1021) b = 3; // 1015-1021
else if(z > 940 && z < 1000) b = 1; // 966-973
else if(z >= 895 && z < 940) b = 6; // 910
else if(z > 800 && z < 895) b = 2; // 880-886
else if(z > 700 && z < 800) b = 5; // 737
else if(z > 400 && z < 480) b = 4; // 444
#endif
//----------------------------------------------------------------------------------
#ifdef SP_6
// open (USB power: 850) (LiFePO+7812: 1023)
if(z > 300 && z < 800) b = 4; // B1 (USB power: 436) (LiFePO+7812: 719)
else if(z > 50 && z <= 300) b = 1; // B2 (USB power: 91) (LiFePO+7812: 142)
// both:(USB power: 85) (LiFePO+7812: 132)
if(!digitalRead(10)){ // on this rig, the mechanical encoder's pushbutton is used to change radix
while(!digitalRead(10)) ; // spin here until encoder button is released
b = 6;
}
#ifdef DIAGNOSTIC_DISPLAY
diagnostic_flag = true; // trace on the display as a diagnostic
// diagnostic_int = z; // trace 'z'
refresh_display();
#endif
#endif
//----------------------------------------------------------------------------------
#ifdef SP_7
// open (USB power: xxx) (LiFePO+7812: xxx)
if(z > 300 && z < 800) b = 4; // B1 (USB power: xxx) (LiFePO+7812: xxx)
else if(z > 50 && z <= 300) b = 1; // B2 (USB power: xxx) (LiFePO+7812: xxx)
// both:(USB power: xxx) (LiFePO+7812: xxx)
#endif
#ifdef SP_8
if(z > 5 && z < 100) b = 4; // B4 increment the band (with wrap-around)
if(!digitalRead(ENCODER_BUTTON)){ // on this rig, the mechanical encoder's pushbutton is used to change radix
while(!digitalRead(ENCODER_BUTTON)) ; // spin here until encoder button is released
b = 6; // B6 increment the radix (with wrap-around)
}
#endif
#ifdef SP_9
if(z > 2 && z < 100) b = 4; // 15 B4 increment the band (with wrap-around)
if(z >= 100 && z < 750) b = 6; // 560 B4 increment the band (with wrap-around)
if(z >= 750 && z < 1000) b = 1; // 842 B4 increment the band (with wrap-around)
if(!digitalRead(ENCODER_BUTTON)){ // on this rig, the mechanical encoder's pushbutton is used to change radix
while(!digitalRead(ENCODER_BUTTON)) ; // spin here until encoder button is released
b = 6; // B6 increment the radix (with wrap-around)
}
#ifdef DIAGNOSTIC_DISPLAY
diagnostic_flag = true; // trace on the display as a diagnostic
diagnostic_int = z; // trace 'z'
refresh_display();
#endif
#endif
#ifdef SP_X
if(z > 500 && z < 800) b = 8; // 580 freq step up
if(z > 180 && z < 400) b = 4; // 236 B4 channel up (with wrap-around)
if(z > 40 && z < 150) b = 9; // 74 freq step down
#endif
#ifdef SP_11
if(z > 700) b = 0; // 1011
else if(z >= 60) b = 6; // 78
else if(z > 5 && z < 60) b = 4; // 42
#endif
#ifdef SS_FAT5_160AM_TX
if(z > 900) b = 0; // 1008-1017
else if(z > 77 && z < 899) b = 1; // 90
else if(z > 55 && z < 76) b = 4; // 66
else if(z > 30 && z < 55) b = 5; // 41
else if(z > 5 && z < 30) b = 6; // 14
#endif
#ifdef SS_VK3SJ_160AM_TX
if (z < 250) b = 1; // 120
else if(z > 900) b = 2; // 1023
#endif
#ifdef SS_VK3SJ_40AM_TX
if ((z> 50) && (z < 100)) b = 1; // 120
else if((z > 25) && (z < 49)) b = 4; // 1023
else if((z > 5) && (z < 24)) b = 6; // 1023
#endif
#ifdef SS_AM_TX_TEST_VFO
if(z > 800) b = 0; // 850
else if(z > 50 && z < 200) b = 4; // 105
else if(z > 250 && z < 800) b = 1; // 438
#endif
#ifdef SS_VK3SJ_160AM_PORTABLE_TX
if(z > 800) b = 0; // 1022
else if(z > 400 && z < 800) b = 1; // top (black) button (525)
else if(z > 20 && z < 400) b = 5; // bottom (red) button (123)
#endif
#ifdef UNIVERSAL_VFO_CONTROLLER
if(z > 0 && z < 200) b = 4; // 14 band up
else if(z > 400 && z <= 645) b = 6; // 522 radix
else if(z > 645 && z <= 900) b = 1; // 768 band down
#endif
if(b>0){ Serial.print("Front button="); Serial.print(b); Serial.print(" z="); Serial.println(z);}
return b;
} // get_front_panel_button()
void read_meter()
// in receive mode, reads an analog port and constructs an S-meter
// in transmit mode, reads 2 analog ports and constructs a power/SWR meter
// analogue port returns 0..1023; meter string is 8 chars.
{
int sum, y, z;
#ifdef SP_V
byte width = 6;
#else
byte width = 8;
#endif
int s_point_val[width] = {0, 128, 256, 384, 512, 640, 768, 896};
// s1 s3 s5 s7 s9 s9+20 s9+40 s9+60
if(mode_tx)
{
// calculate SWR or relative power using fwd_max, rev_max
z = fwd_max*10; // arbitrary scaling for a relative output power indication
}
else
{
// if(((++s_meter_update_cnt) % 2)!=0) return; // dampen a jittery s-meter
// take an S-meter reading
#define NBR_SAMPLES 2
#if defined(SP_7)
// take an averaged reading from the analogue pin with the s-meter on it
for (byte i=0; i<NBR_SAMPLES; i++) sum += analogRead(PIN_S_METER); // read PIN_S_METER analog pin