AD9850 VFO II

It has been some time since I have posted the article on building a simple VFO/signal generator using the AD9850 module and a microcontroller, originally based on the work Richard, AD7C. I have received quite a bit of feedback from several people, along with a few requests for improvements to make the hardware more suitable for HAM radio use (my original goal was a signal generator!). So here it is, the AD9850 VFO Mk II.

The version of the VFO described in this post is based on the original design from my previous post, so you may want to read that first, especially some of the design rationale and gotchas commonly encountered with the cheap AD9850/9851 DDS modules available from eBay and elsewhere.

The main features of this version of the hardware:

RIT/XIT offsets – allow to fine tune/offset the frequency from the one displayed by ±25kHz, in selectable steps

TX signal input, so the micro actually knows when to apply the XIT offset

Revised display layout, TX indication

Revised controls – additional button for RIT/XIT, modified functions of the other buttons and the encoder.

Output limited to 1MHz-30MHz to stay within the specs of the DDS

The person most responsible for pushing me towards making this radio-oriented version of the code is Rich Carstensen, W8VK. He is building some really nice QRP rigs with it and using it as a replacement for the classic mechanical dials.

Rich’s W8VK 40m QRP gear, posted with permission.

Hardware revisions

The current version of the generator/VFO has some minor differences compared to the previous one. Namely there is an extra button added for handling the RIT/XIT offsets and there is a new /RIG-TX input signal added for RX/TX switching. The signal is active low (TX), with an internal pull-up, TTL level (either 3.3 or 5V levels, depending on Vcc). As before, the schematics shows the corresponding Arduino pin names for those using an actual Arduino board to build this.

Modified schematics

The actual hardware

The photo of the hardware shows 4 buttons – the left-most one is Reset, then RIT/XIT (C button), IF (B button) and Cursor mode/Zero (A button). The encoder is of a pushable type with a built-in switch. There is another button barely visible just above the RIT/XIT button – that one I am using to simulate the PTT switch for testing, the schematics shows a connector there instead where the RX/TX switching signal needs to be brought in.

Software

There are several modes which are changed using the buttons and the encoder:

The VFO mode – the display shows the frequency, turning the knob tunes using the pre-selected tuning step. Pressing the encoder allows to change the the step.

“Cursor” mode – Holding down the A button (closest to the encoder) and turning the knob moves a cursor over the displayed frequency, releasing the button and turning the encoder changes the selected decade directly. Pressing the encoder knob returns back to the normal VFO tuning.

IF mode – pressing the B button toggles IF offset on and off. This is indicated on the display by text “±IF”. Pressing both A and B together allows to program in the desired IF offset using the encoder, using the same procedure as the “cursor mode” for the main VFO frequency. Pressing the buttons together again toggles the additive or subtractive IF, pressing the encoder button will return back to the VFO mode.

RIT mode – the C button activates the RIT mode when the /RIG-TX signal is inactive (high). Turning the encoder permits to select the desired offset, up to ±25kHz. Pressing the encoder changes the RIT tuning step, pressing the A button resets the offset to zero.

XIT mode – the C button activates the XIT mode when the /RIG-TX signal is active (key the rig and press the C for a short moment). Turning the encoder permits to select the desired offset, up to ±25kHz. Pressing the encoder changes the tuning step, pressing the A button resets the offset to zero again. If a non-zero XIT offset is selected it will be displayed whenever the rig is keyed to help avoid transmitting on an incorrect frequency.

The settings – frequencies, offsets, IF state – are all saved in the EEPROM if no change was done for 10 seconds, so next time you will be back on the same frequency with the same settings as when you have turned the rig off.

Downloads

You will need the following dependencies (the same as in the original article):

The VFO code itself
(Update 24.5.2017 v. 2.1 – fixed a bug for when the IF > received frequency. Now it will work correctly even for the Bitx 40 that uses 12MHz IF)

Arduino IDE needs to be configured for the LilyPad Arduino because the circuit uses 8MHz clock unlike the original Arduino Uno and similar that use 16MHz clock.

Important note

On the first power up the EEPROMis not programmed so the display may show gibberish and the DDS will output invalid signals. It is best to start without the module connected. Then set the VFO and IF frequencies, check the RIT/XIT and reset them, if required. If the display is showing gibberish, simply keep turning the encoder knob until it hits the frequency limit (either 1MHz or 30MHz) and which point the display will reset. From that point on everything will work as expected.

