AVR и аппаратный ШИМ
Добавлено: 29 фев 2012, 23:26
Чем аппаратный ШИМ отличается от программного? В программном мы просто переключаем ножку контроллера с нуля на единицу с большой частотой и меняем задержку между переключениями. В аппаратном ШИМе мы снимаем сигнал с ножек контроллера OC1A, OC1B, OC2 которые напрямую подключены к таймерам/счетчикам, тут остается лишь настроить сами таймеры и менять верхний предел счета для изменения коэффициента заполнения ШИМ. Ниже представлен код проекта управления RGB светодиодом на atmega8.
Код: Выделить всё
/*** Управление RGB светодиодом. Аппаратный ШИМ ***/
#include <avr/io.h>
#include <util/delay.h>
#define pwm_r OCR1A // канал для красного цвета
#define pwm_g OCR1B // канал для зеленого цвета
#define pwm_b OCR2 // канал для синего цвета
/*** красный цвет ***/
void red (unsigned int time)
{
for (char a = 0; a<254; a++)
{
pwm_r = 255 - a; //увеличение
pwm_g = 0;
pwm_b = 0;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_r = a; //уменьшение
pwm_g = 0;
pwm_b = 0;
_delay_ms(time);
}
}
/*** зеленый цвет ***/
void green (unsigned int time)
{
for (char a = 0; a<254; a++)
{
pwm_g = 255 - a;
pwm_r = 0;
pwm_b = 0;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_g = a;
pwm_r = 0;
pwm_b = 0;
_delay_ms(time);
}
}
/*** синий цвет ***/
void blue (unsigned int time)
{
for (char a = 0; a<254; a++)
{
pwm_b = 255 - a;
pwm_g = 0;
pwm_r = 0;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_b = a;
pwm_g = 0;
pwm_r = 0;
_delay_ms(time);
}
}
/*** белый цвет ***/
void white (unsigned int time)
{
for (char a = 0; a<254; a++)
{
pwm_r = 255 - a;
pwm_g = 255 - a;
pwm_b = 255 - a;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_r = a;
pwm_g = a;
pwm_b = a;
_delay_ms(time);
}
}
/*** переход цветов ***/
void rgb (unsigned int time)
{
for (char a = 0; a<254; a++)
{
pwm_r = a;
pwm_b = 255 - a;
pwm_g = 0;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_b = a;
pwm_g = 255 - a;
pwm_r = 0;
_delay_ms(time);
}
for (char a = 0; a<254; a++)
{
pwm_g = a;
pwm_r = 255 - a;
pwm_b = 0;
_delay_ms(time);
}
}
int main (void)
{
DDRB |= (1 << PB3)|(1 << PB2)|(1 << PB1); // PB3,2,1 - выходы
TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10); // сброс OC1A/OC1B при достижении верхнего предела счета
TCCR1B |= (1<<CS10); // без предделителя
TCCR2 |= (1<<CS20)|(1<<COM21)|(1<<WGM20); // без предделителя, сброс OC2 при достижении верхнего предела счета
pwm_r = 0; // начальные установки ШИМ
pwm_g = 0;
pwm_b = 0;
while(1)
{
red(5);
green(5);
blue(5);
white(5);
for(;;)
{rgb(100);}
}
}