|
|
  |
Злополучная функция what_day(), Вычисление дня недели |
|
|
|
Jun 6 2008, 15:52
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Это выходит за всякие рамки понимания и попахивает чертовщиной... Написал третью функцию вычисления дня недели: Код unsigned char what_day(unsigned int year, unsigned int month, unsigned int day) { unsigned char YEAR[]={0, 2, 3, 4}; unsigned char MONTH[]={0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; unsigned char a, b, c, e, tmp; tmp = year - 1996; a = tmp & 3; b = (tmp >> 2) + (tmp & 0xfc); c = MONTH[month-1]; if((a == 0) && (month > 2)) c++; a = YEAR[a]; e = (a + b + c + day) % 7; return e; } Функцию переписал у Сергея Фролова. В ней нет тяжелых делений. Она работает. Но при вызове все равно приводит к тому глюку! Ради эксперимента попробовал вместо этой функции вызвать какую-нибудь сложную математическую функцию , например решение квадратного уравнения и укруглением результата до 5 знака после запятой. Код //_____________________________________________________________________________ double quadratic(double a, double b, double c) { double d, x; d=b*b-4.*a*c; // Дискриминант if(d<0.) return 0; // Уравнение не имеет корней if(d==0.) x=-b/(2.*a); // Уравнение имеет один корень else x=(-b+sqrt(d))/(2.*a); // Уравнение имеет два корня, // но нужен только положительный return x; }
//############################################################################# // round down a number to the decimal place given by power // e.g round(1.0256,-2) means round to 2nd decimal -> 1.03 //_____________________________________________________________________________ double round_to_pow(double x, int power) { double inc, xnew; inc = pow(10.0, (double)power); xnew = inc * (floor(x/inc + 0.5 + SMALL)); return(xnew); }
//--------------------------------------------------------------------------- int main() { volatile unsigned char day; day = (unsigned char)round_to_pow(quadratic(100, 200, 3), -5); Так все нормально. В чем же может быть дело? Какие еще будут предложения? PS. Одна деталь. Если убрать из what_day() (обеих вариантов) операцию % 7, то глюк исчезает. Как это объяснить? В дополнение к функции решения кв. уравнения добавил функцию по расчету давления и температуры цифрового датчика давления. Там точно громоздкие вычисления. И все прошло (глюка не вызвало). А здесь простая операция деления по модулю...
|
|
|
|
|
Jun 6 2008, 19:21
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(alux @ Jun 6 2008, 11:11)  Но по какой-то непонятной причине вызов ее приводит к глюкам программы. В частности, при входе в пункт меню невозможно из него выйти, при этом программа реагирует не так как задумано. Должен сказать, что проект использует ОС (scmRTOS) и ОЗУ использовано на 90%. Контроллер Mega324P (2кБ ОЗУ). Отладочными средствами (JTAG) пользоваться не представляется возможным. Это похоже на переполнение стека. Но. Почему это происходит, если вызов достаточно простой функции вставить в начале функции main (до запуска ОС): Код int main() { what_day(2008, 6, 6); ..................... Больше нигде в процессах она не используется. Пробовал менять размеры CSTACK (100...200) и RSTACK (32...64). Не помогло, не в этом причина . из Вашего мэп Код CSTACK DATA 00000100 - 000001FF 100 dse 0 RSTACK DATA 00000200 - 0000023F 40 dse 0 Теперь мысль, может бредовая но всё-же- может Вы запретили компилятору какие-то регистры в которых компилятор хранит остаток от деления? не знаю как ИАР но в код вижине остаток хранится в 26 регистре. Пример для КВ Код //========================================================= void prog3(char ch) { ch=ch+2; ch=ch/3; ch=ch%3; } void prog4(char ch) { ch=ch/3; ch=ch%3; }
??? Лишние инструкции ??? Оптимальнее было-бы так - _prog3: LD R30,Y SUBI R30,-LOW(2) ST Y,R30 _prog4: LD R26,Y LDI R30,LOW(3) RCALL __DIVB21U ST Y,R30 LD R26,Y LDI R30,LOW(3) RCALL __MODB21U ST Y,R30 ADIW R28,1 RET
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Jun 6 2008, 21:19
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(sKWO @ Jun 6 2008, 22:21)  Не помогло, не в этом причина . из Вашего мэп Код CSTACK DATA 00000100 - 000001FF 100 dse 0 RSTACK DATA 00000200 - 0000023F 40 dse 0 Не понял. Что Вы имели в виду? Цитата(sKWO @ Jun 6 2008, 22:21)  Теперь мысль, может бредовая но всё-же- может Вы запретили компилятору какие-то регистры в которых компилятор хранит остаток от деления? Регистры я не трогаю. Заменил в функции операцию % 7 на -= 7: Код day = a + year + c + day;// % 7; while(day >= 7) day -= 7; return day; Проблема решилась частично: если вызвать эту функцию из main() , то глюк пропал. Но если вызвать ее из другой функции rtc_set_time(), то глюк имеет место быть... Не знаю что и думать. Варианты исчерпались. Пойду-ка я спать. PS2. Все! Наконец-то поборол глюк. Переписал в очередной раз функцию. Прям целая коллекция функций получилась  Код unsigned char what_day(unsigned int year, unsigned int month, unsigned int date) { signed int c=0; unsigned char day; if((date>=1)&&(date<=31)&&(month>=1)&&(month<=12)&&(year>=1582)&&(year<=4903)) { if(month < 3) { month += 10; // Месяц январь или февраль? year -= 1; } else { month -= 2; // Остальные месяцы while(year >= 100) { c++; // Вычисляем столетие year -= 100; // Находим год в столетии } day = (unsigned char)((26*month-2)/10 + date + (year>>2) + year + (c>>2) - 2*c); while(day >= 7) day -= 7; // Вычисляем день недели } } return day; } Сейчас все работает как положено. Хотя неприятный осадок остался... Нет ответов на вопросы - почему такое произошло?
Сообщение отредактировал alux - Jun 6 2008, 22:58
|
|
|
|
|
Jun 7 2008, 06:02
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(alux @ Jun 7 2008, 01:19)  Не понял. Что Вы имели в виду? использование функциями CSTACK и RSTACK я всегда смотрю в листинге. файл с расширением .lst. вот отрывок, удобно Код Maximum stack usage in bytes:
Function CSTACK RSTACK -------- ------ ------ lcd_EN_toggle 0 2 lcd_command 1 2 -> lcd_waitcmd 1 2 -> lcd_write 1 2 -> lcd_waitcmd 1 2 а нащёт остатка от деления и рассположения в регистрах надо будет всё же подумать, может попробовать намного пошаманить с инлайн ассемблером ? Сообщите о результатах. Сам тоже попробую
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Jun 7 2008, 13:24
|
Участник

Группа: Validating
Сообщений: 64
Регистрация: 16-06-05
Пользователь №: 6 073

|
Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки.
PS: time.h использовал как-то. плохо совместимая с экономией памяти вещь.
|
|
|
|
|
Jun 7 2008, 13:40
|
Местный
  
Группа: Свой
Сообщений: 446
Регистрация: 12-03-06
Из: Москва
Пользователь №: 15 142

|
Цитата(Flasher @ Jun 6 2008, 23:38)  Недавно в яре натолкнулся под авр использовал функцию % и прога пошла лесом... как только закоментировал строчку- все заработало. В листинге не разбирался- не было времени. Теперь жалею Странно... Использовал скопипастленную с сахары функцию Код unsigned long DateTimeToLong(TDataTime* pdt){ byte month; word year; unsigned long c, ya; unsigned long res;
month = BCDtoBin(pdt->Month); year = BCDtoBin(pdt->Year)+2000;
if(month > 2){ month -= 3; }/*if*/ else { month += 9; year--; }/*else*/
c = (year / 100L); ya = (year - (100L * c)); res = (146097L * c)/4L + (1461L * ya) /4L + (153L * month + 2L)/5L + BCDtoBin(pdt->Date); pdt->Day=(res+2)%7; return (res - 720000L) * 1440L + (BCDtoBin(pdt->Hour) * 60L + BCDtoBin(pdt->Min)); } Никаких проблем, хотя оптимальности и экономии никакой. IAR AVR 4.30 Значения CSTACK и RSTACK по умолчанию, т.е минимальные.
|
|
|
|
|
Jun 7 2008, 14:00
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(alux) Проблема решилась частично: если вызвать эту функцию из main() , то глюк пропал. Но если вызвать ее из другой функции rtc_set_time(), то глюк имеет место быть... Всё-таки не исключено, что стек. В любой другой функции стека меньше по сравнению с main, т.к. они вызываются после main. Цитата(AlexG) Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки. Действие происходит ещё до запуска ОС, на этапе инициализаций. PS. Либо дайте уже нормальный листинг, либо этот телепатический сеанс затянется надолго. Нужен листинг этой "злополучной" функции и карту ОЗУ со стеком и рядом с ними.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 7 2008, 15:55
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 7 2008, 17:00)  Нужен листинг этой "злополучной" функции и карту ОЗУ со стеком и рядом с ними. Рано обрадовался... Ночью не доглядел, забыл раскомментировать вызов этой функции. Поэтому решил, что проблема решена. Но только-что обнаружил, если вместо вызова функции вставить ее тело, то проблема исчезает. Выкладываю листинги и мап-файлы обоих вариантов (с вызовом функции и с вставленным телом функции). Вызов функции what_day() происходит из rtc_set_time(), которая в свою очередь вызывается из rtc_Init().
Прикрепленные файлы
gluk.rar ( 36.16 килобайт )
Кол-во скачиваний: 34
no_gluk.rar ( 36.59 килобайт )
Кол-во скачиваний: 33
|
|
|
|
|
Jun 7 2008, 21:09
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 7 2008, 20:55)  Вызов функции деления до сих пор присутствует. Код day = (unsigned char)((26*month-2)/10 + date + (year>>2) + year + (c>>2) - 2*c); Выбросить операцию деления я же не могу - без нее не будет вычислять день. Цитата(GetSmart @ Jun 7 2008, 20:55)  Ещё нужен листинг функций PROLOGUE6_L09, S_EC_MUL_L02, US_DIVMOD_L02. Ищется через поиск слова в директории со всеми листингами. Поиск по этим словам в директории list или проекта дает только вызовы этих функций: Код //NOTE: This module defines or uses C++ features that are not // accessible from assembler code. Assembling this file will // not produce an equivalent object file to the one produced // by the C++ compiler.
EXTERN ?EPILOGUE_B6_L09 EXTERN ?EPILOGUE_B8_L09 EXTERN ?PROLOGUE6_L09 EXTERN ?PROLOGUE8_L09 .................... EXTERN ?US_DIVMOD_L02
.................. CALL ?US_DIVMOD_L02 Я не нашел нигде их определения. Судя по замечанию сверху - их ассемблерные инструкции не доступны.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|