An alternative solution to the above procedure is to pre-program the EEPROM as follows:

bytes 0-3 – the main VFO frequency (32 bit signed integer), stored from the least significant byte to the most significant byte.

bytes 4-7 – IF frequency, stored as signed 32 bit integer, stored from least to most significant byte.

58 thoughts on “AD9850 VFO II”

Hi Jan,
I done this program in my arduino pro mini and it is working well .So thanks my friend. But I am facing two problems. I am using BITX 40 transceiver board and here the IF is 12MHz .Inside the DDS vfo, When I set the offset IF as 7MHz-2MHz(F-IF)
I got 5MHz at DDS out and the display of DDS shows 7.000.000Hz.But when it tune to reverse direction only I got the 40m stations . So I try to set the IF in (F-IF) as 12MHz then suddenly the display frequency(value for F) changed to 13.000.000Hz and it cannot tune into anti clockwise. I also try to change the F-IF as IF-F in program but the problem is not rectified.
Also I cannot set the RIT/XIT mode.Which pin I have to use for this.I am using Arduino Pro mini board.
Please help me as early as possible.
Thanks.

I am not very familiar with the BITX TRX, so I am not quite sure what your problem is. What you are describing (display showing 7MHz and 5MHz output) is normal behaviour for 2MHz IF – and your BITX is obviously receiving the 40m (7MHz) stations.

If you keep F as 7MHz and set IF to 12MHz with the F-IF setting, that will cause a numeric overflow (there is no way to get -5MHz that you have asked it to output!). It then gets clamped to the minimum possible output frequency to keep the DDS within sane limits, which is 1MHz. And to get that the F has to be 13MHz – which is what you are seeing.

You need to set the IF correctly, then the problem will go away – if you want to subtract IF from the display frequency, it must be smaller than the display frequency. If you want to have 12MHz IF and work on 40 meters, you will need to use the F+IF mode (upconverting).

The RIT/XIT mode uses the C button (A3 pin), together with the transmitter key/PTT signal (A2 pin). Pressing C in RX mode lets you set RIT, pressing C while the TX is keyed will let you set XIT. It is described in the text on the website, along with the modified schematics.

Dear friend,
Thanks for the response and the valuable suggestions. Every thing ok but one problem is going on . I done F+IF(Up converting) method. Now I can tune the7MHz station in forward direction but cannot decode the SSB stations clearly. Jan what I to do for that my friend?
Thanking You
De Vu2lpj

You are likely having issue with sideband inversion. If you are using F+IF on the VFO and thus have IF at 12MHz, then when receiving 40m signals the sidebands will be inverted and SSB will sound like gibberish:

“Sideband reversal occurs in mixing only if the signal with the modulation is subtracted from the signal that isn’t modulated.”

Keep in mind that what is on the display (F+IF or F-IF) *has nothing* to do with with the way you are doing the mixing – whether you are taking a sum or the difference of the VFO and the signal from the antenna.

The F+IF/F-IF only indicates which way is the VFO frequency offset from the number shown on the display (whether the IF frequency is added or subtracted to get the actual VFO output frequency).

So in order to solve your issue, either put the VFO *below* the 7MHz (e.g. 2MHz or so for 5MHz IF), or you need to take the sum of the two frequencies instead – i.e. using 19MHz IF. Then the sidebands won’t get inverted.

I am stumped. The VFO is working and I can see the correct output from 1 mhz to 30 mhz. The signal on the AD9850 is very clean. The encoder is working fine, but I can not get anything but jibberish on the 16×2 lcd screen. When I power back up it comes to last frequency as well. Any ideas?
I get the correct frequency on the Serial Monitor as well.

That sounds like you have connected the LCD module incorrectly. Make sure that you didn’t swap the RS and E pins on the LCD, R/W must be grounded. A common mistake is to connect the data pins D0-D3 instead of D4-D7 too.

Now building a stand alone VFO using an ARDUINO nano and a modified AD9850 (as per the Yahoo Group PHSNA). Removing the low pass filter from the board (it’s defective) and putting LP filter external improves output range and increases power output.

I don’t actually think the filter is defective, but some of the modules have a very steep one that rolls off early, limiting the useful range of the VFO.

BTW, if you want to use an external filter, there is no need to remove the one on the board – the DDS has two outputs and only one is filtered on most modules, the other one is bare, directly from the chip. So you can use that one. There are also two square wave outputs.

