ROOT> SAA, 22.11.2005 06:36:39:
ROOT> Сделай прерывание как можно короче, обработку вынеси в основной цикл в прерывании только считывание и инкремент. Остальное в главном цикле, не забудь в цикле уйти в "halt" slpeep-ом, тогда после каждого прерывания в системе ты будешь возвращаться в главный цикл и в спокойной обстановке делать обработку (можно даже выключить прерывания на время).
ROOT>
ROOT> Согласен. Но опять не получается получить в главном цикле то, что сохраняю в прерывании. Код сейчас такой:
ROOT> interrupt [ADC_INT] void adc_isr(void)
ROOT> {
ROOT> last_adc_lo = ADCL;
ROOT> last_adc_hi = ADCH;
ROOT> // start conversion
ROOT> ADCSRA |= ADEN;
ROOT> PORTB = last_adc_lo;
ROOT> PORTE = last_adc_hi;
ROOT> sample_index++;
ROOT> PORTD = sample_index;
ROOT> }
ROOT> Все нормально, получаю на PORTB и PORTE непрерывно меняющееся двоичное значение сигнала. Но я не могу поймать в главном цикле значения, которые я сохраняю в прерывании
Тут вот что, сколько еще прерываний происходит в системе, от другого оборудования? Если только одно, то достачтоно будет
code text
ROOT> last_adc_lo = ADCL;
ROOT> last_adc_hi = ADCH;
а в главном цикле так:
while(true) // true - определена не везде, кое где необходимо 1
{
asm("sei");
asm("sleep");
asm("cli");
// // тут мы появимся только после возникновения и отработки прерывания (если в // обработчике прерывания сами прерывания запрещены!!!!// // Проводим обработку.
PORTB = last_adc_lo;
PORTE = last_adc_hi;
PORTD = ++sample_index;
ADCSRA |= ADEN; // только после обработки!!!
}
Но если прерывание в системе не от одного устройства то нужно дополнительно исследовать флаги, на предмет выяснения того кто вынул нас из halt состояния
ROOT> Вот про sleep поподробнее. sleep_enable(), что ли?
Это скорее всего установка режива разрешения "сна". По крайней мере в WinAVR есть две библиотечные функции установки режима sleep[но там используется константа режима "сна"] и самого sleep [перевода процессор ав режим "сна" из которого его выдернет прырывание], причем я предпочитаю использовать именно асм. комманду sleep, так как в WinAVR под sleep подразумевается несколько более универсальная функция. Их описание есть в sleep.h:
extern void set_sleep_mode (uint8_t mode);
extern void sleep_mode (void);
А при возникновении прерывания МП сам "пробуждается"? Или его надо делать перед условием ожидания числа выборок, а потом сбрасывать через sleep_disable()?
Нет нет, режимов "сна" несколько вплоть до Power Save, прерывания выодят его из состояния sleep причем первое прешедшее. Раньше в 8080 была команда HLT, так это сродни этому.
ROOT> АЦП - 125 кГц, проц - 4 Мгц
ROOT> насчет вложенности ты, думаю, прав... Потому что при вышеприведенном коде значение PORTD в симуляторе протеуса - 0 или 1.
Лучше поставить эксперимент в VMLab, а то что то Протеус достаточно сложен в настройке (убедился на собственном примере).
Давай посчитаем при тактовой 4MHz каков у тебя запас кода на прерывание, что бы не получить вложенности (ну вложенность только при условии что прерывания разрешены в обработчике - ты это проверял?)
Длительность одного такта 1/4E6 = 0,25 мкс = 250 нс.
При условии, что прерывания от АЦП приходят с частотой 125 кГц длительность окна свободного от обработки прерывания составит 1/125E3 = 0,008 мс = 8 мкс
Таким образом кол-во тактов от прерывания АЦП до его следующего прерывания = 8/0,25 = 32 такта MCU
При условии что на 1 комманду тратится 2 такта (худший вариант), то у нас 16 комманд
а это очень и очень мало, так как существуют еще непроизводственные потери таие как вход в прерывание - 2 такта, т.е. комманд у нас уже 15. Я думаю если глянешь листинг асм от CodeVision и увидишь что в обработчике прерывания у тебя разрешены прерывания - смело можешь считать что у тебя вложенность.
ROOT> interrupt [ADC_INT] void adc_isr(void)ROOT> { ROOT> last_adc_lo = ADCL;ROOT> last_adc_hi = ADCH; ROOT> // start conversion ROOT> ADCSRA |= ADEN;
^^^^^^^^^^^^^^^^^^^^^^^^^
Если прерывания разрешены, то с этого момента начиинай отсчитывать такты
по хорошему надо тащить это в конец прерывания
ROOT> PORTB = last_adc_lo;ROOT> PORTE = last_adc_hi;ROOT> sample_index++; ROOT> PORTD = sample_index; ROOT> }
Но лучшим выбором будет разнести обработку и само прерывание!!!!