/* === 2024/10/08 itc24 === Arduino UNO 用のFuse設定(Low:0xff, High:0xde, Ext:0xfd)コマンドを追加 */ /* === 2024/10/05 itc24 === Chip Eraser に動作モード(自動モード/手動モード)を選択できるようにする 基盤上の切替SWでAuto/Manualを指定 ・Arduino UNO の電源ON時(USBに接続時)に切替SWの状態をチェック ・Manualの場合、これまでの動作と同じ ・Autoの場合、ターゲットチップの初期化を次の手順で行う 1. 処理開始の表示 (LEDの長い点灯[約 0.8秒]を1回行う) 2. Chip ID の確認 (ATmega328P以外はエラー #1) 3. 初期化前のヒューズ確認 4. Erase処理 5. Fuse bit 初期化 (Low, High, Extend) 6. Lock bit 初期化 7. Fuse bit / Lock bit 読込み (書込値と異なる場合はエラー) Low byte が異なる: エラー #2 High byte が異なる: エラー #3 Ext byte が異なる: エラー #4 Lock Bit が異なる: エラー #5 8. 処理結果をモールス信号的に表示 正常終了:LEDの長い点灯[約 0.8秒]を2回。約2秒休み、同じ点灯を繰り返す エラー時:エラー番号の回数の短い点灯[約 0.2秒]を行い、約2秒休み、同じ点灯を繰り返す */ /* === 2024/09/25 itc24 === Chip Eraser回路の電源チェックコマンドを追加 #1: [D7] VCC-ON:5V #2: [D13]RST-ON:12V #3: [D7] VCC-ON:5V, [D13]RS-ON:12V */ /* === 2024/09/23 itc24 === 参考記事: ラジオペンチさんの「ATmega328P用のヒューズリセッターの製作」 http://radiopench.blog96.fc2.com/blog-entry-563.html 参考資料(下記PDFの184頁〜): http://aitendo3.sakura.ne.jp/aitendo_data/product_img/microcontroller/Colorduino/ATmega328P.pdf 備考: ここで定義されている RST(D13ピン)で、ターゲットChipに供給する12VラインのOn/Off制御をトランジスタを介して行う。 RST=High にすると、トランジスタはOn になり、ターゲットChipの12VラインはGndレベルになる。 RST=Low にすると、トランジスタはOffになり、ターゲットChipの12Vラインは12Vになる。 なお、プログラムは一部変更している。 */ /* ATmega328P チップイレーサー 高電圧書き込みでチップの初期化を実行。 このプログラムは、まりすさんの下記の記事に掲載のプログラム にごく一部の修正を行ったものです。 http://100year.cocolog-nifty.com/blog/2014/05/atmega488816832.html 2015/4/19 ラジオペンチ http://radiopench.blog96.fc2.com/ */ /* EZ_HVFuse written by @maris_HY 2014/05/20 */ /* Original program ideas http://mightyohm.com/blog/2008/09/arduino-based-avr-high-voltage-programmer/ HVFuse.pde HVFuse - Use High Voltage Programming Mode to Set Fuses on ATmega48/88/168 09/23/08 Jeff Keyzer http://mightyohm.com The HV programming routines are based on those described in the ATmega48/88/168 datasheet 2545M-AVR-09/07, pg. 290-297 This program should work for other members of the AVR family, but has only been verified to work with the ATmega168. If it works for you, please let me know! http://mightyohm.com/blog/contact/ */ // Pin Assignments #define VCC 7 // target VCC control #define WR A0 // Analog inputs 0-5 can be addressed as digital pin #define BS1 A1 #define XTAL1 A2 #define XA0 A3 #define XA1 A4 #define DATA0 A5 #define DATA1 2 #define DATA2 3 #define DATA3 4 #define DATA4 5 #define DATA5 6 #define DATA6 8 #define DATA7 9 #define BS2 10 #define OE 11 #define RDYBSY 12 #define RST 13 #define LFUSE 0 #define HFUSE 1 #define EFUSE 2 #define LOCKB 3 #define CHIPERASE B10000000 #define WRITEFUSE B01000000 #define WRITELOCK B00100000 #define READSIG B00001000 #define READFUSE B00000100 const byte data_pin[8] = {DATA0, DATA1, DATA2, DATA3, DATA4, DATA5, DATA6, DATA7}; const char * fuseName[] = {"Low Fuse Bits", "High Fuse Bits", "Ext Fuse Bits", "Lock Bits"}; byte fuseValue_UNO[4] = {0xFF,0xDE,0xFD,0xFF}; // Arduino UNO 標準パターン // 乾電池2本での省電力運用を前提とする byte fuseValue[4] = {0x42,0xDE,0xFE,0xFF}; // Clock:1MHz(内臓8MHzを8分周); Brown-out:1.8V byte chipId = 255; long signature=0; // chipSpec_t *chip; // --- Auto/Manual Mode (2024/10/05) --- #define SW_AM 1 // D1(Tx)端子で AutoMode / ManualMode 切替SWの状態を読む int IsAutoMode = 0; // 0:Manual Mode , 1:Auto Mode int AM_ErrNo = 0; // 0:No Err , ≠0:Err No const int LED_PIN = 10; // 自動初期化の処理結果をLED点滅で表現 ([BS2]端子と共有) long signature_ATmega328P = 0x1E950F; // ATmega328Pのsignature const unsigned long MORSE_BASE_TIME = 150; // 短符の基本時間 150 mSec const int SL_RATE = 5; // 短符と長符の時間長比率 // モールス信号(A-Z, 0-9, 記号[. , ? - / @], SPACE) const char * MorseCode[] = {"SL", "LSSS", "LSLS", "LSS", "S", "SSLS", "LLS", "SSSS", "SS", "SLLL", "LSL", "SLSS", "LL", "LS", "LLL", "SLLS", "LLSL", "SLS", "SSS", "L", "SSL", "SSSL", "SLL", "LSSL", "LSLL", "LLSS", "LLLLL", "SLLLL", "SSLLL", "SSSLL", "SSSSL", "SSSSS", "LSSSS", "LLSSS", "LLLSS", "LLLLS", "SLSLSL", "LLSSLL", "SSLLSS", "LSSSSL", "LSSLS", "SLLSLS", "4"}; unsigned long scanTask_Cnt = 0; // scanTaskの実行回数 // --- Auto/Manual Mode (end) --- void setup() // run once, when the sketch starts { byte data; // 基盤上の切替SW(Auto/Manual)の状態を読む (2024/10/05) // D1端子は、この後シリアル通信で使うTx端子となるので、起動時の1回のみSW読込用に使用する pinMode(SW_AM, INPUT); delay(1); if (digitalRead(SW_AM) == HIGH) { IsAutoMode = 1; } pinMode(RST, OUTPUT); // digitalWrite(VCC, HIGH); -- 2024/09/23 記載ミスと思われるので変更 digitalWrite(RST, HIGH); pinMode(VCC, OUTPUT); digitalWrite(VCC, LOW); Serial.begin(9600); for(byte i=0;i<3;i++){ Serial.println(); } Serial.println(F("..............................")); Serial.println(F("EZ HV Fuse")); Serial.println(F(" for ATmega328P")); Serial.println(); // シグネチャー確認はしない。信号はstandby状態にする standby(); /* Serial.println(F("Type D and Enter Key to Detect a chip.")); Serial.println(); while(1){ while(Serial.available() == 0); data = Serial.read(); if((data == 'D') || (data == 'd')) break; } standby(); ditectChip(); // チップのシグネチャー確認 Serial.println(); */ } void loop() // run over and over again { byte cmd; standby(); // --- Auto Mode (2024/10/05) --- if (IsAutoMode == 1) { AutoMode(); } displayCommandList(); cmd = input1byteCmd(); switch (cmd) { // Chip Eraser回路の電源チェック -- start -- case '1': digitalWrite(VCC, HIGH); // #1: [D7] VCC-ON:5V askChecked(); break; case '2': digitalWrite(RST, LOW); // #2: [D13]RST-ON:12V askChecked(); break; case '3': digitalWrite(VCC, HIGH); // #3: [D7] VCC-ON:5V, [D13]RS-ON:12V digitalWrite(RST, LOW); askChecked(); break; // Chip Eraser回路の電源チェック -- end -- case 'C': case 'c': askChipErase(); break; case 'W': case 'w': askWriteDefaultFuse(); case 'R': case 'r': displayFuse(); break; case 'S': case 's': displaySignature(); break; case 'H': case 'h': askWriteFuse(HFUSE); break; case 'L': case 'l': askWriteFuse(LFUSE); break; case 'E': case 'e': askWriteFuse(EFUSE); break; case 'K': case 'k': askWriteLockBits(); break; case 'D': case 'd': ditectChip(); break; // Arduino UNO Fuse Value設定 (2024/10/08) case 'A': case 'a': askWriteDefaultFuse_UNO(); displayFuse(); break; } Serial.println(); } void displayCommandList(){ // Serial.println(F("Target Chip:ATmega328P")); // printTarget(); // Serial.println(); // Chip Eraser回路の電源チェック /* 変更 (2024/10/08) Serial.println(F("1:[D7] VCC-ON:5V")); Serial.println(F("2:[D13]RST-ON:12V")); Serial.println(F("3:[D7] VCC-ON:5V, [D13]RST-ON:12V")); */ Serial.println(F("1:vcc(5v)-on 2:rst(12v)-on 3:vcc(5v)-on, rst(12v)-on")); Serial.println(F("A:write Arduino uno fuse value. (low:FF, high:DE, ext:FD)")); Serial.println(F("D:Detect chip.")); Serial.print(F("W:Write default fuse value. [for battery operation] (low:")); printHEX(fuseValue[LFUSE]); Serial.print(F(" high:")); printHEX(fuseValue[HFUSE]); Serial.print(F(" ext:")); printHEX(fuseValue[EFUSE]); Serial.println(F(" )")); Serial.println(F("R:Read fuse bytes.")); Serial.println(F("C:Chip erase.")); Serial.println(F("S:read Signature bytes.")); Serial.println(F("L: H: E: input fuse value and write it.")); Serial.println(F("K:input locK bits value and write it.")); Serial.println(); Serial.print(F("Type Command and Enter.")); Serial.println(); } void standby(){ digitalWrite(RST, HIGH); digitalWrite(VCC, LOW); pinMode(WR, INPUT); pinMode(OE, INPUT); pinMode(BS1, INPUT); pinMode(BS2, INPUT); pinMode(XTAL1, INPUT); pinMode(XA0, INPUT); pinMode(XA1, INPUT); setDataPinInput(); } void init_pins(){ digitalWrite(VCC, HIGH); // Apply VCC to start programming process pinMode(WR, OUTPUT); digitalWrite(WR, HIGH); pinMode(OE, OUTPUT); digitalWrite(OE, HIGH); pinMode(BS1, OUTPUT); pinMode(BS2, OUTPUT); pinMode(XTAL1, OUTPUT); pinMode(XA0, OUTPUT); pinMode(XA1, OUTPUT); digitalWrite(BS1, LOW); digitalWrite(BS2, LOW); digitalWrite(XTAL1, LOW); digitalWrite(XA0, LOW); digitalWrite(XA1, LOW); setDataPinOutput(); digitalWrite(RST, LOW); delay(100); } // Power Check 任意文字 + Enter でOK void askChecked() { byte ans; flushSerial(); Serial.println(F("Power checked then enter (Y)")); ans = input1byteCmd(); } void askChipErase() { byte ans; flushSerial(); Serial.println(F("The chip will be erased. Are you sure? (Y/N)")); ans = input1byteCmd(); switch(ans) { case 'Y': case 'y': chipErase(); Serial.println(F("Chip was erased!")); break; } } void askWriteDefaultFuse() { byte ans; flushSerial(); Serial.println(F("Default values will be written to fuses. Are you sure? (Y/N)")); ans = input1byteCmd(); switch(ans) { case 'Y': case 'y': Serial.println(F("Now writeing Fuse!")); for(int i = 0;i<3;i++){ writefuse(i, fuseValue[i]); } Serial.println(F("Finish!")); } } // Arduino UNO 用Fuse設定 (2024/10/08) void askWriteDefaultFuse_UNO() { byte ans; flushSerial(); Serial.println(F("Arduino UNO Default values will be written to fuses. Are you sure? (Y/N)")); ans = input1byteCmd(); switch(ans) { case 'Y': case 'y': Serial.println(F("Now writeing Fuse!")); for(int i = 0; i<3 ; i++){ writefuse(i, fuseValue_UNO[i]); } Serial.println(F("Finish!")); } } void askWriteLockBits() { byte ans; byte value; Serial.println(F("Input Lock bits value.")); flushSerial(); value = inputHEX(); Serial.println(); Serial.println(F("Lock bits can only be cleared by executing Chip Erase.")); Serial.println(F("Lock bits will be written. Are you sure? (Y/N)")); flushSerial(); ans = input1byteCmd(); switch(ans) { case 'Y': case 'y': Serial.println(F("Now writeing lock bits!")); writeLockBits(value); Serial.println(F("Finish!")); } } void displayFuse() { for(int i = 0;i<4;i++){ Serial.print(fuseName[i]); Serial.write(':'); printHEX(readfuse(i)); Serial.println(); } } void displaySignature() { int i; signature = 0; // init_pins(); -- 2024/09/23 readSignature関数内で、都度 init_pins を行うので不要 for(i = 0;i<3;i++){ signature = (signature << 8 )+ readSignature(i); } Serial.print(F("Signature:")); Serial.println(signature,HEX); } void ditectChip(){ // チップの検出 displaySignature(); // シグネチャを読み出し if( signature==0x1E950F){ // ATmega328Pのものと一致していたら Serial.println("Chip=ATmega328P"); // 表示を出す } else{ // 違っていたら Serial.println("Un known CHIP!"); // 2024/09/25 メニューに戻る /* while(1){ } // 無限ループで停止 */ } } void askWriteFuse(byte fuse) { byte ans; byte value; Serial.print(F("Input ")); Serial.print(fuseName[fuse]); Serial.println(F(" value")); flushSerial(); value = inputHEX(); Serial.println(); Serial.print(fuseName[fuse]); Serial.print(F(" will be written ")); printHEX(value); Serial.println(F(". Are you sure? (Y/N)")); flushSerial(); ans = input1byteCmd(); switch(ans) { case 'Y': case 'y': Serial.println(F("Now writeing Fuse!")); writefuse(fuse, value); Serial.println(F("Finish!")); } } // high level functions void chipErase() // チップイレース { init_pins(); delay(1); setDataPinOutput(); loadCommand(CHIPERASE); // Send command to read signature. wrPulse(); while(digitalRead(RDYBSY)==LOW); delay(1); } void writefuse(byte targetFuse, byte fuseValue) // write high or low fuse to AVR { init_pins(); delay(1); setDataPinOutput(); loadCommand(WRITEFUSE); // Send command to enable fuse programming mode loadDataLowByte(fuseValue); // Send fuse data. switch (targetFuse) { case LFUSE: digitalWrite(BS1, LOW); digitalWrite(BS2, LOW); break; case HFUSE: digitalWrite(BS1, HIGH); digitalWrite(BS2, LOW); break; case EFUSE: digitalWrite(BS1, LOW); digitalWrite(BS2, HIGH); break; } wrPulse(); while(digitalRead(RDYBSY)==LOW); delay(1); } void writeLockBits(byte value) { init_pins(); delay(1); setDataPinOutput(); loadCommand(WRITELOCK); // Send command to enable fuse programming mode loadDataLowByte(value); // Send fuse data. wrPulse(); while(digitalRead(RDYBSY)==LOW); delay(1); } byte readfuse(byte targetFuse) { byte data = 0; init_pins(); delay(1); setDataPinOutput(); loadCommand(READFUSE); // Send command to read fuse mode. setDataPinInput(); delay(1); digitalWrite(OE, LOW); switch (targetFuse) { case LFUSE: digitalWrite(BS1, LOW); digitalWrite(BS2, LOW); break; case HFUSE: digitalWrite(BS1, HIGH); digitalWrite(BS2, HIGH); break; case EFUSE: digitalWrite(BS1, LOW); digitalWrite(BS2, HIGH); break; case LOCKB: digitalWrite(BS1, HIGH); digitalWrite(BS2, LOW); break; } delay(1); data = getData(); digitalWrite(OE, HIGH); delay(1); return data; } byte readSignature(byte address) // シグネチャの読み出し { byte data = 0; init_pins(); delay(1); setDataPinOutput(); loadCommand(READSIG); // Send command to read signature. loadAddressLowByte(address); // Send command to read signature. setDataPinInput(); delay(1); digitalWrite(OE, LOW); digitalWrite(BS1, LOW); delay(1); data = getData(); digitalWrite(OE, HIGH); delay(1); return data; } /////////////////////////////////////// // middle layer functions void loadCommand(byte command) // A { setDataPinOutput(); digitalWrite(XA1, HIGH); digitalWrite(XA0, LOW); digitalWrite(BS1, LOW); setData(command); xtal1Pulse(); } void loadAddressLowByte(byte adress) // B { digitalWrite(XA1, LOW); digitalWrite(XA0, LOW); digitalWrite(BS1, LOW); setData(adress); xtal1Pulse(); } void loadDataLowByte(byte data) // C { digitalWrite(XA1, LOW); digitalWrite(XA0, HIGH); setData(data); xtal1Pulse(); } /////////////////////////////////////// // Low layer functions void setDataPinInput(){ for(byte i=0;i<8;i++){ pinMode(data_pin[i],INPUT); } } void setDataPinOutput(){ for(byte i=0;i<8;i++){ pinMode(data_pin[i],OUTPUT); digitalWrite(data_pin[i],LOW); } } void xtal1Pulse() { digitalWrite(XTAL1, HIGH); // positive pulse XTAL1 delay(1); digitalWrite(XTAL1, LOW); } void wrPulse() { delay(1); digitalWrite(WR, LOW); // negative pulse WR delay(1); digitalWrite(WR, HIGH); } void setData(byte data){ byte mask = 1; for(byte i=0;i<8;i++){ if(data & mask){ digitalWrite(data_pin[i],HIGH); } else { digitalWrite(data_pin[i],LOW); } mask = mask << 1; } } byte getData(){ byte data = 0; byte mask = 1; for(byte i=0;i<8;i++){ if(digitalRead(data_pin[i]) == HIGH){ data = data + mask; } mask = mask << 1; } return data; } void printHEX(byte data){ if(data < 16){ Serial.print("0"); } Serial.print(data,HEX); } byte input1byteCmd(){ byte data; flushSerial(); Serial.print(">"); while(1){ while(Serial.available() == 0); data = Serial.read(); // if(((data >= 'A') && (data <='Z')) || ((data >= 'a') && (data <='z'))){ if(((data >= 'A') && (data <='Z')) || ((data >= 'a') && (data <='z')) || ((data >= '0') && (data <='9')) ){ Serial.write(data); Serial.println(); break; } } return data; } int inputHEX(){ int i=0; int data; Serial.print(F(">")); while(1){ while(Serial.available() == 0); data = Serial.read(); if((data >= '0') && (data <= '9')){ Serial.write(data); i = i * 16 + (data - '0'); } else if((data >= 'A') && (data <= 'F')){ Serial.write(data); i = i * 16 + (data - 'A') + 10; } else if((data >= 'a') && (data <= 'f')){ Serial.write(data); i = i * 16 + (data - 'a') + 10; } else if((data == 0x0d) || (data == 0x0a)){ break; } } return i; } void flushSerial() { delay(10); while(Serial.available() > 0){ byte data = Serial.read(); delay(10); } } /* void printTarget(){ char c; char *f = chip->chipName; while(1){ c = pgm_read_byte(f); if(c == NULL) break; Serial.write(c); f++; } Serial.println(); } */ /* --- Auto Mode (2024/10/05) --- ・Autoの場合、ターゲットチップの初期化を次の手順で行う 1. 処理開始の表示 (LEDの長い点灯[約 0.8秒]を1回行う) 2. Chip ID の確認 (ATmega328P以外はエラー #1) 3. 初期化前のヒューズ確認 4. Erase処理 5. Fuse bit 初期化 (Low, High, Extend) 6. Lock bit 初期化 7. Fuse bit / Lock bit 読込み (書込値と異なる場合はエラー) Low byte が異なる: エラー #2 High byte が異なる: エラー #3 Ext byte が異なる: エラー #4 Lock Bit が異なる: エラー #5 8. 処理結果をモールス信号的に表示 正常終了:LEDの長い点灯[約 0.8秒]を2回。約2秒休み、同じ点灯を繰り返す エラー時:エラー番号の回数の短い点灯[約 0.2秒]を行い、約2秒休み、同じ点灯を繰り返す */ void AutoMode(void) { byte fuseData[4] = {0, 0, 0, 0}; // LowByte, HighByte, Extend, Lock byte fuseMask[4] = {0xff, 0xff, 0x07, 0x3f}; // fuseDataの有効ビット const char * AM_ErrCD[] = {"LL", "S", "SS", "SSS", "SSSS", "SSSSS"}; // エラー番号に応じた点滅 const char * AM_SOS = "SOS"; // 想定外のエラー AM_ErrNo = 0; // AutoMode処理でのエラー番号 initLED(); Serial.println(F("--- AutoMode ---")); while(1) { // 1. 処理開始の表示 (長い点灯[約 0.8秒]を1回行う) mc_SLR("L9"); // L:長符 , 9:9単位の休符 Serial.println(F("1. start")); // 2. Chip ID の確認 (ATmega328P以外はエラー #1) getChipSignature(); Serial.print(F("2. Check Chip Signature : ")); Serial.print(signature, HEX); if( signature == signature_ATmega328P) { Serial.println(F(" ==> OK")); } else { AM_ErrNo = 1; // ATmega328Pのものと異なる Serial.println(F(" ==> NG")); } // 3. 初期化前のヒューズ確認 Fuse bit / Lock bit if (AM_ErrNo == 0) { Serial.println(F("3. Current FuseByte / LockBit")); for(int i = 0; i < 4 ; i++) { fuseData[i] = readfuse(i); Serial.print(F(" ")); Serial.print(fuseName[i]); Serial.print(F(" : ")); Serial.println(fuseData[i], HEX); } } // 4. Erase処理 if (AM_ErrNo == 0) { chipErase(); Serial.println(F("4. Erase")); } // 5. Fuse bit 初期化 (Low, High, Extend) if (AM_ErrNo == 0) { for(int i = 0; i < 3; i++){ writefuse(i, fuseValue[i]); } Serial.println(F("5. Init Fuse Byte")); } // 6. Lock bit 初期化 if (AM_ErrNo == 0) { writeLockBits(fuseValue[3]); Serial.println(F("6. Init Lock Bit")); } // 7. Fuse bit / Lock bit 読込み (書込値と異なる場合はエラー) if (AM_ErrNo == 0) { Serial.println(F("7. Read FuseByte / LockBit")); for(int i = 0; i < 4 ; i++) { fuseData[i] = readfuse(i); Serial.print(F(" ")); Serial.print(fuseName[i]); Serial.print(F(" : ")); Serial.print(fuseData[i], HEX); if ((fuseData[i] & fuseMask[i]) == (fuseValue[i] & fuseMask[i])) { Serial.println(F(" ==> OK")); } else { Serial.println(F(" ==> NG")); AM_ErrNo = i + 2; break; } } } // 8. 処理結果を表示 if (AM_ErrNo == 0) { Serial.println(F("Chip Erase Complete.")); } else { Serial.print(F("Error No=")); Serial.println(AM_ErrNo); } // 処理結果をモールス信号的に表示(LED点滅を繰り返す) while (1) { if ((AM_ErrNo >= 0) && (AM_ErrNo <= 5)) { mc_SLR(AM_ErrCD[AM_ErrNo]); // 処理結果に応じてLEDを点滅 mc_SLR("94"); // 9単位 + 4単位 ⇒ 13単位(約2秒)の休符 } else { // 想定外のエラー mc(AM_SOS); // モールス信号で SOS を発信 mc_SLR("94"); // 9単位 + 4単位 ⇒ 13単位(約2秒)の休符 } } } } // Chip Signature void getChipSignature() { signature = 0; for(int i=0; i<3; i++){ signature = (signature << 8 ) + readSignature(i); } } // LEDピン端子の初期化 void initLED(void) { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); } // 短時間で処理が完了するタスク void scanTask(void) { // MORSE_BASE_TIME 以内で完了すること scanTask_Cnt++; int s = task1(1, 100); // Dummy Task } // task1 (Dummy) int task1(int frmNo, int toNo) { int i; int s; s = 0; for (i=frmNo; i<=toNo; i++) { s += i; } return s; } // モールス信号の基本時間待つ (t: 1〜9) void wait_mbt(uint8_t t) { if ((t >= 1) && (t <= 9)) { unsigned long pre_milli = millis(); while(1) { if (millis() - pre_milli >= MORSE_BASE_TIME * t) { break; } else { scanTask(); // 他の短時間のタスクを実行 } } } } // モールス信号をOFFにする void mc_off(int t) { digitalWrite(LED_PIN, LOW); wait_mbt(t); } // モールス信号をONにする void mc_on(int t) { digitalWrite(LED_PIN, HIGH); wait_mbt(t); mc_off(1); } // モールス信号の短符を発信 void mc_short() { mc_on(1); } // モールス信号の長符を発信 void mc_long() { mc_on(SL_RATE); } // モールス信号(文字列を発信) void mc(char * str) { int i; i = 0; while (str[i]) { // NULL文字の前まで1文字単位で発信 mc_cha(str[i]); i++; } } // モールス信号(短符[S]・長符[L]・休符(n)を発信) void mc_SLR(char * str) { int i; i = 0; while (str[i]) { if ((str[i] == 'S') || (str[i] == 's')) { mc_short(); } else if ((str[i] == 'L') || (str[i] == "l")) { mc_long(); } else if ((str[i] >= '1') && (str[i] <= '9')) { int rest; rest = str[i] - '0'; mc_off(rest); } i++; } } // モールス信号(1文字を発信) void mc_cha(char c) { int ix = -1; if ((c >= 'A') && (c <= 'Z')) { ix = c - 'A'; } else if ((c >= 'a') && (c <= 'z')) { ix = c - 'a'; } else if ((c >= '0') && (c <= '9')) { ix = c - '0' + 26; } else if (c == '.') { ix = 36; } else if (c == ',') { ix = 37; } else if (c == '?') { ix = 38; } else if (c == '-') { ix = 39; } else if (c == '/') { ix = 40; } else if (c == '@') { ix = 41; } else if (c == ' ') { ix = 42; } if ((ix >= 0) && (ix <= 42)) { mc_SLR(MorseCode[ix]); // 空白以外の文字の場合、文字間の休符を長符の長さでとる // 但し、直前の短符または長符の1単位の休符を差し引く if (c != ' ') { mc_off(SL_RATE - 1); } } }