回路図
スケッチ
fabcとfkanaは、ANKコード表による。但しコード表にない文字 ヰは#と表示、ヱはェ
(小さいエ)と表示することにした。ANKコードは下表。
モード設定はBCD SW行い、速度はボリュームで設定する。
連続モード(sequenceモード)時は、REP_SW操作でリピート開始/リピート中止ができる。
////////////////////////////////////////////////
// CW Trainer Ver.1.0
// 2025/3/31
// JA2GQP
////////////////////////////////////////////////
#include <LiquidCrystal.h>
/////////////////////////////
// Micro define
/////////////////////////////
#define SP_DO 4 // SP
#define SPEED 8 // SPEED
#define freq 700 // tone freq(Hz)
#define msw_1 7 // mode SW BIT0
#define msw_2 6 // 1
#define msw_4 5 // 2
#define REP_SW 11
const int rs = 10 , en = 9, d4 = 3, d5 = 2, d6 = 1, d7 = 0;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
/////////////////////////////
// Morse Code & font table
/////////////////////////////
byte acode[36] =
{0x06,0x11,0x15,0x09,0x02,0x14,0x0b,0x10,0x04,0x1e, // A B C D E F G H I J
0x0d,0x12,0x07,0x05,0x0f,0x16,0x1b,0x0a,0x08,0x03, // K L M N O P Q R S T
0x0c,0x18,0x0e,0x19,0x1d,0x13,0x3f,0x3e,0x3c,0x38, // U V W X Y Z 0 1 2 3
0x30,0x20,0x21,0x23,0x27,0x2f}; // 4 5 6 7 8 9
byte fabc[36] =
{0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, // A B C D E F G H I J
0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54, // K L M N O P Q R S T
0x55,0x56,0x57,0x58,0x59,0x5a,0x30,0x31,0x32,0x33, // U V W X Y Z 0 1 2 3
0x34,0x35,0x36,0x37,0x38,0x39}; // 4 5 6 7 8 9
byte kcode[50] =
{0x3b,0x06,0x0c,0x3d,0x22,0x12,0x25,0x18,0x1d,0x1f, // ア イ ウ エ オ カ キ ク ケ コ
0x35,0x2b,0x37,0x2e,0x17,0x05,0x14,0x16,0x3a,0x24, // サ シ ス セ ソ タ チ ツ テ ト
0x0a,0x15,0x10,0x1b,0x1c,0x11,0x33,0x13,0x02,0x09, // ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ
0x19,0x34,0x03,0x31,0x29,0x0e,0x39,0x07,0x08,0x0b, // マ ミ ム メ モ ヤ ユ ヨ ラ リ
0x2d,0x0f,0x1a,0x0d,0x2a,0x04,0x2c,0x29,0x26,0x1e}; // ル レ ロ ワ ン " ゜㋼ エ ヲ
byte fkana[50] =
{0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba, // ア イ ウ エ オ カ キ ク ケ コ
0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4, // サ シ ス セ ソ タ チ ツ テ ト
0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce, // ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ
0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8, // マ ミ ム メ モ ヤ ユ ヨ ラ リ
0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,0x23,0xaa,0xa6}; // ル レ ロ ワ ン " ゜㋼ エ ヲ
/////////////////////////////
// memory define
/////////////////////////////
int dottime;
int dashtime;
int interval1;
int interval2;
byte mode_val = 0;
byte mode_i = 0; // mode IRQ flag
byte rep_i = 0; // repeat IRQ flag
//-------- set up --------------------------------------------------//
void setup(){
pinMode(msw_1, INPUT_PULLUP);
pinMode(msw_2, INPUT_PULLUP);
pinMode(msw_4, INPUT_PULLUP);
pinMode(REP_SW, INPUT_PULLUP);
attachInterrupt(msw_1,mode_irq,CHANGE);
attachInterrupt(REP_SW,rep_irq,FALLING);
randomSeed(100);
lcd.begin(8, 2);
lcd.print("CW ABC");
lcd.setCursor(0, 1);
lcd.print("ver1.0");
delay (1000);
lcd.clear();
mode_SW();
};
//-------- main ----------------------------------------------------//
void loop(){
mode_SW();
lcd.clear();
lcd.setCursor(0 ,0);
switch(mode_val){
case 0: // ABC to number sequence
lcd.print("Seq A09");
delay(1000);
HR_BT();
WPM();
lcd.setCursor(0, 1);
seqChar(36);
break;
case 1: // random ABC
lcd.print("Ran ABC");
delay(1000);
HR_BT();
WPM();
lcd.setCursor(0, 1);
rndChar(26);
break;
case 2: // ABC to number ramdom
lcd.print("Ran A09");
delay(1000);
HR_BT();
WPM();
lcd.setCursor(0, 1);
rndChar(36);
break;
case 3: // kana sequence
lcd.print("Seq kana");
delay(1000);
HR_HORE();
WPM();
lcd.setCursor(0, 1);
seqChark(50);
break;
case 4: // kana ramdom
lcd.print("Ran kana");
delay(1000);
HR_HORE();
WPM();
lcd.setCursor(0, 1);
rndChark(50);
break;
case 5:
case 6:
case 7:
break;
default:
break;
}
}
//-------- ABC 0-9 sequence output --------------------------------//
void seqChar(int n){
int cnt=0; // counter clear
while (cnt <n){
morseTone(acode[cnt]); // morsecode out
delay(interval1); // wait
lcd.write(fabc[cnt]); // A to Z LCD out
if (( (cnt+1) % 5) ==0){ // 5 dijit check
delay(300);
lcd.clear();
WPM();
lcd.setCursor(0, 1);
if(rep_i == 1)
cnt = cnt - 5;
}
cnt++;
if(mode_i == 1) // IRQ check
break; // exit loop
}
AR();
lcd.clear();
}
//-------- random ABC output ---------------------------------------//
void rndChar(int n){
int cnt=0; // counter clear
int x;
while (cnt <80){
x = random(n); // randum code
morseTone(acode[x]); // morsecode out
delay(interval1); // wait
lcd.write(fabc[x]); // A to Z LCD out
if (( (cnt+1) % 5) ==0){ // 5 dijit check
delay(500);
lcd.clear() ;
WPM();
lcd.setCursor(0, 1);
}
cnt++;
if(mode_i == 1) // IRQ check
break; // exit loop
}
AR();
lcd.clear();
}
//-------- kana sequence output -----------------------------------//
void seqChark(int n){
int cnt=0; // counter clear
while (cnt <n){
morseTone(kcode[cnt]); // morsecode out
delay(interval1); // wait
lcd.write(fkana[cnt]); // kana LCD out
if (( (cnt+1) % 5) ==0){ // 5 dijit check
delay(300);
lcd.clear() ;
WPM();
lcd.setCursor(0, 1);
if(rep_i == 1)
cnt = cnt - 5;
}
cnt++;
if(mode_i == 1) // IRQ check
break; // exit loop
}
SN();
lcd.clear();
}
//-------- kana random output --------//
void rndChark(int n){
int cnt=0; // counter clear
int x;
while (cnt <80){
x = random(n); // randum code
morseTone(kcode[x]); // morsecode out
delay(interval1); // wait
lcd.write(fkana[x]); // kana LCD out
if (( (cnt+1) % 5) ==0){ // 5 dijit check
delay(500);
lcd.clear() ;
WPM();
lcd.setCursor(0, 1);
}
cnt++;
if(mode_i == 1) // IRQ check
break; // exit loop
}
SN();
lcd.clear();
}
//-------- mode SW -------------------------------------------------//
void mode_SW(){
mode_val = 0;
if(digitalRead(msw_1) == LOW)
mode_val = mode_val + 1;
if(digitalRead(msw_2) == LOW)
mode_val = mode_val + 2;
if(digitalRead(msw_4) == LOW)
mode_val = mode_val + 4;
mode_i = 0;
}
//-------- mode IRQ ------------------------------------------------//
void mode_irq(){
mode_i = 1;
}
//-------- ESC IRQ ------------------------------------------------//
void rep_irq(){
delay(50);
rep_i = rep_i ^ 1;
}
//-------- HR HR BT code output ------------------------------------//
void HR_BT(){
lcd.clear();
WPM();
lcd.setCursor(0 ,1);
HR();
HR();
lcd.print("BT");
morseTone(0x11); // B code output
morseTone(0x03); // T code output
delay(interval2 *2);
lcd.clear();
}
//-------- HR code output ------------------------------------------//
void HR(){
lcd.print("HR ");
morseTone(0x10); // H code output
delay(interval1);
morseTone(0x0a); // R code output
delay(interval1);
}
//-------- AR code output ------------------------------------------//
void AR(){
morseTone(0x2a);
delay(interval1);
}
//-------- ラタ code output ------------------------------------------//
void SN(){
morseTone(0x28);
delay(interval1);
}
//-------- code speed ----------------------------------------------//
void code_speed(){
dottime = analogRead(SPEED) / 5;
dashtime = dottime * 3;
interval1 = dottime * 2;
interval2 = dottime * 4;
}
//-------- code tone output ----------------------------------------//
void morseTone(int m){
while (m != 1){
if ((m & 1) == 0){
tone(SP_DO,freq,dottime); // dot
delay(interval1);
}
else{
tone(SP_DO,freq,dashtime); // dash
delay(interval2);
}
m = m >> 1; // 1bit shift right
}
}
//-------- WPM -----------------------------------------------------//
void WPM(){
code_speed();
lcd.setCursor(0, 0);
lcd.print("WPM");
lcd.print(2400 / interval1);
lcd.setCursor(7, 0);
lcd.print(mode_val);
}
//-------- HR HR ホレ code output ------------------------------------//
void HR_HORE(){
lcd.clear();
WPM();
lcd.setCursor(0 ,1);
HR();
HR();
morseTone(0x09); // ホ code output
morseTone(0x0f); // レ code output
lcd.write(0xce);
lcd.write(0xda);
delay(interval2 *2);
lcd.clear();
}
ダウンロード
スケッチ、回路図はJA2GQP's Download siteCWフォルダーからダウンロードできる。