Реклама на сайте English version  DatasheetsDatasheets

KAZUS.RU - Электронный портал. Принципиальные схемы, Datasheets, Форум по электронике

Новости электроники Новости Литература, электронные книги Литература Документация, даташиты Документация Поиск даташитов (datasheets)Поиск PDF
  От производителей
Новости поставщиков
В мире электроники

  Сборник статей
Электронные книги
FAQ по электронике

  Datasheets
Поиск SMD
Он-лайн справочник

Принципиальные схемы Схемы Каталоги программ, сайтов Каталоги Общение, форум Общение Ваш аккаунтАккаунт
  Каталог схем
Избранные схемы
FAQ по электронике
  Программы
Каталог сайтов
Производители электроники
  Форумы по электронике
Помощь проекту

Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей...

 
Опции темы
Непрочитано 21.08.2010, 00:04  
Godzilla82
Почётный гражданин KAZUS.RU
 
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
Godzilla82 на пути к лучшему
Вопрос Как изменить адрес подпрограммы обработки прерывания?

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

Можно, конечно, в едином обработчике (в начале) прерывания делать проверку и выполнять нужный участок кода, но это будет отнимать такты.

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

Как это сделать на WinAVR ну и на CodeVision AVR.

Заранее спасибо.
Реклама:

Последний раз редактировалось Godzilla82; 21.08.2010 в 00:06.
Godzilla82 вне форума  
Непрочитано 21.08.2010, 00:34  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
Можно, конечно, в едином обработчике (в начале) прерывания делать проверку и выполнять нужный участок кода, но это будет отнимать такты.
Так и делайте, это самое простое. Три-пять лишних тактов всего.
kison вне форума  
Непрочитано 21.08.2010, 02:31  
Godzilla82
Почётный гражданин KAZUS.RU
 
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от kison Посмотреть сообщение
Так и делайте, это самое простое. Три-пять лишних тактов всего.
У меня как раз такая задача, когда всё упирается в эти самые лишние 3-5 тактов. Нужно по адресу вектора прерывания поменять адрес перехода на нужную подпрограмму. Думаю, что это возможно сделать средствами СИ (пусть даже с ассемблерными вставками). Поэтому и спрашиваю.
Godzilla82 вне форума  
Непрочитано 21.08.2010, 02:53  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
Думаю, что это возможно сделать средствами СИ (пусть даже с ассемблерными вставками). Поэтому и спрашиваю.
Возможно. Но не более 10000 раз, или сколько там флеш выдержит перезаписей.
И не в любом АВР, а только в тех, где есть команда SPM.
Можно попробовать еще переход по указателю, но оверхед будет больше. Заводите переменную 16 бит в регистрах. В нее грузите адрес нужного обработчика. В начале прерывания сохраняете в стеке R30 и R31, переносите в них адрес из своей регистровой переменной и icall. Выходит 2+2 такта на сохранение, 1 такт на movw, и 3 такта на icall. Это все нужно на ассемблере делать. Если и реальные обработчики на ассемблере, то можно переходить на них по ijmp, это 1 такт сэкономит. Но перед выходом надо будет извлечь из стека R30 и R31 обратно.
kison вне форума  
Непрочитано 21.08.2010, 07:48  
niXto
Почётный гражданин KAZUS.RU
 
Аватар для niXto
 
Регистрация: 13.10.2007
Адрес: Беларусь
Сообщений: 8,048
Сказал спасибо: 60
Сказали Спасибо 3,954 раз(а) в 2,309 сообщении(ях)
niXto на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

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

Вариант с флагом в начале прерывания самый простой и быстрый, если оптимизировать код - все будет прекрасно
niXto вне форума  
Сказали "Спасибо" niXto
Godzilla82 (21.08.2010)
Непрочитано 21.08.2010, 11:08  
alex_312
Прохожий
 
Аватар для alex_312
 
Регистрация: 08.08.2010
Сообщений: 7
Сказал спасибо: 1
Сказали Спасибо 1 раз в 1 сообщении
alex_312 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
У меня как раз такая задача, когда всё упирается в эти самые лишние 3-5 тактов. Нужно по адресу вектора прерывания поменять адрес перехода на нужную подпрограмму. Думаю, что это возможно сделать средствами СИ (пусть даже с ассемблерными вставками). Поэтому и спрашиваю.
Думаю все можно решить при помощи Си, и мне кажется, что лучше в WinAvr.

Вопрос со сменой адреса вектора прерывания решается так:
PHP код:
 ......
int *my_int_ptr;//указатель 

void my_int_1();//обьявление функции прерывания 1-й вариант
void my_int_2();//обьявление функции прерывания 1-й вариант

int main()
{

    
my_int_ptr = (int*)0;//присваиваем указателю значение 0

    
if(uslovie())
    {
        
my_int_ptr[2] = (int)my_int_1;//поменяли 2-й вектор
    
}
    else
    {
        
my_int_ptr[2] = (int)my_int_2;//поменяли 2-й вектор
    
}

.......................
    return 
0;
}

void my_int_1()
{
INT_PROLOG
    
.....
INT_EPILOG
}

