//KTR-40C3用 Arduino pro mini(5V/16MHz) 2025年6月4日
// VFO with Si5351A and OLED display for CW_Transceiver
// Version 2.4.14 (VFO制御とスクイーズキーヤー・手動電鍵統合版)
#include
#include
#include
#include
#include
#include
// — Global setup —
const unsigned long DEFAULT_FREQ = 19796940UL;
const int EEPROM_ADDR = 0;
unsigned long lastFreqWriteTime = 0;
bool freqChanged = false;
bool freqWritten = true;
unsigned long eeprom_cached_FREQ; // ★ 追加: EEPROMに書き込む予定の周波数を一時的に保持する変数
// TX/RX 状態遷移管理
unsigned long txDelayStartTime = 0; // 送信開始待ち時間計測用
bool txTransitionActive = false; // 送信への移行中フラグ
bool txActive = false; // VFO側がTX状態(RF出力ON)であることを示すフラグ
unsigned long rxDelayStartTime = 0; // 受信開始待ち時間計測用
bool rxTransitionActive = false; // 受信への移行中フラグ
// Loop interval control for bar graph
unsigned long previousMillis = 0;
const long interval = 100;
int previousBarLength = -1;
// OLED and encoder
SSD1306AsciiAvrI2c oled;
Rotary r = Rotary(2, 3);
// Si5351A definitions
#define Si5351A_ADDR 0x60
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define CLK0_CTRL 16
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define OUTPUT_CTRL 3
#define XTAL_LOAD_C 183
#define PLL_RESET 177
// I/O pins
#define SW_STEP 5
#define TX_SW 9 // 手動電鍵およびキーヤーからの送信制御入力
#define TX_ON 7
#define AF_mute 8 // AFミュート制御
// Frequency setup
const long LOW_FREQ = 19796940L;
const long HI_FREQ = 19996940L;
const long IF_FREQ = 12796940L;
unsigned long FREQ = DEFAULT_FREQ;
unsigned long FREQ_OLD = FREQ;
unsigned long txFreq_OLD = 0;
int dF = 120;
int RX_dF = 340;
int STEP = 100;
// — キーヤーピンアサイン —
#define DOT_PIN 11 // 短点パドル入力
#define DASH_PIN 12 // 長点パドル入力
#define SIDETONE_PIN 10 // サイドトーン出力 (D10)
#define SPEED_POT_PIN A6 // スピードコントロール用入力
// — キーヤー定数 —
const int MIN_WPM = 12;
const int MAX_WPM = 35;
const int SIDETONE_FREQ = 800; // サイドトーン周波数 (Hz)
const unsigned long DEBOUNCE_DELAY = 10; // パドル入力のデバウンス時間 (ms)
const unsigned long TX_ON_DELAY_MS = 3; // clk1 オンからTX_ON ONまでの遅延 (ms)
const unsigned long RX_ON_DELAY_MS = 5; // TX_ON OFFからAF_mute 解除までの遅延 (ms)
// — キーヤー グローバル変数 —
volatile int currentWpm = 15;
volatile unsigned long ditTimeMs = 0;
volatile unsigned long dahTimeMs = 0;
volatile unsigned long elementSpaceTimeMs = 0;
// キーヤーの内部動作状態 (割り込み内で更新されるので volatile)
enum KeyerState {
KEYER_IDLE, // アイドル状態 (TX OFF)
KEYER_SENDING_ON, // 符号のON期間送出中 (TX ON)
KEYER_SENDING_OFF // 符号間のOFF期間送出中 (TX OFF)
};
volatile KeyerState currentKeyerState = KEYER_IDLE;
// 現在送出している符号のタイプ (ISRで更新、loopで参照)
enum CurrentlySendingSymbol {
NONE_SENDING,
DOT_SENDING,
DASH_SENDING
};
volatile CurrentlySendingSymbol currentlySendingSymbol = NONE_SENDING;
// 次に送出する符号のタイプ (メモリに記憶された符号) (volatile)
enum BufferedSymbol {
NONE_BUFFERED,
DOT_BUFFERED,
DASH_BUFFERED
};
volatile BufferedSymbol bufferedSymbol = NONE_BUFFERED; // 1つだけバッファする符号
// 割り込みハンドラ内でカウントするティック数
volatile unsigned long currentTickCount = 0;
volatile unsigned long requiredTicks = 0;
// パドル入力の状態 (デバウンス後) – volatileを追加
volatile bool dotPaddleState = false;
volatile bool dashPaddleState = false;
// デバウンス処理のための内部変数
static unsigned long lastDotReadTime = 0;
static unsigned long lastDashReadTime = 0;
static bool rawDotState = false;
static bool rawDashState = false;
static int lastPotValue = -1; // ポテンショメータの値を監視するための変数
// TX_SW (手動電鍵) の状態を保持する変数
volatile bool manualTxSwitchPressed = false; // ISRからも参照される可能性があるのでvolatileに
unsigned long lastManualTxReadTime = 0;
// Note: rawManualTxStateはloop内でローカル変数として処理する
const unsigned long MANUAL_TX_DEBOUNCE_DELAY = 10; // 手動電鍵のデバウンス
// — 関数 (Si5351A / OLED / VFO) —
void rotary_encoder();
void Fnc_Stp();
void drawBar(int currentBarLength);
void Set_CLK_Enable(uint8_t clk0, uint8_t clk1, uint8_t clk2);
void Freq_Disp(unsigned long Fre);
void Step_Disp(int Stp);
void Si5351_write(byte Reg, byte Data);
void Si5351_init();
void PLL_Set(char pll, uint32_t freq);
void MS_Set(uint8_t clk_no);
void Parameter_write(uint8_t REG_ADDR, uint32_t Pa1, uint32_t Pa2, uint32_t Pa3);
// — 関数 (キーヤー) —
void updateKeyerTiming();
void processPaddleInput();
void setTxOnState(bool on); // TX_ON制御を専用の関数に統一
void setupTimer1();
// — Setup —
void setup() {
// Rotary Encoder setup
r.begin();
attachInterrupt(0, rotary_encoder, CHANGE);
attachInterrupt(1, rotary_encoder, CHANGE);
// Pin Modes
pinMode(SW_STEP, INPUT_PULLUP);
pinMode(TX_SW, INPUT_PULLUP); // TX_SW (手動電鍵 & キーヤーからの制御用)
pinMode(TX_ON, OUTPUT);
pinMode(AF_mute, OUTPUT);
// Keyer related pin modes
pinMode(DOT_PIN, INPUT_PULLUP);
pinMode(DASH_PIN, INPUT_PULLUP);
pinMode(SIDETONE_PIN, OUTPUT); // サイドトーン出力ピンを設定
pinMode(SPEED_POT_PIN, INPUT);
// Initial output states
setTxOnState(false); // TX_ONを初期オフ (専用関数経由)
digitalWrite(AF_mute, HIGH); // AF_muteを(受信状態)
// EEPROM read for frequency
EEPROM.get(EEPROM_ADDR, FREQ);
if (FREQ < LOW_FREQ || FREQ > HI_FREQ) FREQ = DEFAULT_FREQ;
FREQ_OLD = FREQ;
eeprom_cached_FREQ = FREQ; // ★ 追加: 初期値を同期
oled.begin(&Adafruit128x64, 0x3C); //0.96インチ128×64用、1.3インチは(&SH1106_128x64, 0x3C)に変更
Si5351_init();
// Initial PLL/MS settings for RX and TX
PLL_Set(‘A’, FREQ + RX_dF);
MS_Set(0); // CLK0 (受信) のマルチシンセサイザ設定
unsigned long initialTxFreq = FREQ + dF – IF_FREQ;
PLL_Set(‘B’, initialTxFreq);
MS_Set(1); // CLK1 (送信) のマルチシンセサイザ設定
txFreq_OLD = initialTxFreq; // 初期送信周波数を記録
Si5351_write(CLK1_CTRL, 0x6D); //CLK1を4mAにおまじない
// Display initial frequency and step
Freq_Disp(FREQ);
Step_Disp(STEP);
// OLED bar graph label
oled.setCursor(0, 4);
oled.setFont(font5x7);
oled.write(“1__3__5__7_9+20+40+60”);
Set_CLK_Enable(1, 0, 0); // 初期はCLK0 (受信) のみ有効
// — キーヤー初期化 —
updateKeyerTiming(); // 初期スピードの計算とタイミング変数の設定
setupTimer1(); // Timer1割り込みを設定 (1ms周期)
// グローバル割り込みを有効化 (setupTimer1でも行うが念のため)
sei();
}
// — Loop —
void loop() {
unsigned long now = millis();
if (digitalRead(SW_STEP) == LOW) Fnc_Stp();
// 手動電鍵のデバウンス処理
bool currentRawManualTx = (digitalRead(TX_SW) == LOW);
// rawManualTxStateはここでローカル変数として定義
static bool rawManualTxState = false; // staticにして値を保持
if (currentRawManualTx != rawManualTxState) {
lastManualTxReadTime = now;
rawManualTxState = currentRawManualTx;
}
if (now – lastManualTxReadTime > MANUAL_TX_DEBOUNCE_DELAY) {
manualTxSwitchPressed = rawManualTxState; // volatile変数に最終状態を書き込み
}
// — TX/RX 状態遷移処理 (VFO側とキーヤー側の両方から制御を統合) —
// 手動電鍵が押されていれば、キーヤーの状態にかかわらず送信要求を優先する
bool requestTx = manualTxSwitchPressed || (currentKeyerState != KEYER_IDLE);
if (requestTx) {
if (!txTransitionActive) {
// 受信から送信への移行開始
txDelayStartTime = now;
txTransitionActive = true;
rxTransitionActive = false; // 受信への移行をリセット
digitalWrite(AF_mute, LOW); // AFミュート解除
// 送信周波数に切り替え
Set_CLK_Enable(0, 1, 0); // CLK1 (送信) を有効
}
// TX_ONはキーヤーISRと手動電鍵の状態に基づいて、setTxOnState()で制御される
// ここでは直接digitalWrite(TX_ON)はしない
txActive = true; // TXがアクティブであることをマーク
} else { // 送信要求がない場合 (キーヤーも手動電鍵もTXを要求していない)
if (!rxTransitionActive) {
rxDelayStartTime = now;
rxTransitionActive = true;
txTransitionActive = false; // 送信への移行をリセット
setTxOnState(false); // 送信要求がなくなった時点でTX_ONをLOWにする
txActive = false; // TX非アクティブをマーク
// TX_ONがオフになったら直ちにRX周波数に切り替え
Set_CLK_Enable(1, 0, 0); // CLK0 (受信) を有効
// AF_muteはまだONにしない (遅延させるため)
}
// RX_ON_DELAY_MS の遅延後にAF_muteをONにする
if (rxTransitionActive && (now – rxDelayStartTime >= RX_ON_DELAY_MS)) {
digitalWrite(AF_mute, HIGH); // AFミュートオン
rxTransitionActive = false; // 受信への移行完了
}
}
// — 周波数変更検出 —
if (FREQ != FREQ_OLD) {
PLL_Set(‘A’, FREQ + RX_dF);
MS_Set(0); // CLK0 (受信) に紐づくマルチシンセサイザ
unsigned long txFreq_new = FREQ + dF – IF_FREQ;
PLL_Set(‘B’, txFreq_new);
MS_Set(1); // CLK1 (送信) に紐づくマルチシンセサイザ
txFreq_OLD = txFreq_new; // 送信周波数を更新
Freq_Disp(FREQ);
FREQ_OLD = FREQ;
freqChanged = true;
lastFreqWriteTime = now;
freqWritten = false;
eeprom_cached_FREQ = FREQ; // ★ 修正: EEPROMに書き込む予定の値を更新
}
// — バーグラフ —
if (now – previousMillis >= interval) {
previousMillis = now;
int sensorValue = analogRead(A0);
const int MIN_ADC = 190;
const int MAX_ADC = 588;
sensorValue = constrain(sensorValue, MIN_ADC, MAX_ADC);
int currentBarLength = map(sensorValue, MAX_ADC, MIN_ADC, 0, 128);
if (currentBarLength != previousBarLength) {
drawBar(currentBarLength);
previousBarLength = currentBarLength;
}
}
// — EEPROM書き込み処理 —
if (freqChanged && !freqWritten && (now – lastFreqWriteTime >= 2000)) {
unsigned long storedFreq;
EEPROM.get(EEPROM_ADDR, storedFreq);
if (storedFreq != eeprom_cached_FREQ) { // ★ 修正: 保持している値と比較
EEPROM.put(EEPROM_ADDR, eeprom_cached_FREQ); // ★ 修正: 保持している値を書き込み
}
freqWritten = true;
freqChanged = false;
}
// — キーヤー関連処理 —
updateKeyerTiming(); // WPMを常に更新し、それに伴うタイミング変数を再計算
processPaddleInput(); // パドル入力を処理 (デバウンスと状態更新)
// サイドトーン制御: TX_ONピンの状態に連動させる
if (digitalRead(TX_ON) == HIGH) { // TX_ONがHIGHの時
tone(SIDETONE_PIN, SIDETONE_FREQ);
} else { // TX_ONがLOWの時
noTone(SIDETONE_PIN);
}
// ここではbufferedSymbolを直接設定せず、ISRに任せる。
// ISRがdotPaddleState/dashPaddleStateとcurrentKeyerState/currentlySendingSymbolを見て
// 適切にbufferedSymbolを更新するロジックを持つ。
}
void drawBar(int currentBarLength) {
oled.setFont(font5x7);
if (currentBarLength > previousBarLength) {
for (int i = previousBarLength; i < currentBarLength; i++) {
oled.setCursor(i, 5);
oled.print("L");
}
} else if (currentBarLength < previousBarLength) {
for (int i = currentBarLength; i < previousBarLength; i++) {
oled.setCursor(i, 5);
oled.print(" ");
}
}
}
void Set_CLK_Enable(uint8_t clk0, uint8_t clk1, uint8_t clk2) {
uint8_t val = 0;
if (!clk0) val |= (1 << 0);
if (!clk1) val |= (1 << 1);
if (!clk2) val |= (1 << 2);
Si5351_write(OUTPUT_CTRL, val);
}
void Freq_Disp(unsigned long Fre) {
unsigned long displayFreq = Fre - IF_FREQ;
String freqt = String(displayFreq);
oled.setFont(fixednums8x16);
oled.setCursor(8, 1);
oled.print(freqt.substring(0, 1) + "." + freqt.substring(1, 4) + "." + freqt.substring(4));
}
void Step_Disp(int Stp) {
oled.setFont(font5x7);
oled.setCursor(100, 2);
oled.print((Stp == 1000) ? " 1K" : (Stp == 100) ? "100" : " 10");
}
void Si5351_write(byte Reg, byte Data) {
Wire.beginTransmission(Si5351A_ADDR);
Wire.write(Reg);
Wire.write(Data);
Wire.endTransmission();
// delayMicroseconds(10);
}
//---初期化---
void Si5351_init() {
Si5351_write(OUTPUT_CTRL, 0xFF); // All outputs disabled
Si5351_write(CLK0_CTRL, 0x80); // Power down CLK0
Si5351_write(CLK1_CTRL, 0x80); // Power down CLK1
Si5351_write(CLK2_CTRL, 0x80); // Power down CLK2
Si5351_write(XTAL_LOAD_C, 0x92); // Set crystal load capacitance
Si5351_write(PLL_RESET, 0xA0); // Reset all PLLs
Si5351_write(CLK0_CTRL, 0x4D); // CLK0: PLLA, 4mA, (RX)
Si5351_write(CLK1_CTRL, 0x6D); // CLK1: PLLB, 4mA, (TX)
Si5351_write(CLK2_CTRL, 0x6C); // CLK2: PLLB, 2mA, (使わないから何でもいい)
Si5351_write(OUTPUT_CTRL, 0xFC); // Enable CLK0 CLK1 at init
}
void PLL_Set(char pll, uint32_t freq) {
uint8_t addr = (pll == 'A') ? MSNA_ADDR : MSNB_ADDR;
uint64_t pll_freq = (uint64_t)freq * 32;
uint32_t mult = pll_freq / 25000000;
uint32_t l = pll_freq % 25000000;
uint32_t num = (uint64_t)l * 1048575 / 25000000;
uint32_t denom = 1048575;
uint32_t P1 = 128 * mult + ((128 * num) / denom) - 512;
uint32_t P2 = (128 * num) % denom;
uint32_t P3 = denom;
Parameter_write(addr, P1, P2, P3);
}
void MS_Set(uint8_t clk_no) {
uint8_t addr;
if (clk_no == 0) addr = MS0_ADDR;
else if (clk_no == 1) addr = MS1_ADDR;
else addr = MS2_ADDR;
uint32_t P1 = 128 * 32 - 512; // Divide by 32
uint32_t P2 = 0;
uint32_t P3 = 1;
Parameter_write(addr, P1, P2, P3);
}
void Parameter_write(uint8_t REG_ADDR, uint32_t Pa1, uint32_t Pa2, uint32_t Pa3) {
Si5351_write(REG_ADDR, (Pa3 >> 8) & 0xFF);
Si5351_write(REG_ADDR + 1, Pa3 & 0xFF);
Si5351_write(REG_ADDR + 2, (Pa1 >> 16) & 0x03);
Si5351_write(REG_ADDR + 3, (Pa1 >> 8) & 0xFF);
Si5351_write(REG_ADDR + 4, Pa1 & 0xFF);
Si5351_write(REG_ADDR + 5, ((Pa3 >> 12) & 0xF0) | ((Pa2 >> 16) & 0x0F));
Si5351_write(REG_ADDR + 6, (Pa2 >> 8) & 0xFF);
Si5351_write(REG_ADDR + 7, Pa2 & 0xFF);
}
// — 補助関数 (キーヤー関連) —
// Rotary encoder ISR (ISR内でmillis()は使用しない)
void rotary_encoder() {
unsigned char result = r.process();
if (result) {
FREQ += (result == DIR_CW) ? STEP : -STEP;
FREQ = constrain(FREQ, LOW_FREQ, HI_FREQ);
freqChanged = true; // millis()の呼び出しを避ける
}
}
void Fnc_Stp() {
STEP = (STEP == 10) ? 1000 : ((STEP == 1000) ? 100 : 10); // 10 -> 1000 -> 100 -> 10 の順に切り替え
delay(10);
Step_Disp(STEP);
while (digitalRead(SW_STEP) == LOW) delay(10); // ボタンが離れるまで待機
}
// WPMに基づいてキーヤーのタイミング変数を更新する関数
void updateKeyerTiming() {
int sensorValue = analogRead(SPEED_POT_PIN);
int newWpm = map(sensorValue, 0, 1023, MIN_WPM, MAX_WPM);
if (newWpm != currentWpm || lastPotValue == -1) {
currentWpm = newWpm;
if (currentWpm == 0) currentWpm = MIN_WPM;
ditTimeMs = 1200L / currentWpm;
dahTimeMs = ditTimeMs * 3;
elementSpaceTimeMs = ditTimeMs * 1;
}
lastPotValue = sensorValue;
}
// パドル入力のデバウンス処理と状態更新
void processPaddleInput() {
unsigned long now = millis();
bool currentRawDot = !digitalRead(DOT_PIN);
if (currentRawDot != rawDotState) {
lastDotReadTime = now;
rawDotState = currentRawDot;
}
if (now – lastDotReadTime > DEBOUNCE_DELAY) {
dotPaddleState = rawDotState;
}
bool currentRawDash = !digitalRead(DASH_PIN);
if (currentRawDash != rawDashState) {
lastDashReadTime = now;
rawDashState = currentRawDash;
}
if (now – lastDashReadTime > DEBOUNCE_DELAY) {
dashPaddleState = rawDashState;
}
}
// TX_ON制御を行うヘルパー関数 – ISRからも呼ばれる
void setTxOnState(bool on) {
if (on) {
digitalWrite(TX_ON, HIGH);
} else {
digitalWrite(TX_ON, LOW);
}
}
// Timer1をセットアップする関数 (1ミリ秒ごとに割り込み)
void setupTimer1() {
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << WGM12); // CTCモード
TCCR1B |= (1 << CS11); // プリスケーラを8に設定 (16MHz / 8 = 2MHz)
OCR1A = 1999; // 1ms周期 (0から1999までカウント)
TIMSK1 |= (1 << OCIE1A); // Timer1 Compare Match A 割り込みを有効化
}
// Timer1 割り込みサービスルーチン (ISR)
ISR(TIMER1_COMPA_vect) {
currentTickCount++; // 現在のON/OFF期間のティック数をインクリメント
// キーヤーの現在の状態とパドル入力に基づいて次に送る符号を決定
// manualTxSwitchPressed が優先されるため、ここではキーヤーの符号決定に集中
BufferedSymbol nextSymbolFromKeyerInput = NONE_BUFFERED;
// バッファが空の場合、リアルタイム入力を確認
if (bufferedSymbol == NONE_BUFFERED) {
if (dotPaddleState) {
nextSymbolFromKeyerInput = DOT_BUFFERED;
} else if (dashPaddleState) {
nextSymbolFromKeyerInput = DASH_BUFFERED;
}
} else {
// バッファに符号がある場合はそれを優先
nextSymbolFromKeyerInput = bufferedSymbol;
}
switch (currentKeyerState) {
case KEYER_IDLE:
currentlySendingSymbol = NONE_SENDING; // IDLEなので送出符号なし
// アイドル時は manualTxSwitchPressed またはキーヤーの符号入力があればTX_ONをHIGHにする
if (manualTxSwitchPressed || nextSymbolFromKeyerInput != NONE_BUFFERED) {
setTxOnState(true); // TX_ONをHIGHにする
// キーヤーが符号を送出する場合のみ、状態を遷移
if (nextSymbolFromKeyerInput != NONE_BUFFERED) {
currentTickCount = 0; // ティックカウントをリセット
currentKeyerState = KEYER_SENDING_ON;
// 次に送出すべきON期間のティック数を設定
if (nextSymbolFromKeyerInput == DOT_BUFFERED) {
requiredTicks = ditTimeMs;
currentlySendingSymbol = DOT_SENDING;
} else if (nextSymbolFromKeyerInput == DASH_BUFFERED) {
requiredTicks = dahTimeMs;
currentlySendingSymbol = DASH_SENDING;
}
bufferedSymbol = NONE_BUFFERED; // 送出を開始したらバッファをクリア
}
} else {
setTxOnState(false); // 送信要求がなければTX_ONをLOWにする
}
break;
case KEYER_SENDING_ON:
// ON期間が終了したら、OFF期間へ移行
if (currentTickCount >= requiredTicks) {
setTxOnState(false); // TX_ONをLOWにする
currentTickCount = 0; // ティックカウントをリセット
currentKeyerState = KEYER_SENDING_OFF;
requiredTicks = elementSpaceTimeMs; // 符号間スペース
// 先打ちロジック: 現在送出中の符号と異なるパドルが押されたらバッファ
if (currentlySendingSymbol == DOT_SENDING && dashPaddleState && !dotPaddleState) {
bufferedSymbol = DASH_BUFFERED;
} else if (currentlySendingSymbol == DASH_SENDING && dotPaddleState && !dashPaddleState) {
bufferedSymbol = DOT_BUFFERED;
}
}
break;
case KEYER_SENDING_OFF:
// OFF期間(符号素間スペース)が終了したら
if (currentTickCount >= requiredTicks) {
// 次に送出する符号があれば、そのON期間を開始
if (nextSymbolFromKeyerInput != NONE_BUFFERED) { // bufferedSymbolに加えてリアルタイム入力も考慮
setTxOnState(true); // TX_ONをHIGHにする
currentTickCount = 0; // ティックカウントをリセット
currentKeyerState = KEYER_SENDING_ON;
// 次に送出すべきON期間のティック数を設定
if (nextSymbolFromKeyerInput == DOT_BUFFERED) {
requiredTicks = ditTimeMs;
currentlySendingSymbol = DOT_SENDING;
} else if (nextSymbolFromKeyerInput == DASH_BUFFERED) {
requiredTicks = dahTimeMs;
currentlySendingSymbol = DASH_SENDING;
}
bufferedSymbol = NONE_BUFFERED; // 送出を開始したらバッファをクリア
} else if (manualTxSwitchPressed) {
// キーヤーからの符号入力がなくても、手動電鍵が押されていればTXを維持
setTxOnState(true);
currentlySendingSymbol = NONE_SENDING; // キーヤーは符号を出していない
currentKeyerState = KEYER_IDLE; // キーヤー自体はアイドル状態に戻す
}
else {
// バッファもリアルタイム入力もなければ、IDLE状態に戻る
currentlySendingSymbol = NONE_SENDING;
currentKeyerState = KEYER_IDLE;
bufferedSymbol = NONE_BUFFERED; // IDLEに戻る際もバッファをクリア
}
}
break;
}
}
コメント