The group PHSNA was adapting the VFO for an existing project. You are right, I forgot the other output. It would have saved me grief.
My AD9850 puts out the following:
1 MHz. -6.7 dBu
15 MHz. -8.7 dBu
30 MHz. -24.41 dBu
Removing the LP filter and one extra resister brings up the output and makes it even from 1-30 MHz

Hello Jan!
Thank you for the gift you make of radio amateurs. Everything works perfectly. Some time ago I came across a construction https://amoghdesai.com/technology/electronics/dds-vfo-using-ad9850-atmega328p/. First test it on Arduino Uno R3, then made an “ugly” board. When I met your design found that more things coincide /normal – everything comes from AD7C/ . I just removed the two resistors added 4 buttons and your SOFTWARE and all work correctly. Now I have a new VFO with many more options.
Once again – thank you very much!
Greetings! LZ1OR – George
PS The translation is made from Bulgarian to English by go?gle translator!

Yes, I took the original circuit and code from Rich AD7C, however I found his code was difficult to use, so I rewrote the majority of it to make it a bit better usable.
On the other hand, this is still nothing really fancy – there is a much better VFO code that is explicitly targeting radio use (my goal was to build an RF generator, not VFO) done by M0XPD (http://m0xpd.blogspot.fr/p/kanga-uk-resources.html#VFO2) which uses a larger display and a slightly different wiring.

Hi Jan,
Just finished building the VFO and it worked first try. I am a cw op and I am using the VFO in a transmitter I built. I want to use my Icom receiver that has been gathering dust. The problem I have is that the vfo can be heard all the time in the reciever so I decided to use RIT mode. While in recieve, the vfo is off set by 3khz and I nolonger hear the vfo on the operating frequency which is what I want. When I key rig-tx with my K3NG arduino cw keyer at 5wpm it works fine but when I go up to my normal speed of 25 wpm, the vfo is not switching fast enough. I am using full break-in. You can hear between the dits and dahs. Is there a way to speed up the switching while keying the rig-tx pin? The 25 wpm dits are not switching the vfo into tx . I hope there is a quick fix, Thanks.. Robert KH2BR

Uff, I am afraid you are using the thing for something a bit beyond what it has been designed for 🙂 The TX/RX offset switching is debounced because it is meant to be used with a mechanical button/relay contact. So there is an unavoidable delay which is likely what causes your problem at higher speeds. The default debouncing time is 10ms.

You could try to change that by adding the following after the line btnTX.attach… in the setup() function in the “configure debouncers” block:

btnTX.interval(1);

That will set the debouncing time to 1ms. I haven’t tested this as I don’t really have the means to do so (I am not a CW op). However, this isn’t going to be magic – the circuit needs a bit of time to retune anyway, so if you need a really quick transitions, this isn’t really the best solution, IMO.

If you need full break-in, I would say you should keep the VFO running constantly and add some transistors or a multiplexer to switch the outputs off when in RX instead. That would be orders of magnitude faster than anything the firmware in the Arduino can do. Also shielding the VFO, using a coax to connect it to the rig and putting chokes in the power lines would help from stray RF getting into your receiver.

Hi JAN! I am love CW QRP.So may you explain to me, is it possible to get Tx frequency without mixing with BFO. And during RX as usial F+or F_minus Beat frequency. If this is possible, it will simplify TX chain.
No TX mixer – only may be filter and PA. Big majority of ham synt VFO dont give such ability.
May be you will be first who do a nice present to CW QRP fraturnity.
Serge RW3DF

There is nothing in the code or the build that would prevent you using the VFO as-is for CW, sans mixing. Don’t set the IF offset and off you go.

This VFO is not meant to be used as BFO, the F+IF or F-IF are meant for IF mixing in superhets. If you want the VFO frequency to be offset on receive only in a direction conversion setup (you mix the incoming signal with the VFO down to audio range), you can use use the RIT/XIT function to give you an offset of 600Hz (or whatever tone you prefer) on receive.

Jan! Good afternoon! Yes I understand very well how to use such VFO in usial superheterodine technics. But I try to simplify CW QRP TRCVs. If in TX mode VFO produce signal on our working frequency ( on RX frequency) without additional mixing ( like it made in VHF trcvs) we simlify TX chain in cw trcv. For example, RX mode – Fvfo= F+ Fbfo or minus Fbfo.
TX mode Fvfo=F. In all modes F is Frx. Numeric explain is much easyer for understanding – BAND 14mHz, IF 9 mHz . RX mode – Fvfo is 14-9=5 mHz.
TX mode F vfo =14 Mhz.
All others (RIT,XIT, A/B) we yet have in your nice soft.
Serge RW3DF

Yes, I understand what you want to do. I just don’t see what is the problem with the VFO or what are you actually asking.

There is nothing inherent about it that would force you to use a mixer. Just filter it, amplify it and off you go if that is your preference. If you don’t set any offsets (IF or RIT/XIT), the frequency you see on the display is the frequency that is at the output.

My comment about the BFO was because I have assumed you want to simplify the design as much as you can and go with a direct conversion receiver. Then the RIT offset will provide you a way to get around the need of a separate BFO, but it is not the only way to solve that problem.

If you want to have no IF on transmit but have IF on receive only (that’s what I assume from your 14MHz-9MHz = 5MHz equation), then no, that isn’t possible without modifying the code.

You can do it by modifying the sendFrequency() function, just change the condition:

Jan! Thank you very, very much! I have built former winter synts LU5xxx, OK1DX, UR3ILF – but no one allow to work in such mode during CW. My present project – synt constructed by UT5QBC with STM+5351+TFT disp. After it I will return to arduino – my eyesight become poorer each year – I am over 70 now. You explanations of the code I hope allow to make useful project of simple CW QRP trcv.
SERGE RW3DF

You are welcome. Feel free to come back to me should you have any issues with it.

What you want to do is not a very common configuration (usually the IF offset is always on), so most other VFO systems don’t really take it into account. It would be fairly easy to modify the code for the others to do this too, though – the DDS doesn’t really care what numbers you send in if they are within the valid ranges.

Hmm, I quite like the UT5QBC design, I may use it in my current project too – a Bitx/Minima inspired receiver for 40m. I was going to use Si5351 anyway, so I can as well save time and use this instead.

Hi Jan!
I am glad that my info is useful to you also.
My browser -Google chrom alow to read even japaneese sites – but I ask Google to translate it into English. The quality of such translahion is much better then translation into Russian. But slavic languages Google Chrom translate into Russian without mistakes – I could recommend it to you.
Another project with 5351 is discribed in the blog of UR5FFR. But he is using arduino. Type of display also could be TFT.
Best wishes SERGE RW3DF

Oh no worries, my Russian is rusty, I didn’t speak it for 20 years, but I can still read it (surprisingly) fine “natively” without going through Google Translate 🙂 We used to have Russian mandatory in school as everywhere in the Eastern Bloc, so I had 6 years of it.

Conversation would be another matter, though – I can still understand most of it (I am Slovak by origin, so slavic languages are close for me), but finding the right words to respond would require some work after so many years not speaking it.

Unfortunately UT5QBC doesn’t publish the source code for his device, only a compiled binary. That’s no good for me, because I wouldn’t be able to adapt it to my needs (different wiring, USB, etc) 🙁

I have found the UR5FFR one too, but that one uses a normal 1602 LCD module from what I can see. That is not really much different from what I have already – I have basic Si5351 control code running already, so adapting the VFO code to drive this instead of the DDS would be simple.

Hi Jan , made the dds, great stuff , almosr worked first time , i had to change the r in rotary . How do you change the upper feq limits_ At present i have a 10.695 if which is additicve meaning it shutts down at 19 meg…if i want to go over 30 meg , with either this or the 9851 ( master clock freq aside) How do i do it? set clamp from 30e6 to 40e6?https://www.dropbox.com/s/pxo33rrsxxmkj9o/2017-02-05%2013.36.56.jpg?dl=0

You can change the limits in the function clampFreq(). Replace 30e6 with 40e6, yes.

However, do keep in mind that above that 30MHz the output of the DDS starts to be very nasty, lots of noise, harmonics and distortion. That is why I have put the upper limit at 30. You may need to change the output filter and perhaps even amplify/buffer the output, because the signal level drops with frequency. If you decide to move the limits, I strongly suggest checking the output with a scope for both distortion and stability, especially if you are planning to use it in a transmitter.

Hi Jan!
I have an optical encoder that gives 400 pulses per cycle. I connected it to the VFO, but the setting is very steep. I would like to ask whether software is able to reduce the number of input pulses thing as a preliminary divider.
I tried to 74HC74 with 74HC393, but nothing happened. Apparently things are not as simple as I want (HI).
Greetings!
George

I am afraid that is not so simple. The firmware is designed to work with a cheap mechanical quadrature encoder where the signals from the two phases are shifted by 90 degrees relative to each other. The pulses from the two lines generate something called a Gray code – a very specific pattern that the library uses to decode in which direction and by how many steps did the encoder move.

You cannot simply divide those pulses, it would break this relationship and the Rotary library used to decode it will get confused.

If you want to use your optical encoder, as a quick an dirty hack you could try to modify the ISR(PCINT2_vect) interrupt handler function. You could make it ignore every other step of the encoder, effectively dividing the resolution by half (e.g. by adding a counter variable and process the pulse only when it reaches a certain value, otherwise you only increment the counter).

Alternatively you could change the tuning step in the same function, but the navigation between the decades and changing of the tuning steps would still be too fast.

Thank you for your wonderful work! I just built a DDS VFO with an Arduino Nano board. Everything seems to work fine except when I have IF activated, the output frequency does not return to the TX frequency when transmitting even though “TX” is displayed. Any idea where I went wrong?

FYI, for a buffer amplifier I used a LT1227 chip, running on 12 VDC single supply, and get almost 10 V P-P output with very flat response from 1 – 30 MHz even into fairly low impedance loads!

I have encountered another problem. I operate QSK and unfortunately the VFO is not switching between RX and TX modes fast enough. I changed btnTX.interval value to zero and that helps but there is still something not right. I need output on the TX frequency as soon as possible after A2 goes low and return to RX output quickly as well when A2 goes high. Hopefully it is not a limitation of the A9850 module.

Uff, you are pushing the device a bit beyond what it has been designed for. Robert KH2BR asked a similar thing (see his comment above). If you have reduced the debounce interval already (btw, I suggest something like 1ms, not 0 – that could potentially trigger some bug in the debouncing library) and it is still not enough, then there isn’t much you can do. The DDS doesn’t switch frequencies instantly, it takes a bit of time to retune and stabilize.

If you really must have the output instantly, then you need another solution. Have two separate VFOs/oscillators and switch between them using e.g. PIN diodes or transistors. Si5351 based solution could better for that because there you have 3 separate frequency outputs on the same chip.

I’m stumbling on the IF math. I’m on a Bitx40 so on 40 meters. The IF is supposed to range from 4.80 to 5.0 mhz. I set the VFO to -2.000.000 offset and I get 40 meters and normal reception for SSB but the band is inverted. CW and digital is near 6.9 and SSB is lower near 6.75 mhz. I don’t understand this frequency inversion.

Jan,
Delving further into this I see that inversion of tuning is normal with a negative offset for the VFO- when below the BFO frequency. I think this requires a slight software tweak Something like “IF offset is minus THEN invert direction of frequency count up/down.” This trouble is happening to other versions of VFOs when applied to the Bitx40. Jan can you effect this change or suggest a code change I could do myself?

OK, just to make sure – configure the IF frequency to 5MHz (not offset, that’s the actual IF frequency you are entering!), mode F-IF indicated. That will make the VFO tune between 2-2.2MHz for 7-7.2MHz indicated on the display. That will give you the correct, non-inverted band and audio at 5.0MHz IF. Conversely, the F+IF mode would generate 9-9.2MHz and give you sideband inversion for 7-7.2MHz indicated.

If you are using a different IF frequency (I am not sure how to understand your “IF range” – IF normally doesn’t move, that’s the entire point) then modify the above accordingly. If your low pass filter is e.g. for 2MHz, you need 2MHz IF as well to have the mixing product in its passband. Doesn’t Bitx 40 use 12MHz IF? Something seems very wrong with that you are describing.

Jan, I said it slightly wrong. The IF is 12mhz the desired frequency is 7 mhz and the VFO is at 4.8 to 5.0mhz. With a negative 2 mhz offset 7 is 7mhz but as you tune up via the display the frequency actually goes down. This is consistent with problems others have had with the same radio and different VFOs. If you google Bitx40 VFO you’ll find others with different VFO devices and the same problem. There are some academic discussions about this if you dig further with Google.

If you have IF 12MHz, then 12-7 = 5 and 12-7.2=4.8, so there is your “reverse tuning”.

The problem comes from the fact that the code subtracts F – IF instead of IF – F. That works fine when the IF frequency is below the received frequency (e.g. for that 5MHz IF) but not when it is above as in the Bitx.

So if you wanted to make it work, you would have to set IF to 12MHz and use the F+IF setting to get 19MHz output – but that would reverse the sidebands for SSB.

EDIT: [removed obsolete hack to not confuse future readers]

I have uploaded a fixed version 2.1 that should handle the upconversion case when the IF is above the frequency being received correctly.

Jan,
Everything is working fine. I have noticed that when the eeprom updates I hear a small chirp from my speaker. I don’t know if this is intentional of if writing to the eeprom is taxing the Arduino to the extent that it interrupts control of the AD9850 for a moment?

That sounds unlikely – the EEPROM is written after several seconds when you don’t move the encoder knob anymore and only once. That is done to avoid stressing the EEPROM too much, because it has limited lifetime and would wear out too quickly otherwise. It certainly shouldn’t have any effect on the AD9850. That is a “fire & forget” chip where the frequency is set and then you can even completely disconnect the microcontroller and it will keep generating the frequency programmed in its registers until you turn it off. So even if the micro is doing something else than sending data to it (handling the LCD, writing EEPROM, whatever), it cannot matter. How did you come to the conclusion it is happening when the EEPROM is being updated?

I would rather think that if you are hearing a “chirp” whenever you change frequency or settings, it is your receiver picking up some noise from the digital circuitry. Is the problem happening even if you power the VFO from a separate power supply than the rest of the radio? If yes, you may be picking some radiated noise and then some shielding of your RF stuff may be in order. If not, then it is likely some conducted switching noise on the power rails – make sure you have decoupling capacitors in place, good grounding, etc.

Another possibility is that the AD9850 module generates some kind of glitch when changing frequency but I haven’t encountered that myself. According to the datasheet it shouldn’t.

You are the first to report something like that. The EEPROM is inside of the MCU, so if you are able to “hear it” and don’t hear other things that actually “go out” over the external connections, such as the constant display refresh or the I2C traffic, something odd is happening with your radio.

If you want to be sure that you are hearing the EEPROM write, you can comment out the call to the storeFreq() function at the end of the loop() function. That will disable it.

It certainly isn’t the EEPROM write affecting the tuning – the frequency is being programmed into the DDS while you are moving the encoder. When nothing is happening for the 10s needed to trigger the EEPROM write there has been no DDS activity since “ages” (in computer terms) ago already.

What you could be hearing is that your receiver is picking up the MCU activity noise, with the EEPROM write sounding like that “chirp” or beep. Aka normal RFI/EMI problem.

Better decoupling/filtering will clean that up. Or better layout – no idea how is your receiver constructed, but keeping the digital stuff as far away from the sensitive input circuits as possible is a good idea. Shielding could help also – if nothing else then a grounded metal plate (or a piece of PCB material) between the analog & digital part could work.

I see you have the schematics drawn in KiCad. Would it be possible for you to publish the schematics file, library and footprint on your website? I’m currently learning to work with KiCad and would like to study and modify a working project.

That wouldn’t be of much use to you because for the published version I have only the schematics file – it never went on a real PCB. So there are some things there I would need to clean up if I had to build a full project, including a board. I have another project in progress where I will publish the entire Kicad setup too, but that is not yet ready for release.

Hi Jan,
I just wanted to give you an update regarding the frequency switching speeds of the A9850. I have been using the code written my AD7C for a while in the same VFO and it does not have the same long delays switching between RX/TX/RX. In fact, the transition time is virtually instantaneous so I don’t think it is an issue inherent to the A9850 but rather the code itself. I think your program features (easy LO offset adjustment, etc.) are the best so I will continue to use it for applications where fast frequency switching is not necessary.

I have rechecked Richard’s original code and the frequency change code is the same (in fact, that was likely the only part that I kept from his code).

The only difference is that my code has the PTT signal debounced, Rich’s doesn’t. If you are sure that the signal is clean (i.e. not coming directly from a physical button), you can try to remove the debouncing and just read the pin state directly instead.

That will save you some milliseconds – at the expense of glitches if the signal isn’t clean.

Hi Jan,
Sorry for the delay, but I’m just getting back to this topic. I will try your suggestions and let you know how it works. If it saves a few ms, then that will probably fix it! Thanks so much for your time. I can’t wait to try it!
73,
Bob N1KW