|
Обработчик прерываний в HI-TECH, Вызов подпрограмм |
|
|
|
May 7 2008, 05:00
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038

|
Здравствуйте. Наконец-таки начал переползать с ассемблера на Си и возникла следующая проблем. Имеется код (приведены только отрывки на которых спотыкается компилятор): Код //изменение скорости обмена void SetBRate(unsigned brate) { .... }
//отправка данных void SendByte(unsigned brate,unsigned char data) { SetBRate(brate); .... }
//отправка данных на индикатор static void _send_byte(unsigned char data) { .... SendByte(br_19200,data); .... SetBRate(br_1200); }
//вывод символа на индикатор void WriteChar(unsigned char chr) { //корректировка кода для русских букв if (chr >= 0xC0 && chr <= 0xEF) chr -= 0x40; else if (chr >= 0xF0) chr -= 0x10; _send_byte(chr); }
//обработчик прерываний от Timer 0 void INT_TMR0(void) { static int cnt = 0; if (++cnt >= 10) { WriteChar('1'); cnt = 0; } T0IF = 0; }
//обработчик прерываний void interrupt INTHandler(void) { if (T0IF) INT_TMR0(); //прерывание от Timer 0 if (RCIF) INT_RxD(); //прерывание от приемника EUSART } При комплияции выдаются следующие сообщения об ошибках: Код Error [472]; . non-reentrant function "__send_byte" appears in multiple call graphs: rooted at "_INTHandler" and "_main"
Error [472]; . non-reentrant function "_SendByte" appears in multiple call graphs: rooted at "_INTHandler" and "_main"
Error [472]; . non-reentrant function "_SetBRate" appears in multiple call graphs: rooted at "_INTHandler" and "_main" В документации на HI-TECH написано, что: (472) non-reentrant function "*" appears in multiple call graphs: rooted at "*" and "*" (Linker) This function can be called from both main-line code and interrupt code. Use the reentrant keyword, if this compiler supports it, or recode to avoid using local variables or parameters, or duplicate the function, e.g.:Однако из описания ошибки я так и не понял, как ее исправить. Подскажить, на какие грабли я наступил? P.S. Используется MPLAB 8.00 + HI-TECH 9.60 LITE (который идет вместе с MPLAB 8.00). Контроллер PIC16F690.
|
|
|
|
|
 |
Ответов
|
May 7 2008, 05:35
|

Местный
  
Группа: Свой
Сообщений: 206
Регистрация: 17-03-07
Из: Москва
Пользователь №: 26 266

|
Цитата(Grigorij @ May 7 2008, 09:00)  ... (472) non-reentrant function "*" appears in multiple call graphs: rooted at "*" and "*" (Linker) This function can be called from both main-line code and interrupt code. Use the reentrant keyword, if this compiler supports it, or recode to avoid using local variables or parameters, or duplicate the function, e.g.:
Однако из описания ошибки я так и не понял, как ее исправить. Подскажить, на какие грабли я наступил?
P.S. Используется MPLAB 8.00 + HI-TECH 9.60 LITE (который идет вместе с MPLAB 8.00). Контроллер PIC16F690. Компилер вам говорит: "Это НЕ функция которая позволяет многократный вход в нее, а она вызываемая в нескольких мест "*" и "*". Эту функцию возможно вызывать из обеих "main" и "interrupt". Пользуйте ключевое слово "reentrant", если этот компилер его поддерживает, или перепишите ее, чтобы она не использовала локальные переменные или продублируйте ее." Дело в том что вы пользуете эту функцию и в основной программе и в обработчике прерывании. Задумайтесь что случится с данными, если прерывание наступит во время исполнении именно этой функции и обработчик прерывания попытается тоже вызвать ее! В прерывании лучше внешние функции вообще не применять.
--------------------
УЭР
|
|
|
|
|
May 7 2008, 05:56
|
Местный
  
Группа: Свой
Сообщений: 460
Регистрация: 5-10-06
Из: Херсон
Пользователь №: 21 006

