Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: продолжить прерывание
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Mikron
Добрый день

есть некоторый код
Код
void funс(void){
    cli();
    ...
    sei();
}
ISR(INT0_vect){
    ...}
ISR(USART1_RX_vect){
    ...}
ISR(USART1_TX_vect){
   ...
   func();
   ...}
ISR(USART1_UDRE_vect){
...  }
...

Функцию я вызываю из прерывания, во время её выполнения прерывания нужно запретить.
Когда я их снова разрешу, то могут возникнуть любые прерывания, а не продолжалось USART1_TX, так ведь?
Вопрос, как сделать так, что бы после разрешения прерываний разрешалось только USART1_TX

Спасибо за помощь
Палыч
Цитата(Mikron @ Feb 9 2011, 17:07) *
...прерывания нужно запретить.
Почему в функции прерывания нужно сначала запрещать, а потом разрешать? Обработчик прерывания у Вас работает при разрешенных прерываниях? Или может быть функция вызывается ещё из другого места и необходимо, чтобы она при своей работе не прерывалась? В этом случае состояние разрешения прерывания нужно сохранять перед запретом, а потом восстанавливать.
Xenia
Цитата(Mikron @ Feb 9 2011, 17:07) *
Функцию я вызываю из прерывания, во время её выполнения прерывания нужно запретить.
Когда я их снова разрешу, то могут возникнуть любые прерывания, а не продолжалось USART1_TX, так ведь?
Вопрос, как сделать так, что бы после разрешения прерываний разрешалось только USART1_TX

Ничего в функциях обработки прерываний запрещать и разрешать не надо, т.к. это происходит полностью автоматически. Т.е. при возникновении ситуации прерывания с последующим перескоком из произвольного места программы на процедуру его обработки, прерывания автоматически запрещаются. И никакой cli дополнительно тут не нужен. Точно так же, прерывания восстановятся сами после выхода из той процедуры по iret.

А вот то, что в процедуре прерывания надо делать обязательно, то это сохранить содержимое регистра флагов (0x3F), а также исходные значения всех регистров, которые в той процедуре используете. Для этого и то, и другое, следует загнать в стек, а перед выходом восстановить из стека.

Если это USART1_TX, то крайне нежелательно разрешать прерывание в процедуре его обработки, т.к. тогда может возникнуть новое прерывание того же типа тогда, когда вы не успели обработать предыдущее. В некоторых замыслах это бывает необходимо, но все-таки лучше так не рисковать.
ILYAUL
Цитата
Когда я их снова разрешу, то могут возникнуть любые прерывания, а не продолжалось USART1_TX, так ведь?
Вопрос, как сделать так, что бы после разрешения прерываний разрешалось только USART1_TX

А вы в обработчике USART1_TX - запретите , сделайте сброс разрешений прерываний в контрольном регисте USART1, тех что Вам не нужны. Вывалитесь из обработчика , у Вас останется только USART1_TX.
Но Вам надо продумать , как потом включить их снова.
Да и вот ещё , TX у Вас "младшее" по приоритету прерывание , смотря как написан код , Вы рискуете туда и не добраться
Mikron
Всем огромное спасибо за помощь)
Что-то я реально затупил, просто, как Палыч написал, функция вызывалась так же из другого места, где прерывания должны были запрещаться
Палыч
Цитата(Mikron @ Feb 10 2011, 00:25) *
...функция вызывалась так же из другого места, где прерывания должны были запрещаться
Если тело функции обязательно не должно прерываться, то в этом случае сохраняют/восстанавливают флаг прерывания
Код
void func(void)
{
  unsigned char savSREG= SREG;  // Сохранить SREG
  CLI();  // Запретить прерывания
.........................
  SREG = savSREG;  // Востановить SREG
}
Mikron
Цитата(ILYAUL @ Feb 9 2011, 19:15) *
Да и вот ещё , TX у Вас "младшее" по приоритету прерывание , смотря как написан код , Вы рискуете туда и не добраться

Возник вопрос, почему могу туда не добраться
Просто в документации на контроллер про прерывания написано

There are basically two types of interrupts. The first type is triggered by an event that
sets the interrupt flag. For these interrupts, the Program Counter is vectored to the
actual interrupt vector in order to execute the interrupt handling routine, and hardware
clears the corresponding interrupt flag. Interrupt flags can also be cleared by writing a
logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the
corresponding interrupt enable bit is cleared, the interrupt flag will be set and remembered
until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or
more interrupt conditions occur while the global interrupt enable bit is cleared, the corresponding
interrupt flag(s) will be set and remembered until the global interrupt enable bit
is set, and will then be executed by order of priority.

То есть произошел как бы запрос на прерывание, установился флаг, и рано или поздно оно все равно произойдет, а почему нет?
_Артём_
Код
void func(void)
{
  unsigned char savSREG= SREG;  // Сохранить SREG
  CLI();  // Запретить прерывания
.........................
  SREG = savSREG;  // Востановить SREG
}


Разве при переходе на вектор прерывания флаг I не сбрасывается?
Тогда CLI(); - лишняя.
Палыч
Цитата(_Артём_ @ Feb 10 2011, 17:18) *
Разве при переходе на вектор прерывания флаг I не сбрасывается? Тогда CLI(); - лишняя.
Мной приведена функция, которую вызывают из обработчика прерывания (в этом случае - флаг I сброшен) и из другого места программы (например, из бесконечного цикла - флаг I установлен), т.е. примерно такая, как у автора вопроса. Код функции таков, что вся функция или её отдельный участок должен работать не прерываясь. Чтобы выполнение кода не прервалось, прерывания нужно запретить (конечно, если вызвана функция из прерывания - флаг I и так сброшен, и делать это не обязательно, но "лишний" раз - не повредит), но вот в конце функции (или её участка) разрешать прерывания нужно не всегда, а только в том случае, если при входе в функцию прерывания были разрешены. Imho, сделать это удобно сохраняя при входе в функцию регистр SREG (из него нам интересен флаг I), а в конце функции(участка кода) - восстановить SREG вместе с флагом I.
ILYAUL
Цитата(Mikron @ Feb 10 2011, 17:09) *
Возник вопрос, почему могу туда не добраться

Всё достаточно просто, TX1 имеет низший приоритет . А вот INT0_vect высший, затем идут USART1_RX_vect и USART1_UDRE_vect и только потом Ваш. Вам надо посчитать насколько часто будут появлятся эти три прерывания, успеете Вы в паузах между ними обработать TX, ведь надо успеть принять символ, загрузить символ и ещё обработать INT0 и на все три уходит время . Смотря как Вы напишете код , у Вас просто может не хватить времени обработать TX . Его "забьют" старшие. Надо бы сказать , что USART1_TX_vect это дублёр USART1_UDRE - этот имеет тенденцию забросил и забыл. Первый (USART1_TX_vect) передачу закончил. В зависимости от требуемых функций ( не путать с функциями Си) можно использовать или UDRE или TX. Так например при обработке DS18B20 лучше не использовать UDRE. Кстати , этот флаг имеет "неприятную" особенность он практически "всегда установлен". С момента сброса и до выключения питания. Увидеть его в ноль можно посылая сразу большой массив данных. И так как он старше TX.....
_Pasha
1111493779.gif Ето винавр, проснитесь!
Код
#include <util/atomic.h>
void func(void)
{
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
  {
   <Function's body&soul>
  }
}

ЗЫ в опциях обязательно включить -std=gnu99

Цитата(ILYAUL @ Feb 10 2011, 21:39) *
Так например при обработке DS18B20 лучше не использовать UDRE.

cranky.gif Стало быть, Вы не умеете его готовить в условиях многозадачности?
ReAl
Цитата(ILYAUL @ Feb 10 2011, 20:39) *
Кстати , этот флаг имеет "неприятную" особенность он практически "всегда установлен". С момента сброса и до выключения питания. Увидеть его в ноль можно посылая сразу большой массив данных. И так как он старше TX.....
Так это же отлично! И я этим радостно пользуюсь. Даже если другие прерывания задержат обработку UDRE и уже поднимется TXC, при освобождении процессора будет выполнен таки обработчик UDRE. Там я сброшу флаг TXC. И в самом же обрабочтике UDRE сниму его разрешение UDRIE при отправке последнего байта пакета. Таким образом, если до обработчика TXC вообще дошло, то это конец пакета.
Постоянное взведение UDRE тоже очень удобно, не нужно никаких танцев с тем, что первый байт пакета надо вручную затолкать в UDR, а уже остальные по прерываниям. Сформировал пакет и поднял UDRIE - данные пошли единообразным способом.
ILYAUL
Цитата(_Pasha @ Feb 11 2011, 08:07) *
cranky.gif Стало быть, Вы не умеете его готовить в условиях многозадачности?

Причём здесь мнонгозадачность и DS18B20. Если Вы возьмёте листок бумаги и посчитаете поведение USART при использовании UDRE в качестве прерывания для обмена с DS , то увидите что , если не изменяет память, на 9 байте начинает лезть ошибка приема ответа DS . Точне посмотрю дома в записях. Считали и не я один. А запрещать и разрешать его в таком случае смысла не имеет , если есть TX.

Цитата
ReAl Так это же отлично! ......
и т.д.
При передачи сразу массива данных , нафинг он вообще нужен TXC ? Tолько что бы "красиво" в конце передачи массива узнать , что последний байт массива передали. Смысл? Всё равно же считаете переданные байты либо в ноль либо до какого-то значения.

Цитата
Кстати , этот флаг имеет "неприятную" особенность он практически "всегда установлен".

А это я написал , так как топикстартер ещё не определился , что он вообще будет использовать и нигде не озвучивал свой замысел. А "неприятную" - как Вы видите я поставил в кавычках
demiurg_spb
Цитата(ILYAUL @ Feb 11 2011, 14:36) *
При передачи сразу массива данных , нафинг он вообще нужен TXC ? Tолько что бы "красиво" в конце передачи массива узнать , что последний байт массива передали. Смысл?
Чтобы максимально быстро перевести драйвер RS485 в на приём и освободить линию после завершения передачи последнего байта.
UART используется и для симплексных каналов связи.

Или чтобы отключить передатчик для экономии батарейки например...
ILYAUL
Цитата(demiurg_spb @ Feb 11 2011, 14:40) *
Чтобы максимально быстро перевести драйвер RS485 в на приём и освободить линию после завершения передачи последнего байта.
UART используется и для симплексных каналов связи.

Или чтобы отключить передатчик для экономии батарейки например...

У Вас счётчик уже обнулился , зачем лишний обработчик прерывания
Палыч
Цитата(ILYAUL @ Feb 11 2011, 16:21) *
У Вас счётчик уже обнулился , зачем лишний обработчик прерывания
Ну, вроде ясно сказано:
Цитата(demiurg_spb @ Feb 11 2011, 14:40) *
Чтобы максимально быстро перевести драйвер RS485 в на приём и освободить линию после завершения передачи последнего байта.
Чтобы передатчик не выключить раньше, чем будут переданы данные...
demiurg_spb
Похоже Илья упускает момент буферирования регистра UDR (один байт выплёвываем, а ещё 2 ждут в очереди).
И может показаться что передача окончена - софтовый fifo опустошили, а на самом деле аппаратный fifo ещё содержит данные для передачи.
Так вот TXC скажет нам когда действительно всё отправлено.
_Pasha
Цитата(ILYAUL @ Feb 11 2011, 14:36) *
Причём здесь мнонгозадачность и DS18B20. Если Вы возьмёте листок бумаги и посчитаете поведение USART при использовании UDRE в качестве прерывания для обмена с DS , то увидите что , если не изменяет память, на 9 байте начинает лезть ошибка приема ответа DS .

