как перейти после прерывания на другой адрес?

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

ARV,
Извиняюсь, как вбил себе один раз AVR, все время так и думал ,мол раз по микроконтроллерам, значит человек взял себе ник AVR, но это дело поправимое.
То, что было посоветовано ,проверил на практике ,но не полкчил нужного результата, так как
цикл прерывался после того как программа доходило на отметку флага, а посему, чиобы ускорить дело надобно флагов расставить большое количество, но все равно не то.
Одна итерация длится 30-40сек. Представьте, что есть 10 устройств и за ними надо наблюдать
по 3 сек .При жулании управлять этими устройствами, надо иметь возможность прервать цикл и произиести другие операции, после чего, быстро перейти на другой ткжим опроса. т.е. прескочить старый цикл и перейти на новый ,с другим алгоритмом работы.
Такого типа задач не мало и хотелось бы отработать подход.
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

testerplus,
Вроде break вставляется внутри цикла на определенное место ,а нужно прервать For с наружи.
Уважаемый urry, может Вы ,что нибудь скажите по проблеме?
Аватара пользователя
testerplus
Встал на лапы
Сообщения: 130
Зарегистрирован: Пн авг 24, 2009 10:41:16
Откуда: SPb
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение testerplus »

zsxdcf писал(а):То, что было посоветовано ,проверил на практике ,но не полкчил нужного результата, так как
цикл прерывался после того как программа доходило на отметку флага, а посему, чиобы ускорить дело надобно флагов расставить большое количество, но все равно не то.

Раз увеличение количества проверок флага внутри цикла не помогает, то тогда подойдет только вытесняющий планировщик. Писать его самому - надо не только в тонкостях компилятора шарить, но и, собственно, хорошо себе представлять принципы вытеснения. Пробуйте готовую RTOS: делайте то, что сейчас делаете в FOR, в низкоприоритетной задаче, а из высокоприоритетной убивайте ее.

Подменой адреса возврата в обработчике прерывания результата можно добиться, но он будет очень шатким, т.к. будет сильно зависеть от версии компилятора и содержимого самих функций (как обработчика перываний, так и main): наличия локальных переменных, вызовов из main других функций (иначе стек загадится). Не работал с CV, не знаю, использует ли он стек под локальные переменные, но с восстановлением контекста точно будут проблемы. Да и разработчики компилятора в новой версии запросто введут использование стека под нужды функций, и тогда программа перестанет работать. То же само касается замены указателя стека вручную.
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

Всетаки хочется найти простое решение.
Будем искать.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение ARV »

что-то не пойму я проблемы... вы как за своими девайсами наблюдаете по 3 секунды? допустим, у вас так:

Код: Выделить всё

for(i = 0; i<10; i++){
   watch_device(i); // эта функция делает что-то страшное целых 3 секунды!!!
}
тогда ЧТО эта функция у вас может так долго делать? кроме как очередного цикла (ожидания там какого-нибудь или обмена) мне ничего на ум не приходит. если так, то что мешает вам и в ней проверять флаг?!

Код: Выделить всё

volatile char stop_now = 0; // это флаг немедленной остановки

ISR(){ // это обработчик вашего прерывания
   stop_now = 1;
}

void watch_device(int dev_num){
   while(defice_ready && !stop_now){
      // тут творите свои черные дела
   }
}



int main(void){
   for(int i=0; !stop_now && (i< 10); i++){ // это ваш страшный цикл
      watch_device(i);
   }
}
ну, и чем плохо?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

Исходя из условия задачи ,пришло такое решение ,которое не терпится вынести на уважаемых мною людей обсуждение,
И так, нужно ,чтобы во время выполнения цикла For, обработать поступающий запрос на прерывание и дальше перескачить оставшуюся часть цикла и идти дальше.
Как было сказано ,изменить адрес перехода по окончании прерывания связано со сложностями,
по этому ,пошол по другому пути.
В цикле For в качестве параметра предела счета ввел переменную "a", "b","k",см. неже пример,
которые инициализируются в зависимости от задачи.
внутри основного For могут быть много других малньких For -иков, которые могу используются и в качестве задержки тоже. Весь цикл(Одна итерация основного For длиться 40сек В основном за счет задержек ).
При наступлении прерывания, после его выполнения, под конец ,параметры a,b,k принимают значения "нуль" ,после чего, цикл сварачивается и дальше идет программа своим ходом.
Таким образом осуществляется "быстрый" перескок на конец цикла ,что по сути и надо было.
Главное ,программа четко сработала без глюков и она очень наглядна, никакого волшебства.
Конечно переход одним goto было бы куда лучше, но увы, пришлось выкручиваться вышеприведенным образам.
Мне кажется, что такой вариант перехода могут заинтересовать дюдей и если они им будут пользоватся то значит Мы с вами нек зря обсуждали вопрос.
Задача решена и не без Вашей помощи за что Вам Всем низкий поклон.

int a=0x12,b=0xAAAA,k=0x0DFA;
-------
interrupt [EXT_INT0] void ext_int0_isr(void)
{
-------
---

a=0;
b=0;
k=0;
};

----
---

void main(void)
{
---
---
};

while(1)
{
---
For(с=0;c<a;c++)
{
---
---
For(с=0;c<b;c++)
delay_ms(1);
---
----
For(с=0;c<k;c++)
--


}

};
}
neon-f
Потрогал лапой паяльник
Сообщения: 392
Зарегистрирован: Сб дек 12, 2009 02:15:45

Re: как перейти после прерывания на другой адрес?

Сообщение neon-f »

а еще можно сделать чтоб в прерывании выполнилось условие прекращение твоего цикла For
например

Код: Выделить всё

unsigned char x;
 {
тело твоего прерывания
х=100;  //  100 взял для примера,  поставь то что в условии прекращения твоего цикла for
}
.............
for (x=0; x!=100;  x++)  //твое цикл for
{
тело цикла
}

т.е. в прерывании ты выполняешь условие окончания цикла. по выходу программа замечает что условие прекращения цыкла наступило и прекращает его и переходит к следующему оператору, как ты и хотел.
Аватара пользователя
testerplus
Встал на лапы
Сообщения: 130
Зарегистрирован: Пн авг 24, 2009 10:41:16
Откуда: SPb
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение testerplus »

zsxdcf писал(а):Исходя из условия задачи ,пришло такое решение

Так это Вы просто усложнили (читай: "ухудшили") варианты, предлоенные Arduino и ARV. Зачем мудрить с пачкой переменных? Которые, тем более, объявлены неправильно (где volatile?). Заведите одну переменную и по ней прерывайте циклы (я так понял, "моментальность" выхода из цикла Вам не нужна, учитывая вариант, который Вы сами предложили).
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение ARV »

neon-f писал(а):а еще можно сделать чтоб в прерывании выполнилось условие прекращение твоего цикла For т.е. в прерывании ты выполняешь условие окончания цикла. по выходу программа замечает что условие прекращения цыкла наступило и прекращает его и переходит к следующему оператору, как ты и хотел.

очень много существует вещей, которые сделать можно, но не нужно. мало того, что читаемость программы с такими циклами будет совершенно невозможной, вы еще огребете заметное замедление скорости работы, т.к. для циклов оптимизатор компилятора обычно старается использовать регистровые переменные, а в вашем случае это будет глобальная статическая переменная, доступ к которой минимум в 3 раза дольше длится.

стремитесь писать программу так, чтобы при попытке "перевода" ее текста на русский язык, получалось нормальное описание алгоритма работы. сравните:
for(i=0; !stop_now && (i<100); i++) - перевод: цикл для переменной i, изначально равной 0, до тех пор, пока нет немедленной остановки и i меньше 100, выполнять каждую итерацию увеличение i на 1.

а теперь попробуйте перевести ваш вариант - станет понятно, что кроме условия i<100 есть еще какое-то условие завершения цикла?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

Я ничуть не сомневаюсь ,что предложенные ватианты грамотнее моего, но раз уж этот заработал,
для ускорения дело ,пока досканально не вникаю в предложенные, из за того ,что попытки
их скорейшего использования не увенчались успехом ,опять таки из за недостаточного моего опыта.
Конечно Я постараюсь четко их представить и попытаться реализовать.
Постараюсь быть по возможности достоиным Вашего общения ,но мне еще долго пахать.
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

ARV,

Стал опять тспитывать Ваш вариант.
Привожу конкретный пример где в For отрабатывается большая задержка, скажем 40сек.
Через 5 сек произошло прерывание, после чего нужно игнорировать оставшуюся часть задержки.
Тут мгновенно нажимается PINB.0 и через 40 сек зажигается PORTC.0 .Так ,в каком месте нужно поставить флаг чтобы после завершения препывания (тоже нажатие и отпускание кнопки)сразу зажогся PORTC.0?
---
int c;
volatile char stop_now = 0;
----
interrupt [EXT_INT0] void ext_int0_isr(void)
{
-------
---

int0_isr_flag = 1;

};

----
---

void main(void)
{
---
---
};

while (1)
{

if(PINB.0==0)
{




for(c=0;c<0xAAAA;c++)
delay_ms(1);



PORTC.0=1;

}
}
};
Аватара пользователя
Yftul
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Пт фев 20, 2009 12:26:26

Re: как перейти после прерывания на другой адрес?

Сообщение Yftul »

Что Вам мешает устанавливать в прерывании флаг и проверять его в цикле, после delay? При установленном флаге делаете break и выходите из цикла. Если 1 мс слишком много, делайте задержку в цикле меньше.

что-то вроде

Код: Выделить всё

for(чтототам){
   delay_us(1000);
   if (flag) break;
 }
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение ARV »

мне кажется, я достаточно подробно изложил свою идею и подкрепил ее вполне читаемым кодом. то, что нарисовали вы, я не понимаю - в каждой строчке только точки... блин...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

Yftul,arv,
вот программа без точек
После прерывания PORTC.0 не зажигается
Я все правильно сделал по поводу флага?




