Индикатор уровня сигнала на адресной светодиодной ленте WS2812B (Arduino)

Адресная светодиодная лента представляет собой ленту на которой размещены адресные светодиоды, каждый светодиод состоит из RGB светодиода и контроллера. Адресная лента имеет как правило имеет три входных контакта: +5V, GND и DIN. Каждый отдельный светодиод ленты (пиксель) имеет выход DOUT, для передачи управляющего сигнала к следующему светодиоду.

Наиболее популярные адресные ленты работают на чипах WS2812b и WS2811. Чип WS2812b размещен внутри RGB светодиода, питание 5 В, а в адресных лентах использующих чип WS2811 установлен отдельно от светодиода, напряжение питания 12 В, так же чип WS2811 управляет сразу тремя RGB светодиодами, которые представляют собой один пиксель.

Те же адресные ленты имеют разное кол-во светодиодов на 1 метр и соответственно разную мощность потребления и цену.

Если просто подать питание на адресную ленту, то она работать не будет, чтобы она заработала необходимо подать управляющий цифровой сигнал на вход DIN. Управляющий цифровой сигнал состоит 24 бит, по 8 бит на каждый цвет, причем в начале каждого байта первый бит старший.

При этом один бит передается за 1,25 мкс, все 24 бита передаются за 30 мкс. Длительность импульса при передачи логического нуля равна 0,4 мкс ±0,125 мкс, а скважность 0,85 мкс ±0,125 мкс, длительность импульса для логической единицы равна 0,85 мкс ±0,125 мкс, а скважность 0,4 мкс ±0,125 мкс.

После передачи всех 24 бит в первый RGB светодиод следует пауза не более 50 мкс, далее снова передаются 24 бита, но первый светодиод не реагирует на них, он просто передается эту информацию следующему светодиоду и так далее по цепочке до последнего светодиода. После окончания передачи следует пауза больше 50 мкс, после чего лента переходит в исходное состояние и готова принимать цифровой сигнал начиная с первого светодиода.

На базе адресной светодиодной ленты WS2812B можно собрать простой индикатор уровня аудио сигнала. Индикатор уровня собран на адресной ленте плотностью 96 пикселей на 1 метр.

На индикатор уровня подается стерео сигнал на аналоговые входы А0 и А1, центр ленты является разделителем правого и левого канала, поэтому ленту можно разделить на две части, отдельно для правого и левого канала. Так же в индикации уровня присутствует пиковый индикатор.

Кнопка MODE служит для переключения режима расцветки свечения светодиодов.

Особенностью индикатора уровня аудио сигнала является, то что Вы можете использовать разную длину адресной ленты с четным количеством светодиодов. Для настройки индикатора в скетче необходимо указать четное количество пикселей Вашей ленты, яркость, усиление сигнала и плавность работы пикового индикатора.

#define LED_MAX  60
#define GAIN 1  // усиление 1...20
#define STEP 5  // плавность полос 1...20
#define BRIG 2  // яркость 2...255

При установке яркости более 10 единиц, необходимо использовать отдельный от Arduino источник питания 5 В, так ток потребления адресной ленты может превысить 2 А. 

// Atmega328, Atmega8 16MHz
 
#include <avr/io.h>
#include <util/delay.h>
 
#define L_BIT    PORTB &= ~(1<<PB0)
#define H_BIT    PORTB |=  (1<<PB0)    
#define LED_MAX  60
#define GAIN 1  // усиление 1...20
#define STEP 5  // плавность полос 1...20
#define BRIG 2  // яркость 2...255
 
  byte rr[LED_MAX],gg[LED_MAX],bb[LED_MAX];
  int ur,ul,urr,ull,urrr,ulll;
  int x,i,u_maxr,u_maxl;
  int u_l0[20],u_r0[20];
  int ull_sum,urr_sum;
  byte r,g,b;
  int u_r,uur,u_l,uul;
  int mode;
  unsigned long times, times0;
  bool w;
 
 
int main(void){
  cli();
  DDRB |= (1<<PB0); // INPUT WS2812B (D8 - ARDUINO)
  DDRD &= ~(1<<PD2);// BUTTON (D2 - ARDUINO)
  PORTD |=(1<<PD2); // INPUT_PULLUP
  ADCSRA = 0b10000100; 
  TCCR0A = 0;TCCR0B = 0;TCNT0 = 0;
  OCR0A = 249;
  TCCR0A |= (1 << WGM01);
  TCCR0B |= (1 << CS01) | (1 << CS00);
  TIMSK0 |= (1 << OCIE0A);
  sei();
  mode = EEPROM_read(0);
 
 
 while(1){
  if(((PIND >> PD2) & 1) == 0){mode++;if(mode>4){mode=0;}_delay_ms(300);w=1;times0=times;}
////////// ANALOG READ
 ADMUX = 0b01000001; // input A1 
  do{ADCSRA |= (1 << ADSC);}while ((ADCSRA & (1 << ADIF)) == 0);urr = (ADCL|ADCH << 8)*GAIN;if(urr>LED_MAX/2){urr=LED_MAX/2;}
 ADMUX = 0b01000000; // input A0
  do{ADCSRA |= (1 << ADSC);}while ((ADCSRA & (1 << ADIF)) == 0);ull = (ADCL|ADCH << 8)*GAIN;if(ull>LED_MAX/2){ull=LED_MAX/2;}
  uur = urr;if(uur<u_r){u_r=u_r-1;_delay_ms(STEP);}else{u_r = uur;} 
  uul = ull;if(uul<u_l){u_l=u_l-1;_delay_ms(STEP);}else{u_l = uul;} 
////////// RGB ////////////////////////////////////////////////
 
  for(int i1=u_l;i1<LED_MAX/2;i1++){data_led(LED_MAX/2-i1-1,  0,0,0);}led_rgb();res();
  for(int i1=u_r;i1<LED_MAX/2;i1++){data_led(i1+LED_MAX/2,  0,0,0);}led_rgb();res();
 
  if(mode==0){
  for(int i1=1;i1<u_l-1;i1++){if(i1<LED_MAX/2/3){r=0;g=1*BRIG;b=0;}
  else if(i1>=LED_MAX/2/3&&i1<LED_MAX/2/2){r=0;g=0;b=1*BRIG;}
  else {r=1*BRIG/2;g=1*BRIG/2;b=1*BRIG/2;}   data_led(LED_MAX/2-i1-1,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2-1,  1*BRIG,1*BRIG,0);led_rgb();res();
 
  for(int i1=1;i1<u_r-1;i1++){if(i1<LED_MAX/2/3){r=0;g=1*BRIG;b=0;} 
  else if(i1>=LED_MAX/2/3&&i1<LED_MAX/2/2){r=0;g=0;b=1*BRIG;}
  else {r=1*BRIG/2;g=1*BRIG/2;b=1*BRIG/2;}  data_led(i1+LED_MAX/2,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2,  1*BRIG,1*BRIG,0);led_rgb();res();
  }
  if(mode==1){
  for(int i1=1;i1<u_l-1;i1++){if(i1<LED_MAX/2){r=1*BRIG;g=1*BRIG;b=1*BRIG;}
  data_led(LED_MAX/2-i1-1,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2-1,  1*BRIG,1*BRIG,0);led_rgb();res();
 
  for(int i1=1;i1<u_r-1;i1++){if(i1<LED_MAX/2){r=1*BRIG;g=1*BRIG;b=1*BRIG;} 
  data_led(i1+LED_MAX/2,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2,  1*BRIG,1*BRIG,0);led_rgb();res();
  } 
  if(mode==2){
  for(int i1=1;i1<u_l-1;i1++){if(i1<LED_MAX/2){r=0;g=1*BRIG;b=1*BRIG;}
  data_led(LED_MAX/2-i1-1,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2-1,  1*BRIG,1*BRIG,0);led_rgb();res();
 
  for(int i1=1;i1<u_r-1;i1++){if(i1<LED_MAX/2){r=0;g=1*BRIG;b=1*BRIG;} 
  data_led(i1+LED_MAX/2,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2,  1*BRIG,1*BRIG,0);led_rgb();res();
  } 
  if(mode==3){
  for(int i1=1;i1<u_l-1;i1++){if(i1<LED_MAX/2){r=0;g=0;b=1*BRIG;}
  data_led(LED_MAX/2-i1-1,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2-1,  1*BRIG,1*BRIG,0);led_rgb();res();
 
  for(int i1=1;i1<u_r-1;i1++){if(i1<LED_MAX/2){r=0;g=0;b=1*BRIG;} 
  data_led(i1+LED_MAX/2,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2,  1*BRIG,1*BRIG,0);led_rgb();res();
  } 
  if(mode==4){
  for(int i1=1;i1<u_l-1;i1++){if(i1<LED_MAX/2){r=0;g=1*BRIG;b=0;}
  data_led(LED_MAX/2-i1-1,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2-1,  1*BRIG,1*BRIG,0);led_rgb();res();
 
  for(int i1=1;i1<u_r-1;i1++){if(i1<LED_MAX/2){r=0;g=1*BRIG;b=0;} 
  data_led(i1+LED_MAX/2,  r,g,b);}led_rgb();res();
  data_led(LED_MAX/2,  1*BRIG,1*BRIG,0);led_rgb();res();
  } 
 
 i++;if(i<19){u_l0[i]=ull-2;u_r0[i]=urr-2;}else{i=0;}
 if(i==18){u_maxr=0;u_maxl=0;
   for(x=1;x<=15;x++){
    u_maxl=maxim(u_maxl,u_l0[x]);
    u_maxr=maxim(u_maxr,u_r0[x]);}}
 if(u_maxl<=ull){u_maxl=ull+1;} 
 if(u_maxr<=urr){u_maxr=urr+1;}
 if(u_maxl<ulll){ulll=ulll-1;_delay_ms(STEP);}else{ulll = u_maxl;}
 if(u_maxr<urrr){urrr=urrr-1;_delay_ms(STEP);}else{urrr = u_maxr;}
 if(ulll>LED_MAX/2){ulll=LED_MAX/2;}
 if(urrr>LED_MAX/2){urrr=LED_MAX/2;}
    data_led(LED_MAX/2-ulll,  1*BRIG,0,0);led_rgb();res();
    data_led(urrr-1+LED_MAX/2,  1*BRIG,0,0);led_rgb();res();
    _delay_ms(2);  
////// EEPROM ///////////////////
 if(times-times0>10000&&w==1){if(EEPROM_read(0)!=mode){EEPROM_write(0,mode);}w=0;} 
}} // end loop
 
ISR(TIMER0_COMPA_vect) {times++;}// millis = 1 ms
 
int maxim(int basa, int srav){if(srav>basa){basa = srav;}return basa;}
 
unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));  // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EECR |= (1<<EERE);// чтение EEPROM
    return EEDR; // вывод значения
}
 
void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
  while(EECR & (1<<EEPE)); // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EEDR = ucData; // регистр данных 
    EECR |= (1<<EEMPE);// Разрешение записи в EEPROM
    EECR |= (1<<EEPE); // Запись в EEPROM
} 
 
void bit_0(){H_BIT;asm("nop");asm("nop");   L_BIT;asm("nop");asm("nop");asm("nop");   asm("nop");} 
void bit_1(){H_BIT;asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   L_BIT;}
void bit_w(bool x){if(x) bit_1(); else bit_0();}
void res(){_delay_us(100);}
 
void data_led(int num, byte rrr, byte ggg, byte bbb){
  bb[num]=bbb;rr[num]=rrr;gg[num]=ggg;
  }
 
void led_rgb(){
  for(int num_i=0;num_i<LED_MAX;num_i++){ 
  cli();
bit_w((bb[num_i] & 0x80)>>7);
bit_w((bb[num_i] & 0x40)>>6);
bit_w((bb[num_i] & 0x20)>>5);
bit_w((bb[num_i] & 0x10)>>4);
bit_w((bb[num_i] & 0x08)>>3);
bit_w((bb[num_i] & 0x04)>>2);
bit_w((bb[num_i] & 0x02)>>1);
bit_w((bb[num_i] & 0x01)>>0);
 
bit_w((rr[num_i] & 0x80)>>7);
bit_w((rr[num_i] & 0x40)>>6);
bit_w((rr[num_i] & 0x20)>>5);
bit_w((rr[num_i] & 0x10)>>4);
bit_w((rr[num_i] & 0x08)>>3);
bit_w((rr[num_i] & 0x04)>>2);
bit_w((rr[num_i] & 0x02)>>1);
bit_w((rr[num_i] & 0x01)>>0);
 
bit_w((gg[num_i] & 0x80)>>7);
bit_w((gg[num_i] & 0x40)>>6);
bit_w((gg[num_i] & 0x20)>>5);
bit_w((gg[num_i] & 0x10)>>4);
bit_w((gg[num_i] & 0x08)>>3);
bit_w((gg[num_i] & 0x04)>>2);
bit_w((gg[num_i] & 0x02)>>1);
bit_w((gg[num_i] & 0x01)>>0);
   sei(); 
}}

Добавить комментарий

Войти с помощью: