{"id":117,"date":"2014-08-22T11:15:47","date_gmt":"2014-08-22T17:15:47","guid":{"rendered":"http:\/\/www.kv6o.com\/wordpress\/?p=117"},"modified":"2014-08-30T12:04:47","modified_gmt":"2014-08-30T18:04:47","slug":"a-kenwood-dg-5-emulated-on-arduino","status":"publish","type":"post","link":"https:\/\/www.kv6o.com\/wordpress\/2014\/08\/22\/a-kenwood-dg-5-emulated-on-arduino\/","title":{"rendered":"A Kenwood DG-5 emulated on Arduino"},"content":{"rendered":"<p>A few months ago, I bought a Kenwood TS-520S. The Kenwood hybrid&#8217;s are beautiful radios, and the TS-520 is the first radio I was on the air with (on amateur HF bands) while I was in High School in the early 80&#8217;s. \u00a0So when I had an opportunity to pick one up locally, I jumped at it.<\/p>\n<p>I have had a great time playing around with it and ragchewing. It takes a bit more work than my K3 or TS-2000 (tuning, calibrating) but that&#8217;s the beauty &#8211; it&#8217;s like an older car with points, condensers, and a carburetor &#8211; takes some more tweaking, but you can fiddle with it easily. I replaced the HV caps, adjusted the calibrator, and cleaned the switches and pots, but that&#8217;s about it. It just works.<\/p>\n<p>I came across a site called <a href=\"http:\/\/www.toddfun.com\/\" target=\"_blank\">Toddfun.com<\/a>\u00a0while doing some TS-520 searches, and found a series of <a href=\"http:\/\/www.toddfun.com\/2013\/02\/07\/arduino-frequency-display-for-kenwood-ts-520s-hf-ham-radio-part-1\/\" target=\"_blank\">very well documented posts<\/a> (with in depth videos) about\u00a0\u00a0building a Kenwood DG-5 type display for the TS-520. \u00a0The Kenwood DG-5 was an optional digital display for the TS-520\/820, and on the used market they go for more than I paid for the radio! \u00a0He was using the Arduino platform, something I have been using for a few years here. \u00a0I thought, &#8220;I can do this!&#8221;, but instead of a display, I wanted to have it talk to my computer so my logging program (<a href=\"http:\/\/www.dxlabsuite.com\/\" target=\"_blank\">DXLab<\/a>) could read the frequency of the radio.<\/p>\n<p>There&#8217;s lots I could do better, and the Mega 328 isn&#8217;t the best platform to be doing frequency counting, updating a display, and servicing a serial port at the same time. \u00a0The frequency counter needs the limited internal timers on the 328 which limits use of I2C, SPI, and software serial libraries as far as I can see. \u00a0Nevertheless, getting the TS-520 to talk to my computer is what I set out to do, and it works beautifully!<\/p>\n<p>A quick and dirty demo of it:<\/p>\n<p><iframe loading=\"lazy\"  id=\"_ytid_86896\"  width=\"625\" height=\"352\"  data-origwidth=\"625\" data-origheight=\"352\" src=\"https:\/\/www.youtube.com\/embed\/vwjkei1kma0?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;\" class=\"__youtube_prefs__  epyt-is-override  no-lazyload\" title=\"YouTube player\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><\/p>\n<p>I don&#8217;t have a schematic for it, if you watch Todd&#8217;s video&#8217;s you can figure it out. \u00a0Basically, the signals are buffered and conditioned by the TI PLL&#8217;s, the (HFO frequency needs to be pre-scaled as it&#8217;s outside the range of the Arduino counter), and the 3 are mux&#8217;ed into the Arduino on pin 5.<\/p>\n<p>Arduino DG-5 code:<\/p>\n<pre class=\"brush: php; collapse: true; light: false; title: ; toolbar: true; notranslate\" title=\"\">\/* \r\n\r\nKenwood DG5 digital display emulator, sort of.\r\n\r\nStephen Leander, KV6O\r\nAugust 22, 2014\r\n\r\nNo display in this revision, outputs Kenwood Commander commands on the Serial\/USB port for a logging program (DXLab's Commander)\r\nNo idea if it will work with other programs because I haven't tested anything else!\r\n\r\nGot the idea from Todd Harrison's website, Toddfun.com, where he outlined and built an Adrunio DG-5 emulator, with the plans of using this to display\r\nthe frequency, just like the DG-5.\r\n\r\n<blockquote class=\"wp-embedded-content\" data-secret=\"vAkZSr9UpV\"><a href=\"http:\/\/www.toddfun.com\/2013\/02\/07\/arduino-frequency-display-for-kenwood-ts-520s-hf-ham-radio-part-1\/\">Arduino Frequency Display for Kenwood TS-520S HF ham radio PART 1<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Arduino Frequency Display for Kenwood TS-520S HF ham radio PART 1&#8221; &#8212; ToddFun.com\" src=\"http:\/\/www.toddfun.com\/2013\/02\/07\/arduino-frequency-display-for-kenwood-ts-520s-hf-ham-radio-part-1\/embed\/#?secret=vAkZSr9UpV\" data-secret=\"vAkZSr9UpV\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\r\n\r\nCounter code based on Arduino timer code by Nick Gammon\r\nhttp:\/\/www.gammon.com.au\/forum\/?id=11504\r\n\r\nEmulates a TS-790 for DX Commander, based on input from Dave, AA6YQ:\r\n\r\n From Dave AA6YQ, DXLab's author:\r\n From: dxlab@yahoogroups.com &#x5B;mailto:dxlab@yahoogroups.com] Sent: Tuesday, August 05, 2014 10:42 PM To: dxlab@yahoogroups.com Subject: &#x5B;dxlab] Kenwood\r\n\r\n &gt;&gt;&gt;If your emulator responds to the ID; command with \r\n\r\n ID007;\r\n\r\n &gt;&gt;&gt;Commander will think its controlling a TS-790. The only other commands to which your emulator will then have to respond are IF; and FB;\r\n\r\n &gt;&gt;&gt;Note: Commander pays attention to the following bytes of the radio's response to an IF; command:\r\n\r\n 3-13: VFO A frequency\r\n 29: RX vs TX status\r\n 30: Mode\r\n 31: VFO selection\r\n 33: split status\r\n\r\n &gt;&gt;&gt;Operation won't be convenient unless your emulator can correctly report the radio's mode.\r\n\r\nSee http:\/\/www.kenwood.com\/i\/products\/info\/amateur\/ts_480\/pdf\/ts_480_pc.pdf for more on Kenwood command set.\r\n\r\n8\/22\/14 - Version 1.0 Prototyped the circuit using 3 TI PLL's (74HC4046A's), a 74HC93 counter for prescaling the HFO, and 74HC153 for selecting the\r\nsignal (VFO, BFO, or HFO) to be counted by the Arduino on pin 5.\r\n\r\n*\/\r\n\r\n\/\/#define DEBUG \/\/Uncomment for debugging\r\n\r\nvolatile unsigned long timerCounts;\r\nvolatile boolean counterReady;\r\n\r\n\/\/ internal to counting routine\r\nunsigned long overflowCount;\r\nunsigned int timerTicks;\r\nunsigned int timerPeriod;\r\n\r\nunsigned long vfo = 0;\r\nunsigned long bfo = 0;\r\nunsigned long hfo = 0;\r\n\r\nvoid startCounting (unsigned int ms)\r\n {\r\n counterReady = false; \/\/ time not up yet\r\n timerPeriod = ms; \/\/ how many 1 mS counts to do\r\n timerTicks = 0; \/\/ reset interrupt counter\r\n overflowCount = 0; \/\/ no overflows yet\r\n\r\n \/\/ reset Timer 1 and Timer 2\r\n TCCR1A = 0;\r\n TCCR1B = 0;\r\n TCCR2A = 0;\r\n TCCR2B = 0;\r\n\r\n \/\/ Timer 1 - counts events on pin D5\r\n TIMSK1 = bit (TOIE1); \/\/ interrupt on Timer 1 overflow\r\n\r\n \/\/ Timer 2 - gives us our 1 mS counting interval\r\n \/\/ 16 MHz clock (62.5 nS per tick) - prescaled by 128\r\n \/\/ counter increments every 8 \u00b5S.\r\n \/\/ So we count 125 of them, giving exactly 1000 \u00b5S (1 mS)\r\n TCCR2A = bit (WGM21) ; \/\/ CTC mode\r\n OCR2A = 124; \/\/ count up to 125 (zero relative!!!!)\r\n\r\n \/\/ Timer 2 - interrupt on match (ie. every 1 mS)\r\n TIMSK2 = bit (OCIE2A); \/\/ enable Timer2 Interrupt\r\n\r\n TCNT1 = 0; \/\/ Both counters to zero\r\n TCNT2 = 0; \r\n\r\n \/\/ Reset prescalers\r\n GTCCR = bit (PSRASY); \/\/ reset prescaler now\r\n \/\/ start Timer 2\r\n TCCR2B = bit (CS20) | bit (CS22) ; \/\/ prescaler of 128\r\n \/\/ start Timer 1\r\n \/\/ External clock source on T1 pin (D5). Clock on rising edge.\r\n TCCR1B = bit (CS10) | bit (CS11) | bit (CS12);\r\n } \/\/ end of startCounting\r\n\r\nISR (TIMER1_OVF_vect)\r\n {\r\n ++overflowCount; \/\/ count number of Counter1 overflows\r\n } \/\/ end of TIMER1_OVF_vect\r\n\r\n\/\/******************************************************************\r\n\/\/ Timer2 Interrupt Service is invoked by hardware Timer 2 every 1ms = 1000 Hz\r\n\/\/ 16Mhz \/ 128 \/ 125 = 1000 Hz\r\n\r\nISR (TIMER2_COMPA_vect)\r\n {\r\n \/\/ grab counter value before it changes any more\r\n unsigned int timer1CounterValue;\r\n timer1CounterValue = TCNT1; \/\/ see datasheet, page 117 (accessing 16-bit registers)\r\n unsigned long overflowCopy = overflowCount;\r\n\r\n \/\/ see if we have reached timing period\r\n if (++timerTicks &lt; timerPeriod)\r\n return; \/\/ not yet\r\n\r\n \/\/ if just missed an overflow\r\n if ((TIFR1 &amp; bit (TOV1)) &amp;&amp; timer1CounterValue &lt; 256)\r\n overflowCopy++;\r\n\r\n \/\/ end of gate time, measurement ready\r\n\r\n TCCR1A = 0; \/\/ stop timer 1\r\n TCCR1B = 0; \r\n\r\n TCCR2A = 0; \/\/ stop timer 2\r\n TCCR2B = 0; \r\n\r\n TIMSK1 = 0; \/\/ disable Timer1 Interrupt\r\n TIMSK2 = 0; \/\/ disable Timer2 Interrupt\r\n\r\n \/\/ calculate total count\r\n timerCounts = (overflowCopy &lt;&lt; 16) + timer1CounterValue; \/\/ each overflow is 65536 more\r\n counterReady = true; \/\/ set global flag for end count period\r\n } \/\/ end of TIMER2_COMPA_vect\r\n\r\nString inputString = &quot;&quot;; \/\/ a string to hold incoming command date\r\nboolean stringComplete = false; \/\/ whether the string is complete\r\n\r\nvoid setup ()\r\n {\r\n pinMode(2, OUTPUT); \/\/ for signal select on the 74HC153. Using Pins 2 and 3.\r\n pinMode(3, OUTPUT);\r\n\r\n Serial.begin(9600);\r\n \/\/ reserve 200 bytes for the inputString:\r\n inputString.reserve(200);\r\n\r\n \/\/ end of setup\r\n\r\n }\r\n\r\nvoid loop ()\r\n {\r\n for (int x=0; x &lt; 3; x++){ \/\/ Loop thru the 3 signals to count the signals.\r\n if (x==0) { \/\/Select VFO\r\n digitalWrite(2, LOW);\r\n digitalWrite(3, HIGH);\r\n }\r\n if (x==1) { \/\/Select BFO\r\n digitalWrite(2, HIGH);\r\n digitalWrite(3, LOW);\r\n }\r\n\r\n if (x==2) { \/\/Select HFO\r\n digitalWrite(2, LOW);\r\n digitalWrite(3, LOW);\r\n } \r\n\r\ndelay (20); \/\/settle time\r\n\r\n \/\/ stop Timer 0 interrupts from throwing the count out\r\n byte oldTCCR0A = TCCR0A;\r\n byte oldTCCR0B = TCCR0B;\r\n TCCR0A = 0; \/\/ stop timer 0\r\n TCCR0B = 0; \r\n\r\n startCounting (100); \/\/ how many mS to count for\r\n\r\n while (!counterReady)\r\n { } \/\/ loop until count over\r\n\r\n \/\/ adjust counts by counting interval to give frequency in Hz\r\n float frq = (timerCounts * 1000.0) \/ timerPeriod;\r\n\r\n\/\/ Serial.print (&quot; freq: &quot;);\r\n\/\/ Serial.print ((unsigned long) frq);\r\n\r\n if (x==0)vfo=frq; \/\/ load frequency's into vfo, bfo, and hfo.\r\n if (x==1)bfo=frq;\r\n if (x==2)hfo=(frq*8);\r\n\r\n#ifdef DEBUG \/\/ for debugging and monitoring the results.\r\nSerial.print(&quot;VFO: &quot;);\r\nSerial.print (vfo);\r\nSerial.print(&quot; BFO: &quot;);\r\nSerial.print (bfo);\r\nSerial.print(&quot; HFO: &quot;);\r\nSerial.print (hfo);\r\nSerial.print (&quot; FREQ: &quot;);\r\nSerial.println (hfo-(bfo+vfo));\r\n\r\n#endif\r\n\r\n \/\/ restart timer 0\r\n TCCR0A = oldTCCR0A;\r\n TCCR0B = oldTCCR0B;\r\n\r\n }\r\n\r\n \/\/ Check serial port to see if we have a command\r\n if (stringComplete) {\r\n\r\n if (inputString == &quot;ID;&quot;) { \/\/ID the radio as a &quot;ID007&quot; - Kenwood TS790. There is no TS-520S. ;-)\r\n Serial.print(&quot;ID007;&quot;);\r\n }\r\n else if (inputString == &quot;FB;&quot;){ \/\/ Probably not needed as Commander uses the &quot;IF&quot; command, used for debugging..\r\n Serial.print(&quot;FB00014195000;&quot;);\r\n }\r\n else if (inputString == &quot;IF;&quot;){\r\n\r\n if ((hfo-(bfo+vfo)) &gt; 9000000){ \/\/ Used 9Mhz as the cutoff so I could properly format the string with the additiona digit returned above 10Mhz.\r\n Serial.print (&quot;IF000&quot;);\r\n Serial.print (hfo-(bfo+vfo));\r\n Serial.print (&quot;000000000000000020000000;&quot;); \/\/ The &quot;2&quot; is the mode, above 9Mhz it returns &quot;USB&quot;\r\n }\r\n else\r\n {\r\n Serial.print (&quot;IF0000&quot;);\r\n Serial.print (hfo-(bfo+vfo));\r\n Serial.print (&quot;000000000000000010000000;&quot;); \/\/ Mode set to 1 for &quot;LSB&quot;.\r\n }\r\n } \r\n\r\n \/\/ clear the string:\r\n inputString = &quot;&quot;;\r\n stringComplete = false;\r\n\r\n \/\/ end of loop\r\n\r\n }\r\n } \r\n\r\n \/*\r\n SerialEvent occurs whenever a new data comes in the\r\n hardware serial RX. This routine is run between each\r\n time loop() runs, so using delay inside loop can delay\r\n response. Multiple bytes of data may be available.\r\n *\/\r\n\r\nvoid serialEvent() {\r\n while (Serial.available()) {\r\n \/\/ get the new byte:\r\n char inChar = (char)Serial.read();\r\n \/\/ add it to the inputString:\r\n inputString += inChar;\r\n \/\/ if the incoming character is a newline, set a flag\r\n \/\/ so the main loop can do something about it:\r\n if (inChar == ';') { \/\/ Look for &quot;;&quot; - this is the Kenwood command terminator.\r\n stringComplete = true;\r\n }\r\n }\r\n} <\/pre>\n<p>[wpdm_file id=2 title=&#8221;true desc=&#8221;true&#8221;]<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A few months ago, I bought a Kenwood TS-520S. The Kenwood hybrid&#8217;s are beautiful radios, and the TS-520 is the first radio I was on the air with (on amateur HF bands) while I was in High School in the early 80&#8217;s. \u00a0So when I had an opportunity to pick one up locally, I jumped [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-117","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p2NQIK-1T","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/posts\/117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/comments?post=117"}],"version-history":[{"count":14,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/posts\/117\/revisions"}],"predecessor-version":[{"id":135,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/posts\/117\/revisions\/135"}],"wp:attachment":[{"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/media?parent=117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/categories?post=117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kv6o.com\/wordpress\/wp-json\/wp\/v2\/tags?post=117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}