/*****************************************************


Chip type : ATmega8
Program type : Application
Clock frequency : 4,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/


#include <mega8.h>
#include <delay.h>
char c,g;


// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
g = 1;
}

void main(void)
{

PORTB=0xFF;
DDRB=0x00;


PORTC=0x00;
DDRC=0xFF;

PORTD=0xFE;
DDRD=0x01;




// Global enable interrupts
#asm("sei")

while (1)
{

if(PINB.0==0)
{
for(c=0;c<0x2AAA;c++)
{
delay_ms(1);
if(g==1)
break;

};
PORTC.0=1;
};
// ----------



};
};
Аватара пользователя
Yftul
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Пт фев 20, 2009 12:26:26

Re: как перейти после прерывания на другой адрес?

Сообщение Yftul »

какой ужас :)

- сделайте нормальную инициализацию железа и переменных;
- уберите while(1) или сделайте так, что бы он был действительно необходим;
- учтите, что если прерывание происходит по нажатию кнопки, что у вас флаг может установиться еще при нажатии;
- итд, итп;

вообще, имхо, Вам бы вначале написать программу без прерываний, просто чтобы понять как это вообще делается, после чего уже можно осваивать что-то посложнее. выходить же из прерывания по "левому" адресу действительно не стоит без серьезной нужды.

Досдаете что-то или для себя?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение ARV »

во-первых, разве вы не умеете пользоваться вставкой кода в собщение форума? и, соответственно, форматировать код для удобства чтения?

Код: Выделить всё

//*** вступительные комментарии никому не интересны - не надо их и приводить
#include <mega8.h>
#include <delay.h>
char c,g;
//*** большое количество пустых строк так же на форуме не нужны - уважайте тех, кто будет это читать

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
   g = 1; //*** по правилам хорошего тона флаг g надо описывать, как volatile
}

void main(void)
{
   PORTB=0xFF;
   DDRB=0x00;

   PORTC=0x00;
   DDRC=0xFF;

   PORTD=0xFE;
   DDRD=0x01;

   // Global enable interrupts
   #asm("sei")
 
   //*** не увидел настройки внешних прерываний вообще - это так и есть или вы сэкономили код?
   while (1)
   {
      if(PINB.0==0) //*** странная какая-то ситуация - если на пине 0, то аж на 11 секунд все прочее тормозится...
      {
         for(c=0;c<0x2AAA;c++)
         {
            delay_ms(1);
            if(g==1)
               break;
         }; //*** после закрывающей фигурной скобки не требуется наличие точки с запятой
         PORTC.0=1;
      };
      // ---------- *** а эта строка зачем коллективному разуму?
   };
};
по ходу вашего кода я дал свои комментарии - начинаются с ***
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

уважаемый ARV,
Большое Вам спасибо за исключитеотно сердечное и человеческое отношение .То что Вы указали мне на счет форума совершено верно. На счет лаконичности и читабельности кода тоже урок для меня
конечно многому надо научится чтобы людей по пустякам не беспокоить.
Здес тоже пытался быть кратким но как то затянулся вопрос.
Да в основно тексте все инициализируется .Я их просто вынул из кода дабы сделать по меньше.
С вашего позволения продолжу самому разобратся дальше и просто сообщу резултаты если они будут.
С глубоким уважением.
zsxdcf
Открыл глаза
Сообщения: 61
Зарегистрирован: Вт авг 25, 2009 08:14:38

Re: как перейти после прерывания на другой адрес?

Сообщение zsxdcf »

Мучался долго и опять ничего не получался и совершенно случайно вместо одного раза нажал на прерывание два раза и все четко сработала. Зажегся сразу PORTС.0 .В начало ветки когда
Digikey
предложил вариант с флагом, потому и не получался, что нажимал на прерывание один раз.
Я еще не выиснил почему требует двухкратного нажатия, чтобы выити из цикла, но буду выяснивать и сообщу.
Прмвожу код упорядоченный после справедливых замкчании
ARV.

#include <mega8.h>
#include <delay.h>
char c;
volatile char g;
interrupt [EXT_INT0] void ext_int0_isr(void)
{
g=1;
}
interrupt [EXT_INT1] void ext_int1_isr(void)
{
}
void main(void)
{
PORTB=0xFF;
DDRB=0x00;

PORTC=0x00;
DDRC=0xFF;

PORTD=0x00;
DDRD=0x00;

TCCR0=0x00;
TCNT0=0x00;

TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
GICR|=0xC0;
MCUCR=0x0A;
GIFR=0xC0;

TIMSK=0x00;

ACSR=0x80;
SFIOR=0x00;

#asm("sei")

while (1)
{
if(PINB.0==0)
{
for (c=0;c<0x2AAA;c++)
{
delay_ms(1);
if(g==1)
break;
}
PORTC.0=1;
}

};
}
Kirill_west
Родился
Сообщения: 5
Зарегистрирован: Ср мар 18, 2009 10:31:35
Контактная информация:

Re: как перейти после прерывания на другой адрес?

Сообщение Kirill_west »

Простите. а нельзя ли так?

while (1)
{
if(PINB.0==0)
{
for (c=0;c<0x2AAA;c++)
{
delay_ms(1);
if(PINB.0==1) // без всяких прерываний (если операция делится целых 3 минуты нафих точное прерывание? ну подумаешь 3 такта пропустим)
break; // или goto куда-то
}
PORTC.0=1;
}

};
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»