Управление RGB светодиодом с помощью аппаратной ШИМ ATmega8

Как известно, RGB светодиод представляет собой три излучающих кристалла, красного, зеленого и синего цвета, на одной подложке. Смешивая эти три цвета в разных пропорциях, можно получить всю цветовую гамму, воспринимаемую людским глазом. Для управления цветом потребуется включать кристаллы с разной яркостью, то есть управлять током через диод. Проще всего, это сделать с помощью микроконтроллера, а точнее его аппаратной ШИМ, которой нам потребуется 3 канала.

Микроконтроллер ATmega8 как раз имеет требуемых 3 аппаратных ШИМ канала, так что будем проводить эксперименты с его участием. В качестве подопытного будем использовать RGB светодиод Сree MC-E. У этого светодиода 4 кристалла: красного, зеленого, синего и как бонус, белого цвета. Белый кристалл задействовать не будем. Схема включения ничем принципиальным не отличается от той, которую использовали при опытах с аппаратной ШИМ:

Транзисторы Q1-Q3 – ZXTN19020, резисторы R4,R5,R7 – 10 ом (я не проводил балансировку цветов, так как для этого нужен спектрограф, которого у меня нет, все ограничивающие резисторы поставил одного номинала). Резисторы R3,R6,R8 по 1 килоому. Все остальное – обвес микроконтроллера, с которым должно быть все понятно. X1 – кварцевый резонатор на 4Мгц, конденсаторы С1,С2 – по 18-20 пФ. R1,C7 соответственно по 10 килоом и 0,1 мкФ. D1- светодиод, показывает, что на схему подается питание, R2 – ограничивающий резистор на 200 ом.

Конденсаторы
C3 – 100мкФ, С5 – 50мкф, С4,С6 – блокировочные, по 0,1мкФ. L7805 – стабилизатор напряжения 5В, подойдет любой аналог: LM7805, КРЕН5А. D2-D3-D4 – наш RGB светодиод, соответственно синий, зеленый и красный его кристаллы. Гореть одним цветом нашему светодиоду будет скучно. Эффектней будет плавное переливание цветов. Например, красный цвет постепенно переходит в зеленый, зеленый в синий, а синий в красный, и так по кругу в вечном цикле. Для этого напишем программу:

  1. #include <avr/io.h> //Стандартная библиотека ввода/вывода
  2.  
  3. #define R_channel OCR1AL //Определяем канал OCR1AL для Красного цвета
  4. #define G_channel OCR1BL //Определяем канал OCR1BL для Зеленого цвета
  5. #define B_channel OCR2 //Определяем канал OCR2 для Синего цвета
  6.  
  7. #define RGB_pause 2000 //Пауза для задержки
  8.  
  9. //Программа формирования задержки
  10. void pause (unsigned int a)
  11. {
  12. unsigned int i; //Переменная для задержки
  13. for (i=a;i>0;i--); //Цикл формирования задержки
  14. }
  15.  
  16. //Программа инициализации ШИМ
  17. void init_pwm (void)
  18. {
  19. //Инициализация порта
  20. DDRB=0x0e; //OC1A,OC1B,OC2 - выхода
  21.  
  22. TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM10); //Конфигурация счетчика OC1A
  23. TCCR1B=(1<<CS10); //Конфигурация счетчика OC1B
  24. TCCR2=(1<<CS20)|(1<<COM21)|(1<<WGM20); //Конфигурация счетчика OC2
  25.  
  26. //Установка начальных значений счетчиков
  27. OCR1AL=0xff; //Соответсвует Красному цвету
  28. OCR1BL=0x00; //Выключен 0
  29. OCR2=0x00; //Выключен 0
  30. }
  31.  
  32. //Основная программа
  33. int main(void)
  34. {
  35. unsigned char i;
  36.  
  37. init_pwm(); //Инициализация ШИМ каналов
  38.  
  39. while (1) //Вечный цикл
  40. {
  41. for(i=0;i<255;i++) //Переход от красного к зеленому
  42. {
  43. R_channel--;
  44. G_channel++;
  45. pause(RGB_pause);
  46. }
  47. for(i=0;i<255;i++) //Переход от зеленого к синему
  48. {
  49. G_channel--;
  50. B_channel++;
  51. pause(RGB_pause);
  52. }
  53.  
  54. for(i=0;i<255;i++)//Переход от синего к красному
  55. {
  56. B_channel--;
  57. R_channel++;
  58. pause(RGB_pause);
  59. }
  60. }
  61. }

Программа очень проста, инициализируем ШИМ каналы, и плавно меняем цвета в вечном цикле. Даже нечего добавить, кроме того, что регистрам, отвечающие за заполнение ШИМ, мы переопределили новые имена, для легкости запоминания.

Видео работы:

Скачать исходники в виде проекта по AVR Studio 4.

Здраствуйте. Помогите

Здраствуйте.
Помогите разобратса, как изменить код для светодиода с общим vcc и без транзисторов.
Спасибо большое.

Вопрос

Немного подзабыл

Откуда вы взяли начение 0х0е и знаете что оно именно инициализирует именно эти порты?

//Инициализация порта
DDRB=0x0e; //OC1A,OC1B,OC2 - выхода

Спасибо

А можна ли добавить шим на

А можна ли добавить шим на остальные ножки. Меня интересует шим на всех ножках кроме PD2, PD3, PB6, PB7? заранее спасибо за ответ.

Можно в функционал добавить

Можно в функционал добавить режим цветомузыки-
подключить микрофон на АЦП сделать дискретизацию 15-25 Гц и соответственно полученному напряжению генерировать цвет. Если сильно позаморачиваться можно даже программный АРУ сделать.

По материалам данной статьи

По материалам данной статьи был изготовлен RGB контроллер для подсветки/ освещения комнаты.
Используется метровый шлейф двойной плотности (60 светодиодов ), приклеенный у потолка, может позже добавлю еще метр. Режим при включении - белый свет, можно переключать 16 режимов цвета/ яркости, либо плавный перелив- мне больше особо ничего не нужно. Яркость белого света не высокая, но в самый раз для работы за компом и тд. Потребление в режиме белого цвета 12в х 1А, 0,35А при переливании итого не более 15 Вт от сети.
видео работы:

прошу прощения за низкое качество- телефон что-то глючит.

Хочу сказать спасибо всем, кто помогал в доработке исходника, исправлении моих ошибок.

Мне понравилось, классно! Я

Мне понравилось, классно! Я рад что сайт полезен людям)))

привязка к термодатчику

Сижу вот, пытаюсь лепить разные эффекты. Появилась вот задумка - повесить на контроллер DS18B20 - и задать зависимость эффектов от температуры. Смотрел статью "Шина 1-wire, пример термометра на DS18B20 и микроконтроллере AVR" - что-то сложновато выходит, да и там половина программы на ЖКИ завязана. Мне бы оставить самый минимум - инициализацию и получение значения температуры в переменную. Что с ней делать дальше - разберусь, думаю. Буду очень рад, если кто поможет.

У меня есть схожая идея

У меня есть схожая идея сделать термометр, т.е. линейка из 60 rgb светодиодов, которые меняют заполнение и цвет в зависимости от температуры.

А по поводу статьи, там все просто. Все что имеет отношение к ЖКИ можно смело выкинуть. Оставить только 2 переменные:

unsigned int temperature;
unsigned char temperature_sign;

которые содержат абсолютное значение температуры и ее знак (+-). Исходя из этих переменных менять цвет светодиода как вздумается.

например, если температура минусовая - ставить синий цвет. Если от 0 до 10 то ставить голубой, если от 10 до 20 - зеленый, от 20-30 - желтый, выше 30 - красный.

Спасибо! Почти сам

Спасибо! Почти сам разобрался, опытным путем - удаляя все лишнее, на мой взгляд, и проверяя компилятором на ошибки. Но все равно, спасибо, что не оставляете без внимания комментарии! Ваш вариант "термометра" меня тоже заинтересовал, кстати.

Регистрируйся на сайте и

Регистрируйся на сайте и выкладывай фотки что у тебя вышло, будет интересно посмотреть.

Доработка

Я немного изменил схему и доработал исходник, взяв кусок кода из соседней статьи по прерываниям сделал функцию регулировки скорости через int0 int1
Хотелось бы сделать законченое устройство для декоративной подсветки с дополнительными функциями:

- регулировка скорости (условно реализовано)
- регулировка яркости на 2-х кнопках
- возможность по нажатию кнопки остановить цикл, тем самым "зафиксировать" выбранный оттенок
- если оттенок выбран и установлен записать его в еепром и при следующем включении начать с этого режима.

Прошу помощи продвинутых алгоритмом или кодом.

код с регулировкой скорости через int0 int1:

  1. //R_channel=PB1 //G_channel=PB2 //B_channel=PB3
  2. #include <avr/io.h>
  3. #include <avr/interrupt.h>
  4. #define nop() {asm("nop");}
  5.  
  6. #define R_channel OCR1AL
  7. #define G_channel OCR1BL
  8. #define B_channel OCR2
  9.  
  10. int s = 2000;//переменная для задержки
  11. unsigned int x,i;//перечисление переменных
  12.  
  13. // Функция задержки(пауза)
  14. void delay(int t)
  15.  
  16. {
  17. for (x=t; x>0 ;x--)
  18. nop ();
  19. }
  20. SIGNAL(SIG_INTERRUPT0)//обработка прерываний
  21. {s = s+500;//увеличиваем переменную s на 500
  22. }
  23.  
  24. SIGNAL(SIG_INTERRUPT1)//обработка прерываний
  25. {s = s-500;//уменьшаем переменную s на 500
  26. }
  27.  
  28. void init_pwm (void)
  29. { DDRB=0x0e;
  30. TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM10);
  31. TCCR1B=(1<<CS10);
  32. TCCR2=(1<<CS20)|(1<<COM21)|(1<<WGM20);
  33.  
  34. OCR1AL=0xff; OCR1BL=0x00; OCR2=0x00;
  35.  
  36. GIMSK=0b11000000; //разрешаем прерывание int0 и int1 - кнопка
  37. MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2
  38. sei();//разрешение прерываний
  39. }
  40.  
  41. int main(void)
  42. { unsigned char i;
  43. init_pwm();
  44.  
  45. while (1)
  46. { for (i=0;i<255;i++)
  47. {R_channel--; G_channel++;
  48. delay(s);//задержка
  49. }
  50. for (i=0;i<255;i++)
  51. {G_channel--; B_channel++;
  52. delay(s);//задержка
  53. }
  54. for (i=0;i<255;i++)
  55. {B_channel--; R_channel++;
  56. delay(s);//задержка
  57. }
  58. }
  59. return 1;
  60. }

