реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> Злополучная функция what_day(), Вычисление дня недели
rezident
сообщение Jun 6 2008, 12:20
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(alux @ Jun 6 2008, 18:08) *
Изначально там были int. Я char поставил для экономии. Проверил. Не помогло (в смысле, если на int все поменять). Да и логики в этом не вижу...
Логика тут простая - ваша экономия мнимая. Компилятор все равно приводит все вычисления к типу int, а временные переменные разместит в регистрах.
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 12:41
Сообщение #17


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Если это хоть как-то наведет на мысли... Глюк проявляется при входе при входе к определенным пунктам меню ("Редактирование параметров"). При этом редактирование и сохранение параметра идет как положено, за исключением того , что вместо кнопки "UP"-смещение на одно знакоместо происходит замена цифрой '6', а вместо "ESC", котороя возвращает в предыдущий п. меню происходит вставка цифры '2'. Некоторые пункты меню работают нормально. Напомню, что все это происходит, если вызвать функцию what_day();
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 15:52
Сообщение #18


Знающий
****

Группа: Свой
Сообщений: 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;
}

Функцию переписал у Сергея Фролова. В ней нет тяжелых делений. Она работает. Но при вызове все равно приводит к тому глюку! 07.gif

Ради эксперимента попробовал вместо этой функции вызвать какую-нибудь сложную математическую функцию , например решение квадратного уравнения и укруглением результата до 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, то глюк исчезает. Как это объяснить? В дополнение к функции решения кв. уравнения добавил функцию по расчету давления и температуры цифрового датчика давления. Там точно громоздкие вычисления. И все прошло (глюка не вызвало). А здесь простая операция деления по модулю... cranky.gif
Go to the top of the page
 
+Quote Post
sKWO
сообщение Jun 6 2008, 19:21
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 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


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
Flasher
сообщение Jun 6 2008, 19:38
Сообщение #20


Местный
***

Группа: Свой
Сообщений: 374
Регистрация: 6-09-05
Из: Тирасполь, Приднестровье
Пользователь №: 8 294



Недавно в яре натолкнулся под авр использовал функцию % и прога пошла лесом... как только закоментировал строчку- все заработало. В листинге не разбирался- не было времени. Теперь жалею
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 21:19
Сообщение #21


Знающий
****

Группа: Свой
Сообщений: 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. Все! Наконец-то поборол глюк.
Переписал в очередной раз функцию. Прям целая коллекция функций получилась smile.gif
Код
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
Go to the top of the page
 
+Quote Post
vet
сообщение Jun 7 2008, 04:51
Сообщение #22


Знающий
****

Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32



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


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post
sKWO
сообщение Jun 7 2008, 06:02
Сообщение #23


Местный
***

Группа: Участник
Сообщений: 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

а нащёт остатка от деления и рассположения в регистрах надо будет всё же подумать, может попробовать намного пошаманить с инлайн ассемблером ? Сообщите о результатах. Сам тоже попробую


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
AlexG_changed
сообщение Jun 7 2008, 13:24
Сообщение #24


Участник
*

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



Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки.

PS: time.h использовал как-то. плохо совместимая с экономией памяти вещь.
Go to the top of the page
 
+Quote Post
Andreas1
сообщение Jun 7 2008, 13:40
Сообщение #25


Местный
***

Группа: Свой
Сообщений: 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 по умолчанию, т.е минимальные.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 7 2008, 14:00
Сообщение #26


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(alux)
Проблема решилась частично: если вызвать эту функцию из main() , то глюк пропал. Но если вызвать ее из другой функции rtc_set_time(), то глюк имеет место быть...
Всё-таки не исключено, что стек. В любой другой функции стека меньше по сравнению с main, т.к. они вызываются после main.

Цитата(AlexG)
Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки.
Действие происходит ещё до запуска ОС, на этапе инициализаций.

PS. Либо дайте уже нормальный листинг, либо этот телепатический сеанс затянется надолго. Нужен листинг этой "злополучной" функции и карту ОЗУ со стеком и рядом с ними.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 7 2008, 15:55
Сообщение #27


Знающий
****

Группа: Свой
Сообщений: 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
 
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 7 2008, 17:55
Сообщение #28


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Вызов функции деления до сих пор присутствует.

Ещё нужен листинг функций PROLOGUE6_L09, S_EC_MUL_L02, US_DIVMOD_L02. Ищется через поиск слова в директории со всеми листингами.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 7 2008, 21:09
Сообщение #29


Знающий
****

Группа: Свой
Сообщений: 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
Я не нашел нигде их определения. Судя по замечанию сверху - их ассемблерные инструкции не доступны.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 7 2008, 21:48
Сообщение #30


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Тогда выкладывайте HEX-файл. Функция деления - она общая для деления и остатка, кстати.

В MAP-файле с глюком указано, что последний адрес в раме = 087B, что вроде бы выходит за пределы чипа. Под рукой есть только описание mega323, у которого тоже 2 КБ и адреса в раме заканчиваются на 085F. Может файл линковки неправильный. Тоже выложите посмотреть.

Сообщение отредактировал GetSmart - Jun 7 2008, 22:06


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 11:23
Рейтинг@Mail.ru


Страница сгенерированна за 0.01508 секунд с 7
ELECTRONIX ©2004-2016