/***** Tiny85(8pin)でLEDテープWS2812B駆動テスト *****/ // 2021-02-02 "tn85_rgb1.c" // クロック:16MHz, BOD:2.7V // fuse X:0xFF H:0xDD L:0xF1 ←★重要 // LED制御ポートはPB4(3pin) // LEDの数=3  2つ目と3つ目は同じ色 // 1つ目と異なるタイミングで色変化 // 5msに1回showする。 // 「FastLED-master」を参考に /***** インクルードファイル *****/ #include #include #include #include /***** データサイズ *****/ typedef uint8_t byte; typedef uint16_t word; /***** マクロ *****/ #define nop() asm volatile("nop" "\n\t") // NOPコード // 配列のデータ数を返すマクロ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) // I/O処理(テストパルス用) #define PB0_H (PORTB |= (1 << PB0)) // PB0 (5pin) H/L #define PB0_L (PORTB &= ~(1 << PB0)) #define PB1_H (PORTB |= (1 << PB1)) // PB1 (6pin) H/L #define PB1_L (PORTB &= ~(1 << PB1)) #define PB2_H (PORTB |= (1 << PB2)) // PB2 (7pin) H/L #define PB2_L (PORTB &= ~(1 << PB2)) #define PB3_H (PORTB |= (1 << PB3)) // PB3 (2pin) H/L #define PB3_L (PORTB &= ~(1 << PB3)) /****************************************/ /* LEDテープ WS2812B 制御 */ /****************************************/ // LEDの個数などデータ設定 #define LED_N 3 // LEDの数 // LED制御ポートH/L (直接アドレスを記述 asmの関係で) #define LED_H "sbi 0x18, 4" "\n" // PB4 H/L #define LED_L "cbi 0x18, 4" "\n" // LEDバッファ byte led_bff[LED_N * 3]; // G,R,B LED輝度データバッファ // 明るさ byte led_bright = 255; // 明るさデータ 0~255 // ledsetで使用 /***** 表示実行 *****/ // led_bffの全データをWS2812Bに転送 // LED_N : LEDの数(255コまで) // LED_H、LED_Lで直接出力ポートの操作を記述 // 0 H:310ns L:870ns // 1 H:750ns L:370ns void ledShow(void) { byte *p; PB3_H; // (!!!) p = led_bff; // バッファの先頭 cli(); // 割り込み禁止 asm volatile( "ldi r24, %0" "\n\t" // LEDの数*G,R,B "loop1%=:" "\n\t" "ld r25, %a1+" "\n\t" // 1バイト読み出し "ldi r18, 8" "\n\t" // 8bit loop "loop2%=:" "\n\t" LED_H // ※LED出力:H "nop" "\n\t" "nop" "\n\t" "sbrs r25, 7" "\n\t" LED_L // ※0の時:L "nop" "\n\t" "nop" "\n\t" // 時間調整 "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" LED_L // ※1の時:L "lsl r25" "\n\t" "dec r18" "\n\t" "brne loop2%=" "\n\t" // 8回loop "dec r24" "\n\t" "brne loop1%=" "\n\t" // バッファバイト数loop : : "M" (3*LED_N), // %0:LEDの数*G,R,B "e" (p) // %a1:バッファアドレス ); sei(); // 割込許可 PB3_L; // (!!!) } /********************************/ /* タイマー処理 */ /********************************/ /***** タイマーデータ *****/ volatile word delay_1ms; // 1msでダウンカウント volatile byte f_1ms; // 1msフラグ volatile byte f_5ms; // 5msフラグ /***** 1kHzタイマー割り込み *****/ ISR(TIM0_COMPA_vect) { static byte cnt5 = 0; // 5msカウンタ PB0_H; // (!!!) if(delay_1ms) delay_1ms--; // 1msダウンカウント f_1ms = 1; // 1msフラグをon cnt5++; if(cnt5 >= 5){ // 5ms経過 cnt5 = 0; f_5ms = 1; // 5msフラグをon } PB0_L; // (!!!) } /***** 時間待ち (1ms単位) *****/ // tm : 1msでの待ち時間 void delay(word tm) { volatile word d; cli(); // 割り込み禁止 delay_1ms = tm; // タイマー値プリセット sei(); // 割込許可 do{ cli(); // 割込禁止 d = delay_1ms; // 1msダウンカウントデータ sei(); // 割込許可 } while(d); // 0になるまで } /****************************/ /* 乱数など */ /****************************/ /***** 線形補間 *****/ long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } /***** 乱数:0~xで *****/ int randx(int x) { if (x <= 0) { return 0; } return (rand() % (x + 1)); } /***** 乱数:x~yで *****/ int randxy(int x, int y) { int a; if (x >= y) { return x; } a = y - x; return randx(a) + x; } /********************************/ /* 色データ制御 */ /********************************/ /***** RGBデータをLED表示バッファにセット *****/ // p:位置 r,g,b:色データ // led_brightを乗じて明るさ調整 void ledSetRGB(word p, byte r, byte g, byte b) { PB2_H; // (!!!) led_bff[3*p + 0] = ((word)g * (word)led_bright) / 256; // G led_bff[3*p + 1] = ((word)r * (word)led_bright) / 256; // R led_bff[3*p + 2] = ((word)b * (word)led_bright) / 256; // B #if 0 led_bff[3*p + 0] = g; // 生の処理で led_bff[3*p + 1] = r; led_bff[3*p + 2] = b; #endif PB2_L; // (!!!) } /***** 32bit色データを表示バッファにセット *****/ void ledSet32(word p, uint32_t c) { byte r,g,b; r = (uint8_t)(c >> 16), g = (uint8_t)(c >> 8), b = (uint8_t)c; ledSetRGB(p, r, g, b); } /***** 32bit色データ変換 *****/ // RGBデータをまとめて32bitに uint32_t ledColor(uint8_t r, uint8_t g, uint8_t b) { return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } /***** 色相環データ取得 *****/ // WheelPos : 0 ~ 255 色相データ uint32_t ledWheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return ledColor(255 - WheelPos * 3, 0, WheelPos * 3); } if(WheelPos < 170) { WheelPos -= 85; return ledColor(0, WheelPos * 3, 255 - WheelPos * 3); } WheelPos -= 170; return ledColor(WheelPos * 3, 255 - WheelPos * 3, 0); } /***** 虹色表示 *****/ // 256パターンの色相環データを表示 // wait:待ち時間(ms) void rainbow(uint16_t wait) { uint16_t i, j; for(j = 0; j < 256; j++) { for(i = 0; i < LED_N; i++) { ledSet32(i, ledWheel((i+j) & 255) ); // 1つずつ色を変えて } ledShow(); // WS2812Bへ転送 delay(wait); // 時間待ち } } /********************************/ /* イニシャル処理 */ /********************************/ /***** マイコンI/Oの初期化 *****/ // ヒューズを書き換えて16MHzクロックで void ioinit(void) { cli(); // 割り込み禁止で // I/Oイニシャル PORTB = 0b00000000; // data/pull up DDRB = 0b00011111; // portin/out指定 // |||||+---- PB0 out // ||||+----- PB1 out // |||+------ PB2 out // ||+------- PB3 out (X1) // |+-------- PB4 out (X2) →LED制御出力 // +--------- PB5 out (RESET) // タイマー0 16MHzを1/64して250kHz TCCR0A = 0b00000010; // モード設定 // |||| ++--- WGM: CTCモード // ||++------- COM0B // ++--------- COM0A TCCR0B = 0b00000011; // クロック設定 // |+++--- CS:1/64 : 250kHz // +------ WGM02 OCR0A = 250 - 1; // 250カウントで1kHzを TIMSK = 0b00010000; // |||||+--- TOIE0 // ||||+----- TOIE1 // |||+------ OCIE0B // ||+------- OCIE0A TM0 コンペアマッチA割り込み有効 // |+-------- OCIE1B // +--------- OCIE1A } /********************************/ /* メインループ */ /********************************/ // 色指定データ 全部で3つ 2,3つ目は同じ uint8_t col_0; // LED 1つ目の色 0~255 uint8_t col_1; // LED 2,3つ目の色 uint16_t tm_0; // LED 1つ目のタイマー (1ms) uint16_t tm_1; // LED 2,3つ目のタイマー /***** メイン *****/ // クロックは内蔵16MHz int main(void) { ioinit(); // マイコンI/Oの初期化 // loop while(1){ sei(); // 割込許可 // LEDデータ転送 if(f_5ms){ // 5msサイクルで f_5ms = 0; ledShow(); // WS2812BへLEDデータを転送 } // 1msタイミング if(f_1ms){ // 1ms経過 f_1ms = 0; // LED #0 if(tm_0) tm_0--; // LED 1つ目 if(tm_0 == 0){ col_0++; // 色相環256サイクル ledSet32(0, ledWheel(col_0)); tm_0 = randxy(10,50); // 次タイマー } // LED #1,2 if(tm_1) tm_1--; // LED 2つ,目3つ目 if(tm_1 == 0){ col_1++; // 色相環256サイクル ledSet32(1, ledWheel(col_1)); ledSet32(2, ledWheel(col_1)); tm_1 = randxy(20,100); // 次タイマー #0とタイミングを変える } } } } /*==== end of "tn85_rgb1.c" =====*/