Ничего не понимаю! Цель уарта при обмене с далласом - формировать точные времянки без отрыва МК от задачи. Причем тут вообще UDRE? Какое он отношение к времянкам имеет, если его основное назначение - помочь несчасному в обеспечении непрерывной передачи данных? cranky.gif
Палыч
Цитата(demiurg_spb @ Feb 11 2011, 18:25) *
...один байт выплёвываем, а ещё 2 ждут в очереди
А, разве не один "выплёвываем" (из регистра сдвига), а ещё один ждёт (в регистре данных)?
ILYAUL
Цитата(demiurg_spb @ Feb 11 2011, 18:25) *
Похоже Илья упускает момент буферирования регистра UDR (один байт выплёвываем, а ещё 2 ждут в очереди).
И может показаться что передача окончена - софтовый fifo опустошили, а на самом деле аппаратный fifo ещё содержит данные для передачи.
Так вот TXC скажет нам когда действительно всё отправлено.

Нет не упускаю, один в регистре сдвига , второй в UDR. И так ситуация , тот что в регисре сдвига - предпоследний байт. В UDR - последний, возражений нет, надеюсь.
Поехали, переходим к языку , который здесь понимают лучше чем русский . Кстати вот это "... буферирования регистра UDR ..." и мешает работать нормально с DS.

Код
USART1_UDRE:
                      push ....... не комментирую
                      ________  сам обработчик
                      dec   count; вычитаем счётчик количества передаваемых байт ( наш мвассив данных )
                      brne  END; проверяем всё передали, если нет всё уходим из обработчика
; Всё передали ---------------------------
                       ldi     temp,1<<RXCIE1|0<<UDRIE1|1<<RXEN1|1<<TXEN1; 0 - в UDRIE написал для наглядности-на самом деле его можно и не писать
                       sts    UCSR1B,temp  ; Изменили  режим работы USART
END:                pop  ......
                       reti


Мы изменили режим работы при передачи в UDR последнего байта массива. Он ещё "телепается" или в UDR или ,если повезло ему , в сдвиговом регистре , что очень мало вероятно.
Какое будет следующее прерывание- только прием, что там с передатчиком начхать. Пусть он себе передает дальше , но как только slave , захочет нам что-то передать , мы уже готовы.
Итог: Всё мы готовы принимать данные.

С вариантом TX: Даже страшновато писать , хоть и asm

Код
USART1_UDRE:
                      push ....... не комментирую
                      ________  сам обработчик
                      dec   count; вычитаем счётчик количества передаваемых байт ( наш мвассив данных )
                      brne  END; проверяем всё передали, если нет всё уходим из обработчика
; Всё передали ---------------------------
                       ldi     temp,0<<UDRIE1|1<<RXEN1|1<<TXEN1; 0 - в UDRIE написал для наглядности-на самом деле его можно и не писать
                       sts    UCSR1B,temp  ; Изменили  режим работы USART
END:                pop  ......
                       reti


MAIN: Торчим в Main и возможно чем-то заняты , если не в цикле rjmp main
И вот оно счастье

Код
USART1_TXC:
                      push  ...........
; Естественно SREG - а куда же без него , туда же
                       ldi     temp,1<<RXCIE1|0<<UDRIE1|1<<RXEN1|1<<TXEN1
                       sts    UCSR1B,temp  ; Опять изменили  режим работы USART
                       pop ..............
                       reti


И итог: Всё мы готовы принимать данные.
И что , мы в той же точке т.к. пока мы не изменим режим USART, о каком приёме может идти речь. Вот оно того стоило ждать этот USART1_TXC

Цитата
Ничего не понимаю! Цель уарта при обмене с далласом - формировать точные времянки без отрыва МК от задачи. Причем тут вообще UDRE? Какое он отношение к времянкам имеет, если его основное назначение - помочь несчасному в обеспечении непрерывной передачи данных?

Времянки от нас никуда не денутся- мы байт передали (1) или (0) и тут же должны вернуть его в массив данных,если работаете с SRAM, особенно при чтении температуры , когда каждый байт (Чтение 1) - возвращает значение или 0 или 1 и "выстрел" сразу все единиц через UDRE к чему приведёт? RX-то неуспевает - там ведь где-то ещё ответ только от первого байта принимается, а TX - уже второй передает. Посчитайте ,учитывая обработку приема - сколько тактов при Вашей частоте . И очень интересный материал:
Палыч
Цитата(ILYAUL @ Feb 11 2011, 21:16) *
Итог: Всё мы готовы принимать данные.
Да, USART готов принимать данные. Но, за USART'ом, обычно, стоит некая микросхема-драйвер, которая как раз может быть и не готовой для приёма, и нужно дождаться окончания передачи и переключить её на приём...
ILYAUL
Цитата(Палыч @ Feb 11 2011, 22:01) *
Да, USART готов принимать данные. Но, за USART'ом, обычно, стоит некая микросхема-драйвер, которая как раз может быть и не готовой для приёма, и нужно дождаться окончания передачи и переключить её на приём...

Классная получается тема, сейчас мы USART, разберём по косточкам и при возникновении тем на эту тематику будем давать ссылку. smile3046.gif
Давайте рассуждать - эта некая микросхема состоит из двух буферов - один на прием , второй передача и имеют один управляющий вход , который в зависимости , логический 0 или 1 , переключается в передача -приём. Не ошибся? Вариантов нет - случай 2. Но это всё абстракция, в любом случае при разработке системы учитываешь и такие вещи.
_Pasha
Цитата(ILYAUL @ Feb 12 2011, 00:40) *
Но это всё абстракция

Эта абстрация называется RS-485...
А вот насчет далласа на уарте - ну настолько несимпатичная реализация... На одном пине TxD- включаем уарт, отправляем 0х30 для скорости 1,875мкс/бит, по TXC отключаем уарт и читаем состояние пина(пин на ввод). Остальные элементы - не проблема.
demiurg_spb
Цитата(Палыч @ Feb 11 2011, 18:51) *
А, разве не один "выплёвываем" (из регистра сдвига), а ещё один ждёт (в регистре данных)?
Возможно и так, но мне что-то помнится циферка 2.
Вот глянул DS на mega128:
Цитата
In addition to the recovery units, the receiver includes a parity checker, control logic, a Shift Register and a two level receive buffer (UDR).
Не уверен отлична-ли глубина буфера регистра UDR при передаче... Но на приём сдвиговый регистр + ещё 2 уровня буфера.
Посмотрел картиночку с блок-схемой UARTa - на передачу похоже действительно лишь один уровень буферизации.
Вы похоже правы.
ILYAUL
Цитата(_Pasha @ Feb 12 2011, 01:22) *
Эта абстрация называется RS-485...

Вот имено такой ответ и называется- абстракция.
А моя не абстракция называется MAX232xxx ,4332....Вы что считаете я не найду буфер RS485, который не надо переключать? Давайте всё таки придерживатся предмета спора и уважать мнение друг друга. Мы не говорили об "обвязки" AVR .Мы говорили , как он работает.
P/S/ Я выложил не тот материал, есть пример работы с DS18B20 от производителя , Там собственнно есть всё - вплоть до написанных функций на Си, но я поменял комп и он в стадии разбора -куды и чё. Но я не забуду и обязательно выложу пример и протокол , как работать used USART и c DS18B20 - Application.
_Pasha
Цитата(ILYAUL @ Feb 12 2011, 15:17) *
Вот имено такой ответ и называется- абстракция.

sad.gif
demiurg_spb
Цитата(ILYAUL @ Feb 12 2011, 14:17) *
Давайте всё таки придерживатся предмета спора
Я уже потерял нить...
Напомните за что мы тут спорим? :-)
ILYAUL
Цитата(demiurg_spb @ Feb 12 2011, 16:05) *
Напомните за что мы тут спорим? :-)

Да ни о чём , так просто smile3009.gif , что бы мозги не застаивались biggrin.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.