Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Пару вопросов по Си для MCS51
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > MCS51
Lotor
Доброе время суток. Начал тут изучать C для 51-х и возникли глупые вопросы:
1) Как Вы отсчитываете (формируете) боле-мене точные временные интервалы? Допустим надо сформировать задержку в 1 секунду, стандартной функции у Keil'a нет, надо писать самим. Есть ли стандартные приемы? Или надо написать какую-нить простенькую конструкцию аля for (i=40;i>0;i--), посмотреть какой ассемблеровский код ей соответствует после компиляции и затем прикинуть? Или в программном симуляторе засечь? Но это же так тоскливо... Можно ли решить задачу не методом такого подбора?
2) Как массив помещается в память програм? Keil пихает в драгоценное ОЗУ даже при объявлении со спецификатором const.
Буду благодарен за ответы)
alcosar
Цитата(Lotor @ Jul 8 2007, 18:32) *
Доброе время суток. Начал тут изучать C для 51-х и возникли глупые вопросы:
1) Как Вы отсчитываете (формируете) боле-мене точные временные интервалы? Допустим надо сформировать задержку в 1 секунду, стандартной функции у Keil'a нет, надо писать самим. Есть ли стандартные приемы? Или надо написать какую-нить простенькую конструкцию аля for (i=40;i>0;i--), посмотреть какой ассемблеровский код ей соответствует после компиляции и затем прикинуть? Или в программном симуляторе засечь? Но это же так тоскливо... Можно ли решить задачу не методом такого подбора?
2) Как массив помещается в память програм? Keil пихает в драгоценное ОЗУ даже при объявлении со спецификатором const.
Буду благодарен за ответы)


const и не должен помещать в ОЗУ. Вам нужен code. Пример:
unsigned char code password[] = "65535";
SALOME
Цитата(Lotor @ Jul 8 2007, 22:32) *
Доброе время суток. Начал тут изучать C для 51-х и возникли глупые вопросы:
1) Как Вы отсчитываете (формируете) боле-мене точные временные интервалы?

Временные интервалы лучше формировать встроенными в МК51 таймерами...
Lotor
Цитата(alcosar @ Jul 8 2007, 23:51) *
const и не должен помещать в ОЗУ. Вам нужен code. Пример:
unsigned char code password[] = "65535";

Спасибо, именно то, что надо.
Цитата(SALOME @ Jul 9 2007, 07:46) *
Временные интервалы лучше формировать встроенными в МК51 таймерами...

Это-то понятно, но есть вагон и маленькая тележка ситуаций, когда таймер занят, например опрос АЦП каждую секунду, а при этом I2C формируется программно и нужны боле-мене точные задержки...
oran-be
Цитата
Это-то понятно, но есть вагон и маленькая тележка ситуаций, когда таймер занят, например опрос АЦП каждую секунду, а при этом I2C формируется программно и нужны боле-мене точные задержки...

Ваяете в перывании одного таймера ядро с циклом, к примеру 1мС и в этом ппрерывании лепите таймеры, от которых тактируете запуск АЦП и меряете секундные интервалы. Точность - 0.1%. Обычно достаточно.
Lotor
Цитата(oran-be @ Jul 9 2007, 22:17) *
Ваяете в перывании одного таймера ядро с циклом, к примеру 1мС и в этом ппрерывании лепите таймеры, от которых тактируете запуск АЦП и меряете секундные интервалы. Точность - 0.1%. Обычно достаточно.

Спасибо за идею, стоит попробывать.

Еще возник вопрос (навеное от нежелания вчитываться в несамую лучшую документацию) - KEIL побитово к порту не позволяет обращаться? Например ругается на конструкцию "P1.1=1"...
Sergu
Цитата(Lotor @ Jul 9 2007, 22:21) *
Еще возник вопрос (навеное от нежелания вчитываться в несамую лучшую документацию) - KEIL побитово к порту не позволяет обращаться? Например ругается на конструкцию "P1.1=1"...


удобно это делать вот так:

объявить
sbit SCL = P3^4;
sbit SDA = P3^5;

и потом их использовать:
SDA = 1;
SCL = 1;
Lotor
Цитата(Sergu @ Jul 10 2007, 07:51) *
удобно это делать вот так:

объявить
sbit SCL = P3^4;
sbit SDA = P3^5;

и потом их использовать:
SDA = 1;
SCL = 1;

Мне привычнее через #define, главное синтаксис P3^4 - спасибо, не знал.
msn
Цитата(Lotor @ Jul 9 2007, 19:18) *
Это-то понятно, но есть вагон и маленькая тележка ситуаций, когда таймер занят, например опрос АЦП каждую секунду, а при этом I2C формируется программно и нужны боле-мене точные задержки...


По простому:
пишем asm файл с кодом (нужно знать частоту ядра и время исполнения инструкций):
Код
см. delay.a51


В файле заголовка:
Код
см. delay.h


Использование:
Код
SDA = 1;
Delay_Nop_us(20);
SDA = 0;
zltigo
Цитата(msn @ Jul 11 2007, 00:25) *
пишем...

Потрудитесь оформить свои чрезмено обширные вcтавки предыдущего поста в виде приложения.
silc
alcosar: const и не должен помещать в ОЗУ. Вам нужен code. Пример:
unsigned char code password[] = "65535";
в иар для авр, использовал flash unsigned char Rn[] = { 0x30,0x31,0x32,0x33,0x34} ;

off: такая тема очень актуально для тех кто начинает, её бы прикрепить, а еще лучще оформить как faq.
Цитата
alcosar
Sir Jon
Цитата(Lotor @ Jul 9 2007, 19:18) *
Это-то понятно, но есть вагон и маленькая тележка ситуаций, когда таймер занят, например опрос АЦП каждую секунду, а при этом I2C формируется программно и нужны боле-мене точные задержки...


ну в общем то правильные идеи уже прозвучали. Вы успешно подберете контроллер с количеством таймеров равным количеству необходимых задач (по одной на каждый таймер), если таких задач одна-две. Хорошим тоном в программе средней сложности является организация "службы времени" которая в большинстве случаев базируется на одном из таймеров прерыванию на переполнение. В обработке прерывания анализируется количество переполнений (необходимые Вам периоды времени). В зависимости от свободных ресурсов либо расставляются "флажки" действий, которые можно обработать в основном цикле Main, либо эти действия отрабатываются прямо в прерывании.
kolobok0
Цитата(Sir Jon @ Sep 7 2007, 14:51) *
..Хорошим тоном в программе средней сложности является организация "службы времени" которая в большинстве случаев базируется на одном...


+1
Василий_Безкатегорийный
Насчет побитового обращения к портам. Я пытаюсь работать с cy7c68013A и там можно к порту обращаться побитово. Реализуется это так. Есть отдельный файл с описанием всех регистров и вот как там например порт А описывается:
sfr IOA = 0x80;
/* IOA */
sbit PA0 = 0x80 + 0;
sbit PA1 = 0x80 + 1;
sbit PA2 = 0x80 + 2;
sbit PA3 = 0x80 + 3;

sbit PA4 = 0x80 + 4;
sbit PA5 = 0x80 + 5;
sbit PA6 = 0x80 + 6;
sbit PA7 = 0x80 + 7;

Далее в тексте программы рпосто обращаешься к битам порта:
OEA=0xff;
PA1=0x00;
PA1=0x01;
AndreyS
Добрый день.

Не стал создавать новую тему.

Вопрос в следующем. Вернее проблемма.
Дано:
компилятор Keil
C Compiler C51.exe v8.06
Assembler A51.exe v8.00c
Linker/Locator BL51.exe v6.05
Librarian LIB51.exe v4.24
Hex Converter OH51.exe v2.6

Суть проблеммы
В рабочем режиме иногда прошивка виснет. Выяснил, что зависает (зацикливается) она по причине того что локальные переменные процедуры кто-то запорол.
Нашел в карте памяти что данные ячейки относятся еще к двум процедурам (причем там эти переменные тоже локальные). Одна из которых вызывается в прерывании.
Как мне теперь заставить Keil убрать из перекрестных ссылок эти переменные (чтобы они лежали в разных адресах DATA)?
Делать их глобальными внутри одного файла желания нет.

Пока я проверил только локальные переменные в области DATA, быть может такая петрушка есть еще с переменными в области XDATA. Почему Keil их так расположил? Ведь при компиляции он знает какие процедуры попадают в прерывание и по идее должен этим процедурам для локальных переменных выдилять свои адреса. Может нужно что-то указать??

Спасибо.
AndreyS
Люди!!! Помогите. Пока перебросил переменные одной процедуры в XDATA, чтобы они ушли из перекрестка.

Вот настройки проекта:
barabek
Цитата(AndreyS @ Dec 10 2008, 18:56) *
Суть проблеммы
В рабочем режиме иногда прошивка виснет. Выяснил, что зависает (зацикливается) она по причине того что локальные переменные процедуры кто-то запорол.
Нашел в карте памяти что данные ячейки относятся еще к двум процедурам (причем там эти переменные тоже локальные). Одна из которых вызывается в прерывании.
Как мне теперь заставить Keil убрать из перекрестных ссылок эти переменные (чтобы они лежали в разных адресах DATA)?
Делать их глобальными внутри одного файла желания нет.

Пока я проверил только локальные переменные в области DATA, быть может такая петрушка есть еще с переменными в области XDATA. Почему Keil их так расположил? Ведь при компиляции он знает какие процедуры попадают в прерывание и по идее должен этим процедурам для локальных переменных выдилять свои адреса. Может нужно что-то указать??

Спасибо.

Как я понял, у Вас есть функция которая вызывается из функции обработки прерывания? Если так, то это очень не гуд smile.gif. Для этого нужны очень веские основания. Только в том случае, если Вы эту функцию вызываете еще из другого места. Но эту ситуацию линкер возможно и не отслеживает и нужно в этой функции переменные объявить static, хотя это равносильно глобальной переменной. Да и тем более возможен повторный вход в функцию со всеми вытекающими. Этот вариант отметаем sad.gif
Если же вызов только из прерывания, тогда лучше вобще обойтись без дополнительной функции, все стащить в одно место, в функцию-обработчик. Вы же наверняка пользуетесь using-ами, может быть линкер эти переменные через регистры протащит, будет маленькое счастье smile.gif. А нельзя вобще обойтись в прерывании без обработки, выставив соответствующий флажок и обработать в другом месте?
AndreyS
Цитата(barabek @ Dec 10 2008, 17:18) *
Как я понял, у Вас есть функция которая вызывается из функции обработки прерывания? Если так, то это очень не гуд smile.gif. Для этого нужны очень веские основания. Только в том случае, если Вы эту функцию вызываете еще из другого места. Но эту ситуацию линкер возможно и не отслеживает и нужно в этой функции переменные объявить static, хотя это равносильно глобальной переменной. Да и тем более возможен повторный вход в функцию со всеми вытекающими. Этот вариант отметаем sad.gif
Если же вызов только из прерывания, тогда лучше вобще обойтись без дополнительной функции, все стащить в одно место, в функцию-обработчик. Вы же наверняка пользуетесь using-ами, может быть линкер эти переменные через регистры протащит, будет маленькое счастье smile.gif. А нельзя вобще обойтись в прерывании без обработки, выставив соответствующий флажок и обработать в другом месте?


Огромное спасибо за содержательный ответ.

В прерывании использую процедуру которая вызывается еще и по коду. Суть процедуры сформировать (подготовить запрос на SPI шину и поставить его в очередь). Т.е. по сути - это и флажок и короткий обработчик этого флажка.

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

Вы подняли мне веки smile.gif

Правда это не отменяет объединения (отображения части переменных по одним и тем же адресам) локальных переменных двух разных процедур (я пока просто перебросил переменные в одной процедуре в XRAM и таким образом развязал эти процедуры).

Буду переписывать обработчик.
Axel
Если функция не написана, как реентерабельная (слово не я придумал!) и при этом может вызываться из основной петли и из прерываний, то это, вобщем, конкретные грабли.
barabek
Цитата(AndreyS @ Dec 11 2008, 02:08) *
Правда это не отменяет объединения (отображения части переменных по одним и тем же адресам) локальных переменных двух разных процедур (я пока просто перебросил переменные в одной процедуре в XRAM и таким образом развязал эти процедуры).

Если две функции не могут вызываться одновременно (случай с прерыванием) - то конечно же пусть они используют одни и те же адреса для локальных переменных. В этом и соль этих переменных в отличии от глобальных. Если посмотреть на листинг то почти в каждой функции для локальных переменных используются регистры. И это очень хорошо, это только плюс компилятору-линкеру. Ведь памяти очень немного smile.gif
tag
Цитата(barabek @ Dec 11 2008, 04:31) *
В этом и соль этих переменных в отличии от глобальных.


