Прервать бесконечный цикл по таймеру - как?
Добавлено: Пн дек 02, 2013 12:53:20
Всем здравствуйте. Осваиваю свой первый в жизни микроконтроллер - Attiny2313. Хочу сделать подсветку на RGB-светодиоде. Алгоритм работы должен быть такой: при включении девайса RGB-светодиод выдает цвет из памяти (EEPROM). При нажатии кнопки запускается выбор цвета (светодиод переливается цветами по всему спектру). При отпускании кнопки светодиод горит выбранным цветом (которым он светился при отпускании кнопки). Вроде бы все просто. Но дело в том, что когда работает бесконечный цикл функции selcolor, на прерывание по таймеру МК не реагирует, и никак невозможно из этого бесконечного цикла его вырвать. Что я делаю не так. Или может кто-то подскажет более правильный алгоритм???
Код (реализацию ШИМ почерпнул в интернете). Работа с EEPROM пока не реализована. Кнопка висит на PB0, а светодиод на PD0,PD1,PD2:
Код (реализацию ШИМ почерпнул в интернете). Работа с EEPROM пока не реализована. Кнопка висит на PB0, а светодиод на PD0,PD1,PD2:
Код: Выделить всё
#include <avr/io.h>//подключаем библиотеку ввода/вывода
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#define nop() {asm("nop");}//функция необходимая для реализации задержки
volatile unsigned int ir,ig,ib,p,pp,c,buf,ms,x;//перечисление переменных
// функция задержки
void delay_ms(int ms)
{
for (x=ms;x>0;x--) nop();
}
// функция включения красного светодиода
void ledon0(int ms)
{
PORTD &= ~_BV(PD0); delay_ms(ms);
}
Спойлер
Код: Выделить всё
// функция включения зеленого светодиода
void ledon1(int ms)
{
PORTD &= ~_BV(PD1); delay_ms(ms);
}
// функция включения синего светодиода
void ledon2(int ms)
{
PORTD &= ~_BV(PD2); delay_ms(ms);
}
// функция выключения красного светодиода
void ledoff0(int ms)
{
PORTD |= _BV(PD0); delay_ms(ms);
}
// функция выключения зеленого светодиода
void ledoff1(int ms)
{
PORTD |= _BV(PD1); delay_ms(ms);
}
// функция выключения синего светодиода
void ledoff2(int ms)
{
PORTD |= _BV(PD2); delay_ms(ms);
}
void normwrk(void)
{
while(1)
{
//Когда кнопка выбора цвета не нажата, остается выбранный цвет
ledon1(ig); ledoff1(pp-ig);
ledon0(ir); ledoff0(pp-ir);
ledon2(ib); ledoff2(pp-ib);
}
}
void selcolor(void)
{
while(1)
{
//Зажигаем красный светодиод
PORTD &= ~_BV(PD0);
//плавное зажигание зеленого светодиода
for (ig = 0; ig < pp; ig++)
{
p=pp-ig; ledon1(ig); ledoff1(p);
}
//Зеленый светодиод остается гореть
PORTD &= ~_BV(PD1);
//плавное гашение красного светодиода
for (ir = 0; ir < pp; ir++)
{
p=pp-ir; ledon0(p); ledoff0(ir);
}
//Зеленый светодиод остается гореть
PORTD &= ~_BV(PD1);
//плавное зажигание синего светодиода
for (ib = 0; ib < pp; ib++)
{
p=pp-ib; ledon2(ib); ledoff2(p);
}
//Синий светодиод продолжает гореть
PORTD &= ~_BV(PD2);
//Плавное гашение зеленого светодиода
for (ig = 0; ig < pp; ig++)
{
p=pp-ig; ledon1(p); ledoff1(ig);
}
//Синий светодиод продолжает гореть
PORTD &= ~_BV(PD2);
//постепенное зажигание красного светодиода
for (ir = 0; ir < pp; ir++)
{
p=pp-ir; ledon0(ir); ledoff0(p);
}
//Красный светодиод продолжает гореть
PORTD &= ~_BV(PD0);
//Плавно тушим синий светодиод
for (ib = 0; ib < pp; ib++)
{
p=pp-ib; ledon2(p); ledoff2(ib);
}
}
}
// interrupt service routine (ISR) for timer 0 A compare match
SIGNAL (SIG_TIMER0_COMPA)
{
static char toggle = 0;
// toggle the LED on each interrupt
if (toggle==0 && bit_is_set(PINB,PB0))
{
delay_ms(50);
if (toggle==0 && bit_is_set(PINB,PB0))
{
toggle = 1;
selcolor();
}
}
else if (toggle==1 && !bit_is_set(PINB,PB0))
{
toggle = 0;
normwrk();
}
}
int main( void ) //главная программа
{
//конфигурирование на вывод порта D
DDRD |= _BV(PD0);//конфигурирование битов
DDRD |= _BV(PD1);//PD0, PD1 и PD2
DDRD |= _BV(PD2);//на выход
PORTD = 0xFF; //включаем подтягивающие резисторы
PORTB = 0b11111111; //Конфигурирование битов порта B ("в воздухе" с порта B будет читаться логическая 1)
DDRB = 0b00000000; //Конфигурирование порта B как входа
pp=255; //задаем скорость зажигания /гашения
ir=ig=ib=128;
TCCR0A = 0b00000000; //обычный режим таймера
TCCR0B = 0b00000011; //режим предделителя CLK/1024
TIMSK = 0b00000001; //разрешаем прерывания по переполнению
sei(); // global interrupt enable
normwrk();
while(1){}
}