|
Цитата(evc @ May 7 2008, 08:35)  Компилер вам говорит: "Это НЕ функция которая позволяет многократный вход в нее, а она вызываемая в нескольких мест "*" и "*". Эту функцию возможно вызывать из обеих "main" и "interrupt". Пользуйте ключевое слово "reentrant", если этот компилер его поддерживает, или перепишите ее, чтобы она не использовала локальные переменные или продублируйте ее." Ключевое слово #pragma interrupt_level 0 Цитата Дело в том что вы пользуете эту функцию и в основной программе и в обработчике прерывании. Задумайтесь что случится с данными, если прерывание наступит во время исполнении именно этой функции и обработчик прерывания попытается тоже вызвать ее! В прерывании лучше внешние функции вообще не применять.
|
|
|
|
|
May 7 2008, 07:12
|

Местный
  
Группа: Свой
Сообщений: 206
Регистрация: 17-03-07
Из: Москва
Пользователь №: 26 266

|
Цитата(DL36 @ May 7 2008, 09:56)  Ключевое слово #pragma interrupt_level 0 это слово указывает линкеру, что потребитель гарантирует и береть на себя ответственость, что эта функция не будет вызвана обработчиком прерывании и основной программы одновременно, что бы тот (линкер) не выдавал сообщении об ошибке. В некоторых компиляторах (поддерживающие рекурсию, например) есть возможность объявить функцию как "reentrant", т.е. она может быть вызвана еще раз не завершив свою работу.
--------------------
УЭР
|
|
|
|
|
May 8 2008, 04:24
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038

|
Цитата(evc @ May 7 2008, 11:12)  это слово указывает линкеру, что потребитель гарантирует и береть на себя ответственость, что эта функция не будет вызвана обработчиком прерывании и основной программы одновременно, что бы тот (линкер) не выдавал сообщении об ошибке. В некоторых компиляторах (поддерживающие рекурсию, например) есть возможность объявить функцию как "reentrant", т.е. она может быть вызвана еще раз не завершив свою работу. К сожалению ключевое слово #pragma interrupt_level 0 не помогло. Если я объявляю ф-цию следующим образом: Код #pragma interrupt_level 0 void SendByte(unsigned brate,unsigned char data) { SetBRate(brate); TXREG = data; while (!TRMT); } То получаю от компилятор сообщение: Код Error [473]; . function "_SendByte" is not called from specified interrupt_level Проблему пока решил вынесением проверки флагов прерывания в основную программу, убрав обработчик прерываний (потом подумаю как его еще можно использовать). Код void main(void) { Init(); while (1) { if (T0IF) INT_TMR0(); if (RCIF) INT_RxD(); } } Решение, наверное, не слишком красивое, но пока сойдет. Как вариант, думаю продублировать некоторые ф-ции, которые используются как в обработчике прерываний, так и в основной программе, т.е. сделать что-то на подобии: Код void intr_SetBRate(unsigned brate) { .... }
void intr_SendByte(unsigned brate,unsigned char data) { intr_SetBRate(brate); TXREG = data; while (!TRMT); } Но сдерживат тот факт, что произойдет увеличит объем кода, а это не есть хорошо. Тоже каксается и использования макросов. Большое спасибо всем за помощь.
|
|
|
|
|
May 8 2008, 05:19
|
Местный
  
Группа: Свой
Сообщений: 460
Регистрация: 5-10-06
Из: Херсон
Пользователь №: 21 006

|
Цитата(Grigorij @ May 8 2008, 07:24)  К сожалению ключевое слово #pragma interrupt_level 0 не помогло. Если я объявляю ф-цию следующим образом: Надо добавить такую же строчку перед обработчиком прерывания. Хотя в Вашем случае видимо оптимальнее сделать две одинаковые функции с разными именами. Надо учиться использовать прерывания, это основа без нее никак.
|
|
|
|
|
May 8 2008, 06:59
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038

|
Цитата(DL36 @ May 8 2008, 09:19)  Надо добавить такую же строчку перед обработчиком прерывания. Хотя в Вашем случае видимо оптимальнее сделать две одинаковые функции с разными именами. Спасибо, действительно помогло добавление #pragma interrupt_level 0 перед обработчиком прерываний. Хотя я думаю в обработчик прерываний вынести обработку только наиболее значимых прерываний, а все остальные обработать так, как я писал выше (т.е. в основном цикле программы). Думаю должно получиться неплохо. Хотя вариант с использованием двух одинаковых функции с разными именами я пока еще не отбросил. Цитата(DL36 @ May 8 2008, 09:19)  Надо учиться использовать прерывания, это основа без нее никак. Знаю, что основа. Поэтому и задал вопрос, чтобы понять как пользоваться прерываниями в HI-TECH, т.к. в asm-е у меня вопросов с ними вроде не возникало.
|
|
|
|
|
May 8 2008, 09:24
|
Местный
  