Я делал похожее. У меня MC-E

Я делал похожее. У меня MC-E RGB.
Есть 2 кнопки и 2 режима: "цветной" и "белый".
Переход между режимами производиться одновременным нажатием обоих кнопок. В "белом" режиме можно менять яркость белого кристалла. А в "цветном" - цвет свечения (изменяется по кругу).

Я бы не писал данные в EEPROM, а просто бы переводил МК в спящий режим, потребление минимально и содержимое переменных целое, да и мороки минимум.

идея классная! хотел так

идея классная! хотел так сделать и что бы это все можно было управлять с дивана с ик пульта. :)
самому соображалки не хватает...

Готовый пульт + RC5? :)

Готовый пульт + RC5? :)

Если надо делать стоп по

Если надо делать стоп по нажатию кнопки - значит эта кнопка от внешнего прерывания должна быть. Соответственно вторая кнопка прерывания должна срабатывать и заводить в меню! В котором и можно выбрать записать значение в память или изменить яркость, после чего можно записать в память.

Я думаю логика понятна.

Изменение скорости

Я San. Почему-то не работает регистрация. Письмо не приходит.:(
Это мне принадлежит комментарий "То, что я искал! :)".
Я решил усовершенствовать схему и добавить в неё две кнопки, как было написано в статье "Работа с прерываниями INT0 и INT1", чтобы изменять скорость смены цветов.
Не получается в части внесения каких-либо изменений при нажатии кнопок, только программа в начало при нажатии сбрасывается и всё.
Жду, когда смогу зарегистрироваться, создать тему на Вашем форуме и выложить код.

Все вновь зарегистрированные

Все вновь зарегистрированные проходят ручную модерацию, ОООООЧЕНЬ много спам ботов. Через минуту отправлю логин и пароль. По поводу кода обязательно выкладывай, единственное когда будешь выкладывать код перед его началом напиши так:
тэг для кода программы

И выбери "Input format" - "ac"

это сделает подсветку кода, будет красиво как в редакторе.

Не могу тему в форуме создать

Не могу тему в форуме создать или не понял, как это сделать.
А я-то думал, как так: у других коды разноцветные, а у меня ч/б. :)

Попробуй еще разок, там надо

Попробуй еще разок, там надо нажать Create content, Blog entry и все должно работать. Сайт новый, еще просто никто на форуме не писал кроме меня и Сереги.

Вот теперь вижу - "Post new

Вот теперь вижу - "Post new Forum topic". :)
Подкоплю материальчика и создам тему.

То, что я искал! :)

То, что я искал! :)

Давай давай, пробуй собирать

Давай давай, пробуй собирать и отписывайся как успехи!

Собрал, работает! :) Вот

Собрал, работает! :) Вот только у светодиодов ВАХ не линейная и яркость отдельных светодиодов резко возрастает. Сделать бы более плавное увеличение яркости в начале. Подбором значения RGB_Pause удалось добиться более-менее приемлемого результата. :) Но из-за того, что у красного светодиода напряжение падения меньше, чем у зелёного и синего, кажется, что красные резко вспыхивает. Добавить бы функцию в красный канал, чтобы значение изменялось бы нелинейно. Я так пока ещё не умею. :(

Видео

Добавил видеоответ на ютубе на ваш ролик "Cree MC-E RGB with ATmega8 3 PWM channels". :)

"резисторы R4,R5,R7 – 10 ом

"резисторы R4,R5,R7 – 10 ом (я не проводил балансировку цветов..."

1)Поиграйся с номиналом ограничительного резистора, для красного кристалла.
2)Можно сделать "нелинейность" увеличивая-уменьшая R_channel не на 1 как в примере, а на 1,5 а потом округлять до ближайшего целого функцией lround();

Для этого делаю переменную double Red_brightness=0;
В вечном цикле увеличиваем-уменьшаем ее на 1,5-2,5 единицы, а потом заносим это все в R_channel вот так: R_channel=lround(Red_brightness); Также не забываем подключать модуль , где содержится функция lround.
Но нужно предусмотреть проверку на переполнение R_channel.