Перейти к содержанию
    

Злополучная функция what_day()

Изначально там были int. Я char поставил для экономии. Проверил. Не помогло (в смысле, если на int все поменять). Да и логики в этом не вижу...
Логика тут простая - ваша экономия мнимая. Компилятор все равно приводит все вычисления к типу int, а временные переменные разместит в регистрах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если это хоть как-то наведет на мысли... Глюк проявляется при входе при входе к определенным пунктам меню ("Редактирование параметров"). При этом редактирование и сохранение параметра идет как положено, за исключением того , что вместо кнопки "UP"-смещение на одно знакоместо происходит замена цифрой '6', а вместо "ESC", котороя возвращает в предыдущий п. меню происходит вставка цифры '2'. Некоторые пункты меню работают нормально. Напомню, что все это происходит, если вызвать функцию what_day();

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это выходит за всякие рамки понимания и попахивает чертовщиной...

Написал третью функцию вычисления дня недели:

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:

 

Ради эксперимента попробовал вместо этой функции вызвать какую-нибудь сложную математическую функцию , например решение квадратного уравнения и укруглением результата до 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:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но по какой-то непонятной причине вызов ее приводит к глюкам программы. В частности, при входе в пункт меню невозможно из него выйти, при этом программа реагирует не так как задумано. Должен сказать, что проект использует ОС (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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не помогло, не в этом причина . из Вашего мэп

CSTACK               DATA          00000100 - 000001FF         100   dse    0
RSTACK               DATA          00000200 - 0000023F          40   dse    0

Не понял. Что Вы имели в виду?

 

Теперь мысль, может бредовая но всё-же- может Вы запретили компилятору какие-то регистры в которых компилятор хранит остаток от деления?
Регистры я не трогаю.

 

Заменил в функции операцию % 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понял. Что Вы имели в виду?

использование функциями 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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

PS: time.h использовал как-то. плохо совместимая с экономией памяти вещь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Странно... Использовал скопипастленную с сахары функцию

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 по умолчанию, т.е минимальные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Вызов функции what_day() происходит из rtc_set_time(), которая в свою очередь вызывается из rtc_Init().

gluk.rar

no_gluk.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

day = (unsigned char)((26*month-2)/10 + date + (year>>2) + year + (c>>2) - 2*c);

Выбросить операцию деления я же не могу - без нее не будет вычислять день.

 

Ещё нужен листинг функций 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

Я не нашел нигде их определения. Судя по замечанию сверху - их ассемблерные инструкции не доступны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...