/* クリスマスツリーイルミネーション 低消費電流タイプ(delayWDT使用) CPUのプルアップ抵抗を使って17個のLEDを点灯。8MHz内部CRオシレーター、足伸ばしチップへ書き込んだ内容 流れ星を追加 2019/12/13 ラジオペンチ http://radiopench.blog96.fc2.com/ */ #include // スリープモードを使用 #include // ウォッチドッグタイマーを使用 unsigned long data = 0; int i, n; unsigned long fS[4][12] = { // 流れ星のパターン定義 { 0b00000000000000000, // トレース0 0b00000000100000000, 0b00000000100000000, 0b00000000110000000, 0b00000000010000000, 0b00000000010100000, 0b00000000000100000, 0b00000000000101000, 0b00000000000001000, 0b00000000000001010, 0b00000000000000010, 0b00000000000000010 }, { 0b00000000000000000, //トレース1 0b00000000100000000, 0b00000000100000000, 0b00000000101000000, 0b00000000001000000, 0b00000000001010000, 0b00000000000010000, 0b00000000000010100, 0b00000000000000100, 0b00000000000000101, 0b00000000000000001, 0b00000000000000001 }, { 0b00000000000000000, //トレース2 0b00000000100000000, 0b00000000100000000, 0b00000001100000000, 0b00000001000000000, 0b00000101000000000, 0b00000100000000000, 0b00010100000000000, 0b00010000000000000, 0b01010000000000000, 0b01000000000000000, 0b01000000000000000, }, { 0b00000000000000000, //トレース3 0b00000000100000000, 0b00000000100000000, 0b00000010100000000, 0b00000010000000000, 0b00001010000000000, 0b00001000000000000, 0b00101000000000000, 0b00100000000000000, 0b10100000000000000, 0b10000000000000000, 0b10000000000000000 } }; void setup() { allOn1000(); // 最初に開始表示 } // pinModeを指定していないので全部inputになる void loop() { // メインループ for (int j = 0; j < 245; j++) { // 約6時間実行 (1サイクル88秒×245回=6時間) allOn1000(); // ループ開始表示 singleR(1); // 単発右回転 singleL(1); // 単発左回転 waveR(1); // ウェ−ブ右回転 waveL(1); // ウェーブ左回転 x_rotate(2); // 単発左右同時 allOn5000(); // 全点灯5秒 Vcross(2); // 逆Vクロス Hline(2); VrotateR(3); // 縦線右移動 fullRotateR(3); // 横ワイプ右 VrotateL(3); // 縦線左移動 fullRotateL(3); // 横ワイプ左 wipeUpDown(2); // 縦上昇/降下 shootingStars(); // 流れ星 randomFlash(75); // ランダム点灯 } timeUp(); // 指定時間終了後は停止中表示(センターLEDフラッシュ) } void allOn1000() { led(0); // 一旦消灯 delayWDT(5); // 0.5秒 led(0x1FFFF); // 全点灯 delayWDT(6); led(0); delayWDT(4); // 256ms } void allOn5000() { led(0); // 一旦消灯 delayWDT(5); // 0.5秒 led(0x1FFFF); // 全点灯 delayWDT(8); // 4秒 delayWDT(6); // 1秒 led(0); delayWDT(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; // 左にシフト delayWDT(2); // 64ms } delayWDT(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; // 右にシフト delayWDT(2); // 64ms } delayWDT(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; // 左にシフト delayWDT(2); // 64ms } for (n = 0; n <= 16; n++) { data = data & 0x1FFFE; // 下位ビットを消す led(data); // LED表示 data = data << 1; // 左にシフト delayWDT(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; // 右にシフト delayWDT(2); // 64ms } for (n = 0; n <= 16; n++) { data = data & 0x0FFF; // 右端のビットを消す led(data); // LED表示 data = data >> 1; // 右にシフト delayWDT(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; // 上のタネを右シフト delayWDT(2); // 64ms; } } } void Vcross(int count) { for (i = 1; i <= count; i++) { led(0b00000000000000001); delayWDT(2); // 64ms led(0b00000000000000101); delayWDT(2); // 64ms led(0b00000000000010101); delayWDT(2); // 64ms led(0b00000000001010101); delayWDT(2); // 64ms led(0b00000000101010101); delayWDT(2); // 64ms センター (点灯) led(0b00000001101010101); delayWDT(2); // 64ms led(0b00000101101010101); delayWDT(2); // 648ms led(0b00010101101010101); delayWDT(2); // 64ms led(0b01010101101010101); delayWDT(2); // 64ms led(0b11010101101010101); delayWDT(2); // 64ms led(0b11110101101010101); delayWDT(2); // 64ms led(0b11111101101010101); delayWDT(2); // 64ms led(0b11111111101010101); delayWDT(2); // 64ms led(0b11111111101010101); delayWDT(2); // 64ms センター led(0b11111111111010101); delayWDT(2); // 64ms led(0b11111111111110101); delayWDT(2); // 64ms led(0b11111111111111101); delayWDT(2); // 64ms led(0b11111111111111111); delayWDT(2); // 64ms led(0b11111111111111110); delayWDT(2); // 64ms led(0b11111111111111010); delayWDT(2); // 64ms led(0b11111111111101010); delayWDT(2); // 64ms led(0b11111111110101010); delayWDT(2); // 64ms led(0b11111111110101010); delayWDT(2); // 64ms センター led(0b11111110110101010); delayWDT(2); // 64ms led(0b11111010110101010); delayWDT(2); // 64ms led(0b11101010110101010); delayWDT(2); // 64ms led(0b10101010110101010); delayWDT(2); // 64ms led(0b00101010110101010); delayWDT(2); // 64ms led(0b00001010110101010); delayWDT(2); // 64ms led(0b00000010110101010); delayWDT(2); // 64ms led(0b00000000110101010); delayWDT(2); // 64ms led(0b00000000010101010); delayWDT(2); // 64ms センター(消灯) led(0b00000000000101010); delayWDT(2); // 64ms led(0b00000000000001010); delayWDT(2); // 64ms led(0b00000000000000010); delayWDT(2); // 64ms led(0b00000000000000000); delayWDT(2); // 64ms } } void Hline(int count) { // 水平線 for (i = 1; i <= count; i++) { led(0b00000000000000000); delayWDT(2); // 64ms led(0b00000000000000010); delayWDT(2); // 64ms led(0b00000000000000001); delayWDT(2); // 64ms led(0b10000000000000000); delayWDT(2); // 64ms led(0b01000000000000000); delayWDT(2); // 64ms led(0b00000000000000000); delayWDT(2); // 64ms led(0b00000000000001000); delayWDT(2); // 64ms led(0b00000000000000100); delayWDT(2); // 64ms led(0b00100000000000000); delayWDT(2); // 64ms led(0b00010000000000000); delayWDT(2); // 64ms led(0b00000000000000000); delayWDT(2); // 64ms led(0b00000000000100000); delayWDT(2); // 64ms led(0b00000000000010000); delayWDT(2); // 64ms led(0b00001000000000000); delayWDT(2); // 64ms led(0b00000100000000000); delayWDT(2); // 64ms led(0b00000000000000000); delayWDT(2); // 64ms led(0b00000000010000000); delayWDT(2); // 64ms led(0b00000000001000000); delayWDT(2); // 64ms led(0b00000010000000000); delayWDT(2); // 64ms led(0b00000001000000000); delayWDT(2); // 64ms led(0b00000000100000000); delayWDT(3); // 128ms センター (点灯) } } void VrotateR(int count) { // 縦線右移動 for (i = 1; i <= count; i++) { led(0b00000000110101010); delayWDT(3); // 128ms led(0b00000000101010101); delayWDT(3); // 128ms led(0b10101010100000000); delayWDT(3); // 128ms led(0b01010101100000000); delayWDT(3); // 128ms led(0b00000000100000000); delayWDT(3); // 128ms } } void fullRotateR(int count) { for (i = 1; i <= count; i++) { led(0b00000000110101010); delayWDT(3); // 128ms led(0b00000000111111111); delayWDT(3); // 128ms led(0b10101010111111111); delayWDT(3); // 128ms led(0b11111111111111111); delayWDT(4); // 250ms ここだけ長め led(0b11111111101010101); delayWDT(3); // 128ms led(0b11111111100000000); delayWDT(3); // 128ms led(0b10101010100000000); delayWDT(3); // 128ms led(0b00000000100000000); delayWDT(3); // 128ms } } void VrotateL(int count) { // 縦線左移動 for (i = 1; i <= count; i++) { led(0b01010101100000000); delayWDT(3); // 128ms led(0b10101010100000000); delayWDT(3); // 128ms led(0b00000000101010101); delayWDT(3); // 128ms led(0b00000000110101010); delayWDT(3); // 128ms led(0b00000000100000000); delayWDT(3); // 128ms } } void fullRotateL(int count) { for (i = 1; i <= count; i++) { led(0b01010101100000000); delayWDT(3); // 128ms led(0b11111111100000000); delayWDT(3); // 128ms led(0b11111111101010101); delayWDT(3); // 128ms led(0b11111111111111111); delayWDT(4); // 250ms ここだけ長め led(0b10101010111111111); delayWDT(3); // 128ms led(0b00000000111111111); delayWDT(3); // 128ms led(0b00000000110101010); delayWDT(3); // 128ms led(0b00000000100000000); delayWDT(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を埋める delayWDT(2); // 64ms } delayWDT(4); // 250ms 全点灯したのでちょっと間をとる for (n = 0; n <= 8; n++) { // 下から上に消灯 data = a | b; // 左右のタネを合成 led(data); // LED表示 a = a << 1; // 下位を繰り上げて a &= 0x1FF; b = b >> 1; // 上位を繰り下げて b &= 0x1FF00; delayWDT(2); // 64ms } delayWDT(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; delayWDT(2); // 64ms } for (n = 0; n <= 9; n++) { // 上から下へ消灯 data = a | b; // 左右のタネを合成 led(data); // LED表示 a = a >> 1; // a &= 0x0FF; b = b << 1; // b &= 0x1FE00; delayWDT(2); // 64ms } delayWDT(4); // 250ms } } void shootingStars() { // たくさんの流れ星 int x; unsigned int pixP[4]; // 流星の位置記録。4ライン×12位置をビットマップで表現。LSBが開始位置 unsigned int bP; // ビット操作ポインタ unsigned long pLED; // LEDの光る位置操作バッファ for (int i = 0; i < 4; i++) { // 位置記録バッファをクリア pixP[i] = 0; } for (int c = 1000; c > 0; c--) { // 1000回ループで実行 for (int i = 0; i < 4; i++) { // 4つのラインの星の位置を pixP[i] = pixP[i] << 1; // 一つ先に進める } x = random(0, c / 100); // ループ回数に反比例で乱数の発生範囲を決め if (x == 0) { // ヒットしていたら、 x = random(0, 4); // 4つの軌跡のいずれかに pixP[x] |= 0x0001; // 新しい種を植える } pLED = 0; // LED表示レジスタをクリア for (int n = 0; n < 4; n++) { // 4ライン一つつづつ bP = 0x01; for (int m = 0; m < 12; m++) { // 12箇所のビットを先頭から調べて if ((pixP[n] & bP) != 0) { // もし種が入っていたら、 pLED |= fS[n][m]; // 点灯パターンを複写して該当するLED点灯ビットをON } bP = bP << 1; // 次回のためにビットポインターを進めておく } } led(pLED); // LEDを点灯 delayWDT(1); } led(0x1FFFF); // 最後に全点灯 delayWDT(7); // 2秒間 } 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表示 delayWDT(3); // 128ms } } void timeUp() { for (;;) { led(0x100); // 先端LEDだけ delayWDT(2); // 64ms点灯 led(0); delayWDT(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 delayWDT(unsigned long t) { // パワーダウンモードでdelayを実行 delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定 ADCSRA &= ~(1 << ADEN); // ADENビットをクリアしてADCを停止(120μA節約) set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード sleep_enable(); sleep_mode(); // ここでスリープに入る sleep_disable(); // WDTがタイムアップでここから動作再開 ADCSRA |= (1 << ADEN); // ADCの電源をON (|=が!=になっていたバグを修正2014/11/17) } 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++; // 必要ならコメントアウトを外す }