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

 
 
 
Reply to this topicStart new topic
> Прерывания в Mega32, Много неясностей
Чип-Хрум
сообщение May 26 2007, 13:29
Сообщение #1


Участник
*

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



Накопились вопросы по программированию прерываний на си.
1. Может ли находится основная программа в прерывании в плоть до вывода на жк экран
к примеру таймера 1 ? На сколко она может быть большой ?
2. Можно-ли прерывание осуществлять из прерывания (из таймера делать вызов ацп).
3. Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки),
Короче говоря на что расчитан стек он же не безграничен.
4. Насколько я понял прерывания эта функция с входными и выходными переменными типа void.
То бишь с переменными работать не придется?А как же тогда работать с переменными?
Go to the top of the page
 
+Quote Post
mempfis_
сообщение May 26 2007, 14:18
Сообщение #2


Профессионал
*****

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



2. "Можно-ли прерывание осуществлять из прерывания (из таймера делать вызов ацп)."
Можно, если уверен, что период прерываний от таймера будет больше, чем время, необходимое для запуска АЦП+время на преобразование+время на обработку прерывания от АЦП+время на сохранение или обработку результатов преобразования. Правда если останавливать ТС или маскировать его прерывание, то это время можно не учитывать.

3. "Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки),
Короче говоря на что расчитан стек он же не безграничен."
Подпрограмма в прерывании может быть.
Кол-во зависит от того, сколько входных данных использует подпрограмма и от их типа.

4. "Насколько я понял прерывания эта функция с входными и выходными переменными типа void.
То бишь с переменными работать не придется?А как же тогда работать с переменными?"
Я, например, объявляю переменные так: volatile char (или int, или long int, или bit) variable_name
и в любом месте программы получаю к ней доступ (даже в прерывании).

[/quote]
Go to the top of the page
 
+Quote Post
defunct
сообщение May 26 2007, 15:43
Сообщение #3


кекс
******

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



Цитата
То бишь с переменными работать не придется?

Интересный вывод.

main() тоже можно описать как void main(void),
разве это как-то помешает работать с переменными?


Цитата
Может ли быть подпрограмма в прерывании, и сколько их может быть внутрь(матрешки),

Конечно.
Количество зависит от объема стека выделенного вами.. для m32 легко можно отвести 512b-1kb под стек.


Цитата
Может ли находится основная программа в прерывании в плоть до вывода на жк экран
к примеру таймера 1 ?

В прерывании или не в прерывании не имеет особого значения.
Значение имеет то, сможет ли конкретный подход обеспечить выполнение всех задач поставленных в ТЗ.
Если основная функция программы выполняется в прерывании (где другие прерывания запрещены), то в этой функции некоторые действия придется решать путем программного опроса (например нельзя будет организовать одновременный прием/передачу по уарту, т.к. в режиме опроса надо проверять флаги состояния; нельзя будет одновременно работать с несколькими периферийными устройствами).. Если вас это устраивает, и программа не сильно сложная - то тогда безусловно можно.

Прерывания организованы для того чтобы сделать возможным обработку множества устройств в самый подходящий для этого момент. В вашем случае процессор что-то считает, выводит данные на LCD. Вдруг в какой-то момент времени АЦП заканчивает преобразование - происходит прерывание, процессор переходит на ПП обслуживания АЦП - вычитывает данные, запускает следующее преобразование и возвращается к прерванной задаче вывода данных на LCD.. В какой-то момент времени приходит символ по УАРТ. Процессор - отвлекается от текущей задачи - вынимает символ пришедший на УАРТ ложит его в очередь и возвращается к выводу данных на LCD.. В момент когда процессор закончит вывод на LCD и ему понадобятся данные с АЦП или с УАРТа, ему уже не придется ждать этих данных, надо будет просто взять их из очереди и обрабатывать.

Так что на мой взгляд не стоит размещать все в прерывании.
Go to the top of the page
 
+Quote Post
ReAl
сообщение May 26 2007, 15:45
Сообщение #4


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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 гарантирует невыбрасывание обращений при оптимизации, но не гарантирует атомарности обращений к многобайтовым переменным.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Spider
сообщение Jun 4 2007, 05:49
Сообщение #5


В поисках истины
***

Группа: Свой
Сообщений: 431
Регистрация: 7-01-06
Из: Россия
Пользователь №: 12 923



Ребят, а что будет если у меня например работает прерывание по UART_RECV и в этот момент сработало прерывание по таймеру? Короче, что будет если во время одного прерывания возникло второе?
И как управлять стеком в WinAVR/AVRStudio?
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Jun 4 2007, 06:37
Сообщение #6


Шаман
******

Группа: Модераторы
Сообщений: 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.
Работу же со стеком осуществляет сам компилятор независимо от пользователя.
Go to the top of the page
 
+Quote Post
ALexx
сообщение Jun 4 2007, 06:42
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 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.
Go to the top of the page
 
+Quote Post
Чип-Хрум
сообщение Jun 9 2007, 09:37
Сообщение #8


Участник
*

Группа: Новичок
Сообщений: 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"
:smile.gif;
}

return adc_end;

}
Go to the top of the page
 
+Quote Post
mdmitry
сообщение Jun 9 2007, 10:11
Сообщение #9


Начинающий профессионал
*****

Группа: Свой
Сообщений: 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;
то все правильно, т.к. присваивание после прерывания, а если после, то надо разбираться подробно.


--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
Go to the top of the page
 
+Quote Post
xemul
сообщение Jun 9 2007, 10:24
Сообщение #10



*****

Группа: Свой
Сообщений: 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.
Go to the top of the page
 
+Quote Post
Чип-Хрум
сообщение Jun 9 2007, 16:13
Сообщение #11


Участник
*

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



Ув. xemul я спрашивал конкретно а ты не ответил , я дал пример на катором наглядно
переменная adc_end изменяет свое значение там где не должна этого делать.
[SENSORED] возьми и откомпелируй прогррамку поставь брейкпойнт
на то место где я тебе предлагаю и запусти отладчик . А потом Подывысь як цыферки то
изменяются.
То что ты предложил изменить прототип я изменил не помогло!

Сообщение отредактировал IgorKossak - Jun 9 2007, 17:07
Go to the top of the page
 
+Quote Post
defunct
сообщение Jun 9 2007, 19:00
Сообщение #12


кекс
******

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



Чип-Хрум

Формулируйте вопрос нормально.
что где чего изменяет?

В main() у вас
adc_end = 2;
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 9 2007, 19:40
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
SunnyDevil
сообщение Jun 11 2007, 13:18
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 108
Регистрация: 15-05-07
Пользователь №: 27 742



Чтобы понять почему написанная программа та себя ведет вернемся к определению "контекста". В контескте обработчика прерывания adc_end это глобальная переменная. В контесте main эта переменная также глобальная. А вот в контесте той функции в конце эта переменная локальная просто с темже именем. Соверешенно естетственно что прерывание, меняя содержимое глобальной переменной никоим образом не касается переменной локальной внутри этой функции и в debug'e вы наблюдаете якобы изменение переменной.Но это не значение переменной меняется, а выводится другая переменная с другим значением просто имена у них совпадают. Минимальные изменения будут:
unsigned char ADC_2(unsigned char &adc_end);
Либо
unsigned char ADC_2(unsigned char *adc_end);

Естественно с небольшими правками кода вызова и кода внутри этой функции.
Go to the top of the page
 
+Quote Post
xemul
сообщение Jun 14 2007, 15:28
Сообщение #15



*****

Группа: Свой
Сообщений: 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] возьми и откомпелируй прогррамку поставь брейкпойнт
на то место где я тебе предлагаю и запусти отладчик . А потом Подывысь як цыферки то
изменяются.
То что ты предложил изменить прототип я изменил не помогло!

Ваша программа не требует для разбора проблемы таких усилий. Кста, если место для брейкпоинта означено //???..., то при заданных начальных условиях исполнение программы до него никогда не дойдет.
Я предложил не изменить прототип, а подумать.
Попробуйте следовать в своих постах элементарным этическим нормам, местами распространным в стране моего проживания, или хотя бы правилам форума.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 19th July 2025 - 21:39
Рейтинг@Mail.ru


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