Уверяю вас соль не в этом. Как известно памяти у 51 немного, плюс компилятор разработан так что локальные переменные сохраняет не на стеке, а либо в регистрах, либо в памяти (в этом вы можете убедится просмотрев руководство). В случае когда переменные располагаются в памяти линковщик может перекрывать область памяти локальных переменных одной подпрограммы и такую же область другой подпрограммы. Видимо так сделано с целью экономии памяти. Тогда, конечно подразумевается что эти фукции к примеру, не могут вызывать друг друга из своего тела. Так линковщик работает если ему не указать опцию nooverlay. Когда данная опция указана области локальных переменных подпрограмм не пересекаются и следовательно проблема порчи локальных переменных исчезает.
barabek
Цитата(tag @ Dec 11 2008, 20:05) *
Уверяю вас соль не в этом. Как известно памяти у 51 немного, плюс компилятор разработан так что локальные переменные сохраняет не на стеке, а либо в регистрах, либо в памяти (в этом вы можете убедится просмотрев руководство). В случае когда переменные располагаются в памяти линковщик может перекрывать область памяти локальных переменных одной подпрограммы и такую же область другой подпрограммы...

А я разве сказал не тоже самое?:-D
AndreyS
Цитата(barabek @ Dec 11 2008, 03:31) *
Если две функции не могут вызываться одновременно (случай с прерыванием) - то конечно же пусть они используют одни и те же адреса для локальных переменных. В этом и соль этих переменных в отличии от глобальных. Если посмотреть на листинг то почти в каждой функции для локальных переменных используются регистры. И это очень хорошо, это только плюс компилятору-линкеру. Ведь памяти очень немного smile.gif


Добрый день.

Спасибо всем за ответы.
Все что Вы ранее высказывали, я прекрасно понимаю.
Но тут вещь в следующем.
Компилятор никогда не отображает локальные переменные на одни и теже адреса, если они пересекаются при вызове процедур (РАЗНЫХ ПРОЦЕДУР). Если переменные пересекаются (отображаются на одни и теже адреса) (РЕГИСТРЫ НАПРИМЕР), то компилятор при входе в такую процедуру сохраняет все эти регистры в стек. Если компилятор этого не делает - то это плохой компилятор. Анализирую код Keil'а он (Кейл) именно так и делает. Если я в перерывании (или процедуре) использую вызов процедуры, то в прерывании, перед ее выполнением, сохряняются все регистры и PSW в стек. Если я неиспользую каких либо регистров (ну компилятор в процессе компиляции ничего не задействовал), то на входе он ничего не сохраняет. Для Кейла я это проверял. Правда весь листинг виден только в самом проце, в выходных файлах этого нет.

В данном примере происходит все именно так.
Если у меня есть ряд процедур, которые могут вызваться из прерывания и у них есть локальные переменные, то компилятор не отражает на адреса этих переменных ничего из других процедур.
В данном примере я заметил пересекающиеся области (две ячейки наложились. Две ячейки локальных переменных разных процедур). Причем ячеки входящих переменных (извиняюсь за корявость, но переменных через которые я передаю данные в процедуру).

Есть функция Spi_RD в которую я передаю ряд параметров. Она вызывается в прерывании.
Есть функция Filtrate_long в которую я передаю одно число и в нутри нее есть переменные счетчики.
Так пересеклись две переменные из входящих переменных функции Spi_RD и внутренние переменные-счетчики процедуры Filtrate_long.

На примере других функций я вижу, что используемые регистры для локальных переменных в процедурах, компилятор сохраняет в стек, при вызове внутри одной процедуры другой (с такими же регистрами). Иначе я вообще никогда не смог бы вызывать внутри процедур другие процедуры. Именно так происходит и тут. Просто количество параметров передаваемых в процедуру Spi_RD наверное большое и они вышли за регистры и компилятор о них забыл (мое предположение).

Вот вызовы процедур с которыми я нашел пересечение переменных:
Код
bit Spi_RD(byte * ptr, byte * complete, word LEN, byte type, byte FIRST_SENT, bit cs);

signed long filtrate_long(signed long input_data);


Пересеклись адреса следующих переменных
type, FIRST_SENT с локальными переменными (счетчиками) внутри функции Filtrate_long.

В данный момент локальные переменные функции Filtrate_long я объявил в области XDATA дабы они попросту ушли из карты памяти в другую область (остальные вроде как ен пересекаются). И все работает без глюков.

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

Ведь я не исключаю того что такое же может произойти в области XDATA.