void my_int_2()
{
INT_PROLOG
    
.....
INT_EPILOG

А WinAvr удобнее(наверное) тем, что там можно порытся в исходниках и надыбать макросы, которые определяют пролог и эпилог прерывания, ну чтоб самому не писать ассемблерные вставки для сохранения и восстановления регистров. Возможно надо будет самому сделать вызов cli();

P.S. Хотя, если вам так дороги 5 тактов, то имеет смысл переписать прерывания на асме.

Последний раз редактировалось alex_312; 21.08.2010 в 11:12.
alex_312 вне форума  
Сказали "Спасибо" alex_312
Godzilla82 (21.08.2010)
Непрочитано 21.08.2010, 12:16  
Godzilla82
Почётный гражданин KAZUS.RU
 
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от alex_312 Посмотреть сообщение
Вопрос со сменой адреса вектора прерывания решается так...
PHP код:
#include    ‹avr/io.h›
#include    ‹avr/interrupt.h›

ISR1(SIG_OUTPUT_COMPARE0)
{
...
}

ISR2(SIG_OUTPUT_COMPARE0)
{
...
}

int main (void)
{
if(
uslovie)    ISR ISR1;
else           
ISR ISR2;

ISR = ISR1 - это, естесственно, неверно, просто как бы показывает, что мне надо.

А как вашу конструкцию прикрутить к прерываниям?

Вопрос не в этих 5 тактах. 5 тактов - если 2 режима. На самом деле режимов больше.
Godzilla82 вне форума  
Непрочитано 21.08.2010, 13:49  
E97
Почётный гражданин KAZUS.RU
 
Регистрация: 08.01.2008
Сообщений: 1,143
Сказал спасибо: 379
Сказали Спасибо 430 раз(а) в 274 сообщении(ях)
E97 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Вот как это может выглядеть на asm.


Цитата:
.device ATtiny13

.CSEG
.ORG 0
rjmp RESET ;Reset

.ORG $02
rjmp ExtIntReq ;External Interrupt Request

.ORG $06
ijmp ;Timer/Counter0 Compare Match A

.ORG INT_VECTORS_SIZE

RESET:

;инициализация вектора TimerCompareA
ldi r30,low(TimerCompareA)
ldi r31,high(TimerCompareA)
....
sei
...
Func:
......
Call send
......
rjmp Func

TimerCompareA:
nop
reti

Send:
.....
ldi r30,low(Transmite_Byte)
ldi r31,high(Transmite_Byte)
.....
ret


Transmite_Byte:
.....
ldi r30,low(Delay_Transmit)
ldi r31,high(Delay_Transmit)
reti
EndTransmite:
.......
ldi r30,low(TimerCompareA)
ldi r31,high(TimerCompareA)
reti

Delay_Transmit:
ldi r30,low(Transmite_Byte)
ldi r31,high(Transmite_Byte)
reti

.EXIT
При выполнении процедуры send управление прерыванием Timer0 Compare Match A передается с пустого обработчика TimerCompareA на Transmite_Byte апри завершении передачи снова на пустое прерывание.
Зачем еще тут Delay_Transmit да просто нужно было наружный сигнал поделить на 372.
E97 вне форума  
Сказали "Спасибо" E97
Godzilla82 (21.08.2010)
Непрочитано 21.08.2010, 16:28  
alex_312
Прохожий
 
Аватар для alex_312
 
Регистрация: 08.08.2010
Сообщений: 7
Сказал спасибо: 1
Сказали Спасибо 1 раз в 1 сообщении
alex_312 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
ISR = ISR1 - это, естесственно, неверно, просто как бы показывает, что мне надо.

А как вашу конструкцию прикрутить к прерываниям?

Вопрос не в этих 5 тактах. 5 тактов - если 2 режима. На самом деле режимов больше.
Да, ISR=ISR1 - это неверно, так как ISR это макрос, который потом разворачивается в функцию прерывания.
А привязка в моем примере осуществляется при помощи указателей.

мы создаем указатель который указывает на таблицу векторов прерываний.
в моем примере это
PHP код:
int *my_int_ptr;//указатель 
далее инициализируем его
PHP код:
my_int_ptr = (int*)0
, чтоб он указывал на начало таблцы прерываний.
А далее в прогамме нужному номеру назначаем нужный обработчик
PHP код:
my_int_ptr[2] = (int)my_int_1;//поменяли 2-й вектор 
И еще, может вам использовать конструкцию
PHP код:
switch(state)
{
case 
0:
//do do do
break;
.....
case 
n:

break;

default:
state=0


alex_312 вне форума  
Непрочитано 21.08.2010, 17:00  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от alex_312 Посмотреть сообщение
А далее в прогамме нужному номеру назначаем нужный обработчик
Попобуйте в реале, удивитесь результату. Куча регистров уйдет в стек, ведь компилятор по сути вызывает обычную функцию по указателю. Которая имеет право изменять Call used регистры, что в прерывании недопустимо. Так что вместо экономии тактов 30-40 в начале уйдет на сохранение регистров.

Сообщение от alex_312 Посмотреть сообщение
так как ISR это макрос, который потом разворачивается в функцию прерывания.
Это не в функцию разворачивается, а сего лишь аттрибуты функции присваивает.
Так что чисто на Си ничего не получится, минимум - разместить обработчики на неиспользованных векторах и переключать эти обработчики из ассемблерной обертки. И хранить указатель в регистровой переменной. Ограничение - количество свободных векторов прерывания. Впрочем можно в каждый еще ветвления вставлять. А нормально сделать получится только если обработчики будут тоже на ассемблере. Тут скорость почти максимальна. Оверхед - 8 тактов на вход и 7 на выход.
kison вне форума  
 

Закладки
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Решено] Как внедрялась АСУ chermnv Отвлекитесь, эмбеддеры! 743 14.02.2010 23:11
[Решено] Третье Послание Человечеству lelkanet Отвлекитесь, эмбеддеры! 201 06.01.2010 00:33
Вход в прерывания для PIC микроконтроллеров dimmich Микроконтроллеры, АЦП, память и т.д 4 06.12.2009 17:17
Keil C51 как изменить адрес загрузки Kabron Микроконтроллеры, АЦП, память и т.д 4 09.10.2009 23:31


Часовой пояс GMT +4, время: 03:26.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot