Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Добавление смещения к указателю на функцию.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
_Алекс
Объявил переменную – указатель на функцию, вызываю pf();, получилось. Стало необходимо добавить смещение к началу вызова функции, чтоб выполнялась с определенного места а не сначала, пытаюсь прибавить константу, пишет не совместимость типов. Не подскажите как правильно добавить смещение к указателю на функцию, в виде константы типа usigned int или char.
jorikdima
То есть чтоб функция не с начала начала работать???
Такое невозможно помоему, да и не логично
_Алекс
Цитата(jorikdima @ Dec 25 2006, 15:53) *
То есть чтоб функция не с начала начала работать???
Такое невозможно помоему, да и не логично


Такое возможно, но не знаю как преобразовать тип указатель на функцию и константу, чтоб их суммировать. Нужно вот для чего, например есть в функции задержка на 20мс, чтоб колом все не стояло 20мс, выходим из функции запоминаем адрес возврата, делаем что –то другое полезное и возвращаемся через примерно 20мс в точку выхода.
zltigo
Цитата(_Алекс @ Dec 25 2006, 15:14) *
Нужно вот для чего, например есть в функции задержка на 20мс, чтоб колом все не стояло 20мс, выходим из функции запоминаем адрес возврата,

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

Все не просто а очень просто - сладкая парочка setjmp() longjmp() официальный путь решения подобных проблем.
Ну а вообще и о системе подумать можно - вариации на тему sleep().
dxp
Цитата(_Алекс @ Dec 25 2006, 19:14) *
Цитата(jorikdima @ Dec 25 2006, 15:53) *

То есть чтоб функция не с начала начала работать???
Такое невозможно помоему, да и не логично

Такое возможно, но не знаю как преобразовать тип указатель на функцию и константу, чтоб их суммировать.

Функции в С всегда работают сначала. Нельзя средствами языка валидно вызвать функцию, чтоб попасть в ее середину.

Цитата(_Алекс @ Dec 25 2006, 19:14) *
Нужно вот для чего, например есть в функции задержка на 20мс, чтоб колом все не стояло 20мс, выходим из функции запоминаем адрес возврата, делаем что –то другое полезное и возвращаемся через примерно 20мс в точку выхода.

Это вам RTOS нужна. Под ней все это реализуется нативно. Или тогда руками соорудить автомат состояний и ходить по состояниям. Т.е. при входе в функцию анализируется переменная состояния и осуществляется переход за цикл (или куда там еще надо).
sensor_ua
Механизм сопрограмм на макросах поможет и без RTOS
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
vmp
Если нельзя, но очень хочется...
Попробуйте привести указатель к типу unsigned int, выполнить арифметику и затем привести к исходному типу. Не обещаю, что получится.

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

Как показывает практика, подобными извращениями обычно страдают люди, переходящие с ассемблера на Си и стремящиеся сэкономить несколько микросекунд в редко используемой функции исключительно из любви к искусству. Со временем и опытом это проходит.
zltigo
Цитата(sensor_ua @ Dec 25 2006, 15:58) *
Механизм сопрограмм на макросах поможет и без RTOS

Конечный автомат уже поминался (во что его оборачивать это дело уже второе), но решает он часть проблемы, ибо про 20ms он ведать не ведает и тем более прервать текущую задачу для более-менее точной выдержки не сможет. Если, конечно вырожденные случаи не рассматривать.

Цитата
Не обещаю, что получится.

Да формально изменить указатель получится - не имеет права не получиться. А вот результат сего действия будет покрыт мраком sad.gif.
sensor_ua
Цитата
Конечный автомат уже поминался

Согласен, но, ИМХО, странный вопрос товарища как-раз о том, КАК сделать, а не ЧТО. Механизм сопрограмм позволяет именно вернуться в точку предыдущего выхода. Вызов той же функции через сколько-то там мс позволит продолжить выполнение чего-то там по алгоритму.
Цитата
про 20ms он ведать не ведает и тем более прервать текущую задачу для более-менее точной выдержки не сможет

Разве кто-то говорил о точности выдержки времени (и на чём и при каких других условиях?) и о жёстком риалтайме? Тут, похоже, _Алекс сам не знает ещё чего хочетwink.gif или захочет...
zltigo
Цитата(sensor_ua @ Dec 25 2006, 16:53) *
Тут, похоже, _Алекс сам не знает ещё чего хочетwink.gif или захочет...

Посему и поминание RTOS как средства максимально припособленного к "незнаю что" было вполне уместным smile.gif.
_artem_
Цитата(_Алекс @ Dec 25 2006, 14:49) *
Объявил переменную – указатель на функцию, вызываю pf();, получилось. Стало необходимо добавить смещение к началу вызова функции, чтоб выполнялась с определенного места а не сначала, пытаюсь прибавить константу, пишет не совместимость типов. Не подскажите как правильно добавить смещение к указателю на функцию, в виде константы типа usigned int или char.


имхо в С все траснформации с пойнтером разрешаются через void* тип. продекларируйте такой пойнтер а затем присвойте ему указатель функции с кастингом на void и прибавьте смешение. затем вызом функции через результируюший пойнтер с кастингом как указатель функции. Правда размерность смешения надо урегулировать.
Rst7
Цитата(_artem_ @ Dec 25 2006, 17:13) *
имхо в С все траснформации с пойнтером разрешаются через void* тип. продекларируйте такой пойнтер а затем присвойте ему указатель функции с кастингом на void и прибавьте смешение. затем вызом функции через результируюший пойнтер с кастингом как указатель функции. Правда размерность смешения надо урегулировать.


А с каких пор стали допустимы операции +, += и так далее с указателем типа void* ?
dxp
Цитата(Rst7 @ Dec 26 2006, 12:26) *
Цитата(_artem_ @ Dec 25 2006, 17:13) *

имхо в С все траснформации с пойнтером разрешаются через void* тип. продекларируйте такой пойнтер а затем присвойте ему указатель функции с кастингом на void и прибавьте смешение. затем вызом функции через результируюший пойнтер с кастингом как указатель функции. Правда размерность смешения надо урегулировать.


А с каких пор стали допустимы операции +, += и так далее с указателем типа void* ?

Ну, надо написать класс TVoidPtr, в котором определить оные операции. И будет полная икэбана. smile.gif smile.gif smile.gif Правда, это уже не С. smile.gif
_artem_
Цитата(Rst7 @ Dec 26 2006, 08:26) *
Цитата(_artem_ @ Dec 25 2006, 17:13) *

имхо в С все траснформации с пойнтером разрешаются через void* тип. продекларируйте такой пойнтер а затем присвойте ему указатель функции с кастингом на void и прибавьте смешение. затем вызом функции через результируюший пойнтер с кастингом как указатель функции. Правда размерность смешения надо урегулировать.


А с каких пор стали допустимы операции +, += и так далее с указателем типа void* ?


Вы правы - в написанном ошибка. Чтоб замалить прошение) написал пример который КОМПИЛИРУЕТСЯ без ошибок на bcc32 :

Код
void test(void)
{
    int i = 0;
    i++;
}


void main (void)
{

    void (*fp)(void);

    fp = (void(*)(void))((unsigned long int)(&test) + 100);

    fp();
}


Наверно надо обратить внимание на правильную размерность указателя на функцию когда делается кастинг перед сложением .
Сергей Борщ
Цитата(_artem_ @ Dec 26 2006, 15:29) *
Наверно надо обратить внимание на правильную размерность указателя на функцию когда делается кастинг перед сложением .
Можно подключить stdint.h, там объявлен тип uintptr_t - беззнаковое целое в которое точно уместится указатель, и использовать этот тип. Но только для чего-нибудь полезного, а не для решения исходной задачи :-)
_artem_
Цитата(Сергей Борщ @ Dec 26 2006, 17:16) *
Цитата(_artem_ @ Dec 26 2006, 15:29) *

Наверно надо обратить внимание на правильную размерность указателя на функцию когда делается кастинг перед сложением .
Можно подключить stdint.h, там объявлен тип uintptr_t - беззнаковое целое в которое точно уместится указатель, и использовать этот тип. Но только для чего-нибудь полезного, а не для решения исходной задачи :-)


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

Все таки нелепость применения данного подхода должна быть подробным образом обьяснена более словохотливым аффтаром.)
_Алекс
Цитата(_artem_ @ Dec 26 2006, 18:55) *
Цитата(Сергей Борщ @ Dec 26 2006, 17:16) *
Цитата(_artem_ @ Dec 26 2006, 15:29) *

Наверно надо обратить внимание на правильную размерность указателя на функцию когда делается кастинг перед сложением .
Можно подключить stdint.h, там объявлен тип uintptr_t - беззнаковое целое в которое точно уместится указатель, и использовать этот тип. Но только для чего-нибудь полезного, а не для решения исходной задачи :-)


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

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


А вот что получилось: маленький кооперативный планировщик задач

void main( void ){
__disable_interrupt();
InitMega8();
OSCreatTask(TaskDI, 0); Регистрируем задачу с приоритетом о
__enable_interrupt();
while(1){
OSscheduler(); При каждом вызове вызывается новая задача.
};
};

А это задача.
//****************Обработка дискретных входов***********
struct T_DI static dDI;

void TaskDI(void){
while(1){
dDI.inDIa = DIInput();
OSDelay(10,0); здесь не стоим и не ждем уходим, давая возможность выполнять код другой задачи.
dDI.inDIb = DIInput(); здесь возвращаемся через 5 мс.
dDI.inDIa ^= dDI.inDIb;
OSDelay(50,0);
dDI.inDIb = DIInput(); здесь возвращаемся через 25 мс.
dDI.inDIa &= dDI.inDIb;
dDI.inDIa ^= dDI.inDIb;
dDI.bDI |= dDI.inDIb;
};

А вот ассемблер
void main( void ){
\ main:
9 __disable_interrupt();
\ 00000000 94F8 CLI
10 InitMega8();
\ 00000002 .... RCALL InitMega8
11 OSCreatTask(TaskDI, 0);
\ 00000004 E020 LDI R18, 0
\ 00000006 .... LDI R16, LOW(TaskDI/2)
\ 00000008 .... LDI R17, (TaskDI/2) >> 8
\ 0000000A .... RCALL OSCreatTask
12 OSCreatTask(TaskTemperature, 1);
\ 0000000C E021 LDI R18, 1
\ 0000000E .... LDI R16, LOW(TaskTemperature/2)
\ 00000010 .... LDI R17, (TaskTemperature/2) >> 8
\ 00000012 .... RCALL OSCreatTask
13 OutKR1561ID1_1(4);
\ 00000014 E004 LDI R16, 4
\ 00000016 .... RCALL OutKR1561ID1_1
14 __enable_interrupt();
\ 00000018 9478 SEI
15 while(1){
16 OSscheduler();
\ ??main_0:
\ 0000001A .... RCALL OSscheduler
\ 0000001C CFFE RJMP ??main_0
17 };
18 };

А вот задачи:
3 //****************Обработка дискретных входов***********

\ In segment NEAR_Z, align 1, keep-with-next
\ 00000000 REQUIRE `?<Segment init: NEAR_Z>`
4 struct T_DI static dDI;
\ dDI:
\ 00000000 DS 3
5

\ In segment CODE, align 2, keep-with-next
6 void TaskDI(void){
\ TaskDI:
\ 00000000 93BA ST -Y, R27
\ 00000002 93AA ST -Y, R26
\ 00000004 .... LDI R26, LOW(dDI)
\ 00000006 .... LDI R27, (dDI) >> 8
7 while(1){
8 dDI.inDIa = DIInput();
\ ??TaskDI_0:
\ 00000008 .... RCALL DIInput
\ 0000000A 930D ST X+, R16
9 OSDelay(10,0);
\ 0000000C E020 LDI R18, 0
\ 0000000E E00A LDI R16, 10
\ 00000010 E010 LDI R17, 0
\ 00000012 .... RCALL OSDelayFunc
\ 00000014 E020 LDI R18, 0
\ 00000016 B7ED IN R30, 0x3D
\ 00000018 B7FE IN R31, 0x3E
\ 0000001A 9731 SBIW R31:R30, 1
\ 0000001C 8100 LD R16, Z
\ 0000001E 8111 LDD R17, Z+1
\ 00000020 .... RCALL OSSaveAddres
\ 00000022 9508 ret
10 dDI.inDIb = DIInput();
\ 00000024 .... RCALL DIInput
\ 00000026 930C ST X, R16
11 dDI.inDIa ^= dDI.inDIb;
\ 00000028 911E LD R17, -X
\ 0000002A 2710 EOR R17, R16
\ 0000002C 931D ST X+, R17
12 OSDelay(50,0);
\ 0000002E E020 LDI R18, 0
\ 00000030 E302 LDI R16, 50
\ 00000032 E010 LDI R17, 0
\ 00000034 .... RCALL OSDelayFunc
\ 00000036 E020 LDI R18, 0
\ 00000038 B7ED IN R30, 0x3D
\ 0000003A B7FE IN R31, 0x3E
\ 0000003C 9731 SBIW R31:R30, 1
\ 0000003E 8100 LD R16, Z
\ 00000040 8111 LDD R17, Z+1
\ 00000042 .... RCALL OSSaveAddres
\ 00000044 9508 ret
13 dDI.inDIb = DIInput();
\ 00000046 .... RCALL DIInput
\ 00000048 930C ST X, R16
14 dDI.inDIa &= dDI.inDIb;
15 dDI.inDIa ^= dDI.inDIb;
\ 0000004A 911E LD R17, -X
\ 0000004C 2310 AND R17, R16
\ 0000004E 2710 EOR R17, R16
\ 00000050 931C ST X, R17
16 dDI.bDI |= dDI.inDIb;
\ 00000052 9612 ADIW R27:R26, 2
\ 00000054 911C LD R17, X
\ 00000056 2B10 OR R17, R16
\ 00000058 931C ST X, R17
\ 0000005A 9712 SBIW R27:R26, 2
\ 0000005C CFD5 RJMP ??TaskDI_0
17 };
18 };
19 //****************Обработка дискретных входов***********
_artem_
И где же Вы это применяете ?
wolfram
Такая штука, которую предлагает Алекс реализована в С компиляторах для PIC16, PIC18: CC5X, CC8E соответственно. Довольно удобная штуковина. Создаешь несколько задач - для кнопок, индикатора и т.п. и работают они сами по себе. Сделать подобную вещь для AVR было бы неплохо. Делал такую штуку с вставками на ASMе в IARе, но это фигня полная.
_artem_
В компиляторах понятно - процесс кодообразования контролируется самим компилятором, но вот что делать с оптимизацией кода ? Нет гарантии что переход со смешением попадет именно туда и выполнит именно тот код который ожидается .
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.