Design Intent

Listening for very weak signals refected back from the moon requires some very sensitive radio equipment, with a very good low-noise front-end. This is usually acomplished by using a tuned low-noise rf preamplifier (LNA) ahead of the radio itself.
So far, so good. But what about bypassing the LNA when the radio is transmitting? It turns out that most radios do have an externally accessible TX signalling line to allow external equipment to be switched on or off for transmit. What they don't have is any guard time. So as the TX signal line is asserted, rf is already making its way out of the radio to the output of our fancy preamplifier.

A sure way to pop the sensitive GaAsFET in the LNA!

Hence this project. A simple bit of hardware to sequentially enable/disable other bits of hardware in such a way that no damage can be inflicted by the inadvertant random button pressing of a distracted user - me, that is!


Hardware Design

A quick google search will show you that designs for such a sequencer are legion, from the sublimely simple to the unbelievably complex.
My version sits somewhere in between. I used a microcontroller to allow for some more precise timings between states (as compared to an R-C timing circuit), but moreover to allow individual states to be bypassed without changing the sequencing timings. This makes the sequencer more flexible in use. Shown right is the basic interconnection between sequencer, radio and accessories.
The ATMEGA16 microcontroller was chosen for this project. A simple low pin count micro with more than enough performance to do the job, and resorce to spare for any future additions.
The sequencer hardware is kept quite simple. A "transmit request" signal input (or Press To Talk, PTT) from the radio is used to trigger the sequencer Finite State Machine. The TS2000 radio has an external Automatic Level Control (ALC) line input, which is used here as a transmit inhibit line by the sequencer.
In operation this works really well, except for the (rather long) release time constant of the ALC in the radio - it takes around 1.5 seconds from the time that TX Inhibit is released to full output power of the radio.

Microcontoller and logic schematic
Power supply and relay schematic
The simplistic front panel UI

Software Design

The software is simplicity itself. It is basiclly a simple state machine, with defined and timed moves between states.
The state diagram is shown left.
Two state variables are maintained, which hold the key to moving between states:

enum {rx_state,pa_state, ptt_state} Current_State, Next_State;

Once these states are defined, all that is then needed is a big switch statement, and some extra logic to decode optional settings. A simple millisecond timer is used as the master clock to derive all other timings for state transitions, key debounce reads etc.

The most interesting aspect of the software design turned out to be the switch debouncing. I spent quite a lot of time on this, as I wanted to come up with something which is simple, would work well and be useful in other projects.

I ended up using a variation of a "vertical stack counter" for my switch debounce. It effectively uses 2 bytes to debounce upto 8 inputs, by adding them "vertically". So 2 8-bit bytes become 8 2-bit variables.

Some of the nifty features of this approach are:

  • Debounce up to 8 keys simultaenously.
  • Very small code footprint.
  • No timers are tied up for debouncing.
  • Debounced state is static.
  • Debounced keys may be read individually or in a group.
  • Sustained "key down" events may be read without affecting the debounced state.

The idea is to call DebounceInputs() every so often, which builds up a byte of DebouncedKeys. The debounced keys may be read at any time by calling GetInputs(key_mask), where key_mask is the key that you wish to read.

					
//------------------------------------------------------
//	Debounce inputs
//------------------------------------------------------
void DebounceInputs(void){
    static uint8_t Count0 = 0xFF, Count1 = 0xFF;	// 8 * 2bit counters
    uint8_t i;

    i = ~PINA^DebouncedKeyState;			// read keys (low active)
    Count0 = ~( Count0 & i );			        // reset or count Count0
    Count1 = Count0 ^ (Count1 & i);			// reset or count Countt1
    i &= Count0 & Count1;				// count until roll over?
    DebouncedKeyState ^= i;				// then toggle debounced state
    DebouncedKeys |= DebouncedKeyState & i;		// 0->1: key press detect
}


//------------------------------------------------------
//	Read Key inputs
//------------------------------------------------------
unsigned char GetInputs(unsigned char key_mask){
ATOMIC_BLOCK(ATOMIC_FORCEON){				// read and clear atomic !
    key_mask &= DebouncedKeys;				// read key(s)
    DebouncedKeys ^= key_mask;				// clear key(s)
}
return key_mask;
}

A Sustained keypress may be read simply by looking at its current state and comparing it with its state in DebouncedKeys, to ensure it has stopped bouncing:


//------------------------------------------------------
//	Read PTT input
//------------------------------------------------------
void GetPTT(void){	
    if((portNr(PTTin) & DebouncedKeys) && (!portbitInputStatus(PTTin))){
        flag.PTT_asserted = 1;
    }
    if((portNr(PTTin) & DebouncedKeys) && (portbitInputStatus(PTTin))){
        flag.PTT_asserted = 0;
    }
}

Another fun project which has now been working well for years, without missing a beat and (most importantly) without destroying any more low noise preamplifier FETs!