Управление светодиодами RGB. Программный ШИМ AVR.

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
lisok88
Родился
Сообщения: 4
Зарегистрирован: Пт май 18, 2012 23:03:42

Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение lisok88 »

Здравствуйте! Хотелось бы поуправлять светодиодами RGB, и не одним, а например десятью. Как я понимаю аппаратным ШИМ не получится, не хватит выводов . Попробовал программный, но светодиод заметно мерцает. Работает схема на внутреннем кварце частота 1 МГц. Может поэтому? Возможно ли частоту внутреннего кварца повысить или подключать внешний? Микросхема Atmega16. Вот программа:

Код: Выделить всё

#include <mega8.h>
#include <delay.h>

volatile char pwm_counter,pwm_r,pwm_g,pwm_b;

/*** прерывание по переполнению Таймера 0 ***/
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
	if (pwm_counter++ > 163) 
	{
        PORTB = 0x00;
	pwm_counter = 0;
	}
	if (pwm_counter > pwm_r)
	PORTB.1 = 1;
	if (pwm_counter > pwm_g)
	PORTB.2 = 1;
	if (pwm_counter > pwm_b)
	PORTB.3 = 1;	
}

/*** красный цвет ***/
void red (unsigned int time)
	{char a;
        for (a = 0; a<165; a++)
		{
                 pwm_r = 164 - a; //увеличение
	         pwm_g = 164;
                 pwm_b = 164;
	         delay_ms(time);
		}     
        for (a = 0; a<165; a++)
		{
                 pwm_r = a; //уменьшение
		 pwm_g = 164;
		 pwm_b = 164;
		 delay_ms(time);
		}
	}

/*** зеленый цвет ***/
void green (unsigned int time)
	{char a;
        for (a = 0; a<165; a++)
		{
                 pwm_r = 164;
		 pwm_g = 164 - a;
                 pwm_b = 164;
		 delay_ms(time);
		}     
        
		for (a = 0; a<165; a++)
		{
                 pwm_r = 164;
		 pwm_g = a;
		 pwm_b = 164;
		 delay_ms(time);
		}

	}
/*** синий цвет ***/
void blue (unsigned int time)
	{char a;
        for (a = 0; a<165; a++)
		{
                 pwm_r = 164;
		 pwm_g = 164;
                 pwm_b = 164 - a; 
		 delay_ms(time);
		}     
        for (a = 0; a<165; a++)
		{
                 pwm_r = 164;
		 pwm_g = 164;
		 pwm_b = a; 
		 delay_ms(time);
		}
	}
/*** белый цвет ***/
void white (unsigned int time)
	{char a;
        for (a = 0; a<165; a++)
		{
                 pwm_r = 164 - a;
		 pwm_g = 164 - a;
                 pwm_b = 164 - a;
		 delay_ms(time);
		}     
        for (a = 0; a<165; a++)
		{
                 pwm_r = a;
		 pwm_g = a;
		 pwm_b = a; 
		 delay_ms(time);
		}
	}
/*** переход цветов ***/
void rgb (unsigned int time)
	{char a;
	    for (a = 0; a<165; a++)
		{
		 pwm_r = a;
		 pwm_b = 164 - a;
		 delay_ms(time);
		}

		for (a = 0; a<165; a++)
		{
		 pwm_b = a;
		 pwm_g = 164 - a;
		 delay_ms(time);
		}
		
		for (a = 0; a<165; a++)
		{
		 pwm_g = a;
		 pwm_r = 164 - a;
		 delay_ms(time);
		}
	}

void main (void) 
{
	DDRB = 0x0E; // PB3,2,1 - выходы
        PORTB = 0x00;
        TIMSK = 0x01; // разрешение прерывания
	TCCR0 = 0x01; // без предделителя
	
	#asm("sei"); // глобальное разрешение прерываний

        while(1)
	{ 	
        red(5);
        green(5);		
        blue(5);
	white(10);
	for(;;) 
	{rgb(100);}
	}
}


Еще вопрос. Как бы рациональнее все это осуществить. Просто через транзисторы или брать сразу драйвер для светодиодов. Заранее спасибо!!!
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15571
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение BOB51 »

на ассемблере подскажу, на Сии - избави... :beer:
Реклама
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение Engineer_Keen »

Внутреннего кварца не бывает, бывает внутренний RC-генератор. Обычно у АВР-ок его можно выставить фьюзами до 8 МГц. У вас таймер переполняется с частотой 1МГц/256 = 3900Гц, а частота ШИМ получается 3900/164=24Гц, что конечно маловато. Можно не менять источник тактирования, вариантов много. Можно сделать прерывание по совпадению с регистром (OCRxx), занести в него 128 и в его обработчике скопировать обработчик из прерывания по переполнению - будет в 2 раза чаще. Можно перевести таймер в режим CTC, и занести в OCR например 32, тогда ШИМ будет с частотой в 8 раз больше.
lisok88
Родился
Сообщения: 4
Зарегистрирован: Пт май 18, 2012 23:03:42

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение lisok88 »

Спасибо!!! Я начинающий и пока не понимаю как это все сделать... Ладно надо тогда еще поучиться :)) )))
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
urry
Сверлит текстолит когтями
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница
Контактная информация:

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение urry »

я здесь целую оперу написал
http://radiokot.ru/forum/viewtopic.php? ... 3#p1280463
Реклама
lisok88
Родился
Сообщения: 4
Зарегистрирован: Пт май 18, 2012 23:03:42

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение lisok88 »

Поменял частоту на 8 Мгц мерцание пропало. Но заметил странную вещь. Программой предусматривается плавное изменение цвета. Сначала включается например красный и синий и меняется значение синего, потом синий и зеленый и т.д Но почему то не всегда происходит смешивание, т.е отдельно видно красный и отдельно синий. И еще интересно есть ли какая нибудь палитра для светодиодов, что бы быстро получить нужный тебе цвет? Или легче сделать схему для подборки вручную? :roll:
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15571
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение BOB51 »

для глаза одно восприятие- для железа это совсем другое
один и тот же уровень по осциллографу вызовет разные ощущения на красном, зеленом или синем
да и индивидуальное восприятие во многом зависит от конструкции экрана
лучше предусмотреть возможность окончательной подгонки параметров на уже завершенной конструкции :beer:
Аватара пользователя
Финский
Открыл глаза
Сообщения: 59
Зарегистрирован: Сб авг 28, 2010 13:29:43
Откуда: Докучаевск, Донецк
Контактная информация:

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение Финский »

Вот здесь почитайте о программном ШИМ - BAM: Альтернатива ШИМу
И рядом - управление RGB светодиодом - Mood Lamp – лампочка с характером
[color=#800000]Техноманьяк и IT-шаман. Танцы с бубном на дому.[/color]
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15571
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение BOB51 »

ой-ой-ой!!!
на том bamе свои "камушки" имеются!!!
проверенно на практике - если работать с фиксированным уровнем все хорошо, но только попытайся сделать простенький приемчик - плавный перебор уровней от 0 до 0xFF и затем к 0 (по кольцу) сразу эта проблемка вылезет 8)
lisok88
Родился
Сообщения: 4
Зарегистрирован: Пт май 18, 2012 23:03:42

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение lisok88 »

Нашел инфу по BAMу и примеры реализации. Но код пока не очень понятен особенно какую роль играет здесь
direct
. Ладно попробую изучить что такое маски. Может кто разъяснит хоть немного? )) Вот код:

Код: Выделить всё

#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//Global variables here
volatile unsigned char leds[22], direct[22]; //leds - непосредственно значения BAM для светодиодов, direct - направление изменения яркостей для эффектов
unsigned char mask_b, mask_c, mask_d;
unsigned char stage;

char compAArray[8][2] = { {0x4B, 0}, {0x96, 0}, {0x2C, 0x01}, {0x58, 0x02}, {0xB0, 0x04}, 
                                                                                                                {0x60, 0x09}, {0xC0, 0x12}, {0x80, 0x25} };
#define COMPA_HI 1
#define COMPA_LO 0

ISR(TIMER1_COMPA_vect)
{       
        //Паузу делаем после текущего бита. Т.е. если текущий - 7, пауза максимальная
        OCR1AH = compAArray[stage][COMPA_HI];
        OCR1AL = compAArray[stage][COMPA_LO];
        
        PORTB = mask_b;
        PORTC = mask_c;
        PORTD = mask_d;

        TCNT1 = 0;      //Обнуляем таймер-счетчик, иначе он будет продолжать считать до 0xFFFF
        
        //Следующее значение stage
        if (stage > 0)
        {
                stage --;
        } else
        {
                stage = 7;
        }
    mask_b = 0;
    mask_c = 0;
    mask_d = 0;
                
        //Вычисляем маски для следующего вызова прерывания
/************************************************/
        if( (leds[0] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 0);
        } 
/**************************************/                
        if( (leds[1] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 1);
        } 

/************************************************/
        if( (leds[2] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 2);
        } 
/**************************************/                
        if( (leds[3] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 7);
        }               
/************************************************/              
        if( (leds[4] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 5);
        } 
/**************************************/                
        if( (leds[5] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 6);
        } 
/************************************************/              
        if( (leds[6] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 5);
        } 
/**************************************/                
        if( (leds[7] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 4);
        } 
/************************************************/              
        if( (leds[8] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 3);
        } 
/**************************************/                
        if( (leds[9] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 3);
        } 
/************************************************/              
        if( (leds[10] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 4);
        } 
/**************************************/                
        if( (leds[11] & (1 << stage)) != 0)
        {
                mask_d |= (1 << 7);
        } 
/************************************************/              
        if( (leds[12] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 0);
        } 
/**************************************/                
        if( (leds[13] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 2);
        } 
/************************************************/              
        if( (leds[14] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 1);
        }
/**************************************/                
        if( (leds[15] & (1 << stage)) != 0)
        {
                mask_c |= (1 << 0);
        } 
/************************************************/              
        if( (leds[16] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 5);
        }       
/**************************************/                
        if( (leds[17] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 4);
        } 
/************************************************/              
        if( (leds[18] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 3);
        } 
/**************************************/                
        if( (leds[19] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 6);
        } 
/************************************************/              
        if( (leds[20] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 2);
        } 
/**************************************/                
        if( (leds[21] & (1 << stage)) != 0)
        {
                mask_b |= (1 << 1);
        } 




}





void TimerInit(void)
{

        // Timer/Counter 1 initialization
        // Clock source: System Clock
        // Clock value: 8000,000 kHz
        // Mode: CTC top=OCR1A
        // OC1A output: Discon.
        // OC1B output: Discon.
        // Noise Canceler: Off
        // Input Capture on Falling Edge
        // Timer 1 Overflow Interrupt: On
        // Input Capture Interrupt: Off
        // Compare A Match Interrupt: Off
        // Compare B Match Interrupt: Off
        TCCR1A = 0x00;
        TCCR1B = 0x09;
        TCNT1H = 0x00;
        TCNT1L = 0x00;
        ICR1H  = 0x00;
        ICR1L  = 0x00;
        OCR1AH = 0x00;
        OCR1AL = 0x10;
        OCR1BH = 0x00;
        OCR1BL = 0x00;
        TIMSK  = 0x10;
}




int main(void)
{
        DDRB = 0xFF;
        DDRC = 0xFF;
        DDRD = 0xFF;
        TimerInit();
        stage = 7;
        mask_b = 0x00;
        mask_c = 0x00;
        mask_d = 0x00;
        
        unsigned char i, j, f = 0, mode = 0;
        for(i = 0; i < 22; i++)
                {
                        leds[i] = 0;
                        direct[i] = 0;
                }
        asm("sei");

        while(1)
        {

                switch(mode)
                {
                        case 0:
                                for(i = 0; i < 22; i++)
                                {
                                        leds[i] = rand();
                                }
                
                                _delay_ms(500);

                                break;
                        case 1:  //плавно гасим все
                                for(j = 0; j< 255; j++)
                                {
                                        for(i = 0; i< 22; i++)
                                        {
                                                if (leds[i]>0) { f = 1; leds[i]--; }
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(10);
                                                f = 0;
                                        }
                                }
                                break;
                        
                        case 2:  //плавно зажигаем все
                                for(j = 0; j< 255; j++)
                                {
                                        for(i = 0; i< 22; i++)
                                        {
                                                if (leds[i]<255) { leds[i]++; f = 1;}
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(8);
                                                f = 0;
                                        }
                                }
                                break;

                        case 3:  //плавно зажигаем случайно выбранные
                                for(i = 0; i< 22; i++)
                                {
                                        direct[i] = rand() % 2; //остаток от деления на 2 - четное/нечетное (1/0)
                                }
                                for(j = 0; j< 255; j++)
                                {       
                                        for(i = 0; i< 22; i++)
                                        {
                                                if ( (leds[i]<255) && (direct[i]==1) ) { f = 1; leds[i]++; }
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(10);
                                                f = 0;
                                        }
                                }
                                break;
                        case 4:  //плавно гасим случайно выбранные
                                for(i = 0; i< 22; i++)
                                {
                                        direct[i] = rand() % 2; //остаток от деления на 2 - четное/нечетное (1/0)
                                }
                                for(j = 0; j< 255; j++)
                                {       
                                        for(i = 0; i< 22; i++)
                                        {
                                                if ( (leds[i]>0) && (direct[i]==1) ) { f = 1; leds[i]--; }
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(10);
                                                f = 0;
                                        }
                                }
                                break;
                        case 5:  //Плавно зажигаем, потом тушим по очереди, зажигаем по очереди 
                                
                                for(j = 0; j< 255; j++) //Плавно зажигаем все
                                {
                                        for(i = 0; i< 22; i++)
                                        {
                                                if (leds[i]<255) { leds[i]++; f = 1; }
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(12);
                                                f = 0;
                                        }
                                }


                                for(i = 0; i< 22; i++)
                                {
                                        direct[i] = rand() % 2; //остаток от деления на 2 - четное/нечетное (1/0)
                                }
                                for(j = 0; j< 255; j++)
                                {       
                                        for(i = 0; i< 22; i++)
                                        {
                                                if ( (leds[i]>0) && (direct[i]==1) ) { f = 1; leds[i]--; }
                                        }
                                        if (f == 1)
                                        {
                                                _delay_ms(10);
                                                f = 0;
                                        }
                                }
                                break;
                }
                mode = rand() % 6;
        }

}
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15571
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение BOB51 »

блин... опять Сии... :cry:
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение YS »

опять Сии...
Вообще, С гораздо читабельнее асма. :wink:

Топикстартер, а зачем именно программный ШИМ? Что мешает юзать аппаратный?
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15571
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление светодиодами RGB. Программный ШИМ AVR.

Сообщение BOB51 »

это как кто пишет и мыслит (и кто к чему привык) - можно и алгоритм нарисовать - а там уже не все ли равно на каком языке реализовать 8)
кстати... неплохо бы наборчик алгоритмов собрать без привязки к конкретному семейству и языку... :roll:
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»