alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Для инициализации 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. Но сделаю это в последнюю очередь. Может быть есть другой способ вычисления дня недели? Какие будут предложения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 16 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба интересно, а куда она возвращает результат? int main() { what_day(2008, 6, 6); ..................... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба интересно, а куда она возвращает результат? Так ничего не меняет. Просто вызов самой ф-ции приводит к проблеме. int main() {volatile unsigned char day; day = what_day(2008, 6, 6); ..................... P.S. Появилась мысль. Может для этой цели использовать библиотеку <time.h> ? Буду разбираться... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Листинг кода посмотрите, в MAP-файле должен указываться раход стека в процедурах what_day, ??div16 (может по-другому называется). И вообще, листинги при всяких неполадках читать очень рекомендуется. В процедуре what_day куча временных переменных. В стеке они лежат или нет - хз. Всё зависит от мозговитости компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Листинг кода посмотрите, в MAP-файле должен указываться раход стека в процедурах what_day, ??div16 (может по-другому называется). И вообще, листинги при всяких неполадках читать очень рекомендуется. По листингу не ясно, сколько расходует стек функция what_day. Может, плохо искал. Если не трудно, взгляните сами. Буду очень признательный. В процедуре 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; } Та же проблема: функция работает, но приводит к тому же глюку. Почему вызов функции в начале программы может переполнять стек. Неужели ей мало 0x100 CSTACK ? device_list.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба В листинге нет процедуры ??what_day. Дайте листинг файла, в котором расположена данная процедура (what_day). Я не очень хорошо разбираюсь в стеках AVR. RSTACK - это стек с указателем в SP только для вызовов процедур? А CSTACK - для данных? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Я не очень хорошо разбираюсь в стеках 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Прерывания запретите перед вызовом этой процедуры. После выхода разрешите. Может поможет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Вызов идет в начале main(). Естественно, прерывания еще не разрешены. Что, получается выход один - менять процессор на пожирнее? Эта проблема точно связана с нехваткой ОЗУ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 16 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Насколько я понимаю, 0х8f это не совсем 100, вернее, совсем не 100, а 143. Так что 100 никак не хватит. Не процессор надо пожирнее, а лишний жир с этой функции срезать. Или стек задать поширше. Неужели ей мало 0x100 CSTACK ? Думаю, что да. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 (изменено) · Жалоба 0х8f это не совсем 100, вернее, совсем не 100, а 143. Так что 100 никак не хватит. ...0x100 - это 256 байт ОЗУ. Не процессор надо пожирнее, а лишний жир с этой функции срезать. Или стек задать поширше.А что срезать? И CSTACK я увеличивать больше 0x150 не могу. PS. может быть есть более легковесная функция вычисления дня недели? Типа табличным методом... Кто знает? Изменено 6 июня, 2008 пользователем alux Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Отладочными средствами (JTAG) пользоваться не представляется возможным. JTAG отладчик и не нужен поскольку в этой функции не используется периферия. Вполне достаточно симулятора. В простейшем случае, разумеется, только с этой функцией в пустой main. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Коллеги, какая нехватка ОЗУ? три параметра, три переменных, пара математических функций выльются от силы в парочку вложенных вызовов и полдюжины байт стека; даже проверять не буду. alux, ищите ошибку в программе. Чип поменять тоже можно попробовать - сталкивался со всякими чудесами вроде сбоя указателя стека на ровном месте, пропадавшими при замене кристалла. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Совет из области паранойи, но все же попробуйте привести все временные переменные и константы в вашей функции к одному типу - int. Не используйте char при вычислениях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 6 июня, 2008 Опубликовано 6 июня, 2008 · Жалоба Чип поменять тоже можно попробовать - сталкивался со всякими чудесами вроде сбоя указателя стека на ровном месте, пропадавшими при замене кристалла. В смысле поменять на такой же? Это можно. У меня DIP корпус на панельке. Только мне кажется маловероятным брак чипа. Совет из области паранойи, но все же попробуйте привести все временные переменные и константы в вашей функции к одному типу - int. Не используйте char при вычислениях.Изначально там были int. Я char поставил для экономии. Проверил. Не помогло (в смысле, если на int все поменять). Да и логики в этом не вижу... ищите ошибку в программе.Программа работает нормально (без этой функции). Я не вижу связи между ней и процессами ОС. //--------------------------------------------------------------------------- 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 } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться