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

 
 
> Злополучная функция what_day(), Вычисление дня недели
alux
сообщение Jun 6 2008, 07:11
Сообщение #1


Знающий
****

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



Для инициализации Real Time Clock возникла необходимость вычисления дня недели по дате. Функция достаточно простая:
Код
//----------------------------------------------------------------------------
// Вычисления дня недели по дате
// Все деления целочисленные (остаток отбрасывается).
// Результат: 0 — воскресенье, 1 — понедельник и т. д.
//----------------------------------------------------------------------------
unsigned char what_day(unsigned int year, unsigned char month, unsigned char date)  
{
  unsigned char a = (14 - month) / 12;
  unsigned int y = year - a;        
  unsigned char m = month + 12*a - 2;
  
  return (7000 + (date + y + y/4 - y/100 + y/400 + (31*m)/12 ))% 7;  
}


Но по какой-то непонятной причине вызов ее приводит к глюкам программы. В частности, при входе в пункт меню невозможно из него выйти, при этом программа реагирует не так как задумано. Должен сказать, что проект использует ОС (scmRTOS) и ОЗУ использовано на 90%. Контроллер Mega324P (2кБ ОЗУ). Отладочными средствами (JTAG) пользоваться не представляется возможным. Это похоже на переполнение стека. Но. Почему это происходит, если вызов достаточно простой функции вставить в начале функции main (до запуска ОС):
Код
int main()
{
  what_day(2008, 6, 6);
.....................

Больше нигде в процессах она не используется. Пробовал менять размеры CSTACK (100...200) и RSTACK (32...64). Не помогло. Думаю менять контроллер на AT90USB1287. Но сделаю это в последнюю очередь. Может быть есть другой способ вычисления дня недели? Какие будут предложения?
Go to the top of the page
 
+Quote Post
4 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 14)
MrYuran
сообщение Jun 6 2008, 08:08
Сообщение #2


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



