Для отображения всей палитры видимых оттенков теоретически достаточно иметь три цвета. Это — так называемый RGB-синтез (Red — красный, Green — зеленый, Blue — синий). Но в реальности трех цветов бывает недостаточно. Смешивание цветов может происходить одним из трех способов. Светодиоды могут раздельно располагаться в светильнике, а цвета смешиваются уже непосредственно на освещаемом объекте. Преимущества такого подхода — простота конструкции и высокая светоотдача. Недостаток — наличие нескольких разноцветных теней для объектов, расположенных близко к светильнику. Более сложный вариант — оптическая система, смешивающая лучи от разных светодиодов. Наконец, выпускаются специальные RGB-светодиоды, объединяющие в одном корпусе три кристалла разных цветов. Использование RGB-светодиодов позволяет создать очень тонкий осветительный прибор, дающий равномерный свет без заметных зон затенения.
Аноды RGB светодиода подключаем к линиям 1,2,3 порта В, катоды соединяем с минусом. Чтобы получить разнообразные палитры цвета на аноды будем подавать ШИМ сигнал в определенной последовательности. В этом примере мы специально используем программный ШИМ, хотя на ATmega8 можно без проблем получить аппаратный ШИМ на 3 канала. Программный ШИМ можно использовать в случаях нехватки таймеров/счетчиков и по другим причинам. Для генерации ШИМ определенной частоты используем прерывание по переполнению 8-ми битного таймера Т0(TIMER0_OVF_vect). Так как предделитель не используем частота переполнения таймера будет равна 31250Гц. В обработчике прерывания исходя из значений в переменных pwm_r, pwm_g, pwm_b переключаются ножки порта В. Цветовые эффекты настраиваются с помощью функций, где задается время свечения светодиода. В тестовой программе сначала загораются красный, зеленый, синий, белый цвета, а потом начинается цикл с переходами цвета.
// Управление RGB светодиодом. Программный ШИМ #include <avr/interrupt.h> #include <avr/io.h> volatile unsigned char pwm_r, pwm_g, pwm_b; // Прерывание по переполнению Т0 ISR(TIMER0_OVF_vect) { static unsigned char pwm_counter; // Если значение яркости больше значения счетчика // включаем соответствующий вывод if(pwm_counter < pwm_r) PORTB |= (1 << PB1); // Иначе вывод выключен else PORTB &= ~(1 << PB1); if(pwm_counter < pwm_g) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); if(pwm_counter < pwm_b) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Инкрементируем счетчик pwm_counter++; } // Процедура задержки в микросекундах void delay_us(unsigned char time_us) { register unsigned char i; for(i = 0; i < time_us; i++) // 4 цикла { asm (" PUSH R0 "); // 2 цикла asm (" POP R0 "); // 2 цикла // 8 циклов = 1 us для 8MHz } } // Процедура задержки в миллисекундах void delay_ms(unsigned int time_ms) { register unsigned int i; for(i = 0; i < time_ms; i++) { delay_us(250); delay_us(250); delay_us(250); delay_us(250); } } // Красный цвет void red (unsigned char time) { for(unsigned char a = 0; a < 255; a++) { pwm_r = a; // Увеличение pwm_g = 0; pwm_b = 0; delay_ms(time); } for(unsigned char a = 255; a > 0; a--) { pwm_r = a; // Уменьшение pwm_g = 0; pwm_b = 0; delay_ms(time); } } // Зеленый цвет void green (unsigned char time) { for(unsigned char a = 0; a < 255; a++) { pwm_r = 0; pwm_g = a; pwm_b = 0; delay_ms(time); } for(unsigned char a = 255; a > 0; a--) { pwm_r = 0; pwm_g = a; pwm_b = 0; delay_ms(time); } } // Синий цвет void blue (unsigned char time) { for(unsigned char a = 0; a < 255; a++) { pwm_r = 0; pwm_g = 0; pwm_b = a; delay_ms(time); } for(unsigned char a = 255; a > 0; a--) { pwm_r = 0; pwm_g = 0; pwm_b = a; delay_ms(time); } } // Белый цвет void white (unsigned char time) { for(unsigned char a = 0; a < 255; a++) { pwm_r = a; pwm_g = a; pwm_b = a; delay_ms(time); } for(unsigned char a = 255; a > 0; a--) { pwm_r = a; pwm_g = a; pwm_b = a; delay_ms(time); } } // Переход цветов void rgb (unsigned char time) { for(unsigned char a = 0; a < 255; a++) { pwm_r = a; pwm_g = 255 - a; delay_ms(time); } for(unsigned char a = 0; a < 255; a++) { pwm_b = a; pwm_r = 255 - a; delay_ms(time); } for(unsigned char a = 0; a < 255; a++) { pwm_g = a; pwm_b = 255 - a; delay_ms(time); } } int main (void) { // Порты ввода/вывода DDRB = 0xFF; // Порт B выход PORTB = 0x00; // Таймер 0 TCCR0 |= (1 << CS00); // Тактирование Т0 без предделителя TIMSK |= (1 << TOIE0); // Разрешаем прерывание по переполнению Т0 sei(); // Глобально разрешаем прерывания while(1) { red(5); // Включаем эффекты green(5); blue(5); white(10); for(;;) { rgb(100); } } }
Обсуждение статьи на форуме
Архив для статьи "Зажигаем RGB светодиод. Программный ШИМ" | |
Описание: Файлы проекта для AVR Studio | |
Размер файла: 26.71 KB Количество загрузок: 2 441 | Скачать |
Комментарии
функции "Процедура задержки в микросекундах" и "Процедура задержки в миллисекундах"
Для малых значений задержки используем ассемблерные вставки(две
команды по 2 цикла МК) - это я понял.
Но не вижу где используем эти функции.
Что обозначают переменные time_us и
time_ms?
такие функции(или подобные) встречаются
довольно часто.
запись в цикле while(1):
red(5); // Включаем эффекты
green(5);
blue(5);
white(10);
for(;;)
{
rgb(100);
}
Спасибо.
Спасибо.