注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BA5AG的博客

业余电台 Arduino RaspberryPi

 
 
 

日志

 
 

用Arduino做一个自动键  

2013-02-05 14:52:07|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
用Arduino做一个自动键 - kc2wag - BA5AG的博客
 
Arduino是一个简便易用的单片机平台,它有数字输入、输出,有现成的库函数做音频输出,可以用C++语言写程序,显然用来做一个自动键控制器是游刃有余的。

现代产品设计最重要的手段之一就是remix:在别人的产品——包括硬件和软件——基础上做组合和二次开发。所以,我们也不从头开始,在Bill Bishop的这篇博客“Arduino Iambic Keyer and Side Tone Generator”中给出了一个良好的自动键的电路和程序,非常好用,我们就从这里开始吧。

这是我做的自动键的Frizting连线图:
用Arduino做一个自动键 - kc2wag - BA5AG的博客
与Bill的作品不同,我增加了三个功能:
* 用电位器调节拍发的速度;
* 输出控制FM电台PTT的信号;
* 输出的音频幅度可以调节。

另外,作为Arduino 1.0.1的新功能,我用了带上拉的数字输入,这样就省了两个10k的电阻。

修改后的程序如下:

///////////////////////////////////////////////////////////////////////////////
//
//  Iambic Morse Code Keyer Sketch
//  Copyright (c) 2009 Steven T. Elliott
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details:
//
//  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
//  Boston, MA  02111-1307  USA
//
//  http://openqrp.org/?p=343
//
//  "Trimmed" by Bill Bishop - wrb[at]wrbishop.com
//  "Remixed" By Weng Kai - kc2wag@163.com
//
///////////////////////////////////////////////////////////////////////////////
//
//                         openQRP CPU Pin Definitions
//
///////////////////////////////////////////////////////////////////////////////
//
// Digital Pins
//
const int         tonePin  = 8;       // Tone output pin
const int         LPin     = 2;       // Left paddle input
const int         RPin     = 3;       // Right paddle input
const int         ledPin   = 13;      //
const int         pttPin   = 12;      // PTT
//
////////////////////////////////////////////////////////////////////////////////
//
//  keyerControl bit definitions
//
#define     DIT_L      0x01     // Dit latch
#define     DAH_L      0x02     // Dah latch
#define     DIT_PROC   0x04     // Dit is being processed
#define     PDLSWAP    0x08     // 0 for normal, 1 for swap
#define     IAMBICB    0x10     // 0 for Iambic A, 1 for Iambic B
//
////////////////////////////////////////////////////////////////////////////////
//
//  Library Instantiations
//
////////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
//
//  Global Variables
//
 
unsigned long       ditTime;                    // No. milliseconds per dit
unsigned char       keyerControl;
unsigned char       keyerState;
unsigned int        speedPot;
unsigned char       note = 500;
unsigned char       ptt = false;
unsigned int        pttdelay = 50;

//#define NOTE_D5  440    // "pitch.h" at http://arduino.cc/en/Tutorial/Tone
 
///////////////////////////////////////////////////////////////////////////////
//
//  State Machine Defines
 
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
 
///////////////////////////////////////////////////////////////////////////////
//
//  System Initialization
//
///////////////////////////////////////////////////////////////////////////////
 
void setup() {
 
    // Setup outputs
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 
    // Setup control input pins
    pinMode(LPin, INPUT_PULLUP);        // sets Left Paddle digital pin as input with pullup
    pinMode(RPin, INPUT_PULLUP);        // sets Right Paddle digital pin as input with pullup
    pinMode(pttPin, OUTPUT);    
    digitalWrite(pttPin, LOW);  // ptt off
    digitalWrite(ledPin, LOW);   // turn the LED off
 
    keyerState = IDLE;
    keyerControl = IAMBICB;      // Or 0 for IAMBICA
    loadWPM(25);                 // Init speed at 25 WPM
}
 
///////////////////////////////////////////////////////////////////////////////
//
//  Main Work Loop
//
///////////////////////////////////////////////////////////////////////////////
 
