Hello,
The context
A hamradio transceiver connected to a PC via RS232. The software on the PC retrieves some information every 500 ms or send data to the radio to control it.
I want to retrieve more information than the PC requests and display them on an OLED display.
So I have created a small circuit with an Arduino Pro Mini and a MAX232 whiwh is inserted in the RS232 line.
Library SoftwareSerial is used to add a second Serial port.
How it works
The Arduino forwards the data between both serial ports, and waits for the last information from the radio, which is "MD"
After this string is received, it sends:
"PC;" request, then process the answer (ie PC255) to display the output power
"AN0;" request, then process the answer (ie AN10) to know the antenna output selected
"KS;" request, then process the answer (ie KS26)
The information are displayed, then it loops.
By the way, it also reads IF0 and FB to compare the frequencies currently in use, then calculates the difference to display it.
My concern is that after a few loops (between 10 and sometimes 200), the OLED display freezes.
The "nb" value, displayed for debugging, don't change anymore after some iterations.
The sketch is still running correctly, the informations are correctly forwarded from one serial to the other (if it didn't work, the software on the PC would tell the communication is broken).
Plus, data is still interpreted by the sketch. For example, if AN0 answer changes, RelaisRxAnt state changes
Only the display is frozen.
The most annoying is that it worked like a charm for the past 2 years. I recently recompiled if just for moving some text of a few pixels.
The only change I can see is that Arduino IDE and libraries are newer.
/*
Le montage intercepte et transfere les commandes CAT, en 19200 8N2.
Si le VFO-B est selectionne en emission, allumage de la LED
Lorsque le dernier champ est envoye par le TRX (MD), l'Arduino envoie les requetes additionnelles :
- PC (lecture de la puissance pour affichage OLED)
- KS (lecture de la vitesse du keyer pour affichage OLED)
- AN0 (lecture de l'antenne pour declenchement du relais coax si ANT = RX)
*/
#include <SoftwareSerial.h>
#include <U8glib.h>
// Entrees/sorties
SoftwareSerial CAT(12,11); // RX, TX
U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / A4-A5
const int Split_led = 10; // LED split
const int RelaisRxAnt = 9; // Relais RX
// Variables
int old_power = -1;
int power;
String str;
String text_pwr;
int bandVFOa;
float freqVFOa;
int bandVFOb;
float freqVFOb;
float upVal;
int split = 0;
int wpm;
int nb = 0;
void setup() {
pinMode(Split_led, OUTPUT);
pinMode(RelaisRxAnt, OUTPUT);
Serial.begin(19200); // regular serial
CAT.begin(19200); // CAT serial
digitalWrite(Split_led, LOW); // LED éteinte
digitalWrite(RelaisRxAnt, LOW); // Relais RX Ant off
}
void draw(void) {
if (Serial.available()) {
str = Serial.readStringUntil(';');
str.concat(";");
Serial.print(str);
}
if (CAT.available()) {
str = CAT.readStringUntil(';');
str.concat(";");
CAT.print(str);
/*** LED split ***/
if (str == "FT0;") { // TX sur VFO-A
digitalWrite(Split_led, LOW);
split = 0;
}
if (str == "FT1;") { // TX sur VFO-B
digitalWrite(Split_led, HIGH);
split = 1;
}
if (str.startsWith("MD")) { // Envoi requête PC apres dernier champ reçu (MD)
Serial.print("PC;");
}
if (str.startsWith("PC")) { // Lecture puissance TX (PCxxx;)
String power_str = str.substring(2,str.length()-1);
power = power_str.toInt();
if (power != old_power) { // Si la puissance a changé
text_pwr = Convert(power); // Correspondance xxx (0-255) -> puissance
old_power = power;
}
Serial.print("AN0;"); // Envoi requête "Antenne selectionnee"
nb++;
}
if (str.startsWith("AN")) {
String rx_ant = str.substring(4,str.length()-1); // Lecture Antenne ANxxY
String tx_ant = str.substring(3,4); // Lecture Antenne ANxZx
if (rx_ant == "1") { // Y = 1 donc RX -> bascule relais coax RX Ant
digitalWrite(RelaisRxAnt, HIGH);
} else {
digitalWrite(RelaisRxAnt, LOW);
}
Serial.print("KS;"); // Envoi requete "Key Speed (WPM)"
}
if (str.startsWith("KS")) { // Lecture vitesse Keyer KSxxx
String str_wpm = str.substring(2,str.length()-1);
wpm = str_wpm.toInt();
}
if (str.startsWith("IF0")) { // Lecture freq VFO A
String str_freqVFOa = str.substring(7,12);
freqVFOa = str_freqVFOa.toInt();
String str_bandVFOa = str.substring(5,7);
bandVFOa = str_bandVFOa.toInt();
}
if (str.startsWith("FB")) { // Lecture freq VFO B
String str_freqVFOb = str.substring(4,9);
freqVFOb = str_freqVFOb.toInt();
String str_bandVFOb = str.substring(2,4);
bandVFOb = str_bandVFOb.toInt();
}
if ((bandVFOa == bandVFOb) && (split == 1)) { // Bandes identiques, comparaison freq
upVal = (freqVFOb-freqVFOa)/100;
} else {
upVal = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Affichage - Important de le laisser a la fin de la boucle
//
u8g.setContrast(10);
u8g.setFont(u8g_font_ncenB18); // Affichage valeur Puissance
u8g.setPrintPos(4, 22);
u8g.print(text_pwr);
u8g.setFont(u8g_font_7x14); // Affichage valeur Split
u8g.setPrintPos(92, 30);
if (upVal != 0) {
u8g.print(upVal);
} else {
u8g.print(" ");
}
u8g.setPrintPos(92, 12); // Affichage valeur WPM
if (wpm != 0) {
u8g.print(wpm);
} else {
u8g.print(" ");
}
u8g.setFont(u8g_font_6x10); // Affichage "wpm"
u8g.setPrintPos(110, 12);
u8g.print("wpm");
u8g.setPrintPos(0, 32);
u8g.print(nb);
}
void loop(void) {
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
}
//////////////////////////////////////////////////////////////////////////////////////////////
// La valeur PWR envoyée est comprise entre 0 (10W) et 255 (200W)
// Conversion de cette valeur numérique en texte
String Convert(int power) {
String real_pwr;
if (power == 0 || (power >= 0 && power < 31)){
real_pwr = " 10 W";
} else if (power >= 32 && power < 44) {
real_pwr = " 15 W";
} else if (power >= 44 && power < 60) {
real_pwr = " 20 W";
} else if (power >= 60 && power < 70) {
real_pwr = " 25 W";
} else if (power >= 70 && power < 75) {
real_pwr = " 30 W";
} else if (power >= 75 && power < 81) {
real_pwr = " 35 W";
} else if (power >= 81 && power < 86) {
real_pwr = " 40 W";
} else if (power >= 86 && power < 91) {
real_pwr = " 45 W";
} else if (power >= 91 && power < 99) {
real_pwr = " 50 W";
} else if (power >= 99 && power < 105) {
real_pwr = " 60 W";
} else if (power >= 105 && power < 118) {
real_pwr = " 70 W";
} else if (power >= 118 && power < 126) {
real_pwr = " 80 W";
} else if (power >= 126 && power < 140) {
real_pwr = " 90 W";
} else if (power >= 140 && power < 145) {
real_pwr = "100 W";
} else if (power >= 145 && power < 150) {
real_pwr = "110 W";
} else if (power >= 150 && power < 160) {
real_pwr = "120 W";
} else if (power >= 160 && power < 166) {
real_pwr = "130 W";
} else if (power >= 166 && power < 170) {
real_pwr = "140 W";
} else if (power >= 170 && power < 177) {
real_pwr = "150 W";
} else if (power >= 177 && power < 193) {
real_pwr = "160 W";
} else if (power >= 193 && power < 201) {
real_pwr = "170 W";
} else if (power >= 201 && power < 211) {
real_pwr = "180 W";
} else if (power >= 211 && power < 224) {
real_pwr = "190 W";
} else if (power >= 224) {
real_pwr = "200 W";
}
return real_pwr;
}