интересно, а куда она возвращает результат?
Код
int main()
{
  what_day(2008, 6, 6);
.....................


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 08:41
Сообщение #3


Знающий
****

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



Цитата(MrYuran @ Jun 6 2008, 11:08) *
интересно, а куда она возвращает результат?

Так ничего не меняет. Просто вызов самой ф-ции приводит к проблеме.
Код
int main()
{volatile unsigned char day;
  day = what_day(2008, 6, 6);
.....................


P.S. Появилась мысль. Может для этой цели использовать библиотеку <time.h> ? Буду разбираться...
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 6 2008, 08:52
Сообщение #4


.
******

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



Листинг кода посмотрите, в MAP-файле должен указываться раход стека в процедурах what_day, ??div16 (может по-другому называется). И вообще, листинги при всяких неполадках читать очень рекомендуется.

В процедуре what_day куча временных переменных. В стеке они лежат или нет - хз. Всё зависит от мозговитости компилятора.


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


Знающий
****

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



Цитата(GetSmart @ Jun 6 2008, 11:52) *
Листинг кода посмотрите, в MAP-файле должен указываться раход стека в процедурах what_day, ??div16 (может по-другому называется). И вообще, листинги при всяких неполадках читать очень рекомендуется.

По листингу не ясно, сколько расходует стек функция what_day. Может, плохо искал. Если не трудно, взгляните сами. Буду очень признательный.

Цитата(GetSmart @ Jun 6 2008, 11:52) *
В процедуре what_day куча временных переменных. В стеке они лежат или нет - хз.

Так разве после возврата из ф-ции стек не освобождается? В одном из процессов ОС у меня применяются вычисления двойной точности. И ничего, справляется. Хватает 100 байт для процесса.

P.s. Нашел еще одну функцию вычисления дня недели:
Код
enum Month {January=1,February,March,April,May,June,July,August,
            September,October,November,December};
struct Date
{
  float day;
  Month month;
  int year;
};

signed int DayOfWeek(Date date)
{
    float F;
    if (date.month<March)
      F=365*date.year+date.day+31*(date.month-1)+
        (signed int)((date.year-1)/4)-(signed int)(3*(signed int)((date.year-1)/100+1)/4);
    else
      F=365*date.year+date.day+31*(date.month-1)-(signed int)(0.4*date.month+2.3)+
        (signed int)(date.year/4)-(signed int)(3*(signed int)(date.year/100+1)/4);
    return  (signed int)F-7*(signed int)(F/7)-1;
}

........................
int main()
{volatile unsigned char day;
  Date Today={5,June,2008};
  
    switch (DayOfWeek(Today))
  {
       case -1: day=1;break;  // printf("Sunday\n");break;
       case 0:  day=2;break;  //printf("Monday\n");break;
       case 1:  day=3;break;  //printf("Tuesday\n");break;
       case 2:  day=4;break;  //printf("Wednesday\n");break;
       case 3:  day=5;break;  //printf("Thursday\n");break;
       case 4:  day=6;break;  //printf("Friday\n");break;
       case 5:  day=7;break;  //printf("Saturday\n");break;
  }

Та же проблема: функция работает, но приводит к тому же глюку. wacko.gif
Почему вызов функции в начале программы может переполнять стек. Неужели ей мало 0x100 CSTACK ?
Прикрепленные файлы
Прикрепленный файл  device_list.rar ( 27.56 килобайт ) Кол-во скачиваний: 43
 
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 6 2008, 10:02
Сообщение #6


.
******

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



В листинге нет процедуры ??what_day. Дайте листинг файла, в котором расположена данная процедура (what_day).

Я не очень хорошо разбираюсь в стеках AVR. RSTACK - это стек с указателем в SP только для вызовов процедур? А CSTACK - для данных?


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


Знающий
****

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



Цитата(GetSmart @ Jun 6 2008, 13:02) *
Я не очень хорошо разбираюсь в стеках AVR. RSTACK - это стек с указателем в SP только для вызовов процедур? А CSTACK - для данных?
RSCTAK - стек возвратов. CSTACK - стек данных.
Вот новый map-файл. В опциях Linker поставил все галки для генерации map-файла. Если пользоваться поиском компилятора (Edit->Find (F3)) , можно быстро найти нужное место:
Код
  02    what_day(unsigned int, unsigned char, unsigned char)
        | Stack used (prev) :  0000008F 00000038
        | + function block  :  00000008 00000004

Если я правильно понимаю, то вызов этой ф-ции потребляет CSTACK=0x8f и RSTACK=0x38 ? Ну так должно хватать...
Прикрепленные файлы
Прикрепленный файл  device_map.rar ( 29.07 килобайт ) Кол-во скачиваний: 48
 
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 6 2008, 10:33
Сообщение #8


.
******

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



Прерывания запретите перед вызовом этой процедуры. После выхода разрешите. Может поможет.


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


Знающий
****

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



Вызов идет в начале main(). Естественно, прерывания еще не разрешены. Что, получается выход один - менять процессор на пожирнее? Эта проблема точно связана с нехваткой ОЗУ?
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 6 2008, 10:53
Сообщение #10


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Насколько я понимаю, 0х8f это не совсем 100, вернее, совсем не 100, а 143.
Так что 100 никак не хватит.
Не процессор надо пожирнее, а лишний жир с этой функции срезать. Или стек задать поширше.
Цитата
Неужели ей мало 0x100 CSTACK ?

Думаю, что да.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 11:16
Сообщение #11


Знающий
****

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



Цитата(MrYuran @ Jun 6 2008, 13:53) *
0х8f это не совсем 100, вернее, совсем не 100, а 143.
Так что 100 никак не хватит.

...0x100 - это 256 байт ОЗУ.

Цитата(MrYuran @ Jun 6 2008, 13:53) *
Не процессор надо пожирнее, а лишний жир с этой функции срезать. Или стек задать поширше.
А что срезать? И CSTACK я увеличивать больше 0x150 не могу.

PS. может быть есть более легковесная функция вычисления дня недели? Типа табличным методом... Кто знает?

Сообщение отредактировал alux - Jun 6 2008, 11:42
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Jun 6 2008, 11:38
Сообщение #12


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата
Отладочными средствами (JTAG) пользоваться не представляется возможным.

JTAG отладчик и не нужен поскольку в этой функции не используется периферия.
Вполне достаточно симулятора. В простейшем случае, разумеется, только с этой функцией в пустой main.
Go to the top of the page
 
+Quote Post
vet
сообщение Jun 6 2008, 11:41
Сообщение #13


Знающий
****

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



Коллеги, какая нехватка ОЗУ? три параметра, три переменных, пара математических функций выльются от силы в парочку вложенных вызовов и полдюжины байт стека; даже проверять не буду.
alux, ищите ошибку в программе.
Чип поменять тоже можно попробовать - сталкивался со всякими чудесами вроде сбоя указателя стека на ровном месте, пропадавшими при замене кристалла.


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post
rezident
сообщение Jun 6 2008, 11:47
Сообщение #14


Гуру
******

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



Совет из области паранойи, но все же попробуйте привести все временные переменные и константы в вашей функции к одному типу - int. Не используйте char при вычислениях.
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 6 2008, 12:08
Сообщение #15


Знающий
****

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



Цитата(vet @ Jun 6 2008, 14:41) *
Чип поменять тоже можно попробовать - сталкивался со всякими чудесами вроде сбоя указателя стека на ровном месте, пропадавшими при замене кристалла.

В смысле поменять на такой же? Это можно. У меня DIP корпус на панельке. Только мне кажется маловероятным брак чипа.

Цитата(rezident @ Jun 6 2008, 14:47) *
Совет из области паранойи, но все же попробуйте привести все временные переменные и константы в вашей функции к одному типу - int. Не используйте char при вычислениях.
Изначально там были int. Я char поставил для экономии. Проверил. Не помогло (в смысле, если на int все поменять). Да и логики в этом не вижу...

Цитата(vet @ Jun 6 2008, 14:41) *
ищите ошибку в программе.
Программа работает нормально (без этой функции). Я не вижу связи между ней и процессами ОС.
Код
//---------------------------------------------------------------------------
int main()
{
volatile unsigned char day;
  day = what_day(2008, 6, 16);

  // Initialise variables from EEPROM
  area = ee_area;         // Площадь поперечного сечения газохода, m^2
  Kt = ee_Kt;             // Коэффициент напорности трубки
  Y0 = ee_Y0;             // Плотность газа при 0 градусов, kg/m^3
  rate = ee_rate;         // Частота обновления данных, Hz
  nmax = ee_nmax;         // Коэффициент усреднения данных
  
  // Initialise
  uart_Init(baud_select);
  i2c_Init(100);          // set TWI bit rate to 100KHz    
  spi_Init();             // Master mode, clock = f/16, select clock phase positive-going in middle of data
  key_Init();
  pca9557_Init();
  lcd_Init();
  menu_Init();
  hp03_Init();
  ds75_Init();
  rtc_Init();

  SLEEP_ENABLE;
  SELECT_IDLE;
  
__enable_interrupt();    // set the Global Interrupt Enable Bit
  ad7799_Init();
  
  //beep();                 // Инициализация прошла успешно
  
  TCCR0B = 0x03;          // Start System Timer f_clk/64
  TIMSK0 |= (1 << TOIE0); // Разрешить прерывания Timer0 по переполнению (OVF)
                          // Период переполнения при f_clk=7.3728 Mhz 2.222 ms
  OS::Run();              //                     при f_clk=20 Mhz 0.8192 ms
}
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 20th July 2025 - 22:30
Рейтинг@Mail.ru


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