Mikhail1954 0 8 мая, 2008 Опубликовано 8 мая, 2008 · Жалоба ...у Вас где то ошибка в концепции построения программы. а может концепция верная. В PICC-18 User Guide, 4.11.4 Interrupt Levels рассматривается ситуация использования одной и той же функции из interrupt и из main-line code. Для этого случая специально предназначена #pragma interrupt_level 0, возможно еще значение 1. Компилятор после этого ругаться перестает. Считается, что пользователь для всех функций, которым приписан один уровень (для чего надо написать эту волшебную фразу перед каждой из них), обеспечит правильную работу - т.е. они не будут вызваны одновременно из interrupt и main-line. Напрмер, перед вызовом функции из main-line можно запретить прерывания (и разрешить прерывания сразу после возврата из нее). этим достигается компактность кода и лучшая читаемость. однако временный запрет прерывания чреват его пропуском, так что должен быть анализ в каждом случае. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Grigorij 0 8 мая, 2008 Опубликовано 8 мая, 2008 · Жалоба 2DL36: Постараюсь в кратце описать программу. Она предназначена для считывания данных с датчика, их анализа и вывода на индикатор необходимой информации. При этом данные также архивируют и заносятся в EEPROM. Программа разделена на 2 части. Первая - работа с периферийными устройствами (индикатор, интерфейс RS-232/485, RTC, EEPROM, клавиатура и пр.). Вторая - это математика (пока еще математический аппарат не описан, но скорее всего будет простейший алгоритм апроксимации полученных данных и вывод графика на индикатор). Сейчас я сделал следующим образом (только часть, чтобы описать концепцию программы): 1) в основной программе я проверяю: а) флаг прерывания от таймер (он мне нужен только для опроса кнопок), которые выставляется не чаще 3-х раз в секунду б) ряд своиг флагов (как например, готовность данных к обработке) 2) в обработчике прерываний я: а) принимаю данные и складываю их в буфер, как только буфер заполниться выставляю флаг готовности данных б).... Одним словом, так как Вы и описали. В целом же меня больше интересовал вопрос о вызове как в обработчике прерываний, так и в основной программе одних и тех же ф-ций. Как я и писал, проблема решалась использованием #pragma interrupt_level 0. 2XVR: К счастью, описанные Вами грабли по работе с одним физическим ресурсом из параллельных поток вычислений были успешно преодалены введеним переменной-семафора, которая в нужный момент запрещает или разрешает доспут с данным. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость DL36 8 мая, 2008 Опубликовано 8 мая, 2008 · Жалоба В целом же меня больше интересовал вопрос о вызове как в обработчике прерываний, так и в основной программе одних и тех же ф-ций. Как я и писал, проблема решалась использованием #pragma interrupt_level 0. Вообще применение #pragma interrupt_level это исключительный случай, я так считаю. Попробуйте в симуляторе программно поднять какой нибуть флаг и посмотрите сколько тактов пройдет от момента поднятия флага до начала обработки прерывания. Если это время Вас устраивает то проблем нет. Кстати именно столько времени потребуется для выхода из прерывания. В случае одновременного применения функции в прерывания и основном цикле, это время бывает достаточно значительным и уменьшение размера кода это не окупает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
asmon 0 22 мая, 2008 Опубликовано 22 мая, 2008 (изменено) · Жалоба А кто может обьяснить назначение директивы хайтека #pragma inline func_name ? :07: По логике С++ функци с этой директивой должны быть подобны макросам. И тогда обсуждаемая проблема отпадёт сама собой (и вырастет код :) ). Но как - то непонятно эта директива описана в даташите и в своё время я с ней не разобрался... :wassat: Изменено 22 мая, 2008 пользователем asmon Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 22 мая, 2008 Опубликовано 22 мая, 2008 · Жалоба А кто может обьяснить назначение директивы хайтека #pragma inline func_name ? :07: По логике С++ функци с этой директивой должны быть подобны макросам. И тогда обсуждаемая проблема отпадёт сама собой (и вырастет код :) ). Но как - то непонятно эта директива описана в даташите и в своё время я с ней не разобрался... :wassat: И не разбирайтесь - для мелких пиков не актуально. Из мануала к писс 9.60: The #pragma inline directive is used to indicate to the compiler that a function is to be inlined. The directive is only able to be used on functions that are hard coded in the code generator of the compiler. User defined and library function are not able to be inlinded. 2Grigorij: а зачем Вам что-то передавать не в прерывании? Положили все, что нужно, (через Ваш send_byte() или как-нибудь еще) в (кольцевой) буфер передачи, установили TXIE = 1, и контроллер, если не занят передачей, сразу попадает в прерывание УСАРТа. В прерывании кидаете очередной байт из буфера в TXREG. Когда все данные будут переданы, останется только сделать TXIE = 0. Нужда в дублировании функций и прочем геморе при этом не возникает. (кста, прошная версия писс сама сделает дубль функции, используемой и в прерываниях, и вне их). И дергать конфиг УСАРТа перед каждым байтом совершенно бессмысленно - один раз настроились (можно и автободом, если он нормально работает, т.е. сначала читаем ерраты на используемый кристалл) и забыли. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Grigorij 0 23 мая, 2008 Опубликовано 23 мая, 2008 · Жалоба 2xemul Рассказываю. В моей программе USART используется для 2-х целей: управление индикатором GP1184A01A и связь с датчиком давления и температуры по RS-485. Скорость общения с датчиком 1200 бод (перенастроить нельзя никак). Минимальная скорость, на которой можно общаться с индикатором 9600 бод. В следствие все этого приходится время от времени перенастраивать USART. Сейчас я "минимизировал" кол-во перенастроек, т. к. всегда приходится отправлять не менее 4-х байт (т.е. не приходится "И дергать конфиг УСАРТа перед каждым байтом"). Если бы скорость была все время одна и таже проблем бы не было, то действительно "один раз настроились и забыли". Что касается вызова ф-ций. У меня в основной ф-ции (то бишь в main) происходит настройка индикатора и для этого, естественно, используется ф-ция SendByte. При возникновении прерывания от таймера (с помощю таймера сделан RTC) необходимо отослать запрос на датчик с целью получения от него данных, опять же используется ф-ция SendByte. В итоге компилятор начинал ругаться. Конечно, можно и просто все складывать в буфер, как Вы и говорите, но, на мой взгля в программе потом очень легко будет запутаться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 23 мая, 2008 Опубликовано 23 мая, 2008 · Жалоба 2xemul Рассказываю. В моей программе USART используется для 2-х целей: управление индикатором GP1184A01A и связь с датчиком давления и температуры по RS-485... Заведите два буфера передачи. Если понадобится передавать на 3-ей скорости, добавите еще один. И т.д. В send_byte() в качестве параметра можно передавать указатель на требуемый буфер, или использовать персональный send_byte() для каждого буфера. Но вся физическая работа с УСАРТом все равно будет происходить только в прерывании. Наверху (в send_byte()) Вы только заполняете буферы и разрешаете передачу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Grigorij 0 23 мая, 2008 Опубликовано 23 мая, 2008 · Жалоба Заведите два буфера передачи. Если понадобится передавать на 3-ей скорости, добавите еще один. И т.д. В send_byte() в качестве параметра можно передавать указатель на требуемый буфер, или использовать персональный send_byte() для каждого буфера. Но вся физическая работа с УСАРТом все равно будет происходить только в прерывании. Наверху (в send_byte()) Вы только заполняете буферы и разрешаете передачу. Наверное мы друг друга не понимаем :). Сейчас для работы с USART-ом у меня используются следующие ф-ции: //изменение скорости обмена void SetBRate(unsigned brate) { SPEN = 0; SPBRGH = (brate >> 8); SPBRG = (brate & 0x00FF); SPEN = 1; CREN = 1; TXEN = 1; } //отправка данных void SendByteUART(unsigned char data) { CREN = 0; TXREG = data; while (!TRMT); CREN = 1; } Когда мне надо передать команду, например, на датчик, я переключаю скорость обмена USART на 1200 и отправляю небходимое кол-во байт. Аналогично делаю и для индикатора (только скорость 19200). Никаких здесь проблем не возникает. Но ф-цию SendByteUART мне приходилось (сейчас концепция слегка переработана) вызывать, как в ф-ции main, так и в обработчике прерываний (и никуда деться нельзя). В итоге компилятор на это ругался (конечно если не использовать #pragma interrupt_level), причем абсолютно не важно, что делает ф-ция SendByteUART. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 24 мая, 2008 Опубликовано 24 мая, 2008 · Жалоба Наверное мы друг друга не понимаем :). Угу. typedef struct { u8_t buf[BUF_SIZE]; // обычный кольцевой буфер u8_t *head, *tail, cnt; // можно обойтись без cnt // имхо, BRGH можно на Ваших скоростях не трогать u8_t baud; } usart_buf_t; volatile usart_buf_t buf1, buf2; void SendByteUart(u8_t data, usart_buf_t *pbuf) { while(pbuf->cnt == BUF_SIZE) continue; *pbuf->head = data; if(++pbuf->head == &pbuf->buf + BUF_SIZE) pbuf->head = &pbuf->buf; pbuf->cnt++; TXIE = 1; // естесно, отсюда мы сразу улетим в прерывание // поэтому, возможно, следующий вариант будет интересней // if(++pbuf->cnt == FLUSH_USART_CNT) { FlushUsartTmr = 0; TXIE = 1; } // else if(!FlushUsartTmr) FlushUsartTmr = FLUSH_USART_TIME; // и где-нибудь, где обрабатываюся программные таймеры, добавить // if(FlushUsartTmr) if(!--FlushUsartTmr) TXIE = 1; } // имхо (после некоторых раздумий), для мелких пиков таки разумнее будет // сделать персональные SendByteUart() для каждого буфера // &pbuf->buf - для совместимости разных версий хт писс между собой :) void main(void) { ... buf1.baud = BAUD1; buf2.baud = BAUD2; SendByteUart('a', &buf1); SendByteUart('b', &buf2); ... } interrupt void isr(void) { ... if(TXIE && TXIF) { if(buf1.cnt) { if((SPBRG != buf1.baud) && !TRMT) break; SPBRG = buf1.baud; TXREG = *buf1.tail; buf1.cnt--; if(++buf1.tail == &buf1.buf + BUF_SIZE) buf1.tail = &buf1.buf; } else if(buf2.cnt) { if((SPBRG != buf2.baud) && !TRMT) break; SPBRG = buf2.baud; TXREG = *buf2.tail; buf2.cnt--; if(++buf2.tail == &buf2.buf + BUF_SIZE) buf2.tail = &buf2.buf; } else TXIE = 0; } ... } Но ф-цию SendByteUART мне приходилось (сейчас концепция слегка переработана) вызывать, как в ф-ции main, так и в обработчике прерываний Иногда _отладочную_ инфу мне приходится выдавливать в УСАРТ непосредственно в прерывании, но через отдельный отладочный буфер. (и никуда деться нельзя). Станиславский - рулезз форева. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mad_kvmg 0 7 июня, 2008 Опубликовано 7 июня, 2008 · Жалоба Если еще, не решили свою проблему, то вот почитайте http://www.microchip.su/showthread.php?t=2...%E2%E0%ED%E8%E9 не так давно тоже с этим маился. P.S. а функции и правда нехорошо использовать в ISR и объем кода получается больше и нестабильности добавляет все это дело. Используйте флаги, а в майне их анализируйте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Grigorij 0 10 июня, 2008 Опубликовано 10 июня, 2008 · Жалоба Если еще, не решили свою проблему, то вот почитайте http://www.microchip.su/showthread.php?t=2...%E2%E0%ED%E8%E9 не так давно тоже с этим маился. P.S. а функции и правда нехорошо использовать в ISR и объем кода получается больше и нестабильности добавляет все это дело. Используйте флаги, а в майне их анализируйте. Проблема уже давно решилась :). При этом на настоящее время есть 3 варианта решения: 1) #pragma interrupt level 2) использование флагов (собственно я остановился на этом варианте) 3) как недавно оказалась, в версии HI-TECH 9.60 PRO такой проблемы не возникает (специально пробовал одну и туже ф-цию вызывать как в main-е так и ISR, компилятор ругаться не стал) Думаю на этом тему можно закрыть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться