10 aprilie 2020

CW and Voice memory keyer for ICOM IC-7300

After a long time I decided to came back to CW.

Just for fun and to use the Pandemia holiday I thought will be interesting to have a little remote for the Voice and CW memory.
While the Voice memory callback is relatively simple with CI-V protocol, for CW memory there are no commands provided by ICOM.
Therefore, the keyer will store the preset messages (10 messages) and send them using a 4 x 4 keypad.
The uC of choice is an Arduino with Atmega 328 on UNO platform.
The keypad is also used to Power On and OFF the radio and TUNE the ATU (I use an AH-4).



The 4 x 4 keypad is able to send: -In CW, 10 preprogrammed CW messages, each of 128 bytes; -in SSB, AM, FM, 8 prerecorded voice messages -"A" is Power ON -"B" is Power OFF -"C" is TUNE

Here is a small video on youtube about this


Here is the code
/*
CI-V Voice/Morse keyer
Version 1.1
https://yo3hjv.blogspot.com/2020/04/cw-and-voice-memory-keyer-for-icom-ic.html
This is a CW memory keyer for ICOM CI-V radios.
It was tested on IC-7300 and it is working well.
It was tested on IC-703 and was find not compatible.
Many thanks for inspiring the structure to KEN - KC9UMR.
The 4 x 4 keypad is able to send:
-In CW, 10 preprogrammed CW messages, each of 128 bytes;
-in SSB, AM, FM, 8 prerecorded voice messages
-"A" is Power ON
-"B" is Power OFF
-"C" is TUNE
The rest will be defined later on other versions.
This was a good opportunity for me to learn to use Arrays and Switch/case
Many thanks for the whole community from where I learned!
Thanks also to our wise government for keeping us at home...
de Adrian Florescu, YO3HJV. April, 2020
This code is released under the EUPL v1.2.
*/
#include <SoftwareSerial.h>
#include <Keypad.h>
const byte numRows = 4;
const byte numCols = 4;
byte keymap[numRows][numCols] =
{ {'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[numRows] = {9, 8, 7, 6}; //Rows 0 to 3
byte colPins[numCols] = {5, 4, 3, 2}; //Columns 0 to 3
//initializes an instance of the Keypad class
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
/*
When sending the power ON commandCW (18 01), you need
to repeatedly send “FE” before the standard format. The
following values for pON has to be observed.
••115200 bps: 150 “FE”s
••57600 bps: 75 “FE”s
••38400 bps: 50 “FE”s
••19200 bps: 25 “FE”s
••9600 bps: 13 “FE”s
••4800 bps: 7 “FE”s
*/
#define START_BYTE 0xFE // Start byte
#define STOP_BYTE 0xFD // Stop byte
#define SEND_CW 0x17
#define VOICE_MEM 0x28
#define ZERO byte(0x00)
#define CONTROLLER_ADDRESS 0xE3 // The hex adress of the Arduino controller
char toSend;
byte asciiCW;
byte i;
byte j;
byte n = 1; // variable. how many times the message is repeated. TBD
int RPTint; // Memory repeat interval. TBD
byte p;
byte pON = 180;
char key;
byte radio;
byte voiceMem1 = 0x01;
byte voiceMem2 = 0x02;
byte voiceMem3 = 0x03;
byte voiceMem4 = 0x04;
byte voiceMem5 = 0x05;
byte voiceMem6 = 0x06;
byte voiceMem7 = 0x07;
byte voiceMem8 = 0x08;
byte vMem;
/*
* The following are USER-DEFINED values.
* The values are to be modified according to the settings on the radio
*/
#define RADIO_ADDRESS 0x94 // ic7300 has default address 0x94
#define CAT_BAUDRATE 19200 // Arduino to radio Baudrate on CI-V interface
#define RX 12 // CAT RX on Arduino UNO for software serial
#define TX 13 // CAT TX on Arduini UNO for software serial
SoftwareSerial CAT(RX, TX); // RX, TX
// THIS ARE THE PRESET CW MESSAGES TO BE SENT
// both Upper-case or Lower-case letters can be used and the following symbols
// * . , ! ? / = ( ) [SPACE] _ -
char msg_1[] = "CQ CQ DE YO3HJV yo3hjv"; // max lenght 128
char msg_2[] = "YO3HJV"; // max lenght 128
char msg_3[] = "5NN 5NN TU 73 DE YO3HJV KN"; // max lenght 128
char msg_4[] = "QRL? QRL? DE YO3HJV K"; // max lenght 128
char msg_5[] = "R R = OP HR ADI ADI BK"; // max lenght 128
char msg_6[] = "NAME ADI ADI ADI BTU"; // max lenght 128
char msg_7[] = "CQ"; // max lenght 128
char msg_8[] = "= TNX FER QSO = GL HP CU AGN 73 DE YO3HJV"; // max lenght 128
char msg_9[] = "5NN 5NN TU 73 K"; // max lenght 128
char msg_0[] = "V";
void setup() {
Serial.begin(19200);
CAT.begin(CAT_BAUDRATE); // set the data rate for the Software Serial port
delay(2);
CAT.flush();
}
void loop() {
checkPad();
}
void checkPad() {
// This is where the magic is happening
char keypressed = myKeypad.getKey();
if (keypressed != NO_KEY) {
key = keypressed;
switch (key) {
/////////// NUMBERS ///////////
case '1':
for (byte j = 0; j < n; j++) {
sendMem1();
vMem = voiceMem1;
sendVoice();
}
break;
case '2':
for (byte j = 0; j < n; j++) {
sendMem2();
vMem = voiceMem2;
sendVoice();
}
break;
case '3':
for (byte j = 0; j < n; j++) {
sendMem3();
vMem = voiceMem3;
sendVoice();
}
break;
case '4':
for (byte j = 0; j < n; j++) {
sendMem4();
vMem = voiceMem4;
sendVoice();
}
break;
case '5':
for (byte j = 0; j < n; j++) {
sendMem5();
vMem = voiceMem5;
sendVoice();
}
break;
case '6':
for (byte j = 0; j < n; j++) {
sendMem6();
vMem = voiceMem6;
sendVoice();
}
break;
case '7':
for (byte j = 0; j < n; j++) {
sendMem7();
vMem = voiceMem7;
sendVoice();
}
break;
case '8':
for (byte j = 0; j < n; j++) {
sendMem8();
vMem = voiceMem8;
sendVoice();
}
break;
case '9':
for (byte j = 0; j < n; j++) {
sendMem9();
}
break;
case '0':
for (byte j = 0; j < n; j++) {
sendMem0();
}
//////////////////// LETTERS //////////////////////
break;
case 'A':
for (byte j = 0; j < n; j++) {
powerON();
}
break;
case 'B':
for (byte j = 0; j < n; j++) {
powerOFF();
}
break;
case 'C':
for (byte j = 0; j < n; j++) {
ATUne();
}
break;
case 'D':
for (byte j = 0; j < n; j++) {
// something ;
}
break;
case '*':
for (byte j = 0; j < n; j++) {
// something();
}
break;
case '#':
for (byte j = 0; j < n; j++) {
// something();
}
break;
}// End of SWITCH
}
}
void sendVoice(){
send_preamble();
commandVOICE();
send_post();
}
void sendMem0() {
for (byte i = 0; i < sizeof(msg_0) - 1; i++) {
toSend = msg_0[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem1() {
for (byte i = 0; i < sizeof(msg_1) - 1; i++) {
toSend = msg_1[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem2() {
for (byte i = 0; i < sizeof(msg_2) - 1; i++) {
toSend = msg_2[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem3() {
for (byte i = 0; i < sizeof(msg_3) - 1; i++) {
toSend = msg_3[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem4() {
for (byte i = 0; i < sizeof(msg_4) - 1; i++) {
toSend = msg_4[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem5() {
for (byte i = 0; i < sizeof(msg_5) - 1; i++) {
toSend = msg_5[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem6() {
for (byte i = 0; i < sizeof(msg_6) - 1; i++) {
toSend = msg_6[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem7() {
for (byte i = 0; i < sizeof(msg_7) - 1; i++) {
toSend = msg_7[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem8() {
for (byte i = 0; i < sizeof(msg_8) - 1; i++) {
toSend = msg_8[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem9() {
for (byte i = 0; i < sizeof(msg_9) - 1; i++) {
toSend = msg_9[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void ATUne(){
send_preamble();
CAT.write(0x1C);
CAT.write(01);
CAT.write(02);
send_post();
}
void commandCW() {
CAT.write(SEND_CW);
}
void commandVOICE(){
CAT.write(VOICE_MEM);
CAT.write(ZERO);
CAT.write(vMem);
}
void send_CW() {
ASCIItoHEX();
CAT.write(asciiCW);
}
void send_preamble()
{
CAT.write(0xFE);
CAT.write(0xFE);
CAT.write(RADIO_ADDRESS);
CAT.write(CONTROLLER_ADDRESS);
}
void send_post()
{
CAT.write(0xFD);
CAT.flush();
}
////////////////////// Here is ASCII to ICOM HEX ASCII ///////////////////////////////
void ASCIItoHEX () {
switch (toSend) {
////////////////////////////// NUMBERS ///////////////////////
case '0':
asciiCW = 0x30;
break;
case '1':
asciiCW = 0x31;
break;
case '2':
asciiCW = 0x32;
break;
case '3':
asciiCW = 0x33;
break;
case '4':
asciiCW = 0x34;
break;
case '5':
asciiCW = 0x35;
break;
case '6':
asciiCW = 0x36;
break;
case '7':
asciiCW = 0x37;
break;
case '8':
asciiCW = 0x38;
break;
case '9':
asciiCW = 0x39;
break;
////////////////////////////// SYMBOLS ////////////////////////
case ' ' :
asciiCW = 0x20;
break;
case '*': // This is to insert CONTEST NUMBER
asciiCW = 0x2A;
break;
case '/':
asciiCW = 0x2F;
break;
case '-':
asciiCW = 0x2D;
break;
case '?':
asciiCW = 0x3F;
break;
case ',':
asciiCW = 0x2C;
break;
case '.':
asciiCW = 0x2E;
break;
case '@':
asciiCW = 0x40;
break;
case '=':
asciiCW = 0x3D;
break;
case '!':
asciiCW = 0x21;
break;
case '(':
asciiCW = 0x28;
break;
case ')':
asciiCW = 0x29;
break;
case '"':
asciiCW = 0x22;
break;
case '#':
asciiCW = 0x23;
break;
case '_':
asciiCW = 0x5F;
break;
////////////////////// UPPER-CASE LETTERS /////////////////////////////
case 'A':
asciiCW = 0x41;
break;
case 'B':
asciiCW = 0x42;
break;
case 'C':
asciiCW = 0x43;
break;
case 'D':
asciiCW = 0x44;
break;
case 'E':
asciiCW = 0x45;
break;
case 'F':
asciiCW = 0x46;
break;
case 'G':
asciiCW = 0x47;
break;
case 'H':
asciiCW = 0x48;
break;
case 'I':
asciiCW = 0x49;
break;
case 'J':
asciiCW = 0x4A;
break;
case 'K':
asciiCW = 0x4B;
break;
case 'L':
asciiCW = 0x4C;
break;
case 'M':
asciiCW = 0x4D;
break;
case 'N':
asciiCW = 0x4E;
break;
case 'O':
asciiCW = 0x4F;
break;
case 'P':
asciiCW = 0x50;
break;
case 'Q':
asciiCW = 0x51;
break;
case 'R':
asciiCW = 0x52;
break;
case 'S':
asciiCW = 0x53;
break;
case 'T':
asciiCW = 0x54;
break;
case 'U':
asciiCW = 0x55;
break;
case 'V':
asciiCW = 0x56;
break;
case 'W':
asciiCW = 0x57;
break;
case 'X':
asciiCW = 0x58;
break;
case 'Y':
asciiCW = 0x59;
break;
case 'Z':
asciiCW = 0x5A;
break;
///////////////////// LOWER CASE LETTERS ////////////////////////////////
case 'a':
asciiCW = 0x41;
break;
case 'b':
asciiCW = 0x42;
break;
case 'c':
asciiCW = 0x43;
break;
case 'd':
asciiCW = 0x44;
break;
case 'e':
asciiCW = 0x45;
break;
case 'f':
asciiCW = 0x46;
break;
case 'g':
asciiCW = 0x47;
break;
case 'h':
asciiCW = 0x48;
break;
case 'i':
asciiCW = 0x49;
break;
case 'j':
asciiCW = 0x4A;
break;
case 'k':
asciiCW = 0x4B;
break;
case 'l':
asciiCW = 0x4C;
break;
case 'm':
asciiCW = 0x4D;
break;
case 'n':
asciiCW = 0x4E;
break;
case 'o':
asciiCW = 0x4F;
break;
case 'p':
asciiCW = 0x50;
break;
case 'q':
asciiCW = 0x51;
break;
case 'r':
asciiCW = 0x52;
break;
case 's':
asciiCW = 0x53;
break;
case 't':
asciiCW = 0x54;
break;
case 'u':
asciiCW = 0x55;
break;
case 'v':
asciiCW = 0x56;
break;
case 'w':
asciiCW = 0x57;
break;
case 'x':
asciiCW = 0x58;
break;
case 'y':
asciiCW = 0x59;
break;
case 'z':
asciiCW = 0x5A;
break;
}
delay(1); // For stability
}
void powerON() {
for (byte p = 0; p <= pON; p++) {
CAT.write(0xFE); // preamble is sent multiple times
}
send_preamble();
CAT.write(0x18);
CAT.write(0x01);
send_post();
}
void powerOFF() {
send_preamble();
CAT.write(0x18);
CAT.write(ZERO);
send_post();
}
view raw gistfile1.txt hosted with ❤ by GitHub



Un comentariu:

rfranc spunea...

Arduino:1.8.13 (Windows 10), Plošča:"Arduino Nano, ATmega328P"

Dear friend
I have a problem encoding your program:
CI-VMemory_Keyer_R_1_1.
I am using an Arduino 1.8.13.
what is wrong. can you help me?
73 Franc S52RF franc.s52rf@gmail.com


C:\Users\rf\AppData\Local\Temp\ccTza5kG.ltrans0.ltrans.o: In function `global constructors keyed to 65535_0_CI_VMemory_Keyer_R_1_1.ino.cpp.o.2180':

:(.text.startup+0x8c): undefined reference to `Key::Key()'

:(.text.startup+0xa6): undefined reference to `Key::Key()'

collect2.exe: error: ld returned 1 exit status

exit status 1

Error compiling for board Arduino Nano.



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Most viewed posts in last 30 days