Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вызов функции из interrupt [TIM2_OVF]
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Savrik
Есть обработчик прерывания(1 мс)
Код
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
    // Reinitialize Timer 2 value
    TCNT2=0x83;  //сразу переинициализируем таймер
    // Place your code here
    timer++;
    if ((timer%2000) == 0)lcdUpdateStatus = 1;
    if (timer == 10000)
        {  
            timer = 0;
        }
}

и есть функция
Код
void systemCheck()
{
    uchar i;
    if (systemBusy)return;
    systemBusy = 1;
    ADMUX = ADC_U_MINUS;
    for (i = 0; i < 20; i++)
    {
        ADCSRA.6 = 1;    
        while(ADCSRA.6 != 0);    
    }    
    currSysStatus.Uminus = adc_data;  //currSysStatus глобальная структура
    ADMUX = ADC_U_PLUS;
    for (i = 0; i < 20; i++)
    {
        ADCSRA.6 = 1;    
        while(ADCSRA.6 != 0);    
    }    
    currSysStatus.Uplus = adc_data;
    selectInput(MULTIPLEX_L_TEMP);//выбираем соот. вход мультиплексора
    ADMUX = ADC_MULTIPLEX;
    for (i = 0; i < 20; i++)
    {
        ADCSRA.6 = 1;    
        while(ADCSRA.6 != 0);    
    }    
    currSysStatus.temp_L = adc_data;
    selectInput(MULTIPLEX_R_TEMP);    //выбираем соот. вход мультиплексора
    for (i = 0; i < 20; i++)
    {
        ADCSRA.6 = 1;    
        while(ADCSRA.6 != 0);    
    }    
    currSysStatus.temp_R = adc_data;
    systemBusy = 0;  
}

Если вызывать функцию из основного тела программы(напр., цикла в main() каждые 2000 мс), то все так, как надо
Цитата
Umin 1023 Uplus 0, ACErr 0 Lalar 0 Ralar 0 Ltemp 275 Rtemp 254

но если я вызываю из обработчика прерывания каждые 2000, то валится какой-то бред..
Цитата
Umin 259 Uplus 0, ACErr 0 Lalar 0 Ralar 0 Ltemp 259 Rtemp 259
Функция критична, так как в ней фактически реализован контроль за питанием усилителя.. вызывать из основного тела нереально ввиду того, что есть многоуровневое меню.. Что я не так делаю, и какие есть варианты.. мне нужно быть уверенным, что функция ТОЧНО вызовется через каждые 50 мс..
smac
Цитата(Savrik @ Feb 3 2010, 03:56) *
Что я не так делаю, и какие есть варианты.. мне нужно быть уверенным, что функция ТОЧНО вызовется через каждые 50 мс..

Вызывать функции из обработчиков прерываний совсем не комильфо, но если очень хочется, тогда нужно обратить внимание на стек ну и ассемблерный листинг неплохо бы посмотреть.
jasper
Возможно, следует объявить глобальные переменные, как volatile.
ut1wpr
Цитата(jasper @ Feb 3 2010, 08:12) *
Возможно, следует объявить глобальные переменные, как volatile.

Для начала попробуй выключить всю оптимизацию. Абсолютно всю. Затем посмотри, может стека мало.
Уж очень большую функцию вызываешь. Правильно сказано, не кошерно это.
Программирование чаще всего - не реализация алгоритма, а его поиск. Может, в консерватории что-то подправить? smile.gif
_Pasha
Цитата(ut1wpr @ Feb 3 2010, 09:42) *
Может, в консерватории что-то подправить? smile.gif

Там, похоже, надо голову сменить. Кстати, одно исключение имеется когда ситуация
Цитата
Функция критична ... вызывать из основного тела нереально ввиду того, что есть многоуровневое меню

возможна в реальной жизни - для Low Power Design, там где нельзя мучить МК переключением контекстов.
Сергей Борщ
Цитата(jasper @ Feb 3 2010, 07:12) *
Возможно, следует объявить глобальные переменные, как volatile.
Ага. Все. Не глядя. Вот объясните - какими мыслями вы руководствуетесь, давая такие советы?


Цитата(ut1wpr @ Feb 3 2010, 07:42) *
Для начала попробуй выключить всю оптимизацию. Абсолютно всю.
Тоже совет из серии "закрой окно, по колесу постучи".


Цитата(Savrik @ Feb 3 2010, 02:56) *
и есть функция
все операции с SystemBusy можно смело выкинуть - у вас нет разрешения вложенных прерываний, значит этот код не будет прерван. Покажите объявление currSysStatus. Добавьте в его еще конец одно поле и выводите его вместе с остальными данными. Если увидите там не 0 - у вас нехватка стека, надо переделывать программу, сокращая количество глобальных переменных. Какой смысл делать 20 преобразований АЦП, не используя их результат? Добавьте дерганье ногой в начале и конце этой функции, убедитесь, что прерывание таймера вызывает ее именно раз в 2 сек.

Цитата(Savrik @ Feb 3 2010, 02:56) *
какие есть варианты.. мне нужно быть уверенным, что функция ТОЧНО вызовется через каждые 50 мс..
Кристалл не указан - у новых мег есть возможность запускать АЦП от событий таймера. Точне вы не получите. А тем более программно.
Savrik
Цитата(smac @ Feb 3 2010, 06:56) *
Вызывать функции из обработчиков прерываний совсем не комильфо, но если очень хочется, тогда нужно обратить внимание на стек

Стек в порядке.. из других, намного тяжелее функций, вызов идет нормально. К тому же, (правда, не знаю, насколько это оптимально и как правильно работает в компиляторе CAVR) стек увеличен до 300 байт.

Цитата(Сергей Борщ @ Feb 3 2010, 10:00) *
все операции с SystemBusy можно смело выкинуть - у вас нет разрешения вложенных прерываний, значит этот код не будет прерван. Покажите объявление currSysStatus. Добавьте в его еще конец одно поле и выводите его вместе с остальными данными. Если увидите там не 0 - у вас нехватка стека, надо переделывать программу, сокращая количество глобальных переменных. Какой смысл делать 20 преобразований АЦП, не используя их результат? Добавьте дерганье ногой в начале и конце этой функции, убедитесь, что прерывание таймера вызывает ее именно раз в 2 сек.
Кристалл не указан - у новых мег есть возможность запускать АЦП от событий таймера. Точне вы не получите. А тем более программно.

20 преобразований это на будущее) Прерывание точно вызывает раз в 2 секунды. Извините, забыл - ATMega16L. Добавил поле, и оно 0.. вот и сама структура
Код
typedef struct sysSettings {
    uchar        brightness;
    uchar        contrast;
    uint         fan1;
    uint         fan2;
    uint         temp_L;
    uint         temp_R;
    uint         Uplus;
    uint         Uminus;
    uchar          LAlarm;
    uchar          RAlarm;
    uchar          ACError;
    uchar        Mute;
    uchar test;
} c_SystemSettings;

используется по всей программе, нигде проблем со стеком не замечено. Могу грешить только на adc_data, так как во всех переменных, изменяемых systemCheck() они одинаковые..


P.S. тьфу.. я же из прерывания запускаю преобразование АЦП. Смогу ли я получить прерывание по завершению преобразования, если сейчас нахожусь в другом, более низкоуровневом прерывании?


P.P.S. так как нету прерывания по завершению АЦП, решил следующим образом:
Код
...
currSysStatus.temp_R = ADCW;  //вместо currSysStatus.temp_R = adc_data;
...

Прошу прощения за собственную глупостьsmile.gif И спасибо всем за советы, направили мозги в нужное направление)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.