-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathyaesu-oled-tx-timer.ino
396 lines (335 loc) · 11.9 KB
/
yaesu-oled-tx-timer.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
// Libraries to be used
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Configure the Display
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
// Setup the display driver with the above settings
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Are we using a temperature sensor? If we are not, comment this line.
// The Temperature Sensor code is compatible with LM-35 sensors.
//#define TEMP_SENS A0 // The Port where the temperature is being read
// Configure the GPIO pins
#define TX_GND 1 // The GPIO pin where you connected the TXGND signal
#define PULLUP 13 // The GPIO pin that is driving TXGND up
#define GPIO_FAN 10 // The GPIO pin where we control the fan relay.
#define RX_ON 4 // The GPIO pin where you connected the SQL signal
// Comment out to disable monitoring RX.
#define TIME_ALERT 120 // TX time alert threshold (seconds)
#define CALLSIGN "PY2RAF" // Your callsign. Comment out to disable splash screen.
#define TEMP_ON_TX 1 // Do we want to show the radio temperature in TX mode?
#define TEMP_THRESHOLD 40 // Starts external fan when temp greater than this
#define MONITOR_SQUELCH 1 // Monitor squelched time? If not desired, comment.
#define MONITOR_UPTIME 1 // Monitor uptime? If not desired, comment.
#define MONITOR_STATE 1 // Print SQ/RX state? If not desired, comment.
// General variables
unsigned long t; // Timer (secs)
unsigned long h; // Derived timer hours
unsigned long m; // Derived timer Minutes
unsigned long s; // Derived timer seconds (60-second fraction)
unsigned long t_event; // Time-of-start (based on uptime) of event
unsigned long u; // Uptime (secs)
unsigned long mu; // Derived uptime minutes
unsigned long hu; // Derived uptime hours
unsigned long du; // Derived uptime days
int temperature; // Current temp; Celsius
int temp_high_counter; // Temperature above Threshold counter
int temp_low_counter; // Temperature under Threshold counter
bool fan_state; // Self Explanatory
String LastState; // The last active state used for proper timer tracking
void setup() {
//Serial.begin(9600); // Setup serial port for debug in case of display failure
//while (!Serial); // Keep this commented after you disconnect from your
// computer, otherwise the board will hang on this instruction
//Serial.print("Initiating setup/bootstrap\n");
// Display initialization
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
Serial.print("Display setup completed\n");
#ifdef RX_ON
pinMode(RX_ON, INPUT);
#endif
// If we are controlling a fan...
#ifdef GPIO_FAN
pinMode(GPIO_FAN, OUTPUT);
digitalWrite(GPIO_FAN, LOW);
#endif
// Splash Screen
#ifdef CALLSIGN
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(3);
display.setCursor(10,6); // a small padding
display.print(CALLSIGN);
display.display();
delay(4000);
display.invertDisplay(true);
display.display();
delay(300);
display.invertDisplay(false);
display.display();
delay(300);
#endif
// Configure display runtime defaults
display.clearDisplay();
display.setTextColor(WHITE);
// Configure the pin that will be providing the pullup level to TX_GND
pinMode(PULLUP, OUTPUT);
digitalWrite(PULLUP, HIGH);
// Configure the TX_GND pin as a input GPIO
pinMode(TX_GND, INPUT);
Serial.print("Finished setup\n");
}
#ifndef MONITOR_SQUELCH
// Blinking dot every other second
void blinkingdot() {
display.clearDisplay();
display.invertDisplay(false);
if ( u % 2 == 0 ) display.drawPixel(127, 31, WHITE);
display.display();
delay(500);
}
#endif
void printtime(){
if (h < 1) { // Up to 1 hour, Print mm:ss
if (m < 10) display.print(0); // Pad with zero if less than ten
display.print(m); display.print(":");
if (s < 10) display.print(0); // Pad with zero if less than ten
display.print(s);
}
else if (h < 100) { // Less than 100 hours, Print hh h mm
if (h < 10) display.print(0); // Pad with zero if less than ten
display.print(h); display.print("h");
if (m < 10) display.print(0); // Pad with zero if less than ten
display.print(m);
}
else { // More than 100 hours, Print hhh h
display.print(h); display.print("h");
}
// Draw a separator line and print it
display.drawLine(62, 0, 62, 31, WHITE);
display.display();
// Give it a second to sleep until next poll
delay(1000);
}
void calc_event_time(){
// Calculate the event's seconds, minutes and hours
t = u - t_event;
s = t % 60;
m = t / 60 %60;
h = t / 3600;
}
#ifdef MONITOR_UPTIME
// Print the current uptime
void print_uptime(){
mu = u / 60 % 60;
hu = u / 3600;
du = u / 86400;
// Uptime block
display.setTextSize(2); // Medium size
display.setCursor(0, 0); // Bottom top of the screen
if (du < 1 ) { // Up to a day; hh:mm
if (hu < 10) display.print(0);
display.print(hu); display.print("h");
if (mu < 10) display.print(0);
display.print(mu);
}
else { // More than a day; dd:hh
hu = hu - ( du * 86400 / 3600); // Calculate how many hours within the day.
display.print(du); display.print("d");
if (hu < 10) display.print(0);
display.print(hu);
if (du < 10) display.print("h"); // add the h suffix if less than 10 days uptime
}
display.setTextSize(1);
// The temperature block
#ifdef TEMP_SENS
// The uptime text
display.setCursor(12,16);
display.print("Uptime");
// The temperature info
display.setCursor(7,25);
display.print("Temp:");
display.print(temperature);
display.print("C");
// Blink a dot when fan is on
#ifdef GPIO_FAN
if (fan_state == 1) {
if ( u % 2 == 0 ) {
display.setCursor(69,15);
display.print((char)7);
}
}
#endif
#else
// If no temperature selected, just print uptime.
display.setCursor(12,24);
display.print("Uptime");
#endif
}
#endif
// Print Squelched timer
void printsquelch() {
// Reset timer if transitioned state
if (LastState != "Squelch") {
t_event = u;
display.invertDisplay(false);
}
// Calculating the seconds, minutes and hours
calc_event_time();
// Clear the display buffer and prepare for new data
display.clearDisplay();
#ifdef MONITOR_UPTIME
print_uptime();
#endif
#ifdef MONITOR_STATE
display.setTextSize(2);
display.setCursor(87,0);
display.print("SQ");
#endif
display.setTextSize(2); // Medium size
display.setCursor(68,18); // Bottom left of the screen
// Print the SQ timer
printtime();
// Set state
LastState = "Squelch";
}
void loop() {
// Derive uptime from millis()
u = (millis() / 1000);
#ifdef TEMP_SENS
temperature = (float(analogRead(TEMP_SENS))*5/(1023))/0.01;
#endif
// Control logic for fan.
// Runs the fan if temperature gets above threshold for 15 seconds in row.
// Stops the fan if temperature gets below threshold for 2 minutes in row.
#ifdef GPIO_FAN
if (temperature > TEMP_THRESHOLD) {
temp_high_counter++;
temp_low_counter=0; }
else if (fan_state == 1 && temp_low_counter < 120 ) {
temp_low_counter++;
temp_high_counter=0; }
else {
temp_low_counter++;
temp_high_counter=0;
digitalWrite(GPIO_FAN, LOW);
fan_state=0;
}
if ( temp_high_counter > 15 ) {
digitalWrite(GPIO_FAN, HIGH);
fan_state=1;
}
#endif
// If voltage is present - meaning no Transmission; radio receiving or squelched
if (digitalRead(TX_GND) == HIGH) {
// If we are monitoring RX time too
#ifdef RX_ON
// Yaesu radio: Squelch Open, RX=HIGH
if (digitalRead(RX_ON) == HIGH) {
// Icom and Kenwood radio: Squelch open, RX=LOW
// Comment the above "if" and uncomment the below "if".
// (digitalRead(RX_ON) == LOW) {
// Reset timer if transitioned state
if (LastState != "RX") {
t_event = u;
display.invertDisplay(false);
}
// Calculating the seconds, minutes and hours
calc_event_time();
// Clear the display buffer and prepare for new data
display.clearDisplay();
#ifdef MONITOR_UPTIME
print_uptime();
#endif
#ifdef MONITOR_STATE
display.setTextSize(2);
display.setCursor(87,18);
display.print("RX");
#endif
// Where to print the elapsed RX time
display.setTextSize(2); // Medium size
display.setCursor(68,0); // Better screen adjustment
// Print the RX timer
printtime();
// Set state
LastState = "RX";
}
else {
// Print a blinking dot or squelch counter
#ifndef MONITOR_SQUELCH
blinkingdot();
#else
printsquelch();
#endif
}
}
// If we are NOT monitoring RX time
#else
blinkingdot();
LastState = "Squelch";
}
#endif
// However if line is grounded... (meaning: TX is ON)
else {
// Reset timer if radio changed state
if (LastState != "TX") {
t_event = u;
display.invertDisplay(false);
}
// Calculating the seconds and minutes (no cap for minutes)
calc_event_time();
// Clear the display buffer and prepare for new data
display.clearDisplay();
display.setTextSize(4);
display.setCursor(5,2); // Better screen adjustment
// Print the TX time
if (m < 10) display.print(0); // Pad with zero if less than ten
display.print(m); display.print(" ");
if (s < 10) display.print(0); // Pad with zero if less than ten
display.print(s);
#ifdef TEMP_SENS
#ifdef TEMP_ON_TX
#ifdef GPIO_FAN
if (fan_state == 1 ) { // Fan on, temperature font/color inverted
display.fillRect(54,9,18,15,WHITE);
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(58,13);
display.print(temperature);
display.setTextColor(WHITE); }
else { // Fan off, just temperature inside a box.
display.drawRect(54,9,18,15,WHITE);
display.setTextSize(1);
display.setCursor(58,13);
display.print(temperature); }
#else // No Fan Control
display.drawRect(54,9,18,15,WHITE);
display.setTextSize(1);
display.setCursor(58,13);
display.print(temperature); }
#endif
#else // No Temperature on TX
display.setTextSize(4);
display.setCursor(55,2); // Print colon
display.print(":");
#endif
#else // No Temperature sensor
display.setTextSize(4);
display.setCursor(55,2); // Print colon
display.print(":");
#endif
// Are we over time alert threshold?
#ifdef TIME_ALERT
if (t > TIME_ALERT) display.invertDisplay(true);
#endif
display.display();
// Give it a second to sleep until next poll
delay(1000);
// Set state
LastState = "TX";
}
}