А ты свой код дизассемблируй и поймешь. В прерывании от таймера в стэке сохраняются 28(!) регистров. Сохранение-восстановление одного регистра - 8 тактов, плюс столько же на вход и выход из прерывания. То есть если процессор только тем и будет заниматься, что обрабатывать это прерывание, получим 30 шагов - явно маловато, да и процессору кроме этого еще есть чем заняться. Да и вообще делать по принципу "работает - и ладно" - неправильно, ИМХО.
Добавлено спустя 36 минут 59 секунд:- Код: Выделить всё • Развернуть
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
uint8_t* port;
uint8_t* servoPtr;
uint8_t servoValues[9*2];
ISR(TIMER0_COMP_vect)
{
uint8_t time = *servoPtr;
servoPtr++;
*port = *servoPtr;
servoPtr++;
if (time) {
OCR0 += time;
} else {
TCCR0 = 0;
}
}
port - адрес порта, к которому подключены сервы, для обращения как к ячейке памяти.
servoPtr - указатель на текущее значение в таблице servoValues
servoValues - таблица, содержащая значения выводимые в порт, и время, в течение которого это время сохраняется. Каждые 4-5 мс устанавливаем новое значение port, ставим servoPtr на начало таблицы, заполняем таблицу значениями, выводим все 1 в порт и запускаем таймер на срабатывание прерывания через 1000 мкс (мин. длина импульса). Например если у нас 3 сервы подключенные к порту B[1,7,2], и длительность импульсов 1000, 1100, 1300 то таблица будет выглядеть так:
{100, 11111101b, 200, 01111101b, 0, 01111001b}, только длительность естественно надо пересчитать из микросекунд в периоды тактовой частоты таймера, port будет 0x38.
Если все это на ассемблере написать, 100 шагов можно будет получить, причем на любой ноге МК. Ну и все прочие обработчики прерываний пересмотреть, чтобы прерывания были запрещены минимальное время.