KEYERサンプルコード (電波文化祭5)
#include <Arduino.h>
#include <Wire.h>
#include <HardwareTimer.h>
// ==== ピン設定 ====
#define PIN_DOT 7 //パドル左
#define PIN_DASH 8 //パドル右
#define PIN_TONE 9 //トーン出力
#define PIN_SPEED A0 //速度調整用(ADC)
#define PIN_KEYOUT 2 //無線機用KEYOUT
#define PIN_SWA 10 //SW A
#define PIN_SWB 5 //SW B
// ==== 定数 ====
//スクイズ状態
#define SQZ_FREE 0
#define SQZ_SPC0 1
#define SQZ_SPC 2
#define SQZ_DOT0 3
#define SQZ_DOT 4
#define SQZ_DAH_CONT0 5
#define SQZ_DAH_CONT1 6
#define SQZ_DAH_CONT 7
#define SQZ_DASH 8
//パドル状態
#define PDL_DOT 1
#define PDL_DASH 2
#define PDL_FREE 0
#define SQUEEZE_TYPE 0 //スクイーズモード
#define PDL_RATIO 4 //短点・長点比率
#define WPM_MAX 40 //スピード最大値(WPM)
#define WPM_MIN 5 //スピード最小値(WPM)
// ==== 変数 ====
int key_spd = 1000;
int wpm = 20;
bool tone_enabled = false;
int squeeze = 0;
int paddle = PDL_FREE;
int paddle_old = PDL_FREE;
HardwareTimer timer(TIM1); // TIM1を使用
// ==== パドル処理 ====
uint8_t job_paddle() {
static uint32_t left_time = 0;
uint8_t key_dot, key_dash;
key_dot = (!digitalRead(PIN_DOT) || !digitalRead(PIN_SWA));
key_dash = (!digitalRead(PIN_DASH) || !digitalRead(PIN_SWB));
if (left_time != 0) {
left_time--;
} else {
left_time = key_spd / 2;
if (squeeze != SQZ_FREE) {
squeeze--;
}
}
if (squeeze != SQZ_FREE) {
if (paddle_old == PDL_DOT && key_dash) paddle = PDL_DASH;
else if (paddle_old == PDL_DASH && key_dot) paddle = PDL_DOT;
}
if (SQUEEZE_TYPE == 0) {
if (squeeze > SQZ_DASH) paddle = PDL_FREE;
} else {
if (squeeze > SQZ_SPC) paddle = PDL_FREE;
}
if (squeeze > SQZ_SPC) return 1;
else if (squeeze == SQZ_SPC || squeeze == SQZ_SPC0) return 0;
if (paddle == PDL_FREE) {
if (key_dot) paddle = PDL_DOT;
else if (key_dash) paddle = PDL_DASH;
}
if (paddle == PDL_FREE) return 0;
else {
if (paddle == PDL_DOT) squeeze = SQZ_DOT;
else {
uint8_t dash_len = (SQZ_SPC * PDL_RATIO + 5) / 2;
squeeze = SQZ_SPC + dash_len;
}
left_time = key_spd / 2;
paddle_old = paddle;
paddle = PDL_FREE;
return 1;
}
return 0;
}
// ==== トーン制御ON ====
void startTone() {
if (tone_enabled) return;
tone_enabled = true;
tone(PIN_TONE, 600); // 600Hz
digitalWrite(PIN_KEYOUT, HIGH); // ON
}
// ==== トーン制御OFF ====
void stopTone() {
noTone(PIN_TONE);
tone_enabled = false;
digitalWrite(PIN_KEYOUT, LOW); // OFF
}
// ==== ADCからスピード読み込み ====
void update_speed_from_adc() {
int adc = analogRead(PIN_SPEED); // 0 .. 1023
wpm = map(adc, 0, 1023, WPM_MIN, WPM_MAX);
key_spd = 4687.5 / wpm; // = (1200/wpm) /0.256
}
// ==== キーダウン ====
void keydown() {
startTone();
}
// ==== キーアップ ====
void keyup() {
stopTone();
}
// ==== タイマー割り込み ====
void onTimerInterrupt() {
if (job_paddle()) keydown();
else keyup();
}
// ==== セットアップ ====
void setup() {
pinMode(PIN_DOT, INPUT_PULLUP);
pinMode(PIN_DASH, INPUT_PULLUP);
pinMode(PIN_SWA, INPUT_PULLUP);
pinMode(PIN_SWB, INPUT_PULLUP);
pinMode(PIN_TONE, OUTPUT);
pinMode(PIN_KEYOUT, OUTPUT);
pinMode(PIN_SPEED,INPUT_ANALOG);
//タイマー設定 0.256msごとにタイマー割り込み
timer.setOverflow(256, MICROSEC_FORMAT); // 周期設定(256us)
timer.attachInterrupt(onTimerInterrupt); // 割り込み設定
timer.resume(); // タイマー開始
}
// ==== メインループ ====
void loop() {
update_speed_from_adc(); // スピード調整用
delay(100);
}