Tuesday, July 11, 2017

SR-16 Arduino Sketch "Module" - Simple Interrupt Service Routine to Generate CW Side Tone.

I'm going to start this post with a proclamation: I am not a programmer.  Truth be told, I'm not all that wild about computers, but, like any other tool, they've got their purpose, so I try to get along with them when it suits me.

I've got some friends for whom the computer is the means and the end - it's the computer itself that provides the entertainment.  Me, not so much, but, being a guy who spends his free time building ham radios in his basement, I don't think it's my place to judge.  Different strokes.

That being said, computers are usually good at doing things that are mind numbingly routine and stupidly boring, and they do them at lightning speed and with consistent results - something I couldn't do if I wanted to. But, enough about my personality quirks, let's get on to the good stuff.

The Arduino has the tone command that Farhan and others (including me) use to generate the CW sidetone that is (after filtering - it's a square wave) sent to the audio chain for monitoring and the balanced modulator for transmission. 
So, in the code, you're monitoring the input connected to your key and, when it's closed, sending a tone to the appropriate output.  Once you've defined the input and output pins, the code to do this is alarmingly simple:

int buttonState = digitalRead(KEY_IN);  // read "KEY_IN", save value in "buttonState"
  if (buttonState==LOW)                         // is the key closed?
    {
      tone(TONE_OUT,750);    }                // if yes, send 750 HZ tone on "TONE_OUT"
    else                                                     // Otherwise
    {
      noTone(TONE_OUT);                      // send no tone on "Tone_OUT"
    }

Looking at the Raduino sketch, I see where Farhan's got similar code already written to accomplish this, but it looks like he never calls it - actually, he's commented out the lines in the loop() that would call this function - and I think I know why:  The transmitted CW would sound like my fist after a few too many visits to the Guinness low-gravity draught head. 

The loop() function executes it's instructions sequentially, over and over until the cows come home.  So, before it gets to the instruction telling it to check and see if the key's closed, it's gotta finish all the prior instructions.  If you have a very short loop(), this is probably OK - the Arduino is pretty speedy.  On the other hand, if you're doing a lot of things in the loop(), it can be a problem.

A better way to do it would be to use a pin change interrupt. Then, the moment that the key input goes from high to low, the Arduino will stop whatever it was doing (loop())  and execute the commands in the interrupt service routine (ISR).

I've been in the habit of avoiding using interrupts because, truth be told, I didn't know how.  Then, I found this website (https://thewanderingengineer.com/2014/08/11/arduino-pin-change-interrupts/). Print it, study it, learn it, it'll change your life; it's certainly changed mine!

Basically, I just followed the three steps outlined in that blog:

Step 1 - Turn on pin change interrupts:

OK, I'm using input D11.  The Arduino data sheet shows that  will be one of    the inputs on "Port B", so I'll turn that on:
PCICR |= 0b00000001;

Step 2 - Choose which pins to interrupt:

Again referring to the data sheet, D11 is Pin 3 on Port B, so I'll create a "mask" so that we only look at that pin:
PCMSK0 |=0b00001000;

Step 3 - Write the ISR:


/***************************************/
/* Interrupt service routine to       */
/* generate CW tone on keydown  */
/* Version 1                                  */
/**************************************/

ISR(PCINT0_vect) {
//Generate CW:
     int buttonState = digitalRead(KEY_IN);
  if (buttonState==LOW)
    {
      tone(TONE_OUT,750);    }
    else
    {
      noTone(TONE_OUT);
    }
}


And, by golly, that's it!  Loaded it into my rig and it works like nobody's business.

Now, if you cut and paste this into your sketch, I guarantee it's not going to work because I've deliberately left out a few things.  I'm silly that way. But, my intent isn't to write a how-to, but to encourage anyone who, like me, was intimidated by the concept of using interrupts to just go out there and grab 'em by the cajones.  Like most things technical, it's not hard to understand once you find an explanation that "clicks" with you.

73 - Steve N8NM

2 comments:

  1. Steve, thanks for posting this useful information. I'm not a programmer either, but wanting to use Arduinos, LCDs, and Si5351 in radio projects makes it a requirement to at least be able to understand the code. With information like this, maybe I'll be compelled to write my own software instead of just modifying others.

    Thanks again.....btw, I like the rest of your blog as well, good information..

    73

    Dean AC9JQ

    ReplyDelete
  2. Thanks, Dean! I'm still very much learning this stuff myself, one day I might actually get good at it :-)

    ReplyDelete