реклама на сайте
подробности

 
 
> Вызов функции из interrupt [TIM2_OVF], неправильно обрабатывает данные
Savrik
сообщение Feb 3 2010, 00:56
Сообщение #1


наблюдаю..
***

Группа: Свой
Сообщений: 291
Регистрация: 11-12-06
Из: Украина
Пользователь №: 23 369



Есть обработчик прерывания(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 мс..
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Savrik
сообщение Feb 3 2010, 15:26
Сообщение #2


наблюдаю..
***

Группа: Свой
Сообщений: 291
Регистрация: 11-12-06
Из: Украина
Пользователь №: 23 369



Цитата(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 И спасибо всем за советы, направили мозги в нужное направление)

Сообщение отредактировал Savrik - Feb 3 2010, 15:34
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 00:37
Рейтинг@Mail.ru


Страница сгенерированна за 0.01371 секунд с 7
ELECTRONIX ©2004-2016