More on Using an Arduino with IC7700 and MFJ998 tuner


Jeff   VE1ZAC                    May 14, 2011


My previous write up described how I solved the missing remote tuner connection to an IC7700 by using an Arduino single board processor to act as a go between on the Icom CIV line and the tuner’s AH-3 style connection.


I have since refined the code a little and discovered some important ancillary features that need to be considered.


Hardware items:


I replaced the push button from the previous article with a much nicer one that requires very little pressure to activate. Note, in the code, that the button I used is normally closed. If you were using a normally open one, you would need to change a few things.


se2010gg 002


I have also discovered that the “Tune” button on the tuner itself will do some things with the AH-3 control lines that could have been used to initiate the tune cycle, if I had realized it before starting. The push button I added could have been skipped. On the other hand using a push button with an Arduino is about as simple as unwrapping the Arduino when you receive it.


Some Icom things:


The CIV line is prone to collisions of data streams when more than one device is using it. In my case, I want this thing to work at the same time that DXLab Commander is controlling the transceiver. It is just about impossible to avoid collisions or conflicting commands when Commander is running, as it assumes it is the master of the CIV line. I noticed there were some funny goings on when Commander was in “Continuous Interrogate” mode (found in the config window of Commander). When it’s off, there are no problems. When it’s on with a short command interval there are occasional glitches.  Dave Bernstein described this to me as ‘Playing Russian roulette with a loaded gun, and occasionally (some command) will blow up’. Great description!


Further, continuous interrogation provides for the cursor in the bandpsread window following the transceiver frequency… something I am kind of addicted too. I did find I could leave continuous interrogation on if I set the command interval fairly long to 500 mS. This is a compromise, but allows very reliable remote tuner operation. Also, the “Transceive” option in the Icom setup menu must be off.  I have delays tweaked in the code to work with a CIV speed of 19200 baud.


I am using the Icom’s RS232 port as a CIV port for the computer, and the CIV jack on the rear panel for the Arduino/tuner line.


The code and operation was laboriously tested with these parameters in place by initiating a tune 100 times with the push button, about half with transceiver with split VFO’s, and half without.  No glitches, so this is a good setup.


There is another potential refinement I could engage in, and probably will try at some point. Right now I determine if the transceiver is split by polling it myself. This likely increases the probability of collisions. If I was always going to use this with Commander, I could skip the polling and just listen for split data, as Commander does that task now. Then I would assume the transceiver is not split, unless I tapped into a 'split' data stream between the transceiver and Commander. The downside of this method is that Commander would have to be running, where as my present system works with or without.


If you want to try this or adopt this code to work with other CIV functions and want the file drop me a line and I will send it along.


Latest software revisions:


// NOTE.. Commander could interfere with some of the split vfo directives. Caveat Emptor

//this software runs perfectly without Commander doing continuous interrogation.

// checking with Dave Bernstein for a Commander solution

//This is the E1 control version

// Works OK with Commander , and 500 ms

//command interval, continuous interrogate on

// *** Note, this is for IC7700 where Commander uses RS232

//port and Arduino uses CIV line *****

// 19200 baud interfaces, important

//all built in delays are important

//the AH-4 tuner function for Icom CI-V and MFJ 998 control

//commands work with Icom interface enabled in 998 tuner

//and Icom CI-V line with Arduino processor

//reads key line from tuner

//controls start line and radio Tx and Rx


// define the pins we need for interfacing

//LED is to show STARTTUNE running

// Use a delay when turning split on and off before proceeding as rig

//is slow to respond

// this one for NC tune push button

#define TUNEBUTTON 8       // t the PB on unit to start process

#define LEDKEY 13         // LED pin ,

#define LEDTUNE 12        // LED pin

#define KEY 9            // tuner switch normally high off

#define TUNESTART 10     // Start on tuner cable, normally high of

#define TUNEPOWER 11     // delayed response to simulate radio


// These are all the command arrays needed

// Note**that some are not used here.**

//array elements are DEC versions of HEX command

// add more as needed and transmit in byte array loop

int tx[8] = {254,254,110,225,28,00,01,253};       //turn Tx on

int rx[8] = {254,254,110,225,28,00,00,253};       // goto receive

int dis[8] = {254,254,110,225,28,01,00,253};      // disable tuner

int toff[10] = {254,254,110,225,26,5,0,113,0,253};//disable tuner auto

int lp[9] = {254,254,110,225,20,10,0,101,253};    // set to low power

int amlp[9] = {254,254,110,225,20,10,0,144,253};  // set to 80 for AM

int am[7] = {254,254,110,225,6,2,253};            // AM mode

int cw[7] ={254,254,110,225,6,3,253};             // C W mode

int ant4[7] ={254,254,110,225,18,3,253};          // use ant 4 for amp

int hp[9] = {254,254,110,225,20,10,2,85,253};     // back to high power

int tun[8] ={254,254,110,225,28,1,1,253};         // enable tuner

int ton[10] = {254,254,110,225,26,5,0,113,1,253}; // enable tuner auto

int splitoff[7] = {254,254,110,225,15,00,253};

int spliton[7]= {254,254,110,225,15,01,253};

int swapab[7]={254,254,110,225,07,176,253};  // swap vfo A and B

int split;                                   // split indicator

int splitmarker;

int buffcall[6] = {254,254,110,225,15,253};  // command 0F buffer

int buffget[7] ;                             // the receive buffer


// some control variables

int i;

int incoming;

int value;

int value2;

int valuekey;

int old_value = 1;

// This loop run once on start up to set up


void setup() {





pinMode (KEY,INPUT);





//digitalWrite(TUNEPOWER,LOW); // delay showing +V line on tuner for 5 sec

digitalWrite(TUNESTART, HIGH); // be sure TUNESTART pin is high


digitalWrite(TUNEPOWER,HIGH); // 998 interface start line, delay needed

digitalWrite(LEDKEY, LOW);

digitalWrite(LEDTUNE, LOW);




void loop() {

//start the split detector here




int old_value=HIGH;

int k =0;


for (i=0; i<6; i++) {

Serial.print(buffcall[i],BYTE);      //send command to ask for split, 0F





if (Serial.available() >0) {

incoming =;

if (incoming == 254) {   // 1st byte is  an FE look for an FE to start

goto start; }

goto next; }




//Serial.println(" ");



for ( i=0;i<6;i++) {               // get next 6 bytes

if(Serial.available() >0) {

buffget[i]; // load buffget with next 6 characters

delay(1);           //delay 1 ms if true, time for buffer fill


} // OK, got new 6 byte buffget array


if(buffget[1] == 225) {  //is this a return array to arduino ?

goto nexta; }            // yes, now do 0F test

goto listen;             // wrong array, get another




if (buffget[3] == 15){        // check to see if 4th char is 15

goto next1; }                 // 0F detected, goto next1

goto listen;                  // wrong array, get another




// delay(2);

//Serial.print (" split present = ");   // We have an array

// Serial.print(buffget[3]); // print the 0F , or 15 to be sure


if(buffget[5] == 253 ){       // look for FD at end of array

goto maybe; }                 // if FD detected, goto maybe

goto listen;                  // wrong command


maybe:                             // good array on hand, have a split



//Serial.print(" maybe split= "); //have an array that should have a 15

//Serial.print(buffget[4]); // print the split data



if(buffget[4]== 0) {


goto finish; }


if (buffget[4] == 1) {


goto finish;}

goto listen;        // not valid split status . . go again






//Serial.print(" finish = ");

//for( i=0;i<6; i++) { // buffer will be missing first FE

//Serial.print(buffget[i],DEC); // print out entire buffer

//Serial.print(" "); }

//Serial.println(" ");

//Serial.print(" Split is ");


// good to here



wait:                                           // now wait for tune button


value = digitalRead(TUNEBUTTON);

if ((value ==HIGH)&& (old_value==HIGH)) {   

// wait for TUNEBUTTON to push

goto push; }


old_value = value;


if(k>50) {     // if nothing happens in .25 sec, check split again

goto listen; }

goto wait ;


push:                                                   // we have a button event !

//Serial.println(" push");

// decide on what to do about split

if(split == 0) {

splitmarker = 0;              // no split, carry on

goto vfogo;}                  // split must be off

// split must be on, turn off


if(split == 1) {

splitmarker = 1;

goto prep; }

goto listen;        // eject eject ! split is all wrong




for( i=0; i<7; i++){               // swap vfo’s 1st

Serial.print(swapab[i],BYTE); }




for( i=0; i<7; i++){          // turn split off for tune routine

Serial.print(splitoff[i],BYTE); }

delay(300);         // takes a while for the radio to execute split


// beggining of the vfo routine




//Serial.println(" ");

//Serial.print(" splitmarker = "); // just checking



for( i=0; i<8; i++) {

Serial.print (dis[i],BYTE); }        // disable tuner



for(int i=0; i<10; i++) {

Serial.print (toff[i],BYTE); }       // disable auto tuner feature



for(i=0; i<7; i++) {

Serial.print (ant4[i],BYTE); }       // ant 4 select



for(i=0; i<7; i++) {

Serial.print (am[i],BYTE); }         // AM mode



for(i=0; i<9; i++) {

Serial.print (amlp[i],BYTE); }       // AM Low power




digitalWrite (TUNESTART,LOW); // start the tuner, take TUNESTART low

digitalWrite (LEDTUNE, HIGH); // Turn on LED during tune cycle

//Serial.println(" tuner started");

delay(300);                   // minimum on time




valuekey = digitalRead(KEY);

if (valuekey == HIGH) {

goto keyon;

}                                  // wait for tuner to start

//start transmission

//Serial.println("tuner says start");

digitalWrite(LEDKEY, HIGH);        //Flash the KEY LED


for(i=0; i<8; i++) {

Serial.print (tx[i],BYTE); }         // transmit on

delay(100); // minimum Tx time


digitalWrite (TUNESTART,HIGH); //stop the tune cycle,take TUNESTART high




value2 = digitalRead(KEY);         // wait for cycle to finish

if (value2 == LOW) {

goto keyoff; }

digitalWrite(LEDKEY, LOW);         //turn KEY LED off



for( i=0; i<8; i++) {

Serial.print (rx[i],BYTE); }         // transmit  OFF



for(i=0; i<7; i++) {

Serial.print (cw[i],BYTE); }         // back to CW



for(i=0; i<9; i++) {

Serial.print (lp[i],BYTE); }

delay(20);                         //lp power

//Serial.println("... cycle complete");

//check split marker

if(splitmarker == 0){

goto done; }


for(i=0;i<7;i++) {

Serial.print(spliton[i],BYTE); }     // put split back in place


// swap VFO's back

for( i=0; i<7; i++){               // swap VFO’s

Serial.print(swapab[i],BYTE); }




digitalWrite (LEDTUNE, LOW);       // Turn off TUNE LED

split = 0;


goto listen;