Группа: Свой
Сообщений: 460
Регистрация: 5-10-06
Из: Херсон
Пользователь №: 21 006

|
Цитата(Grigorij @ May 8 2008, 09:59)  Спасибо, действительно помогло добавление #pragma interrupt_level 0 перед обработчиком прерываний. Хотя я думаю в обработчик прерываний вынести обработку только наиболее значимых прерываний, а все остальные обработать так, как я писал выше (т.е. в основном цикле программы). Думаю должно получиться неплохо.
Хотя вариант с использованием двух одинаковых функции с разными именами я пока еще не отбросил. Знаю, что основа. Поэтому и задал вопрос, чтобы понять как пользоваться прерываниями в HI-TECH, т.к. в asm-е у меня вопросов с ними вроде не возникало. Старайтесь в прерывании производить только самые необходимые действия. Например принять байт по уарт, положить его в буфер, поднять флаг что надо что то сделать и уйти из прерывания, дабы не потерять другие вызовы. Попробуйте описать тут концептуально свою задачу, думаю народ поможет, поскольку у Вас где то ошибка в концепции построения программы.
|
|
|
|
|
May 8 2008, 10:16
|
Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 5-12-05
Из: Москва, Россия
Пользователь №: 11 818

|
Цитата(DL36 @ May 8 2008, 13:24)  ...у Вас где то ошибка в концепции построения программы. а может концепция верная. В PICC-18 User Guide, 4.11.4 Interrupt Levels рассматривается ситуация использования одной и той же функции из interrupt и из main-line code. Для этого случая специально предназначена #pragma interrupt_level 0, возможно еще значение 1. Компилятор после этого ругаться перестает. Считается, что пользователь для всех функций, которым приписан один уровень (для чего надо написать эту волшебную фразу перед каждой из них), обеспечит правильную работу - т.е. они не будут вызваны одновременно из interrupt и main-line. Напрмер, перед вызовом функции из main-line можно запретить прерывания (и разрешить прерывания сразу после возврата из нее). этим достигается компактность кода и лучшая читаемость. однако временный запрет прерывания чреват его пропуском, так что должен быть анализ в каждом случае.
|
|
|
|
Сообщений в этой теме
Grigorij Обработчик прерываний в HI-TECH May 7 2008, 05:00 Vanizma ты используешь одну функцию и в основном теле прог... May 7 2008, 05:28   DL36 Цитата(evc @ May 7 2008, 10:12) это слово... May 7 2008, 08:54    Сергей Борщ Цитата(DL36 @ May 7 2008, 11:54) Все прав... May 7 2008, 10:13     Vanizma Цитата(Сергей Борщ @ May 7 2008, 14:13) Е... May 7 2008, 15:10     DL36 Цитата(Сергей Борщ @ May 7 2008, 13:13) Г... May 7 2008, 19:34       Grigorij 2DL36:
Постараюсь в кратце описать программу. Она... May 8 2008, 11:06        DL36 Цитата(Grigorij @ May 8 2008, 14:06) В це... May 8 2008, 11:38 Сергей Борщ Цитата(Grigorij @ May 7 2008, 08:00) or r... May 7 2008, 06:18 XVR Цитата(Grigorij @ May 7 2008, 09:00) Здра... May 8 2008, 06:46 asmon А кто может обьяснить назначение директивы хайтека... May 22 2008, 14:22 xemul Цитата(asmon @ May 22 2008, 18:22) А кто ... May 22 2008, 15:16  Grigorij 2xemul
Рассказываю. В моей программе USART исполь... May 23 2008, 04:45   xemul Цитата(Grigorij @ May 23 2008, 08:45) 2xe... May 23 2008, 08:57    Grigorij Цитата(xemul @ May 23 2008, 12:57) Заведи... May 23 2008, 10:54     xemul Цитата(Grigorij @ May 23 2008, 14:54) Нав... May 24 2008, 12:45 Mad_max Если еще, не решили свою проблему, то вот почитайт... Jun 7 2008, 13:10 Grigorij Цитата(Mad_max @ Jun 7 2008, 17:10) Если ... Jun 10 2008, 05:31
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|