/* Arduino sketch for the VK3CV 122GHz transceiver board status display Version 18_12.2 beta Based on v 0.18 beta copyright Barry Chambers, G8AGN, 30 Nov 2020, modified and published with his permission. The original sketch uses a TFT display to show Operating mode Channel number State of A/B switch GPS status GM4ISM additions, 15 May 2021, requiring additional connections as implemented on the GM4ISM display PCB V2.1 see dc2light.co.uk/122GHz.html Slight modifications to what is displayed in some switch conditions, (eg Indicating Full Duplex and renaming LO as TX in that condition Display of supply voltage(s) Status of whether the LO is high or low of the RX frequency and a status line to control a switchable Quadrature combiner. 2 pushbuttons are implemented (INCrement and Enter) to allow user interaction with the software. The Arduino can be used to control the channel selection. It can detect if the channel switches at already set and won't assert contol unless the switches are selecting CH0 (all open). It also relinquishes control if any of the channel switches are set differently from the software commanded channel. In control mode, the Arduino presents either a high impedance (~ 100 MOhms)relying on external pull-ups on the VK3CV board or a low impedance to ground. A CW auto keyer function, able to send looped CW messages in standard QSO format with callsigns up to 11 characters long The Maidenhead Locator for the keyer is set by the GPS. If GPS is not present it can be manually set. It will be overwritten when GPS lock is acheived (but not mid message) Basic button functions are displayed to the user at startup. These additions take a lot of the remaining memory. Some of Barry's Code, which was predomonanlty linear and easy to read, has been altered and compressed by calling more sub-routines Without doing that, this lot would not have fitted. The resulting sketch however is harder to follow. COMPILING .... GM4ISM notes This sketch is large, some older versions of the Arduino IDE may fail to compile it. IDE Versions 1.8.12 an 1.8.13 definatly work Some of the included Libraries also have several versions, some of which seem to increase the size of the compiled file. This version compiles for me using 29580 bytes (96%) of program storage and 1330 bytes (64%) for global variables Uses Arduino 3.3V, 8MHz 328P Pro-Mini and 1.8" 128x160 SPI TFT display It is important to set the IDE software for the 8MHz Arduino. At 16MHz the Arduino may well work overclocked (outside its safe operating zone) but all the timed functions, including serial data timings will be wrong VK3CV status is only updated if an input has been changed. Display connections ------------------- Display Arduino ------- ------- 1 (RST) D7 2 (CS) D9 3 ((D/C) D8 4 (DIN) D11 5 (CLK) D13 6 (VCC) VCC 7 (BL) VCC 8 (GND) Gnd The TFT display uses a ST7735 driver. Adafruit has a library for this ******************** THE 122 GHz BOARD USES 3.3V logic ******************** an 8MHz ATMega 328 Pro-Mini operates at 3.3V so should be OK ******************************************************************************************** 122 board PIC Arduino ------------- ------- RB2 4 RB3 5 RB4 6 KEY IN 14 (A0) KEY OUT 10 PTT IN 15 (A1) RB1 (CH A/B) 16 (A2) Quadrature comb SW out A4 GPS Arduino --- ------- Tx 2 VCC VCC Gnd Gnd The following are implemented on the V2.1 GM4ISM PCB Battery mon Arduino ----------- ------- Vin <30V A6 Aux Voltage mon Arduino ----------- ------- Vin <30V A3 Inc Switch Arduino ------------ ------- 100K Pullup to 3.3V A7 Enter Switch Arduino ------------ ------- to ground A5 CW Keying Arduino ------------ ------- Open Collector controlled by D10 ************************************************************************************************************************* NO RESPONSIBILITY IS ACCEPTED FOR DAMAGE TO YOUR 122 GHz BOARD OR ANY OTHER DEVICE CAUSED BY THESE SUGGESTED CONNECTIONS This program is distributed WITHOUT ANY LIABILITY, WARRANTY OR GUARANTEE OF FITNESS FOR ANY PURPOSE. The software is Copyright of the authors Barry Chambers, G8AGN and Mark Hughes, GM4ISM. All rights are reserved. ************************************************************************************************************************* */ #include #include #include #include #include #include TinyGPSPlus gps; SoftwareSerial ss(2, 3); // 2 = Rx, 3 = Tx //------------------------------------------------------------ // turn on/off internal diagnostic check (1 = 'on', 0 = 'off') int diagCheck = 0; //------------------------------------------------------------ float lat, lon, cd; double d; char MH[11];// 10 digit Locator character array (for display) unsigned long time_old = 25000L; unsigned long time_oldg = 25000L; unsigned long time_last = 25000L; unsigned long time_now; unsigned long KeyDownTimeStart; unsigned long KeyUpTime; unsigned long currentMillis; uint8_t mins; //GPS update rate unsigned long gps_period = 30000L; // Voltage monitoring refresh rate int Vmon_Period = 1000; //ms 1000 = 1 sec float RawV1; //Battery Volts on A6 Resistors fitted on GM4ISM board R3=24K R4=2k7 R5=270 gives 10:1 potential divider +30V Max input float RawV2; //Analogue Voltage on A3 Resistors fitted on GM4ISM board R6=24K R7=2k7 gives 10:1 potential divider10:1 +30V Max input byte LowBatt =10;// Threshold causes displayed battery voltage to go red below this value // channel frequencies // 0 2 4 6 8 A C E // ------------------------------------------------------------------------------------------------ float cha[8] = {122.500400, 122.250100, 122.250240, 122.400000, 122.500400, 122.500400, 122.500400, 122.500400}; float chb[8] = {122.356000, 122.394200, 122.394480, 122.256000, 122.356000, 122.356000, 122.356000, 122.356000}; // CW keyer variables byte CWSpeed; //wpm int CWdelay; // ms period for CW dot 100ms for 12WPM, char MyCall[12];// MAX 11 charctrers, Callsigns are entered / edited as required and then stored in EEPROM Initially the calls will not be set char DXCall[12]; char Locator[9];//8 digit for the CW ID char Report[8]; char Callsign[12]; int CWhangTime = 1200; //ms 1200 = 1.2 sec int CurrentAscii; int tmp; int Message = 1; boolean StopCW = false; boolean Odd = true; boolean CharChange = true; // byte sw_rb4, sw_rb3, sw_rb2, sw_rb4Read, sw_rb3Read, sw_rb2Read, sw_rb1, cn, sw_gps,ImageSw, sw_key, sw_ptt, change_old, change_new, BeaconMode; char AB; byte TFT_RST = 7; byte TFT_DC = 8; int TFT_CS = 9; // 122 board channel select pins const int RB2 = 4; const int RB3 = 5; const int RB4 = 6; // Pin allocations, KEY, PTT and A/B switches etc const int KEY = 14; //A0 const int PTT = 15; //A1 const int RB1 = 16; //A2 A/B switch const int KeyOut = 10; // key ouput Pin const int QS = 18; // A4 (on the I2C Header of ISM PCB) Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); byte ButtonInc = A7; //SW1 A7 Note this pin cannot be used as a digital input and does not have an internal pullup. It is read with analog.read and needs an external pullup to VCC, implemented on the V2.1 board byte ButtonEnter = A5;//SW2 GM4ISM V2 PCB has the ability to select A5 or A6 for this button. USE JUMPER 5 TO CONNECT SW2 to A5. This sketch uses A6 as a voltage monitor input If you use A6 for the button, a pullup is required and AnalogRead not digitalRead must be used OneButton button(ButtonEnter,true);//Onebutton allows user too interact with long press or 'double click' on a single button boolean FreqAssert = false; //SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS void setup() { // Comment the EEPROMload line below out after the first load to save approx 5% programme space //cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc EEPROMload();// pre loads the EEprom with all the CW charactrers and null characters in parameter storage area. It uses EEPROM update so it will age the EEprom unduly. It will not overwrite stored CW messages etc // This can be commented out to save space but on a new Arduino it must run at least once! //cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // Get stored CW parameters from EEPROM int len=0; while(EEPROM.read(300+len) != '\0' && len<12) //Read until null character { MyCall [len]=EEPROM.read(300+len); len++; } len=0; while(EEPROM.read(315+len) != '\0' && len<12) //Read until null character { DXCall [len]=EEPROM.read(315+len); len++; } for (int m=0;m<8;m++) { Locator[m] = EEPROM.read(345 + m); } for (int m=0;m<3;m++) { Report[m] = EEPROM.read(330 + m); } CWSpeed = EEPROM.read(360); if (CWSpeed ==0) CWSpeed = 8;// Sets default value on startup if EEprom not set CWdelay = 1200/CWSpeed; // ms period for CW dot 100ms for 12WPM // ss.begin(9600); //GPS serial comms // initializer for 1.8" TFT 128x160 pixels tft.initR(INITR_BLACKTAB); tft.fillScreen(ST7735_BLACK); tft.setCursor(2, 20); tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); tft.setRotation(1); tft.println(" Version 18_12.2"); tft.println(" Long press Enter"); tft.println(" to change channel"); tft.println(); tft.println(" 'Double click' Enter"); tft.println(" to engage CW keyer "); tft.println(); tft.print(" MyCall "); tft.println(MyCall); tft.print(" DxCall "); tft.print(DXCall); delay(2000); tft.fillScreen(ST7735_BLACK); pinMode(KeyOut,OUTPUT); pinMode(KEY,INPUT_PULLUP);// INPUT for connection to VK3CV which has its own pullup digitalWrite (KeyOut,LOW); // Test Line to check keying cct pinMode(QS,OUTPUT); button.attachDoubleClick(doubleclick); button.attachClick(oneclick); button.attachLongPressStart(longpress); time_oldg = millis(); } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> void loop() { button.tick(); board_status(); if (change_new != change_old) { screen_update(); change_old = change_new; } while (ss.available() > 0) if (gps.encode(ss.read())) if (millis() - time_oldg >= gps_period) { gps_update();; time_oldg = millis(); } // Analogue Voltage Monitoring //................................................. button.tick();// Onebutton check if (millis() - time_last >Vmon_Period) { Vmonitor_update(); time_last = millis(); } //................................................. } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> void board_status() { //read PTT IN line if (digitalRead(PTT) == HIGH) { sw_ptt = 0x1; } else { sw_ptt = 0x0; } //read KEY IN line ISM with Hangtime on external CW keying KeyUpTime = millis() - KeyDownTimeStart; if ((digitalRead(KEY) == HIGH and KeyUpTime >= CWhangTime)or (digitalRead(KEY) == HIGH and digitalRead(PTT) ==LOW )or (digitalRead(KEY) == HIGH and digitalRead(RB1) ==LOW )){// sw_key = 0x1; } if (digitalRead(KEY) == LOW ){ sw_key = 0x0; KeyDownTimeStart = millis(); } if (FreqAssert){// if Arduino is in control of channel setting // Read the channel setting lines if (sw_rb4 == 0x1){ //Check that the setting is already 1, which would indicate that either the SW was open or the RB4 Pin was set to Input if (digitalRead(RB4) == LOW) { sw_rb4= 0x0; FreqAssert = false; } } if (sw_rb3 == 0x1){ //Check that the setting is already 1, which would indicate that either the SW was open or the RB4 Pin was set to Input if (digitalRead(RB3) == LOW) { sw_rb3 = 0x0; FreqAssert = false; } } if (sw_rb2 == 0x1){ //Check that the setting is already 1, which would indicate that either the SW was open or the RB4 Pin was set to Input if (digitalRead(RB2) == LOW) { sw_rb2 = 0x0; FreqAssert = false; } } } else { pinMode(RB2,INPUT);//Ensure all channel setting pins are in read mode ie HIGH (external pullup on VK3CV board) pinMode(RB3,INPUT); pinMode(RB4,INPUT); //read channel switch lines if (digitalRead(RB4) == HIGH) { sw_rb4 = 0x1; } else { sw_rb4 = 0x0; } if (digitalRead(RB3) == HIGH) { sw_rb3 = 0x1; } else { sw_rb3 = 0x0; } if (digitalRead(RB2) == HIGH) { sw_rb2 = 0x1; } else { sw_rb2 = 0x0; } // channel number } cn = 0xE - (sw_rb2 << 1) - (sw_rb3 << 2) - (sw_rb4 << 3); //End of channel read conditional on FreqAssert // read CH A/B line if (digitalRead(RB1) == HIGH) { sw_rb1 = 0x1; AB = 'A'; } else { sw_rb1 = 0x0; AB = 'B'; } if (diagCheck == 1) { //************************************************************************** //DIAGNOSTIC CHECK for testing (comment out these lines afterwards) sw_rb1 = 0x1; // 1 = switch 'off', 0 = 'on' if (sw_rb1 == 0x1)AB = 'A'; else AB = 'B'; sw_rb2 = 0x1; // 1 = switch 'off', 0 = 'on' sw_rb3 = 0x1; // 1 = switch 'off', 0 = 'on' sw_rb4 = 0x1; // 1 = switch 'off', 0 = 'on' cn = 0xE - (sw_rb2 << 1) - (sw_rb3 << 2) - (sw_rb4 << 3); sw_ptt = 0x1; // 1 = switch 'off', 0 = 'on' sw_key = 0x1; // 1 = switch 'off', 0 = 'on' //**************************************************************************** } //generate Quadrature board sideband switch status (display and future control) if (cha[cn / 2] > chb[cn / 2]) { if (sw_rb1 == 0x0) { ImageSw = 0x0; pinMode(QS,OUTPUT);// by definition this is low when trasitioned from Pinmode Input } else { ImageSw = 0x1; pinMode(QS,INPUT); } } else { if (sw_rb1 == 0x1) { ImageSw = 0x0; pinMode(QS,OUTPUT); digitalWrite(RB4, LOW); } else { ImageSw = 0x1; pinMode(QS,INPUT); } } change_new = sw_rb1 + (sw_rb2 << 1) + (sw_rb3 << 2) + (sw_rb4 << 3) + (sw_key << 4) + (sw_ptt << 5); } //sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss void screen_update() { BeaconMode=0;//default // update TFT screen tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.fillRect(0, 0, 160, 110, ST7735_BLACK); tft.setCursor(2, 3); // display 122GHz board mode if ((sw_ptt == 0x1) && (sw_key == 0x1)) //RECEIVE A or B { tft.setTextColor(ST7735_GREEN); if (AB == 'A') { tft.println("Receive A"); } else { tft.println("Receive B"); } tft.setTextColor(ST7735_WHITE); tft.println(""); tft.print("Ch "); tft.setTextColor(ST7735_YELLOW); tft.print(cn, HEX); tft.setTextColor(ST7735_CYAN); tft.print(" ["); tft.print(AB); tft.println("]"); tft.setTextColor(ST7735_WHITE); tft.print("Rx "); tft.setTextColor(ST7735_YELLOW); if (AB == 'A') { tft.println(cha[cn / 2], 4); } else { tft.println(chb[cn / 2], 4); } tft.setTextColor(ST7735_WHITE); tft.print("LO "); tft.setTextColor(ST7735_YELLOW); if (AB == 'B') { tft.println(cha[cn / 2], 4); } else { tft.println(chb[cn / 2], 4); } tft.setTextColor(ST7735_WHITE); tft.print("IF "); tft.setTextColor(ST7735_YELLOW); cd = abs(cha[cn / 2] - chb[cn / 2]); tft.println(1000.0 * cd, 1); } if ((AB == 'A') && (sw_ptt == 0x1) && (sw_key == 0x0)) //TRANSMIT CW CARRIER { tft.setTextColor(ST7735_RED); tft.println("Tx CW A"); DisplayBody1(); } if ((AB == 'B') && (sw_ptt == 0x1) && (sw_key == 0x0)) //TRANSMIT FM TONE { BeaconMode=1; tft.setTextColor(ST7735_RED); tft.println("FM tone B"); DisplayBody1(); } if ((AB == 'A') && (sw_ptt == 0x0) && (sw_key == 0x1)) //TRANSMIT FM AUDIO A { tft.setTextColor(ST7735_RED); tft.println("FM audio A"); tft.setTextColor(ST7735_WHITE); tft.println("Full Duplex");//ISM. added for clarity tft.print("Ch "); tft.setTextColor(ST7735_YELLOW); tft.print(cn, HEX); tft.setTextColor(ST7735_CYAN); tft.print(" ["); tft.print(AB); tft.println("]"); tft.setTextColor(ST7735_WHITE); tft.print("Rx "); tft.setTextColor(ST7735_YELLOW); tft.println(cha[cn / 2], 4); tft.setTextColor(ST7735_WHITE); tft.print("Tx ");//ISM. Changed from LO to Tx, this is full duplex operation FM voice tft.setTextColor(ST7735_YELLOW); tft.println(chb[cn / 2], 4); tft.setTextColor(ST7735_WHITE); tft.print("IF "); tft.setTextColor(ST7735_YELLOW); cd = abs(cha[cn / 2] - chb[cn / 2]); tft.println(1000.0 * cd, 1); } if ((AB == 'B') && (sw_ptt == 0x0) && (sw_key == 0x1)) //TX FM AUDIO B { tft.setTextColor(ST7735_RED); tft.println("FM audio B"); tft.setTextColor(ST7735_WHITE); tft.println("Full Duplex");//ISM. added for clarity tft.print("Ch "); tft.setTextColor(ST7735_YELLOW); tft.print(cn, HEX); tft.setTextColor(ST7735_CYAN); tft.print(" ["); tft.print(AB); tft.println("]"); tft.setTextColor(ST7735_WHITE); tft.print("Rx "); tft.setTextColor(ST7735_YELLOW); tft.println(chb[cn / 2], 4); tft.setTextColor(ST7735_WHITE); tft.print("Tx ");//ISM. Changed from LO to Tx, this is full duplex operation FM voice tft.setTextColor(ST7735_YELLOW); tft.println(cha[cn / 2], 4); tft.setTextColor(ST7735_WHITE); tft.print("IF "); tft.setTextColor(ST7735_YELLOW); cd = abs(cha[cn / 2] - chb[cn / 2]); tft.println(1000.0 * cd, 1); } if ((AB == 'A') && (sw_ptt == 0x0) && (sw_key == 0x0)) //TRANSMIT CW BEACON A { BeaconMode=1; tft.setTextColor(ST7735_RED); tft.println("CW beacon A"); DisplayBody1();//Subroutine to finish displaying this. Saves a few hundred bytes! } if ((AB == 'B') && (sw_ptt == 0x0) && (sw_key == 0x0)) //TRANSMIT FM BEACON B { BeaconMode=1; tft.setTextColor(ST7735_RED); tft.println("FM beacon B"); DisplayBody1(); } // display warning symbol (*) if internal diagnostic check is enabled if (diagCheck == 1) { tft.setTextColor(ST7735_RED); tft.setCursor(145, 2); tft.print("*"); tft.setCursor(2, 3); } else { tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); tft.setCursor(115, 91); if (ImageSw == 1 and BeaconMode == 0) { tft.print("RX HI"); } else { if ( BeaconMode == 0) tft.print("RX LOW"); } tft.setCursor(2, 3); } if (!FreqAssert) { tft.setTextColor(ST7735_ORANGE); tft.setTextSize(1); tft.setCursor(110, 35); tft.print("Ext ctrl"); tft.setCursor(2, 3); } } //ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd void DisplayBody1() { tft.setTextColor(ST7735_WHITE); tft.println(""); tft.print("Ch "); tft.setTextColor(ST7735_YELLOW); tft.print(cn, HEX); tft.setTextColor(ST7735_CYAN); tft.print(" ["); tft.print(AB); tft.println("]"); tft.setTextColor(ST7735_WHITE); tft.print("Tx "); tft.setTextColor(ST7735_YELLOW); if ((AB == 'B')) { tft.println(chb[cn / 2], 4); } else { tft.println(cha[cn / 2], 4); } tft.println(""); tft.println(""); } //ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg void gps_update() { while (ss.available()){ int gpsn = ss.read(); if (gps.encode(gpsn )) { if (gps.location.isUpdated()) { lon = gps.location.lng(); lat = gps.location.lat(); // convert longitude to Maidenhead d = 180.0 + lon; d = 0.5 * d; int ii = (int) (0.1 * d); MH[0] = char(ii + 65); float rj = d - 10.0 * (float)ii; int j = (int) rj; MH[2] = char(j + 48); float fpd = rj - (float)j; float rk = 24.0 * fpd; int k = (int) rk; MH[4] = char(k + 65); fpd = rk - (float)(k); float rl = 10.0 * fpd; int l = (int)(rl); MH[6] = char(l + 48); fpd = rl - (float)(l); float rm = 24.0 * fpd; int mm = (int)(rm); MH[8] = char(mm + 65); // convert latitude to Maidenhead d = 90.0 + lat; ii = (int)(0.1 * d); MH[1] = char(ii + 65); rj = d - 10.*(float)ii; j = (int)rj; MH[3] = char(j + 48); fpd = rj - (float)j; rk = 24.0 * fpd; k = (int)rk; MH[5] = char(k + 65); fpd = rk - (float)(k); rl = 10.0 * fpd; l = int(rl); MH[7] = char(l + 48); fpd = rl - (float)(l); rm = 24.0 * fpd; mm = (int)(rm); MH[9] = char(mm + 65); tft.fillRect(0, 111, 160, 17, ST7735_BLACK); tft.setCursor(0, 112); tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.print(MH); for (int n=0;n<10;n++) { EEPROM.update(345 + n,MH[n]);// Update Locator in EEprom } } if (gps.time.isUpdated()) { tft.setTextSize(1); tft.setCursor(115,101); tft.print(" "); tft.print(gps.time.hour()); tft.print(":"); mins=gps.time.minute(); if(mins < 10)tft.print("0"); tft.print(mins); } else { tft.fillRect(0, 111, 160, 17, ST7735_BLACK); tft.setCursor(1, 113); tft.setTextColor(ST7735_RED); tft.setTextSize(2); if (ss.available() > 0){ tft.println("no GPS Lock"); } } } } } //---------------------------------------------------------------------------------------------------------- void Vmonitor_update(){ // Routine to measure the PCB supply added by GM4ISM RawV1 = analogRead(A6); RawV2 = analogRead(A3); float BattVolt = (RawV1 / 31.0)+0.77;//there is a series diode so add 0.77V (measured forward voltage drop) if (RawV1 <= 50 ) BattVolt=0.0; tft.setCursor(1, 101); tft.setTextSize(1); tft.setTextColor(ST7735_WHITE); tft.print("Supply "); tft.fillRect(40, 101, 160, 10, ST7735_BLACK); if (BattVolt <= LowBatt) { tft.setTextColor(ST7735_RED); } else { tft.setTextColor(ST7735_GREEN); } tft.print(1.0 * BattVolt, 1); tft.print("V "); float BattVolt2 = (RawV2 / 31.0);//there is no series diode so no 0.77V if (RawV2 <= 50 ) BattVolt2=0.0; if (BattVolt2 >0.0) { tft.setTextColor(ST7735_GREEN); tft.print(1.0 * BattVolt2, 1); tft.print("V"); } } //---------------------------------------------------------------------------------------------------------- void oneclick() { // Not defined } // oneclick //................................................................................................................. void longpress() { FrequencySet(); // tft.fillRect(0, 0, 120, 35, ST7735_BLACK); // screen_update(); } // longpress //.................................................................................................................. void doubleclick() { CWmenu(); KeyingLoop(); StopCW = false; } // doubleclick //.................................................................................................................. void FrequencySet(){ // the channel can be changed by this routine. if(FreqAssert == false and cn != 0)//Check if the loop has shown system in under external freq control. If so,the freq will remain under external hardware control { tft.setTextColor(ST7735_ORANGE); tft.setTextSize(1); tft.fillRect(0, 18, 160, 17, ST7735_BLACK); tft.setCursor(2, 23); tft.print("! Freq under ext control !"); pinMode(RB2,INPUT);//Ensure all channel setting pins are in read mode ie HIGH (external pullup on VK3CV board) pinMode(RB3,INPUT); pinMode(RB4,INPUT); delay(2000); } else { //Process the channel changing routine and force the software into control of the frequency, not simply reading external switch states (FreqAssert variable set true) tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.fillRect(40, 33, 30, 18, ST7735_BLACK); tft.setCursor(48, 35); tft.setTextColor(ST7735_WHITE); tft.print("?"); delay(400); long MillisStart2 = millis(); while(millis() < MillisStart2 + 5000) { //5 second timeout with no activity if (analogRead(ButtonInc) <500) //ButtonInc is A7 This cannot be used as a digital input. It must be externally pulled high (100K to 3.3V) and then read as an alalogue voltage which will change nominally from 1024 to 0 when the button is pressed { delay(400); MillisStart2 = millis();// reset the button timeout if (cn<14) { cn = cn+2;//increment channel no (by 2) } else { cn=0; } tft.fillRect(40, 33, 30, 18, ST7735_BLACK); tft.setCursor(48, 35); tft.setTextColor(ST7735_WHITE); tft.print(cn, HEX); tft.fillRect(48, 51, 140, 32, ST7735_BLACK); tft.setCursor(48, 51); if (digitalRead(RB1) == HIGH) { tft.println(cha[cn / 2], 4); tft.setTextColor(ST7735_CYAN); tft.fillRect(84, 35, 14, 16, ST7735_BLACK); tft.setCursor(84, 35); tft.print("A"); } else { tft.println(chb[cn / 2], 4); tft.setTextColor(ST7735_CYAN); tft.fillRect(84, 34, 14, 16, ST7735_BLACK); tft.setCursor(84, 35); tft.print("B"); } tft.setCursor(48, 68); tft.setTextColor(ST7735_WHITE); if (digitalRead(RB1) == HIGH) { tft.println(chb[cn / 2], 4); } else tft.println(cha[cn / 2], 4); } if (digitalRead(ButtonEnter) == 0) break;//immediate return to display mode } tft.fillRect(40, 31, 30, 20, ST7735_BLACK); tft.setCursor(48, 35); tft.setTextColor(ST7735_YELLOW); tft.print(cn); FreqAssert = true; SetFreqPins(); } } //---------------------------------------------------------------------------------------------- void SetFreqPins(){ /* IMPORTANT Control of the VK3CV board frequency requires the Arduino pins controlling RB2, RB3 and RB4 to be set correctly. pinMode INPUT, (not INPUT_PULLUP) is a high impedance state already used to read the pin status. As a control output, without changing anything, this is effectively HIGH as the VK3CV has pullup resistors. To set Logic LOW output, appropriate pins are configured as pinMode OUTPUT which is low impedance. Having transitioned from INPUT this will default to LOW and act like the channel switches, effectively grounding the control line. In this sketch, at no point does the Arduino put out a low impedance HIGH voltage (ie 3.3V) on these lines. The levels presented to the VK3UM boared are either High impedance ~100Mohms or a low impedance to ground. It is important to note that if you set a pinMode to OUTPUT from being INPUT_PULLUP, it does output 3.3V at low impedance. This probably will not damage the VK3CV board but is undesirable. especially if the are grounded swithes on the line. To prevent damage to the Arduino, V2 PCBs have a current limiting 330 Ohm resistor fitted to the RB2, RB3 and RB4 lines, just in case! */ byte cnI = 255-cn;//create and inverse bit pattern to get the sense of the switches correct sw_rb2 = bitRead(cnI,1); // Select Bit for RB2 from Channel number cn sw_rb3 = bitRead(cnI,2); // Select Bit for RB3 from Channel number cn sw_rb4 = bitRead(cnI,3); // Select Bit for RB4 from Channel number cn if(sw_rb2 == 0) pinMode(RB2,OUTPUT);// Low else pinMode(RB2,INPUT);//High if(sw_rb3 == 0) pinMode(RB3,OUTPUT); else pinMode(RB3,INPUT); if(sw_rb4 == 0) pinMode(RB4,OUTPUT); else pinMode(RB4,INPUT); } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void CWmenu() { CwMenuStart: delay(500); tft.fillScreen(ST7735_BLACK); tft.setCursor(2, 3); tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); tft.println(" Select Message with Inc"); tft.setCursor(2, 17); tft.println(" 1 "); tft.setCursor(2, 31); tft.println(" 2 "); tft.setCursor(2, 45); tft.println(" 3 "); tft.setCursor(2, 59); tft.println(" 4 R"); tft.setCursor(2, 73); tft.println(" 5 "); tft.setCursor(2, 87); tft.println(" 6 <73 73 73 73 73>"); tft.setCursor(2, 101); tft.println(" 7 Edit Messages"); tft.setCursor(2, 115); tft.print(" Enter to execute "); tft.setCursor(136, 115); tft.setTextColor(ST7735_GREEN); tft.print(Message); while (digitalRead(ButtonEnter)==HIGH){ if (analogRead(ButtonInc) <500){ delay (200); Message = Message + 1; if (Message ==8) Message = 1; tft.fillRect(136, 115, 10, 10, ST7735_BLACK); tft.setCursor(136, 115); tft.print(Message); } } tft.fillScreen(ST7735_BLACK); if (Message == 7) { SetCWstrings(); goto CwMenuStart; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void SetCWstrings(){ // All CW strings are set by passing the appropriate Character array, length and string identifier to sub CharEntry. At the end of that routine they are stored in EEprom tft.fillRect(0, 0, 162, 130, ST7735_BLACK); tft.setCursor(2, 21); tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); tft.println(" Enter to select parameter"); tft.println(" Inc & Enter to change it"); tft.setCursor(0, 37); tft.setTextColor(ST7735_GREEN); tft.println(" "); tft.setTextColor(ST7735_WHITE); tft.println(" "); tft.println(" "); tft.println(" "); tft.println(" CW Speed"); tft.setTextSize(2); tft.setCursor(2, 101); CharEntry(MyCall,sizeof(MyCall)-1,1); // Set MyCall 11 = no of characters, 1 = StringNo 1. NB The number of characters is 1 less than charater array lenght declaration (-1 because of the array final null character) The maximum that can be accomodated here is 15 Characters because of the space allocated in EEPROM tft.setTextSize(1); tft.setCursor(0, 37); tft.setTextColor(ST7735_WHITE); tft.println(" "); tft.setTextColor(ST7735_GREEN); tft.println(" "); tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.setCursor(2, 101); CharEntry(DXCall,sizeof(DXCall)-1,2); // Set DxCall, length of string, StringNo 2 tft.setTextSize(1); tft.setCursor(0, 45); tft.setTextColor(ST7735_WHITE); tft.println(" "); tft.setTextColor(ST7735_GREEN); tft.println(" "); tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.setCursor(2, 101); CharEntry(Report,sizeof(Report)-1,3); // Set Report = StringNo 3 7 characters allowing for RST a space (.) and 3 digit Serial No tft.setTextSize(1); tft.setCursor(0, 53); tft.setTextColor(ST7735_WHITE); tft.println(" "); tft.setTextColor(ST7735_GREEN); tft.println(" "); tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); tft.setCursor(2, 101); CharEntry(Locator,8,4); // Set Locator = StringNo 4 tft.setTextSize(1); tft.setCursor(0, 61); tft.setTextColor(ST7735_WHITE); tft.println(" "); tft.setTextColor(ST7735_GREEN); tft.println(" CW Speed"); tft.setTextColor(ST7735_WHITE); tft.setTextSize(2); SetCwSpeed();// CWSpeed is set by a seperate routine } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: void SendCW(int CWchar){// the Ascii value of each letter to be sent is passed to this routine //tft.setTextSize(2); tft.setCursor(94, 110); tft.print(char(CWchar)); tft.setTextSize(1); tft.setCursor(118, 110); tft.print(CWSpeed); tft.print(" WPM"); tft.setTextSize(2); if (CWchar!=0){ //Ignore Null Characters which could be sent at the end of a message string if (CWchar != 46) {//stored symbol is not a dot interpreted as an extra space int CWcharStart = (CWchar - 47) * 5;// shifts the Ascii value to match the EEprom adresses for each character for (int i =0; i<5; i++){// each allowed cw character has a maximum of 5 symbols (dot or dash) int Morse = EEPROM.read(CWcharStart + i);// Each byte in the EEprom holds a value that is either 1,2 or 3. 1 is processed as a dot, 2 as a dash, 3 as an end of character flag if (Morse == 1) { //Send a dot and character space digitalWrite (KeyOut,HIGH);// Keying is inverted High is Key down delay(CWdelay); digitalWrite (KeyOut,LOW); delay(CWdelay); if (digitalRead(ButtonEnter) == LOW) {// trap a longish push on the enter key to break out of CW sending routine StopCW = true; delay(300); } } if (Morse == 2) { //Send a dash and character space digitalWrite (KeyOut,HIGH); delay(CWdelay * 3); digitalWrite (KeyOut,LOW); delay(CWdelay); if (digitalRead(ButtonEnter) == LOW) { StopCW = true; delay(300); } } if (Morse == 3) { // character end, send additional key-up character space digitalWrite (KeyOut,LOW); delay(CWdelay); // break; } } delay(CWdelay * 2); } else { delay(CWdelay * 7); } } tft.fillRect(92, 110, 68, 19, ST7735_BLACK); } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void CharEntry(char MsgString[], int MaxStringLen,int StringNo) { int MemLoc = 300 + ((StringNo-1) *15); int AsciiNo=46;// Start of CW Ascii characters. Only letters, Numbers and / can be sent as CW. Selecting a . forces and extra 7 dot length (word) space unsigned long startMils = millis(); //interval start time of the cycle for (int Pointer = 0; Pointer < MaxStringLen; Pointer++){ //max 11 characters in Callsign tft.setCursor(2, 101); tft.print(MsgString); CurrentAscii=char(MsgString[Pointer]); while (digitalRead(ButtonEnter) == HIGH){ CurrentAscii=char(MsgString[Pointer]); if (millis()- startMils >= 125) {//Cursor Flash period ..test whether the period has elapsed to flash the active cursor position Odd = !Odd; CharChange = true; startMils = millis(); //re-start the cycle } tft.setCursor((2 +12*Pointer), 101); if (Odd and CharChange) { tft.fillRect((2+12*Pointer) , 98, 12, 18, ST7735_BLACK); tft.print(MsgString[Pointer]);// active character indicated by alternating'_' with the character } else { if (CharChange){ tft.fillRect((2 +12*Pointer) , 98, 12, 18, tft.color565(70, 70, 70)); if (analogRead(ButtonInc) < 500)//If the Inc Button is being pressed { tft.write(CurrentAscii); CurrentAscii = CurrentAscii - 1; // this prevents an 'overrun' when you hold the inc key down } } } CharChange = false; //delay (100); if (analogRead(ButtonInc) < 500) { delay (150); //should be greater that the cursor flash period if (CurrentAscii >= 90) { CurrentAscii = -1; //skip to space character character being } if (CurrentAscii == 0) CurrentAscii = 45; if (CurrentAscii == 57) { CurrentAscii = 64; //skip to next character being A } MsgString[Pointer] = CurrentAscii + 1; } } EEPROM.update(MemLoc + Pointer,CurrentAscii ); delay(200); tft.fillRect((2+12*Pointer) , 98, 12, 18, ST7735_BLACK); tft.setCursor((2 +12*Pointer), 101); tft.write(CurrentAscii); } tft.setCursor(146, 101); tft.write(char(16));// print a right arrow to indicate that all the symbols have been selected and that the enter button can be released delay(1200); tft.fillRect(2 , 98, 160, 18, ST7735_BLACK); } //]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] void SetCwSpeed() { tft.setCursor(12, 101); tft.print(CWSpeed); tft.setCursor(54, 101); tft.print("WPM"); while (digitalRead(ButtonEnter)==HIGH) { if (analogRead(ButtonInc) < 500)//If the Inc Button is being pressed { delay (100); CWSpeed = CWSpeed +1; if (CWSpeed > 20) CWSpeed = 6;//sets max and min keying speeds tft.fillRect(2 , 98, 40, 18, ST7735_BLACK); tft.setCursor(12, 101); tft.print(CWSpeed); tft.setCursor(54, 101); tft.print("WPM"); CWdelay = 1200/CWSpeed; } } EEPROM.update(360,CWSpeed); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void KeyingLoop() { long CWStartTime= millis(); StartKeying: if (millis() > CWStartTime + 300000) goto Stopit; // CW keyer timeout. 300000 = 5 min sw_key = 0x0; screen_update(); board_status();// checks for changes in switch configurations each message cycle (Under normal circumstances this is not expected) if (change_new != change_old) { screen_update(); change_old = change_new; } tft.setTextColor(ST7735_ORANGE); tft.setTextSize(1); tft.fillRect(0, 18, 160, 17, ST7735_BLACK); tft.setCursor(2, 23); tft.print("CW Keyer - Enter to Break"); tft.setCursor(2, 100); tft.print("Message "); tft.println(Message); tft.setTextSize(2); tft.setCursor(2, 110); tft.print("Sending"); if (Message ==1) { //CQ SendCW(67);//"C" SendCW(81);//"Q" delay (CWdelay *3); //MyCall x2 for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } //LOC for (int SCW=0 ; SCW<8 ; SCW++) { SendCW(EEPROM.read(345+SCW)); } } if (Message ==2){ //DXCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW (EEPROM.read(315+Msg)); } delay (CWdelay *3); //MyCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } } if (Message ==3){ //DXCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW (EEPROM.read(315+Msg)); } delay (CWdelay *3); //MyCall for (int Msg=0 ; Msg<12 ; Msg++) { SendCW(EEPROM.read(300+Msg)); } delay (CWdelay *3); //Report for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(330+Msg)); } delay (CWdelay *3); //Report for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(330+Msg)); } //LOC for (int SCW=0 ; SCW<8 ; SCW++) { SendCW(EEPROM.read(345+SCW)); } } if (Message ==4){ //DXCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW (EEPROM.read(315+Msg)); } delay (CWdelay *3); //MyCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } delay (CWdelay *3); SendCW(82);//"R" //Report for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(330+Msg)); } delay (CWdelay *3); SendCW(82);//"R" //Report for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(330+Msg)); } delay (CWdelay *3); SendCW(82);//"R" //Report for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(330+Msg)); } } if (Message ==5){ //MyCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } delay (CWdelay *3); for (int Roger=0 ; Roger<12 ; Roger++) { if (StopCW == true) goto Stopit; SendCW(82);//"R" } } if (Message ==6){ //MyCall for (int Msg=0 ; Msg<12 ; Msg++) { if (StopCW == true) goto Stopit; SendCW(EEPROM.read(300+Msg)); } delay (CWdelay *3); for (int ST=0 ; ST<6 ; ST++) { if (StopCW == true) goto Stopit; SendCW(55);//"7" SendCW(51);//"3" delay (CWdelay *3); } } if (StopCW == true) goto Stopit; goto StartKeying;// this puts the message keyer into a continuous loop (with a timout set at the start of this routine) //} Stopit: sw_key = 0x1; tft.fillRect(0, 18, 160, 17, ST7735_BLACK); // Blank out the CW Auto Keyer text tft.fillRect(0, 100, 160, 27, ST7735_BLACK); screen_update(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EEPROM Load routine, needs to be run only once on a new Arduino. This loads the CW character array into EEPROM If you forget to comment out thehis routing, it wont hurt! // If necessary this routine could be turned into a stand alone sketch and run once on a new Arduino. This may be necessary if ant other features are needed because remaining programming space // is very low with EEPRONload enabled in this sketch void EEPROMload() { int MemStart = 0; // "/" EEPROM.update(MemStart,2);// Morse Dash EEPROM.update(MemStart + 1,1);//Morse Dot EEPROM.update(MemStart + 2,1);//Morse Dot EEPROM.update(MemStart + 3,2);// Morse Dash EEPROM.update(MemStart + 4,1);//Morse Dot // "0" EEPROM.update(MemStart + 5,2);//Morse Dash EEPROM.update(MemStart + 6,2);// Morse Dash EEPROM.update(MemStart + 7,2);// Morse Dash EEPROM.update(MemStart + 8,2);// Morse Dash EEPROM.update(MemStart + 9,2);// Morse Dash // "1" EEPROM.update(MemStart + 10,1);//Morse Dot EEPROM.update(MemStart + 11,2);// Morse Dash EEPROM.update(MemStart + 12,2);// Morse Dash EEPROM.update(MemStart + 13,2);// Morse Dash EEPROM.update(MemStart + 14,2);// Morse Dash // "2" EEPROM.update(MemStart + 15,1);//Morse Dot EEPROM.update(MemStart + 16,1);// Morse Dot EEPROM.update(MemStart + 17,2);// Morse Dash EEPROM.update(MemStart + 18,2);// Morse Dash EEPROM.update(MemStart + 19,2);// Morse Dash // "3" EEPROM.update(MemStart + 20,1);//Morse Dot EEPROM.update(MemStart + 21,1);// Morse Dot EEPROM.update(MemStart + 22,1);// Morse Dot EEPROM.update(MemStart + 23,2);// Morse Dash EEPROM.update(MemStart + 24,2);// Morse Dash // "4" EEPROM.update(MemStart + 25,1); EEPROM.update(MemStart + 26,1); EEPROM.update(MemStart + 27,1); EEPROM.update(MemStart + 28,1); EEPROM.update(MemStart + 29,2); // "5" EEPROM.update(MemStart + 30,1); EEPROM.update(MemStart + 31,1); EEPROM.update(MemStart + 32,1); EEPROM.update(MemStart + 33,1); EEPROM.update(MemStart + 34,1); // "6" EEPROM.update(MemStart + 35,2); EEPROM.update(MemStart + 36,1); EEPROM.update(MemStart + 37,1); EEPROM.update(MemStart + 38,1); EEPROM.update(MemStart + 39,1); // "7" EEPROM.update(MemStart + 40,2); EEPROM.update(MemStart + 41,2); EEPROM.update(MemStart + 42,1); EEPROM.update(MemStart + 43,1); EEPROM.update(MemStart + 44,1); // "8" EEPROM.update(MemStart + 45,2); EEPROM.update(MemStart + 46,2); EEPROM.update(MemStart + 47,2); EEPROM.update(MemStart + 48,1); EEPROM.update(MemStart + 49,1); // "9" EEPROM.update(MemStart + 50,2); EEPROM.update(MemStart + 51,2); EEPROM.update(MemStart + 52,2); EEPROM.update(MemStart + 53,2); EEPROM.update(MemStart + 54,1); //"A" EEPROM.update(MemStart + 90,1);//Morse Dot EEPROM.update(MemStart + 91,2);// Morse Dash EEPROM.update(MemStart + 92,3); //Null character forces end of character space and break //"B" EEPROM.update(MemStart + 95,2); EEPROM.update(MemStart + 96,1); EEPROM.update(MemStart + 97,1); EEPROM.update(MemStart + 98,1); EEPROM.update(MemStart + 99,3); //Null character forces end of character space and break //"C" EEPROM.update(MemStart + 100,2); EEPROM.update(MemStart + 101,1); EEPROM.update(MemStart + 102,2); EEPROM.update(MemStart + 103,1); EEPROM.update(MemStart + 104,3); //Null character forces end of character space and break //"D" EEPROM.update(MemStart + 105,2); EEPROM.update(MemStart + 106,1); EEPROM.update(MemStart + 107,1); EEPROM.update(MemStart + 108,3); //Null character forces end of character space and break //"E" EEPROM.update(MemStart + 110,1); EEPROM.update(MemStart + 111,3); //Null character forces end of character space and break //"F" EEPROM.update(MemStart + 115,1); EEPROM.update(MemStart + 116,1); EEPROM.update(MemStart + 117,2); EEPROM.update(MemStart + 118,1); EEPROM.update(MemStart + 119,3); //Null character forces end of character space and break //"G" EEPROM.update(MemStart + 120,2); EEPROM.update(MemStart + 121,2); EEPROM.update(MemStart + 122,1); EEPROM.update(MemStart + 123,3); //Null character forces end of character space and break //"H" EEPROM.update(MemStart + 125,1); EEPROM.update(MemStart + 126,1); EEPROM.update(MemStart + 127,1); EEPROM.update(MemStart + 128,1); EEPROM.update(MemStart + 129,3); //Null character forces end of character space and break //"I" EEPROM.update(MemStart + 130,1); EEPROM.update(MemStart + 131,1); EEPROM.update(MemStart + 132,3); //Null character forces end of character space and break //"J" EEPROM.update(MemStart + 135,1); EEPROM.update(MemStart + 136,2); EEPROM.update(MemStart + 137,2); EEPROM.update(MemStart + 138,2); EEPROM.update(MemStart + 139,3); //Null character forces end of character space and break //"K" EEPROM.update(MemStart + 140,2); EEPROM.update(MemStart + 141,1); EEPROM.update(MemStart + 142,2); EEPROM.update(MemStart + 143,3); //Null character forces end of character space and break //"L" EEPROM.update(MemStart + 145,1); EEPROM.update(MemStart + 146,2); EEPROM.update(MemStart + 147,1); EEPROM.update(MemStart + 148,1); EEPROM.update(MemStart + 149,3); //Null character forces end of character space and break //"M" EEPROM.update(MemStart + 150,2); EEPROM.update(MemStart + 151,2); EEPROM.update(MemStart + 152,3); //Null character forces end of character space and break //"N" EEPROM.update(MemStart + 155,2); EEPROM.update(MemStart + 156,1); EEPROM.update(MemStart + 157,3); //Null character forces end of character space and break //"O" EEPROM.update(MemStart + 160,2); EEPROM.update(MemStart + 161,2); EEPROM.update(MemStart + 162,2); EEPROM.update(MemStart + 163,3); //Null character forces end of character space and break //"P" EEPROM.update(MemStart + 165,1); EEPROM.update(MemStart + 166,2); EEPROM.update(MemStart + 167,2); EEPROM.update(MemStart + 168,1); EEPROM.update(MemStart + 169,3); //Null character forces end of character space and break //"Q" EEPROM.update(MemStart + 170,2); EEPROM.update(MemStart + 171,2); EEPROM.update(MemStart + 172,1); EEPROM.update(MemStart + 173,2); EEPROM.update(MemStart + 174,3); //Null character forces end of character space and break //"R" EEPROM.update(MemStart + 175,1); EEPROM.update(MemStart + 176,2); EEPROM.update(MemStart + 177,1); EEPROM.update(MemStart + 178,3); //Null character forces end of character space and break //"S" EEPROM.update(MemStart + 180,1); EEPROM.update(MemStart + 181,1); EEPROM.update(MemStart + 182,1); EEPROM.update(MemStart + 183,3); //Null character forces end of character space and break //"T" EEPROM.update(MemStart + 185,2); EEPROM.update(MemStart + 186,3); //Null character forces end of character space and break //"U" EEPROM.update(MemStart + 190,1); EEPROM.update(MemStart + 191,1); EEPROM.update(MemStart + 192,2); EEPROM.update(MemStart + 193,3); //Null character forces end of character space and break //"V" EEPROM.update(MemStart + 195,1); EEPROM.update(MemStart + 196,1); EEPROM.update(MemStart + 197,1); EEPROM.update(MemStart + 198,2); EEPROM.update(MemStart + 199,3); //Null character forces end of character space and break //"W" EEPROM.update(MemStart + 200,1); EEPROM.update(MemStart + 201,2); EEPROM.update(MemStart + 202,2); EEPROM.update(MemStart + 203,3); //Null character forces end of character space and break //"X" EEPROM.update(MemStart + 205,2); EEPROM.update(MemStart + 206,1); EEPROM.update(MemStart + 207,1); EEPROM.update(MemStart + 208,2); EEPROM.update(MemStart + 209,3); //Null character forces end of character space and break //"Y" EEPROM.update(MemStart + 210,2); EEPROM.update(MemStart + 211,1); EEPROM.update(MemStart + 212,2); EEPROM.update(MemStart + 213,2); EEPROM.update(MemStart + 214,3); //Null character forces end of character space and break //"Z" EEPROM.update(MemStart + 215,2); EEPROM.update(MemStart + 216,2); EEPROM.update(MemStart + 217,1); EEPROM.update(MemStart + 218,1); EEPROM.update(MemStart + 219,3); //Null character forces end of character space and break if (EEPROM.read (300) == 255) // Check that the area is blank, this routine would overwrite stored CW Strings { for (int n = 300;n<400;n++) { EEPROM.update(n,0);// Fill with Null symbol } } }