最終更新時間:2012年12月03日 16時44分44秒
[公開:any]
[電子工作/アマチュア無線]
[電子工作/AVR]
[AVR,FT-817ND,ATtiny861A,PWM,HT7733]
CWに必要なエレキーを探し出してきました。ハイモンドのマニピュレータ(パドル)とカツミ電機のエレキーです。その昔、CQ誌の「買います・売ります」コーナーで数千円で入手した中古です。当時は、これでコンテストをがんばっていました。
ネットで調べてみるとハイモンドは、まだ営業していました。同じ形状のパドルを販売しています。カバーやプラスティックパドルなどの予備品も取り扱いがあるので、まだまだ使えそうです。しかし、残念ながら、カツミ電機は終業したようです。エレキー本体も電源をつないでも動作しません。30年近く前の製品なので修理するのもあきらめました。
FT-817NDには、エレキーが内蔵されています。パドルをつないで使ってみたのですが、速度の可変がいちいちファンクションキーを長押ししてメニューを呼び出して・・・・と面倒です。速度の可変は、運用中に交信相手にあわせて変更するので専用のエレキーが必要だと感じました。
昔なら大変だったでしょうが、現在はワンチップマイコンで簡単にエレキーが作れます。早速、AVRを使ってテストしてみました。スクイーズ動作や短点、長音メモリーも簡単にプログラミングで実装できます。ブレッドボードとATtiny861Aのみで基本的なエレキーが完成です。あとは、これに実際にキーイングするトランジスタがあればOKです。現在の無線機のキー入力は数mAしか流れないのでAVRのみでもキーイング動作するでしょう。
速度可変機能などを追加しながらサイドトーンのスピーカーを選びました。単純なブザー(電圧をかけると音が出る)が一番手軽ですが、手持ちの5V用ブザーでは、電池駆動では音量が小さいことと音程が変えられないのが問題です。かといって普通のマグネティックスピーカではサイズが大きいので、小型の圧電スピーカーを使うことにしました。AVRから高速PWMで圧電スピーカーを鳴らします。音程は好みで決められますが、CWのゼロインがやりやすいように800Hz前後がいいと思います。そのままでは音量がやや大きいのでトリマで可変できるようにしました。
電源は、移動運用などにも使えるように電池動作としました。ATtiny861Aは、1.8Vから動作するので、電源の安定化の必要はないのですが、キーイング速度をAD変換値から得ているので、DC-DCコンバーターICのHT7733で3.3Vに安定化しました。基本的な機能を追加して、消費電流を測ると10mA弱となりました。HT7733は、電池1本でも問題なく動作します。今回は電池2本とすることで長時間の利用が可能です。(単純計算でエネループで200時間程度はいけそう)
ブレッドボードのままFT-817NDにつないでキーイングしてみました。内蔵のエレキーと比較してもキーイングにまったく違和感ありません。無線機本体からもサイドトーンが出るので、エレキーのサイドトーンはオンオフできるようにしたほうがよさそうです。
最終的な回路図です。電源スイッチは、プッシュスイッチをソフトスイッチとして使用します。電源OFFの状態でプッシュすると電源が入ります。その状態では、通常のエレキー動作とアンテナや無線機の調整などに必要な連続キーダウンができるマニュアルモードへの切り替えスイッチとして動作します。スイッチを2秒以上連続して押すと電源OFFとなります。ソフトスイッチとして使うことで自動電源OFFなども可能となります。
使用するトランジスタは、部品数を減らすためにデジタルトランジスタとしています。2SC1815などの汎用のトランジスタと抵抗でも問題ありません。キーイング出力のトランジスタのみUN4219とは別のDTC143を選びましたが、これは消費電流を下げるためです。
回路図には、オプションとして、サイドトーンの音程やウェイト(短点と長音の比の可変)も追加してありますが、あまり必要性を感じなかったので実装はしていません。液晶などの表示部がない状態で、音程やウェイトを可変とすると変化量がモニターできないため、迷うことがありそうだからです。ただ、AVRのポートには空きがあるのでI2C液晶を追加してみるのも面白そうです。
基板への実装図です。基板は秋月電子の小型基板で設計しました。スピーカーのON/OFFスイッチ(実装図にはありません)や音量調整トリマは、使用頻度が少ないと考えて基板上に実装しました。部品数も少ないので空きスペースもあります。音程やウェイトの可変を行うならトリマが追加できます。
部品を取り付けて、バラックで動作確認をしました。
ケースは、秋月電子のポリカーボネートケース中を使用しました。ふたがヒンジで開け閉めできるので電池交換や音量調整が簡単です。
FT-817NDに接続して運用しています。・・・・・といってもキーイングは体が(指が)覚えているので、高速キーイングできるのですが、受信がまったくダメなので実際のQSOはまだまだです。和文も文字を目で見ながら指が勝手に動いてキーイングできるのですが、実際のQSOを受信してみる文字が頭に浮かびません。しばらく受信練習が必要です。
ソフトウェアです。久しぶりのプログラミングでした。パソコンも新しくなったのでAVRStudio6をインストールしてはじめて使ってみました。エディタが良くなったのですが、補間が効きすぎて逆に使いづらい所があります。AVRISPmk2経由での書き込みが面倒なのは閉口しました。
パドルからのキー入力は、タイマー割り込みで読み取っています。短音または長音出力中でも2ms間隔で割り込みがかかり、キー入力を読み取るので結果として短音・長音メモリー機能を実現しています。カツミのエレキーとの比較はできていませんが、市販のものと同じ動作だと思います。短音と長音を同時押しすると交互に音が出るスクイーズ機能も動作します。
エネループ電池などのニッケル水素電池を使用する場合は、過放電に注意する必要があります。このため、AVRのAD変換機能で電池電圧を常時モニターして、ある一定電圧以下になるとLEDを1秒間隔で点滅させる電圧低下アラーム機能を搭載しました。その後、さらに電圧が低下すると自動的に電源が切れるようにしてあります。また、10分以上、パドル入力などの操作がない場合も自動的に電源が切れるオートパワーオフ機能も搭載しました。
マニュアルモードは、無線機やアンテナの調整時などの連続キーダウンが必要なときに使用します。長音側パドル操作で連続してキーダウンできます。短音側は通常動作なので、昔のバグキーのような使い方ができます。マニュアルモード時は、LEDが若干暗くなるようにしてあります。
音程は、やや低めの750Hzとしました。ソースの中には音程の調整機能もありますが、使わないのでコメントアウトしてあります。ウェイトは、短点1に対して長音3.2としてあります。その他、短点や長音のあとの空き時間等は、好みでチューニングしています。
1 |
/* * ele_key.c for ATtiny861A * * Created: 2012/11/25 10:49:51 * Author: henteko.org * * Fuse bit set: Extended 0xff, High 0xd9, Low 0x52 * (8MHz internal clock and CLKDIV8) */ #ifndef F_CPU #define F_CPU 1000000UL #endif #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define cbi(addr, bit) addr &= ~(1<<bit) #define sbi(addr, bit) addr |= (1<<bit) #define ADC_ENABLE (_BV(ADEN)|_BV(ADIF)|0b011) #define ADC_START (ADC_ENABLE|_BV(ADSC)) unsigned int dot, dash; // dot and dash flag unsigned int cnt; // interruput times unsigned int bkmode; // manual mode flag // millisecond order delay void delay_ms(unsigned int t) { while(t--) _delay_ms(1); } // get ADC routine unsigned int get_adc(char ch) { ADMUX = ch; ADCSRA = ADC_START; loop_until_bit_is_set(ADCSRA, ADIF); return ADCW; } // interrupt routine ISR(TIMER0_OVF_vect) { cnt++; if(bit_is_clear(PINA, PA0)) { dot = 1; } if(bit_is_clear(PINA, PA1) && bkmode == 0) { dash = 1; } } // power down routine void powerdown() { cbi(PORTB, PB3); cbi(PORTB, PB6); } int main(void) { unsigned int tim; // switch input time count unsigned int dot_speed, dash_speed, space; // keying speed unsigned int ratio; // dash ratio unsigned int sec; // second unsigned int batt, battcnt; // battery voltage and count unsigned int on, off; // PWM interval unsigned int lowbatt; // lowbatt count DDRA = 0b10011000; // PA0,PA1 key input. PA2,PA5 ADC DDRB = 0b11011111; // PB5 power switch input sbi(PORTB, PB6); // power hold tr on sbi(PORTB, PB3); // status LED on PORTA = 0b00000011; // pullup PA0,PA1 PORTB |= _BV(PB5); // pullup PB5 ADCSRA = ADC_ENABLE; TCCR0B = 2; // Timer0 prescaler 1/8 .. 2.048ms TIMSK = _BV(TOIE0); // Timer0 Overflow Interrupt Enable TCCR1A = _BV(COM1A0)|_BV(COM1A1)|_BV(PWM1A); // PWM1A TCCR1B = 4; // Timer1 prescaler 1/8 .. 2.048ms dot = dash = 0; ratio = 2; // ratio=1 dot1:dash3.1 ratio=2 dot1:dash3.2 sec = 0; cnt = 0; bkmode = 0; // sidetone frequency ( off = 128000 / freq ) off = 170; // 750Hz on = (int)off / 2; // PWM duty 50% OCR1C = off; OCR1A = off; sei(); while(1) { // sense keying speed dot_speed = (int)(get_adc(2) / 10) + 20; dash_speed = (int)dot_speed * (3 + ratio * 0.1); space = (int)dot_speed * 0.9; /* // sidedone frequency off = (int)get_adc(5) / 4; on = (int)off / 2; OCR1C = off; OCR1A = off; */ // check battery batt = get_adc(4); if(batt < 651) // under 2.1V lowbatt++; else { lowbatt = 0; sbi(PORTB, PB3); } if(batt < 558) // under 1.8V battcnt++; else battcnt = 0; if(battcnt > 10) // low battery power down powerdown(); // auto power off if(cnt >= 488) { // 1s / 4.096ms = 244.14 sec++; cnt = 0; if(sec > 600) // 600sec(10min) powerdown(); if(lowbatt > 10) { // low battery alert blink LED if(bit_is_set(PINB, PB3)) cbi(PORTB, PB3); else sbi(PORTB, PB3); } } // power switch check and check manual keying mode while(bit_is_clear(PINB, PB5)) { tim++; delay_ms(10); if(tim > 200) powerdown(); } if(tim > 20) { tim = 0; sec = 0; if(bkmode) bkmode = 0; else bkmode = 1; } // manual keying mode if(bkmode) { while(bit_is_clear(PINA, PA1)) { sbi(PORTA, PA7); OCR1A = on; } cbi(PORTA, PA7); OCR1A = off; cbi(PORTB, PB3); delay_ms(10); sbi(PORTB, PB3); } // send dot if(dot) { sbi(PORTA, PA7); cbi(PORTB, PB3); OCR1A = on; delay_ms(dot_speed); cbi(PORTA, PA7); sbi(PORTB, PB3); OCR1A = off; delay_ms(space); dot = 0; sec = 0; } // send dash if(dash) { sbi(PORTA, PA7); cbi(PORTB, PB3); OCR1A = on; delay_ms(dash_speed); cbi(PORTA, PA7); sbi(PORTB, PB3); OCR1A = off; delay_ms(space); dash = 0; sec = 0; } } } |