Концептуально можно ускорить код - если вместо проверки каждого канала в каждом "Loop'e" таймера, организовать всего 14+1 прерываний от таймера за период в 256 тиков. (Где 14 прерываний соответствуют 14-ти каналам PWM, 15-ое - сброс всех каналов в исходное состояние).
Итого для 8-ми битной глубины у вас будет не 256 прерываний за период длительностью меньше 300 тактов на обработку каждого,
а всего 14+1 с ресурсом 256 * 300 / 15 = 5120 тактов на каждое. Если время срабатывания расчитывать на цикл вперед, то обработчики прерывания будут очень короткими.
Программировать время следующего срабатывания каждого из прерываний можно например при сбросе всех каналов в исходное состояние.
код сведется к чему-то такому:
Код
Timer_CompA_ISR()
{
turn_off( CurrentChan++ );
if (CurrentChan > MAX_CHAN_COUNT)
{
CurrentChan = 0;
return;
}
OCRA = ChanGetLifeTime( CurrentChan );
}
Timer_OvrISR()
{
// врубить все
turn_on( AllChannels );
// посчитать такт отключения каждого из каналов (время "жизни")
UpdateLifeTime( ... );
// отсортировать каналы по времени жизни по-возрастанию
SortChannelsByTimeAscending( ... );
}
А можно и в основном цикле программы. Обработка частных случаев (кода время жизни нескольких каналов будет совадать) тоже большого труда не составит:
Код
Timer_CompA_ISR()
{
turn_off( CurrentChan++ );
if (CurrentChan > MAX_CHAN_COUNT)
{
CurrentChan = 0;
return;
}
if (OCRA == ChanGetLifeTime( CurrentChannel ) )
Timer_CompA_ISR(); // запустить сл. канал прямо сейчас (лучше всего rjmp'ом)
else
OCRA = ChanGetLifeTime( CurrentChan ); // проапдейтить таймер на прерывание в нужное время
}