Arduinoで作っちゃいました ~ CW練習機(パート1) ~
1.
はじめに
2024年8月 船橋市アマチュア無線クラブのArduinoの講習会参加して、生まれて始めてArduinoに接しプログラミングが非常に楽にできることを知りました。
それ以来、Arduinoにハマってハマって抜けられなくなってしまいました。
(講習会と機材の準備してくださいました講師のFQA松本さん、ありがとうございました)
これからArduinoで製作したものをご紹介していきたいと思います。
2.
最初に作るものは、やっぱりCW練習機
まずは、CWの練習機から。パート1として、音を鳴らすだけの基本機能を作ります。 (Lチカや、Tone()関数、digitalRead(), digitalWrite()などの説明は省略します)
プログラムの骨子は、
void loop() {
int key;
// 電鍵(Key)の状態が変化したら、Toneをon/offする
key = check_Key_status();
if (key == BtnOnEdge) { // Key On Edge
tone(SPK_PIN, Pitch); // 音を出す
}
if (key == BtnOffEdge) { // Key Off Edge
noTone(SPK_PIN); // 音を止める
}
}
です。
ここで、check_Key_status()は電鍵のOn/Offの状態変化を見張っています。この中身を確認していきます。
3. 接点(ボタン/Key)の状態監視の方法
ところで、電鍵やボタン、スイッチの接点にはチャタリングがありますので、対策が必要です。
お勧めは、アナログCR積分回路を模したデジタル積分方式です。
(アナログCR積分によるチャタリング対策)
(デジタル積分によるチャタリング対策)
デジタル積分によるチャタリング対策のプログラム例
このプログラムは、Btnの状態(OnかOffか)を返します。
(ボタン番号1が、GPIO Btn1_PINに接続されている前提)
/// ボタン1(Btn1) ///
static int Btn1Cnt = 0;
static int Btn1Status = Off; // normally off
int check_Btn1_status() {
if (digitalRead(BTN1_PIN) == HIGH) { // switch off
Btn1Cnt--;
if (Btn1Cnt < 0) {
Btn1Cnt = 0;
Btn1Status = Off;
}
} else { // switch on
Btn1Cnt++;
if (Btn1Cnt > threshold) {
Btn1Cnt = threshold;
Btn1Status = On;
}
}
}
ヒステリシス特性を決めるThresholdの値は、接点の特性や反応時間、ループの速さによって調整します。(3-100の間くらい)
この方式のメリットは、チャタリング終了判定までの間タイマーで(10msecなど)待つ必要がなく、ループで回っている途中でチェックに入れば良い(他の仕事ができる)という点です。
これを踏まえて、電鍵(Key)のOn/Offの状態変化を監視するcheck_Key_status()を作成します。
/// 電鍵(KEY) ///
static int KeyCnt = 0;
static int KeyStatus = Off; // normally off
int check_Key_status() {
if (digitalRead(KEY_PIN) == HIGH) { // switch off
KeyCnt--;
if (KeyCnt < 0) {
KeyCnt = 0;
if (KeyStatus == On) {
KeyStatus = Off;
return (BtnOffEdge); // Key Off Edge
} else {
return (NoChange); // no change
}
}
} else { // switch on
KeyCnt++;
if (KeyCnt > threshold) {
KeyCnt = threshold;
if (KeyStatus == Off) {
KeyStatus = On;
return (BtnOnEdge); // Key On Edge
} else {
return (NoChange); // no change
}
}
}
}
さらに、モールス信号の音程(pitch)を変えるボタン(upとdown)をloop()に追加してみました。
void loop() {
int key;
// 電鍵(Key)の状態が変化したら、Toneをon/offする
key = check_Key_status();
if (key == BtnOnEdge) { // Key On Edge
tone(SPK_PIN, Pitch); // 音を出す
}
if (key == BtnOffEdge) { // Key Off Edge
noTone(SPK_PIN); // 音を止める
}
//// 以下を追加 ////
// ボタン1 (音程up)
if (check_Btn1_status() == BtnOnEdge) { // Btn On Edge
setTone(+50); // 音程(Pitch)を上げる
}
// ボタン2 (音程down)
if (check_Btn2_status() == BtnOnEdge) { // Btn On Edge
setTone(-50); // 音程(Pitch)を下げる
}
}
(注)上の例では、音程up/downのボタンによる動作(Action)をボタンを押したタイミング(Btn On Edge)としていますが、長押し判定などをする場合は、ボタンを離すタイミング(Btn Off Edge)を使用します。
4. まとめ
以上をまとめると、全体のプログラムは以下になります。
/////////////////////////////
// Blogger CW練習機 (その1) //
// 20250305 by JL1BDL //
/////////////////////////////
/// ハードウェアの接続定義 ///
#define KEY_PIN 4 // 電鍵(Key)を接続
#define BTN1_PIN 9 // ボタン1
#define BTN2_PIN 12 // ボタン2
#define SPK_PIN 8 // スピーカー
#define Off 0
#define On 1
// KEYやボタンの状態変化 //
#define BtnOnEdge 1
#define BtnOffEdge 2
#define NoChange 0
/// 共通変数 ///
int Pitch = 600; // 音程(Pitch)のデフォルト値 600Hz
void setup() {
// 各ピンの設定
pinMode(KEY_PIN, INPUT_PULLUP); // straight key
pinMode(BTN1_PIN, INPUT_PULLUP);
pinMode(BTN2_PIN, INPUT_PULLUP);
}
void loop() {
int key;
// 電鍵(Key)の状態が変化したら、Toneをon/offする
key = check_Key_status();
if (key == BtnOnEdge) { // Key On Edge
tone(SPK_PIN, Pitch); // 音を出す
}
if (key == BtnOffEdge) { // Key Off Edge
noTone(SPK_PIN); // 音を止める
}
// ボタン1 (音程up)
if (check_Btn1_status() == BtnOnEdge) { // Btn On Edge
setTone(+50); // 音程(Pitch)を上げる
}
// ボタン2 (音程down)
if (check_Btn2_status() == BtnOnEdge) { // Btn On Edge
setTone(-50); // 音程(Pitch)を下げる
}
}
// 音程変更 (300-1200Hz)
void setTone(int n) {
Pitch = Pitch + n;
if (Pitch < 300) Pitch = 300;
if (Pitch > 1200) Pitch = 1200;
tone(SPK_PIN, Pitch, 100); // 音程を変更したら、ピッと鳴らす
}
///////////////////////////////////////////////////////
// 以下は、電鍵(Key)、ボタン1,、ボタン2の入力チェック //
// On/Offではなく、on/offの切り替え(Edge)を返す //
// BtnOnEdge =1, BtnOffEdge= 2, NoChange = 0 //
///////////////////////////////////////////////////////
int threshold = 10; // thresholdは、全ボタン共通とした
/// 電鍵(KEY) ///
static int KeyCnt = 0;
static int KeyStatus = Off; // normally off
int check_Key_status() {
if (digitalRead(KEY_PIN) == HIGH) { // switch off
KeyCnt--;
if (KeyCnt < 0) {
KeyCnt = 0;
if (KeyStatus == On) {
KeyStatus = Off;
return (BtnOffEdge); // Key Off Edge
} else {
return (NoChange); // no change
}
}
} else { // switch on
KeyCnt++;
if (KeyCnt > threshold) {
KeyCnt = threshold;
if (KeyStatus == Off) {
KeyStatus = On;
return (BtnOnEdge); // Key On Edge
} else {
return (NoChange); // no change
}
}
}
}
/// ボタン1(Btn1) ///
static int Btn1Cnt = 0;
static int Btn1Status = Off; // normally off
int check_Btn1_status() {
if (digitalRead(BTN1_PIN) == HIGH) { // switch off
Btn1Cnt--;
if (Btn1Cnt < 0) {
Btn1Cnt = 0;
if (Btn1Status == On) {
Btn1Status = Off;
return (BtnOffEdge); // Btn1 Off Edge
} else {
return (NoChange); // no change
}
}
} else { // switch on
Btn1Cnt++;
if (Btn1Cnt > threshold) {
Btn1Cnt = threshold;
if (Btn1Status == Off) {
Btn1Status = On;
return (BtnOnEdge); // Btn1 On Edge
} else {
return (NoChange); // no change
}
}
}
}
/// ボタン2(Btn2) ///
static int Btn2Cnt = 0;
static int Btn2Status = Off; // normally off
int check_Btn2_status() {
if (digitalRead(BTN2_PIN) == HIGH) { // switch off
Btn2Cnt--;
if (Btn2Cnt < 0) {
Btn2Cnt = 0;
if (Btn2Status == On) {
Btn2Status = Off;
return (BtnOffEdge); // Btn2 Off Edge
} else {
return (NoChange); // no change
}
}
} else { // switch on
Btn2Cnt++;
if (Btn2Cnt > threshold) {
Btn2Cnt = threshold;
if (Btn2Status == Off) {
Btn2Status = On;
return (BtnOnEdge); // Btn2 On Edge
} else {
return (NoChange); // no change
}
}
}
}
/////////// EOF ////////////////////
キモとなる電鍵とボタン2個の状態監視部分が長々と(3回)続いていますが、それを除けば、「CW練習機(パート1)音を鳴らす」は、非常に簡単なプログラムで完成しました。
私は、今までは主にSTM32を使ってきました。これはこれで、ベアメタルに近いプログラミングが楽しめるのですが、Arduinoは、最初のハードルが低く、導入しやすい豊富なライブラリが揃っている、また開発環境が機種間で(低速MCUから高速MCUまで)互換性が高いところが、人気の秘密だと思いました。
次回は、電鍵から入力されたコードを読み取って(解読して) LCD表示機に表示させる部分を製作します。
0 件のコメント:
コメントを投稿