/* LEDバッジ(クリスマスツリーイルミネーション) 低消費電流タイプ(delayWDT2使用) CPUのプルアップ抵抗を使って17個のLEDを点灯 8MHz内部CRオシレーター 2018/08/01 ラジオペンチ http://radiopench.blog96.fc2.com/ */ #include // スリープモードを使用 #include // ウォッチドッグタイマーを使用 unsigned long data = 0; int i, n; void setup() { allOn1000(); // 開始表示 } // pinModeを指定していないので全部inputになる void loop() { // メインループ for (int j = 0; j < 392; j++) { // 約6時間実行 (1サイクル55秒×392回=6時間) allOn1000(); // ループ開始表示 singleR(1); // 単発右回転 singleL(1); // 単発左回転 waveR(1); // ウェ−ブ右回転 waveL(1); // ウェーブ左回転 x_rotate(2); // 単発左右同時 allOn5000(); Vcross(2); // 逆Vクロス Hline(2); VrotateR(3); // 縦線右移動 fullRotateR(3); // 横ワイプ右 VrotateL(3); // 縦線左移動 fullRotateL(3); // 横ワイプ左 wipeUpDown(2); // 縦上昇/降下 randomFlash(75); // ランダム点灯 } timeUp(); // 指定時間終了後は停止中表示(センターLEDフラッシュ) } void allOn1000() { led(0); // 一旦消灯 delayWDT2(5); // 0.5秒 led(0x1FFFF); // 全点灯 delayWDT2(6); led(0); delayWDT2(4); // 256ms } void allOn5000() { led(0); // 一旦消灯 delayWDT2(5); // 0.5秒 led(0x1FFFF); // 全点灯 delayWDT2(8); // 4秒 delayWDT2(6); // 1秒 led(0); delayWDT2(5); // 0.5秒 } void singleR(int count) { // 1灯単発右回転点灯 for (i = 1; i <= count; i++) { data = 0x01; // タネを仕込む for (n = 0; n <= 18; n++) { // タネが外に外れるまで実行 led(data); // LED表示 data = data << 1; // 左にシフト delayWDT2(2); // 64ms } delayWDT2(3); // 128ms } } void singleL(int count) { // 1灯左回転点灯 for (i = 1; i <= count; i++) { data = 0x10000; // タネを仕込む for (n = 0; n <= 18; n++) { // タネが外に外れるまで実行 led(data); // ビットパターンを表示 data = data >> 1; // 右にシフト delayWDT2(2); // 64ms } delayWDT2(3); // 128ms } } void waveR(int count) { // 波のように表示(右回り) for (i = 1; i <= count; i++) { for (n = 0; n <= 16; n++) { data |= 0x01; // 最下位に1ビット追加 led(data); // LED表示 data = data << 1; // 左にシフト delayWDT2(2); // 64ms } for (n = 0; n <= 16; n++) { data = data & 0x1FFFE; // 下位ビットを消す led(data); // LED表示 data = data << 1; // 左にシフト delayWDT2(2); // 64ms } } } void waveL(int count) { // 波のように表示(左周り) for (i = 1; i <= count; i++) { for (n = 0; n <= 16; n++) { data |= 0x10000; // 最上位1ビット追加 led(data); // LED表示 data = data >> 1; // 右にシフト delayWDT2(2); // 64ms } for (n = 0; n <= 16; n++) { data = data & 0x0FFF; // 右端のビットを消す led(data); // LED表示 data = data >> 1; // 右にシフト delayWDT2(2); // 64ms } } } void x_rotate(int count) { // 左右同時回転 unsigned long a, b; for (i = 1; i <= count; i++) { a = 0x00001; // 下側のタネ b = 0x10000; // 上側のタネ for (n = 0; n <= 17; n++) { data = a | b; // 上下のタネを合成して、 led(data); // 表示 a = a << 1; // 下のタネを左シフト b = b >> 1; // 上のタネを右シフト delayWDT2(2); // 64ms; } } } void Vcross(int count) { for (i = 1; i <= count; i++) { led(0b00000000000000001); delayWDT2(2); // 64ms led(0b00000000000000101); delayWDT2(2); // 64ms led(0b00000000000010101); delayWDT2(2); // 64ms led(0b00000000001010101); delayWDT2(2); // 64ms led(0b00000000101010101); delayWDT2(2); // 64ms センター (点灯) led(0b00000001101010101); delayWDT2(2); // 64ms led(0b00000101101010101); delayWDT2(2); // 648ms led(0b00010101101010101); delayWDT2(2); // 64ms led(0b01010101101010101); delayWDT2(2); // 64ms led(0b11010101101010101); delayWDT2(2); // 64ms led(0b11110101101010101); delayWDT2(2); // 64ms led(0b11111101101010101); delayWDT2(2); // 64ms led(0b11111111101010101); delayWDT2(2); // 64ms led(0b11111111101010101); delayWDT2(2); // 64ms センター led(0b11111111111010101); delayWDT2(2); // 64ms led(0b11111111111110101); delayWDT2(2); // 64ms led(0b11111111111111101); delayWDT2(2); // 64ms led(0b11111111111111111); delayWDT2(2); // 64ms led(0b11111111111111110); delayWDT2(2); // 64ms led(0b11111111111111010); delayWDT2(2); // 64ms led(0b11111111111101010); delayWDT2(2); // 64ms led(0b11111111110101010); delayWDT2(2); // 64ms led(0b11111111110101010); delayWDT2(2); // 64ms センター led(0b11111110110101010); delayWDT2(2); // 64ms led(0b11111010110101010); delayWDT2(2); // 64ms led(0b11101010110101010); delayWDT2(2); // 64ms led(0b10101010110101010); delayWDT2(2); // 64ms led(0b00101010110101010); delayWDT2(2); // 64ms led(0b00001010110101010); delayWDT2(2); // 64ms led(0b00000010110101010); delayWDT2(2); // 64ms led(0b00000000110101010); delayWDT2(2); // 64ms led(0b00000000010101010); delayWDT2(2); // 64ms センター(消灯) led(0b00000000000101010); delayWDT2(2); // 64ms led(0b00000000000001010); delayWDT2(2); // 64ms led(0b00000000000000010); delayWDT2(2); // 64ms led(0b00000000000000000); delayWDT2(2); // 64ms } } void Hline(int count) { // 水平線 for (i = 1; i <= count; i++) { led(0b00000000000000000); delayWDT2(2); // 64ms led(0b00000000000000010); delayWDT2(2); // 64ms led(0b00000000000000001); delayWDT2(2); // 64ms led(0b10000000000000000); delayWDT2(2); // 64ms led(0b01000000000000000); delayWDT2(2); // 64ms led(0b00000000000000000); delayWDT2(2); // 64ms led(0b00000000000001000); delayWDT2(2); // 64ms led(0b00000000000000100); delayWDT2(2); // 64ms led(0b00100000000000000); delayWDT2(2); // 64ms led(0b00010000000000000); delayWDT2(2); // 64ms led(0b00000000000000000); delayWDT2(2); // 64ms led(0b00000000000100000); delayWDT2(2); // 64ms led(0b00000000000010000); delayWDT2(2); // 64ms led(0b00001000000000000); delayWDT2(2); // 64ms led(0b00000100000000000); delayWDT2(2); // 64ms led(0b00000000000000000); delayWDT2(2); // 64ms led(0b00000000010000000); delayWDT2(2); // 64ms led(0b00000000001000000); delayWDT2(2); // 64ms led(0b00000010000000000); delayWDT2(2); // 64ms led(0b00000001000000000); delayWDT2(2); // 64ms led(0b00000000100000000); delayWDT2(3); // 128ms センター (点灯) } } void VrotateR(int count) { // 縦線右移動 for (i = 1; i <= count; i++) { led(0b00000000110101010); delayWDT2(3); // 128ms led(0b00000000101010101); delayWDT2(3); // 128ms led(0b10101010100000000); delayWDT2(3); // 128ms led(0b01010101100000000); delayWDT2(3); // 128ms led(0b00000000100000000); delayWDT2(3); // 128ms } } void fullRotateR(int count) { for (i = 1; i <= count; i++) { led(0b00000000110101010); delayWDT2(3); // 128ms led(0b00000000111111111); delayWDT2(3); // 128ms led(0b10101010111111111); delayWDT2(3); // 128ms led(0b11111111111111111); delayWDT2(4); // 250ms ここだけ長め led(0b11111111101010101); delayWDT2(3); // 128ms led(0b11111111100000000); delayWDT2(3); // 128ms led(0b10101010100000000); delayWDT2(3); // 128ms led(0b00000000100000000); delayWDT2(3); // 128ms } } void VrotateL(int count) { // 縦線左移動 for (i = 1; i <= count; i++) { led(0b01010101100000000); delayWDT2(3); // 128ms led(0b10101010100000000); delayWDT2(3); // 128ms led(0b00000000101010101); delayWDT2(3); // 128ms led(0b00000000110101010); delayWDT2(3); // 128ms led(0b00000000100000000); delayWDT2(3); // 128ms } } void fullRotateL(int count) { for (i = 1; i <= count; i++) { led(0b01010101100000000); delayWDT2(3); // 128ms led(0b11111111100000000); delayWDT2(3); // 128ms led(0b11111111101010101); delayWDT2(3); // 128ms led(0b11111111111111111); delayWDT2(4); // 250ms ここだけ長め led(0b10101010111111111); delayWDT2(3); // 128ms led(0b00000000111111111); delayWDT2(3); // 128ms led(0b00000000110101010); delayWDT2(3); // 128ms led(0b00000000100000000); delayWDT2(3); // 128ms } } void wipeUpDown(int count) { // 縦上昇/降下(下から上に点灯し、逆順で消す) unsigned long a, b; for (i = 1; i <= count; i++) { a = 0; b = 0; for (n = 0; n <= 9; n++) { // 下から上に点灯 data = a | b; // 左右のタネを合成 led(data); // LED表示 a = a << 1; // 下位を繰り上げて a |= 0x01; // 開いた場所は1を埋める b = b >> 1; // 上位を繰り下げて b |= 0x10000; // 開いた場所は1を埋める delayWDT2(2); // 64ms } delayWDT2(4); // 250ms 全点灯したのでちょっと間をとる for (n = 0; n <= 8; n++) { // 下から上に消灯 data = a | b; // 左右のタネを合成 led(data); // LED表示 a = a << 1; // 下位を繰り上げて a &= 0x1FF; b = b >> 1; // 上位を繰り下げて b &= 0x1FF00; delayWDT2(2); // 64ms } delayWDT2(3); // 128ms for (n = 0; n <= 8; n++) { // 上から下へ点灯 data = a | b; // 左右のタネを合成 data |= 0x100; led(data); // LED表示 a = a >> 1; // a |= 0x180; b = b << 1; // b |= 0x300; delayWDT2(2); // 64ms } for (n = 0; n <= 9; n++) { // 上から下へ消灯 data = a | b; // 左右のタネを合成 led(data); // LED表示 a = a >> 1; // a &= 0x0FF; b = b << 1; // b &= 0x1FE00; delayWDT2(2); // 64ms } delayWDT2(4); // 250ms } } void randomFlash(int count) { // ランダム点灯 for (i = 1; i <= count; i++) { data = random(0, 0x20000); // 0から0x1FFFFの範囲の乱数発生 if ((i % 5) == 0) { // 5回に一回 data |= 0x100; // センターLED点灯 } else { data &= 0x1FEFF; // センターLED消灯 } led(data); // LED表示 delayWDT2(3); // 128ms } } void timeUp() { for (;;) { led(0x100); // 先端LEDだけ delayWDT2(2); // 64ms点灯 led(0); delayWDT2(8); // 4秒消灯 } } void led(unsigned long x) { // LED点灯ルーチン /* 引数に対応するビットのLEDを点灯。 入力ピンにアサインした状態で1を書くと、プルアップ抵抗が有効になりLEDが点灯。 データーは17ビット、ポートとの対応は下記 data x xxxx xxxx xxxx xxxx PORTD 76 5432 digita 2-7 PORTB 432 10 digital 8-12 PORTC 5 4321 0 A 0-5 (digital 14-19) digital 0, 1, 13はブートローダーと干渉するので使わない。 クリスマスツリーのビット位置とLEDの配置 8 ← 先端 (0x100) 7 9 6 10 5 11 4 12 3 13 2 14 1 15 0 17 */ byte d; x = x & 0x1FFFF; // 変な値を排除 // 下位6ビットを digital 2-7 に出力 (0,1はTX,RXなので使わない) d = (x << 2) & B11111100; PORTD = d; // 6ビット目から5ビットを digital 8-12に出力(13は使わない) d = (x >> 6) & B00011111; PORTB = d; // 11ビット目から6ビットを analog0-5(digital 14-19)に出力 d = (x >> 11) & B00111111; PORTC = d; } void delayWDT2(unsigned long t) { // パワーダウンモードでdelayを実行 Serial.flush(); // シリアルバッファが空になるまで待つ delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定 // ADCを停止(消費電流 147→27μA) ADCSRA &= ~(1 << ADEN); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定 sleep_enable(); // BODを停止(消費電流 27→6.5μA) MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定 asm("sleep"); // 3クロック以内にスリープ sleep_mode();では間に合わなかった sleep_disable(); // WDTがタイムアップでここから動作再開 ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される) } void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。 // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記 // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms // 6=1sec, 7=2sec, 8=4sec, 9=8sec byte bb; if (ii > 9 ) { // 変な値を排除 ii = 9; } bb = ii & 7; // 下位3ビットをbbに if (ii > 7) { // 7以上(7.8,9)なら bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする } bb |= ( 1 << WDCE ); MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0 // start timed sequence WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット) // set new watchdog timeout value WDTCSR = bb; // 制御レジスタを設定 WDTCSR |= _BV(WDIE); } ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理 // wdt_cycle++; // 必要ならコメントアウトを外す }