void loop()
{
  static long ktimer;
  static long ptimer;  //  timer for ptt
  int debounce;
 
  // Basic Iambic Keyer
  // keyerControl contains processing flags and keyer mode bits
  // Supports Iambic A and B
  // State machine based, uses calls to millis() for timing.
 
  switch (keyerState) {
    case IDLE:
        // Wait for direct or latched paddle press
        if ((digitalRead(LPin) == LOW) ||
                (digitalRead(RPin) == LOW) ||
                    (keyerControl & 0x03)) {
            update_PaddleLatch();
            keyerState = CHK_DIT;
        }
        if ( abs(speedPot - analogRead(A0)) >10 ) {
          speedPot = analogRead(A0);
          loadWPM(speedPot/25);
          pttdelay = 1200/(speedPot/25)*10;
        }
        if ( millis() >= ptimer ) {
          digitalWrite(pttPin, LOW);  // turn PTT off
        }
        break;
 
    case CHK_DIT:
        // See if the dit paddle was pressed
        if (keyerControl & DIT_L) {
            keyerControl |= DIT_PROC;
            ktimer = ditTime;
            keyerState = KEYED_PREP;
        }
        else {
            keyerState = CHK_DAH;
        }
        break;
 
    case CHK_DAH:
        // See if dah paddle was pressed
        if (keyerControl & DAH_L) {
            ktimer = ditTime*3;
            keyerState = KEYED_PREP;
        }
        else {
            keyerState = IDLE;
            ptimer = millis()+pttdelay;
        }
        break;
 
    case KEYED_PREP:
        // Assert key down, start timing, state shared for dit or dah
        digitalWrite(ledPin, HIGH);         // turn the LED on
        digitalWrite(pttPin, HIGH);         // enable PTT
        tone( tonePin, note );
        ktimer += millis();                 // set ktimer to interval end time
        keyerControl &= ~(DIT_L + DAH_L);   // clear both paddle latch bits
        keyerState = KEYED;                 // next state
        break;
 
    case KEYED:
        // Wait for timer to expire
        if (millis() > ktimer) {            // are we at end of key down ?
            digitalWrite(ledPin, LOW);      // turn the LED off
            noTone( tonePin );
            ktimer = millis() + ditTime;    // inter-element time
            keyerState = INTER_ELEMENT;     // next state
        }
        else if (keyerControl & IAMBICB) {
            update_PaddleLatch();           // early paddle latch in Iambic B mode
        }
        break;
 
    case INTER_ELEMENT:
        // Insert time between dits/dahs
        update_PaddleLatch();               // latch paddle state
        if (millis() > ktimer) {            // are we at end of inter-space ?
            if (keyerControl & DIT_PROC) {             // was it a dit or dah ?
                keyerControl &= ~(DIT_L + DIT_PROC);   // clear two bits
                keyerState = CHK_DAH;                  // dit done, check for dah
            }
            else {
                keyerControl &= ~(DAH_L);              // clear dah latch
                keyerState = IDLE;                     // go idle
                ptimer = millis()+pttdelay;
            }
        }
        break;
    }
}
 
///////////////////////////////////////////////////////////////////////////////
//
//    Latch dit and/or dah press
//
//    Called by keyer routine
//
///////////////////////////////////////////////////////////////////////////////
 
void update_PaddleLatch()
{
    if (digitalRead(RPin) == LOW) {
        keyerControl |= DIT_L;
    }
    if (digitalRead(LPin) == LOW) {
        keyerControl |= DAH_L;
    }
}
 
///////////////////////////////////////////////////////////////////////////////
//
//    Calculate new time constants based on wpm value
//
///////////////////////////////////////////////////////////////////////////////
 
void loadWPM (int wpm)
{
    ditTime = 1200/wpm;
}

程序中我修改的部分只有21行,看,其实改动并不大,这就是remix的魅力。另外,我把拍发的音频频率从原来的宏换成了一个变量,这为今后做音频调节留下了口子。

这个自动键可以接到FM电台上来玩FM CW。不过,有一点点小遗憾的是,FM电台的收发转换时间有点长,所以,要拍发之前,需要先敲一下划,让电台从接收转到发射,然后再开始拍发电文。否则的话,你所拍发的第一个点会被漏掉,而第一个划可能被对方抄收成点。

Have Fun~
  评论这张
 
阅读(891)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018