Цитата(tag @ Dec 11 2008, 13:05) *
Как известно памяти у 51 немного, плюс компилятор разработан так что локальные переменные сохраняет не на стеке, а либо в регистрах, либо в памяти (в этом вы можете убедится просмотрев руководство). В случае когда переменные располагаются в памяти линковщик может перекрывать область памяти локальных переменных одной подпрограммы и такую же область другой подпрограммы. Видимо так сделано с целью экономии памяти. Тогда, конечно подразумевается что эти фукции к примеру, не могут вызывать друг друга из своего тела. Так линковщик работает если ему не указать опцию nooverlay. Когда данная опция указана области локальных переменных подпрограмм не пересекаются и следовательно проблема порчи локальных переменных исчезает.


Добрый день.

Огромное вам спасибо.

Мне кажется - это есть лекарство моей болезни. Так как симптомы вы описали точно.

Черт, а ведь эта директива относится ко всему проекту. С ней области data не хватает smile.gif
А для лечения локально, нужно делать глобальбные переменные. А что же делать с входыми данными процедур??? Тоже глобально??
barabek
Цитата(AndreyS @ Dec 11 2008, 22:00) *
Компилятор никогда не отображает локальные переменные на одни и теже адреса, если они пересекаются при вызове процедур (РАЗНЫХ ПРОЦЕДУР). Если переменные пересекаются (отображаются на одни и теже адреса) (РЕГИСТРЫ НАПРИМЕР), то компилятор при входе в такую процедуру сохраняет все эти регистры в стек. Если компилятор этого не делает - то это плохой компилятор. Анализирую код Keil'а он (Кейл) именно так и делает.

Здесь позвольте с Вами не согласиться. Это относится не конкретно к Keil, а вообще к языку C. Локальные переменные, кроме того что они видны только внутри функции (блока), они еще имеют время жизни только на протяжении выполнения этой функции (блока). Ни в коем случае не гарантируется, что при очередном вызове функции локальная переменная будет иметь тоже значение, что было раньше.
Цитата
Если я в перерывании (или процедуре) использую вызов процедуры, то в прерывании, перед ее выполнением, сохряняются все регистры и PSW в стек. Если я неиспользую каких либо регистров (ну компилятор в процессе компиляции ничего не задействовал), то на входе он ничего не сохраняет. Для Кейла я это проверял. ,,,
....Если у меня есть ряд процедур, которые могут вызваться из прерывания и у них есть локальные переменные, то компилятор не отражает на адреса этих переменных ничего из других процедур.
В данном примере я заметил пересекающиеся области...

Чтобы не сохранять регистры лучше использовать using. А вот для этого случая - просто функции и функции вызываемой из прерывания, Keil действительно подкачал smile.gif, видимо у него нет такой проверки на перекрытие переменных sad.gif. Я когда-то тоже обжигался на этом. Теперь прерывания только наиболее короткие, без вызовов, с использованием отдельного банка памяти для прерываний одинакового приоритета.
Цитата
Правда весь листинг виден только в самом проце, в выходных файлах этого нет.

А в *.LST разве в конце не расписаны адреса под переменные (при соответствующих галочках в настройках), или это не то?

Код
bit Spi_RD(byte * ptr, byte * complete, word LEN, byte type, byte FIRST_SENT, bit cs);

Меня, честно говоря, пугают такие функции с огромным количеством входных переменных smile.gif. Не воспринимайте мои слова близко к сердцу. Это конечно не ошибка, просто я бы использовал структуру и передавал бы указатель на нее.
AndreyS
Цитата(barabek @ Dec 11 2008, 17:00) *
Здесь позвольте с Вами не согласиться. Это относится не конкретно к Keil, а вообще к языку C. Локальные переменные, кроме того что они видны только внутри функции (блока), они еще имеют время жизни только на протяжении выполнения этой функции (блока). Ни в коем случае не гарантируется, что при очередном вызове функции локальная переменная будет иметь тоже значение, что было раньше.

Меня, честно говоря, пугают такие функции с огромным количеством входных переменных smile.gif. Не воспринимайте мои слова близко к сердцу. Это конечно не ошибка, просто я бы использовал структуру и передавал бы указатель на нее.


Я согласен что локальные переменные имеют время жизни только на протяжении функции. Но при этом регистры то он в стек сохраняет (т.е. если я из функци вызову другую, то локальные переменные первой функции он сохранит в стек или будет использовать локальные переменные второй функции в другой области), а вот локальные переменные, что вылезли за диапазон регистров он в стек не сохраняет. Т.е. если я передаю в функцию большое количество параметров есть вероятность пересечения. Тут же у меня была проблемма с изменением ячейки. Я не понял почему это происходит (оставил для разбирательств на потом) просто завел внутри процедуры дублирующую локальную переменную (она видно отразилась в регистры) и в нее перебрасывал срузу при входе в процедуру данные из ихменяющейся переменной. Все заработало номарльно. Тогда я не врубился кто виноват (думал сам куда за диапазон выхожу), а теперь понял. Надо шерстить весь проект на предмет большого числа передаваемых параметров. Делать либо как у вас (заполнять структуру и передавать указатель. Просто я хотел унивирсальности, а так прийдется везде еще таскать обписание этой структуры.) либо урезать часть передаваемых параметров в функцию и переносить их например в глобальные.

Обидно все это. Регистры сохраняет (так как знает что их портит), а часть используемых ячеек не сохраняет. sad.gif
AndreyS
Добрый день.

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

Пересекающихся адресов теперь нет. Все работает нормально.

Печально это sad.gif
И печально именно то, что оказалось что Keil не сохраняет все локальные переменные при входе в процедуры. Сохраняет он только регистры. sad.gif

А еще более печально то, что прошло столько времени, а подобное в нем досих пор существует.

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

Мда. Что еще может подстерегать???

По сему заинтересовал вопрос перехода с Keil на другой компилятор и линковщик. Или просто другой линковщик (вроде как именно он раскидывает переменые по адресам???).

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

Не ну быть может это просто некрасиво конечно с точки зрения написания кода, передавать в функцию такое количество параметров как у меня. Но я надеялся, что компилятору это позубам. А иначе накой хрен переходить с Asm, когда мне и тут приходится заботиться о том чтобы небыло пересекающихся адресов?? На Си ведь переходят для удобства и быстроты написания программы (частный случай и лично мое мнение), быстрой модификации программы. В общем чтобы не иметь в частности такой головной боли как раскидывание по адресам локальных переменных.
Сергей Борщ
Цитата(AndreyS @ Dec 12 2008, 12:38) *
И печально именно то, что оказалось что Keil не сохраняет все локальные переменные при входе в процедуры. Сохраняет он только регистры. sad.gif
Смею предположить, что Кейл все делает правильно. Для цепочки вызовов он строит компилируемый стек и вы сами заметили, что локальные переменные разных функций в такой цепочке не пересекаются. Axel в сообщении №19 сказал вам, что ваш случай отличается от обычного, что вам надо найти способ указать компилятору, что функция является реентерабельной. Штудируйте документацию компилятора на предмет ключевого слова reentrant или подобного. Если бы компилятор каждую функцию делал реентерабельной - вы бы первый взвыли, что он сохраняет кучу лишнего и генерит неэффективный код. Кейлом и x51 уже очень давно не пользуюсь, поэтому не могу подсказать конкретнее, но на 99% уверен, что в нем предусмотрен какой-то атрибут вроде reentrant для функций.
c8051
Цитата(Сергей Борщ @ Dec 12 2008, 15:03) *
Смею предположить, что Кейл все делает правильно.
...вам надо найти способ указать компилятору, что функция является реентерабельной.
Штудируйте документацию компилятора на предмет ключевого слова reentrant или подобного.

c51.pdf
page 129
Reentrant functions can be called recursively and can be called simultaneously
by two or more processes. Reentrant functions are often required in real-time
applications or in situations where interrupt code and non-interrupt code must
share a function.


или в ситуациях, когда код прерывания и код непрерывания должны
совместно использовать функцию.
Сергей Борщ
Цитата(c8051 @ Dec 12 2008, 18:52) *
c51.pdf
page 129
Фух... Кейла оправдали. Очередной "глюк" оказался просто ленью прочитать документацию.
AndreyS
Цитата(Сергей Борщ @ Dec 12 2008, 21:37) *
Фух... Кейла оправдали. Очередной "глюк" оказался просто ленью прочитать документацию.


Добрый день.

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

Большое спасибо за наставление.
Пойду читать документацию (просто читать ее всю подряд, от корки до корки, я не хотел. В этом я действительно поленился smile.gif.

Спасибо.

PS. Да а на сообщение Axel я не обратил внимания laughing.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.