|
|
  |
Прерывания в Mega32, Много неясностей |
|
|
|
May 26 2007, 14:18
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
2. "Можно-ли прерывание осуществлять из прерывания (из таймера делать вызов ацп)." Можно, если уверен, что период прерываний от таймера будет больше, чем время, необходимое для запуска АЦП+время на преобразование+время на обработку прерывания от АЦП+время на сохранение или обработку результатов преобразования. Правда если останавливать ТС или маскировать его прерывание, то это время можно не учитывать.
3. "Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки), Короче говоря на что расчитан стек он же не безграничен." Подпрограмма в прерывании может быть. Кол-во зависит от того, сколько входных данных использует подпрограмма и от их типа.
4. "Насколько я понял прерывания эта функция с входными и выходными переменными типа void. То бишь с переменными работать не придется?А как же тогда работать с переменными?" Я, например, объявляю переменные так: volatile char (или int, или long int, или bit) variable_name и в любом месте программы получаю к ней доступ (даже в прерывании).
[/quote]
|
|
|
|
|
May 26 2007, 15:43
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата То бишь с переменными работать не придется? Интересный вывод. main() тоже можно описать как void main(void), разве это как-то помешает работать с переменными? Цитата Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки), Конечно. Количество зависит от объема стека выделенного вами.. для m32 легко можно отвести 512b-1kb под стек. Цитата Может ли находится основная программа в прерывании в плоть до вывода на жк экран к примеру таймера 1 ? В прерывании или не в прерывании не имеет особого значения. Значение имеет то, сможет ли конкретный подход обеспечить выполнение всех задач поставленных в ТЗ. Если основная функция программы выполняется в прерывании (где другие прерывания запрещены), то в этой функции некоторые действия придется решать путем программного опроса (например нельзя будет организовать одновременный прием/передачу по уарту, т.к. в режиме опроса надо проверять флаги состояния; нельзя будет одновременно работать с несколькими периферийными устройствами).. Если вас это устраивает, и программа не сильно сложная - то тогда безусловно можно. Прерывания организованы для того чтобы сделать возможным обработку множества устройств в самый подходящий для этого момент. В вашем случае процессор что-то считает, выводит данные на LCD. Вдруг в какой-то момент времени АЦП заканчивает преобразование - происходит прерывание, процессор переходит на ПП обслуживания АЦП - вычитывает данные, запускает следующее преобразование и возвращается к прерванной задаче вывода данных на LCD.. В какой-то момент времени приходит символ по УАРТ. Процессор - отвлекается от текущей задачи - вынимает символ пришедший на УАРТ ложит его в очередь и возвращается к выводу данных на LCD.. В момент когда процессор закончит вывод на LCD и ему понадобятся данные с АЦП или с УАРТа, ему уже не придется ждать этих данных, надо будет просто взять их из очереди и обрабатывать. Так что на мой взгляд не стоит размещать все в прерывании.
|
|
|
|
|
May 26 2007, 15:45
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Чип-Хрум @ May 26 2007, 16:29)  Накопились вопросы по программированию прерываний на си. 1. Может ли находится основная программа в прерывании в плоть до вывода на жк экран к примеру таймера 1 ? На сколко она может быть большой ? Не стоит так делать. Лучше в прерывании таймера запустить АЦП и выйти из прерывания, в прерывании АЦП занести значение АЦП в какой-то буфер (максимум - прямо в прерывании обсчитать что-то в духе экспоненциального фильтра, но не дольше) и выставить флаг "есть новое значение", а вещи типа преобразования результата в ASCII и вывода на ЖКИ - лучше делать в фоне (в "основном цикле"). Прерывания хороши, когда их много мелких на короткие "оперативные" задачи, а всё медленное надо вынести наверх. Меньше проблем будет позже, при добавлении других прерываний (UART, другие таймера, внешние источники). Конечно, можно в таймерном прерывании разрешить вложенные прерывания и программно ждать завершения работы АЦП, конвертить, выводить на экран - но это нехорошо. Наворачивается вложенность, растут стеки. Просто некрасиво. Цитата(Чип-Хрум @ May 26 2007, 16:29)  2. Можно-ли прерывание осуществлять из прерывания (из таймера делать вызов ацп). Запустить АЦП можно, но вложенным прерывание станет только если в таймерном после этого запуска задержаться до тех пор, пока АЦП отработает. Но даже в этом случае я бы вышел из таймерного (пусть АЦП подождёт до этого момента) и вошёл в АЦП-шное отдельно. Вложенные прерывания хороши при нормальной приоритетной системе, когда можно расписать что важнее чего и что чем может прерываться. Цитата(Чип-Хрум @ May 26 2007, 16:29)  3. Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки), Короче говоря на что расчитан стек он же не безграничен. Сколько есть памяти. Иногда это (сделать в прерывании что-то срочное, разрешить вложенные прерывания и продолжать потихоньку делать медленную часть) действительно удобно, но только иногда. И если тяжело при разрешении вложенных указать - какие могут "вкладываться", а какие - нет, то область "иногда" сокращается. Цитата(Чип-Хрум @ May 26 2007, 16:29)  4. Насколько я понял прерывания эта функция с входными и выходными переменными типа void. То бишь с переменными работать не придется?А как же тогда работать с переменными? Глобальные, как это не прискорбно :-) Могут быть переменные уровня файла и доступ к ним через специальные функции (запрещающие на время доступа все или только нужные прерывания), могут быть "общедоступные" - тогда обязательно volatile и всё равно иногда придётся запрещать прерывания при доступе к ним. volatile гарантирует невыбрасывание обращений при оптимизации, но не гарантирует атомарности обращений к многобайтовым переменным.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jun 4 2007, 06:37
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Цитата(Alexey Belyaev @ Jun 4 2007, 08:49)  Ребят, а что будет если у меня например работает прерывание по UART_RECV и в этот момент сработало прерывание по таймеру? Короче, что будет если во время одного прерывания возникло второе? Два варианта: 1. Если в теле UART_RECV разрешить прерывания, то прерывание таймера выполнится сразу, а потом управление перейдёт обратно в UART_RECV с прерванного места. 2. Если в UART_RECV не разрешать прерываний, то прерывание от таймера выполнится после выхода из UART_RECV. Цитата(Alexey Belyaev @ Jun 4 2007, 08:49)  И как управлять стеком в WinAVR/AVRStudio? Что значит управлять? Размер и расположение определяется в скрипте линкера, запускаемом обычно из make. Работу же со стеком осуществляет сам компилятор независимо от пользователя.
|
|
|
|
|
Jun 4 2007, 06:42
|

Местный
  
Группа: Свой
Сообщений: 243
Регистрация: 22-09-04
Из: Burbach, Germany
Пользователь №: 704

|
Цитата(Alexey Belyaev @ Jun 4 2007, 08:49)  Ребят, а что будет если у меня например работает прерывание по UART_RECV и в этот момент сработало прерывание по таймеру? Короче, что будет если во время одного прерывания возникло второе? Во время отработки текущего прерывания все остальные по умолчанию запрещены: When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. Т.е. "спокойно" отрабатывается текущее прерывание, выходим из обработчика. и , если есть новый источник прерывания, переходим к его обработке. Однако, есть возможность организовать вложенные прерывания: The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. Т.е. в данном случае вы должны "ручками" установить бит I.
|
|
|
|
|
Jun 9 2007, 09:37
|
Участник

Группа: Новичок
Сообщений: 33
Регистрация: 1-04-07
Пользователь №: 26 675

|
Вот пример программы в ней переменная unsigned char adc_end при возврате из прерывания в подфункцию ADC_2 изменяет значение с 0 на 2 . Кто знает как это исправить подскажите. Да простят меня модераторы но мой файл с расширением .с ваш сайт брать не хочет и пишет вот это "Ошибка загрузки. У Вас нет прав для загрузки файла с таким расширением." #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <stdlib.h> #include <util/delay.h> #include <stdio.h> volatile unsigned int cond1=0; volatile unsigned int adc_col=0; volatile unsigned char adc_end=0; volatile unsigned char adcl=0; unsigned char ADC_2(unsigned char adc_end); ISR(ADC_vect) { adc_col++; if (adc_col>3) { adcl=ADCL; cond1=ADCH; cond1=cond1<<8; cond1=cond1+adcl; ADMUX=0x40; ADCSRA=0xe7; adc_end=0; //при возврате из этой точки переменная изменяет свое значение adc_col=0; } else { ADMUX=0x41; ADCSRA=0xcf; } } int main(void) { sei(); DDRA=0x00; PORTA=0x00; DDRD=0xff; DDRB=0xb0; PORTB=0x00; DDRC=0xff; PORTC=0x00; SFIOR=0x00; adc_end = 2; ADC_2(adc_end); //??????????? ????????? return (0); } unsigned char ADC_2(unsigned char adc_end) { ADMUX=0x41; ADCSRA=0xcf; while (adc_end>1) { asm volatile ("nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" "nop " "\n\t" :  ; } return adc_end; }
|
|
|
|
|
Jun 9 2007, 10:11
|

Начинающий профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648

|
Цитата(Чип-Хрум @ Jun 9 2007, 13:37)  unsigned char ADC_2(unsigned char adc_end);
int main(void) {
sei();
DDRA=0x00; PORTA=0x00; DDRD=0xff;
DDRB=0xb0; PORTB=0x00; DDRC=0xff; PORTC=0x00;
SFIOR=0x00; adc_end = 2;
ADC_2(adc_end);
//??????????? ????????? return (0); } В main нет рабочего цикла: действия выполняются последовательно >adc_end = 2; >ADC_2(adc_end); а прерывание было во время выполнения main? Если нет, то все верно. Никаких изменений для adc_end. Если было, то когда? Если до команды: adc_end = 2; то все правильно, т.к. присваивание после прерывания, а если после, то надо разбираться подробно.
--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
|
|
|
|
|
Jun 9 2007, 10:24
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(Чип-Хрум @ Jun 9 2007, 13:37)  Вот пример программы в ней переменная unsigned char adc_end при возврате из прерывания в подфункцию ADC_2 изменяет значение с 0 на 2 . Кто знает как это исправить подскажите.
volatile unsigned char adc_end=0; unsigned char ADC_2(unsigned char adc_end) { } С точки зрения компилятора глобальная переменная "volatile unsigned char adc_end=0;" и аргумент функции ADC_2 "unsigned char adc_end" никакого отношения друг к другу не имеют. В прототипах функций рекомендуется указывать только типы аргументов, а не имена. Стиль программы комментировать не буду, но предлагаю подумать: 1) куда программа вернется из main() 2) о целесообразности ожидания окончания преобразования АЦП в какой-то п/п в тупом цикле (в предположении, конечно, что программа должна делать что-то еще, и main() все-таки организован наподобие: Код void main(void) { ... for(;;) { ... } } ) Цитата Да простят меня модераторы но мой файл с расширением .с ваш сайт брать не хочет и пишет вот это "Ошибка загрузки. У Вас нет прав для загрузки файла с таким расширением." А рулесы почитать? Аттачить можно zip, rar, txt, pdf, gif, jpg.
|
|
|
|
|
Jun 9 2007, 19:40
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(xemul @ Jun 9 2007, 13:24)  В прототипах функций рекомендуется указывать только типы аргументов, а не имена. Совершенно неразумная "рекомендация", поскольку имя переменной может и является подсказкой-комменарием и совершенно ничему не мешает. Прототипы стиля function( int, int, int ); по сравнению с function( int size, int mask, int start_value); теряют массу полезной для человека информации. Цитата(Чип-Хрум @ Jun 9 2007, 19:13)  я спрашивал ... Настоятельно рекомендую повысить уровень грамотности своих сообщений. Правила: Цитата 2.1.в. Высказываться понятно, полно и грамматически правильно... .... в противном случае пост может быть расценен как текстовый мусор (флуд).
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 14 2007, 15:28
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(Чип-Хрум @ Jun 9 2007, 20:13)  Ув. xemul я спрашивал конкретно а ты не ответил , я дал пример на катором наглядно переменная adc_end изменяет свое значение там где не должна этого делать. Ошибаетесь, я ответил. Вы, вероятно, невнимательно читаете. Код С точки зрения компилятора глобальная переменная "volatile unsigned char adc_end=0;" и аргумент функции ADC_2 "unsigned char adc_end" никакого отношения друг к другу не имеют. Переведу с русского на русский. Вы передаете в функцию ADC_2 один аргумент adc_end по значению, и оно случайно оказывается равно значению глобальной переменной adc_end. То, что имя аргумента и имя глобальной переменной совпадают, не обязывает компилятор С считать их одним и тем же - это не Васик. Как следствие, в прерывании исправно модифицируется значение глобальной переменной adc_end, что никак не отражается на состоянии локальной переменной adc_end функции ADC_2(). Цитата [SENSORED] возьми и откомпелируй прогррамку поставь брейкпойнт на то место где я тебе предлагаю и запусти отладчик . А потом Подывысь як цыферки то изменяются. То что ты предложил изменить прототип я изменил не помогло! Ваша программа не требует для разбора проблемы таких усилий. Кста, если место для брейкпоинта означено //???..., то при заданных начальных условиях исполнение программы до него никогда не дойдет. Я предложил не изменить прототип, а подумать. Попробуйте следовать в своих постах элементарным этическим нормам, местами распространным в стране моего проживания, или хотя бы правилам форума.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|