|
|
  |
Злополучная функция what_day(), Вычисление дня недели |
|
|
|
Jun 6 2008, 07:11
|
Знающий
   
Группа: Свой
Сообщений: 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. Но сделаю это в последнюю очередь. Может быть есть другой способ вычисления дня недели? Какие будут предложения?
|
|
|
|
|
Jun 6 2008, 08:41
|
Знающий
   
Группа: Свой
Сообщений: 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> ? Буду разбираться...
|
|
|
|
|
Jun 6 2008, 09:47
|
Знающий
   
Группа: Свой
Сообщений: 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; } Та же проблема: функция работает, но приводит к тому же глюку. Почему вызов функции в начале программы может переполнять стек. Неужели ей мало 0x100 CSTACK ?
|
|
|
|
|
Jun 6 2008, 10:23
|
Знающий
   
Группа: Свой
Сообщений: 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 ? Ну так должно хватать...
|
|
|
|
|
Jun 6 2008, 10:53
|

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

|
Насколько я понимаю, 0х8f это не совсем 100, вернее, совсем не 100, а 143. Так что 100 никак не хватит. Не процессор надо пожирнее, а лишний жир с этой функции срезать. Или стек задать поширше. Цитата Неужели ей мало 0x100 CSTACK ? Думаю, что да.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Jun 6 2008, 11:16
|
Знающий
   
Группа: Свой
Сообщений: 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
|
|
|
|
|
Jun 6 2008, 12:08
|
Знающий
   
Группа: Свой
Сообщений: 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 }
|
|
|
|
|
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 Я не нашел нигде их определения. Судя по замечанию сверху - их ассемблерные инструкции не доступны.
|
|
|
|
|
Jun 7 2008, 23:21
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 8 2008, 00:48)  Тогда выкладывайте HEX-файл...Может файл линковки неправильный. Тоже выложите посмотреть. Выкладываю файлы линковки, list, map и hex варианта с глюком. В настройках проекта Configure system using dialogы (not in XCL) стоит галка. В функции what_day() , которую выкладывал ранее, закралась маленькая ошибка, не имеющая никакого отношения к глюку - после else нужно убрать пару фигурных скобок.
Прикрепленные файлы
gluk.rar ( 76.3 килобайт )
Кол-во скачиваний: 40
|
|
|
|
|
Jun 8 2008, 09:49
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Так и не понял косяк. Со стеком не может быть проблемы точно. В RSTACK требуется всего 2 вызова, то есть 4 байта. В CSTACK тоже минимум - 6 байт. Портит регистры R0,R1,R17-R21,R30,R31 (не восстанавливаются в прологе/эпилоге). Посмотрел получше. R16-R21 можно портить, в них передаются параметры и возвращается результат. Ну а R0,R1,R30,R31 кажется полюбому можно портить. Кстати, CSTACK - это похоже стек данных, а RSTACK - вызовов.
Кажется глюки вообще не от этой злополучной процедуры.
PS. Не всё она правильно считает. 1 января 2000 года = 6 (суббота). 1 января 2004 неправильно посчитала. 1 января 2008 правильно = 2 (вторник). Результат похоже не нужно увеличивать на 1.
Сообщение отредактировал GetSmart - Jun 8 2008, 10:27
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 8 2008, 19:29
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 8 2008, 12:49)  Кажется глюки вообще не от этой злополучной процедуры. Когда не остается версий, остается одно - валить все на компилятор  Я смирился с глюком. Вышел из положения как говорил - вместо вызова функции вставил само тело. Что от этого изменилось - не понятно. Работает (пусть пока) - ну и ладно. Как сказал один умный человек (Билл Гейтс кажется), компьютер (микроконтроллер, компилятор, ...) настолько сложная штука, что не понятно, каким образом это все работает  Цитата(GetSmart @ Jun 8 2008, 12:49)  Не всё она правильно считает. 1 января 2000 года = 6 (суббота). 1 января 2004 неправильно посчитала. 1 января 2008 правильно = 2 (вторник). Результат похоже не нужно увеличивать на 1. Действительно, 1 января 2004 неправильно посчитало. Алгоритм переписал с Turbo Pascal
. А единицу нужно прибавить, потому-что у DS1338 Sunday=1, Monday=2 ,... и т.д.
|
|
|
|
|
Jun 8 2008, 19:36
|

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

|
Цитата(alux @ Jun 8 2008, 03:21)  Выкладываю файлы линковки, list, map и hex варианта с глюком. В настройках проекта Configure system using dialogы (not in XCL) стоит галка. В функции what_day() , которую выкладывал ранее, закралась маленькая ошибка, не имеющая никакого отношения к глюку - после else нужно убрать пару фигурных скобок. Если я ещё не надоел, то в общем есть предложение переменную day сделать беззнаковой итежер ну и тоже самое возвращаемое значение беззнаковый итежер функции what_day() . при вычислении остатка от деления исспользуется макро US_DIVMOD_L02 - файл стандартный библиотеки ИАР I02.s90. Там происходит вот такое 'short' (i.e. 16 bit) unsigned division and modulo Может поэтому результат возвращается не совсем корректно через беззнаковый чар хотя его размера и достаточно?
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Jun 9 2008, 08:18
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(sKWO @ Jun 8 2008, 22:36)  Если я ещё не надоел, то в общем есть предложение переменную day сделать беззнаковой итежер ну и тоже самое возвращаемое значение беззнаковый итежер функции what_day() . Там же вычисления проводятся с int. К unsigned char day приводится лишь результат. Ну проверил на всякий случай... Не в этом дело. Цитата(GetSmart @ Jun 9 2008, 00:53)  Ещё как вариант, нужно сравнить два листинга с процедурой в которой наблюдаются глюки при вызове what_day(), припоминаю что это было в меню. Первый листинг скомпилированный с вызовом процедуры what_day(), в котором наблюдаются глюки. Второй листинг без этой процедуры и без глюков. Листинги чего? Меню? Дело в том, что программа состоит из десятков файлов. Тем более это все работает под управлением ОС... Вкратце это выглядит так: обработка клавиатуры и получение скан-кода вынесено в высокоприоритетный процесс. Действие, необходимое при нажатии кнопки, зависит от текущего режима: если MainMenu- то навигация по пунктам меню, если EditValue - то редактирование параметров, и т.д.... Код OS_PROCESS void TKeyScan::Exec() //TProc1 { for(;;) { PCInt3.Wait(); Sleep(20); // Задержка 10*2=20мсек для устранения дребезга контактов scan_key(); if(key_code.scan & KEY_PRESSED) { key_code.scan &= ~KEY_PRESSED; // Clear MSB of scan_code (key_pressed) switch(key_code.scan) { case UP: //k_right CurrentMode->Up(); break; case DOWN: //k_left CurrentMode->Down(); break; case LEFT: //k_esc CurrentMode->Left(); break; case RIGHT: //k_enter CurrentMode->Right(); break; default: // 0...9 CurrentMode->Numeric(); break; } } } } PS. Функцию вычисления дня недели заменил на предыдущую (Сергея Фролова). Она вычисляет правильно. По крайней мере мне не удалось найти "неправилные" дни. Причем вызов ее не приводит к глюку. Но стоит добавить что-нибудь, например, проверку валидности данных: Код if((date>=1)&&(date<=31)&&(month>=1)&&(month<=12)&&(year>=1996)&&(year<=2100)) или хотя бы просто : Код i2c_write(year-2000); ... сразу вылазит глюк...
|
|
|
|
|
Jun 11 2008, 15:03
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Этот глюк выпил достаточно моей крови...  Решил досконально разобраться с этой проблемой. И выяснил следующее: каким-то образом портится скан-код нажатой клавиши. За основу программы keymatrix взял апнот Atmel avr243. Проблема исчезает, если убрать #define ALTKEYS (см. avr243). В программе используется следующая структура данных: Код union _key_code { unsigned int complete; // Access all 16 bits struct { union { unsigned char flags; // Access flag status only struct { unsigned char altKey0 : 1; // Access the flags separately unsigned char altKey1 : 1; unsigned char altKey2 : 1; unsigned char altKey3 : 1; unsigned char lckKey0 : 1; unsigned char lckKey1 : 1; unsigned char lckKey2 : 1; }; }; union { unsigned char scan; // Access scancode struct { unsigned char col : 3; // Access column of keypress unsigned char row : 3; // Access row of keypress unsigned char unused : 2; }; }; }; }; extern volatile union _key_code key_code; // Scan result structure extern volatile unsigned char key_altState; // Current alternation flags Так как в отдельный момент времени в памяти может находиться только один из указанных при объявлении объединения типов, то при вызове key_processAltKeys(), в которой осуществляется доступ к переменной key_altState, портится key_code.scan нажатой кнопки со всеми вытекающими последствиями. Т.е. изначально проблема была не в функции what_day(), а в драйвере клавиатуры. Внешне это выглядело довольно странно: скан-код портился выборочно при определенных условиях и на завершающей стадии проекта. Осталось придумать, как решить эту проблему.  PS. Насколько я понимаю, этого не должно быть. Ведь эти переменные относятся к разным union, которые являются членами общей структуры, которая в свою очередь является членом объединения. Или я ошибаюсь?
Прикрепленные файлы
AVR243.zip ( 7.83 килобайт )
Кол-во скачиваний: 36
|
|
|
|
|
Jun 11 2008, 23:15
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(alux) Так как в отдельный момент времени в памяти может находиться только один из указанных при объявлении объединения типов, то при вызове key_processAltKeys(), в которой осуществляется доступ к переменной key_altState, портится key_code.scan нажатой кнопки со всеми вытекающими последствиями. Вряд ли key_code.scan портится в key_processAltKeys(). В объявлении union _key_code тоже вроде бы всё "чисто". Клавиатура сканируется на двух полных портах C и D и получается 6-битный скан-код. Если на этих портах ещё что-нибудь висит, хотя бы один пин используется не для клавиатуры, то будут глюки. Особенно учитывая, что в процедуре convertKey() индекс в массиве символов используется 5-битный, а скан-код 6-битный. То есть можно залететь в следующую кодовую страницу. Запись в PORTA сначала ~key_altState, а потом сразу же кода символа не очень понятна. Если там светодиоды, то на них будет отображаться именно код символа. Ещё одна маловероятная идея. В коде: Код /*** Global variables ***/ volatile unsigned char key_altState; // Holding current alternation flags volatile union _key_code key_code; // Scan result structure Поменяйте местами две этих переменных. Объявляйте key_code перед объявлением key_altState. Может что изменится. А вообще, если какая-нить часть проги портит память с этими переменными, то может в этом дело.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 12 2008, 06:30
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 12 2008, 02:15)  Клавиатура сканируется на двух полных портах C и D и получается 6-битный скан-код. Если на этих портах ещё что-нибудь висит, хотя бы один пин используется не для клавиатуры, то будут глюки. Особенно учитывая, что в процедуре convertKey() индекс в массиве символов используется 5-битный, а скан-код 6-битный. То есть можно залететь в следующую кодовую страницу. Да, выводы мк использованы все. Для клавиатуры пришлось разнести строки и столбцы в разные порты. Не понял на счет глюка, я же прерывания настроил именно на эти выводы, к которым подключена клавиатура: Код // Ports #define KEYMATRIX_COL_PORT PORTB // Command Output Register #define KEYMATRIX_COL_DDR DDRB // Data Direction Register for KeymatrixPort #define KEYMATRIX_COL_PIN PINB // PIN Register for KeymatrixPort
#define KEYMATRIX_ROW_PORT PORTD // Command Output Register #define KEYMATRIX_ROW_DDR DDRD // Data Direction Register for KeymatrixPort #define KEYMATRIX_ROW_PIN PIND // PIN Register for KeymatrixPort
// pins PCINT28..31->PCI3 #define ENABLE_PCINT3 {PCIFR |= (1<<PCIF3); PCICR |= (1<<PCIE3);}// Clear interrupt status flag, Enable pin change interrupt PCINT3 #define DISABLE_PCINT3 PCICR &= ~(1<<PCIE3) // Disable pin change interrupt PCINT3 .......................... void key_Init(void) { /* Init global variables */ key_altState = 0; // Clear alternation flags key_code.complete = 0; // Clear scan result
/* Init ports */ KEYMATRIX_ROW_DDR &= 0x0f; // Set row lines to input KEYMATRIX_ROW_PORT |= 0xf0; // Pull row lines high KEYMATRIX_COL_DDR |= 0x0f; // Set column lines to output KEYMATRIX_COL_PORT &= 0xf0; // Drive all column lines low /* Enable external interrupt */ // PCIFR |= (1<<PCIF3); //Очистить флаги внешних прерываний PCMSK3 = (1<<PCINT31)|(1<<PCINT30)|(1<<PCINT29)|(1<<PCINT28); //Настроить прерывания на выводах PD4...PD7 ENABLE_PCINT3; // Enable pin change interrupt PCINT3 } Цитата(GetSmart @ Jun 12 2008, 02:15)  Запись в PORTA сначала ~key_altState, а потом сразу же кода символа не очень понятна. Если там светодиоды, то на них будет отображаться именно код символа. Это только для демонстрации скан-кода. В моей программе этого нет. Цитата(GetSmart @ Jun 12 2008, 02:15)  Особенно учитывая, что в процедуре convertKey() индекс в массиве символов используется 5-битный, а скан-код 6-битный. То есть можно залететь в следующую кодовую страницу. Скан-код тоже 5-битный - от 0 до 31. Матрица 4х4. Цитата(GetSmart @ Jun 12 2008, 02:15)  Вряд ли key_code.scan портится в key_processAltKeys(). На начальном этапе проекта (до применения ОС) тоже долго не мог понять почему портился скан-код. Тогда случайно обнаружил, что проблема была связана с key_processAltKeys(). Уже не помню, что я тогда изменил (кажется я копировал скан-код в отдельную переменную). Сейчас история повторяется. Действительно, проблема осталась! Сначала после удаления #define ALTKEYS проблема исчезла, о чем я поспешил сообщить. Но после изменения/добавления пунктов меню - снова появилась! Это меня уже достало.
|
|
|
|
|
Jun 12 2008, 11:10
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(alux) Не понял на счет глюка, я же прерывания настроил именно на эти выводы, к которым подключена клавиатура: Вне зависимости от того, на что настроены прерывания, в процедуре переполнения таймера 0 формируется 6-битный скан-код. И если на портах C и D помимо клавиатуры что-то подключено (хоть на вход, хоть на выход) скан-коды будут "левые". Особенно, если для клавиатуры на одном порте используется старшая половина полубайта: Код /* Init ports */ KEYMATRIX_ROW_DDR &= 0x0f; // Set row lines to input KEYMATRIX_ROW_PORT |= 0xf0; // Pull row lines high Как я понял, здесь на битах 4..7 висит клавиатура, а на младших что-то ещё. Прерывание по таймеру сканирует биты от младшего к старшему и найдя еденичный бит в младших битах перестанет дальше сканировать. Даже когда для клавиатуры используются две младших половинки в двух разных портах, то может произойти прерывание по отжатию кнопки, при этом на старших битах порта столбцов будет посторонний нулевой сигнал, то он засчитается за нажатую клавишу. Чтобы всех этих проблем не происходило нужно подправить в файле keymatrix.c процедуру сканирования портов клавиатуры timer0OVFISR().
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 12 2008, 11:31
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 12 2008, 14:10)  Чтобы всех этих проблем не происходило нужно подправить в файле keymatrix.c процедуру сканирования портов клавиатуры timer0OVFISR(). Ну это само собой разумеется. Конечно, я переписал этот keymatrix.c для моего случая: Код //############################################################################# // Вычисление скан-кода нажатой кнопки //_____________________________________________________________________________ void scan_key(void) { TCritSect cs; /* Local variables */ unsigned char lineResult; // Resulting column and row lines unsigned char tempScan; // Temporary scancode
/* Find row of keypress */ lineResult = KEYMATRIX_ROW_PIN&0xf0; // Get row lines if(lineResult != 0xf0) // Any row lines low ? { /* Invert port directions */ KEYMATRIX_COL_PORT |= 0x0f; // Drive all col lines high KEYMATRIX_COL_DDR &= 0xf0; // Set col lines to input, already pulled up KEYMATRIX_ROW_PORT &= 0x0f; // Disable pull-up on row lines KEYMATRIX_ROW_DDR |= 0xf0; // Set row lines to output, already driven low
tempScan = 0; // Init temp scan code while(lineResult & 0x10) // Loop while row line high { lineResult >>= 1; // Next row line into LSB tempScan += 8; // Increment row part of scancode } /* Find col of keypress */ lineResult = KEYMATRIX_COL_PIN&0x0f; // Get col lines
/* Set original port directions */ KEYMATRIX_ROW_PORT |= 0xf0; // Drive all row lines high KEYMATRIX_ROW_DDR &= 0x0f; // Set row lines to input, already pulled up, KEYMATRIX_COL_PORT &= 0xf0; // Disable pull-up on col lines KEYMATRIX_COL_DDR |= 0x0f; // Set col lines to output, alreay driven low
if(lineResult != 0x0f) // Any col lines low ? { while(lineResult & 0x01) // Loop while col line high { lineResult >>= 1; // Next col line into LSB tempScan ++; // Increment col part of scancode } /* Process scancode */ tempScan |= KEY_PRESSED; // Set MSB of scan_code (key pressed) key_code.scan = tempScan; // Save scancode
#ifdef ALTKEYS key_processAltKeys(); // Process alternation keys if implemented #endif } else key_code.scan = 0; // Indicate no keys pressed 0x00 } else key_code.scan = 0; // Indicate no keys pressed 0x00 /* Prepare external interrupt */ ENABLE_PCINT3; // Reenable pin change interrupt } Эта функция вызывается не в прерывании таймера, а в процессе OS_PROCESS void TKeyScan::Exec() с использованием флагов сообщений ОС. Код я приводил в предыдущем посте. PS. Для эксперимента заменил key_code.scan на обычную глобальную volatile unsigned char scan. Не помогло. Все равно портится те же 4 скан-кода кнопок.  Т.е. проблема не в использовании union. Версий пока больше нет... PS2. Все! Наконецто локализовал проблему. Надеюсь в последний раз  . Скан-код портит функция convertKey(); Код char __flash characters[4][32] = { { '1', '2', '3', 0, 0, 0, 0, 0, // No alternation '4', '5', '6', 0, 0, 0, 0, 0, '7', '8', '9', 0, 0, 0, 0, 0, '.', '0', '#', 0, 0, 0, 0, 0 },
{ 'a', 'd', 'g', 0, 'а', 'г', 'є', 'ъ', // First character 'j', 'm', 'p', 0, 'и', 'й', 'м', 'ы', 's', 'v', 'y', 0, 'п', 'т', 'х', 0, '*', '*', '#', 0, 'ш', 'ю', 0, 0 },
{ 'b', 'e', 'h', 0, 'б', 'д', 'ж', 0, // Second character 'k', 'n', 'q', 0, 'і', 'к', 'н', 0, 't', 'w', 'z', 0, 'р', 'у', 'ц', 0, '*', '?', '#', 0, 'щ', 'я', 0, 0 },
{ 'c', 'f', 'i', 0, 'в', 'е', 'з', 0, // Third character 'l', 'o', 'r', 0, 'ї', 'л', 'о', 0, 'u', 'x', '-', 0, 'с', 'ф', 'ч', 0, '*', '!', '#', 0, 'ь', 0, 0, 0 } };
/*** Convert scancode to character ***/ char convertKey(void) { char tempChar;
if(key_code.altKey0) // First char ? tempChar = characters[1][key_code.scan+4]; else if(key_code.altKey1) // Second char ? tempChar = characters[2][key_code.scan+4]; else if(key_code.altKey2) // Third char ? tempChar = characters[3][key_code.scan+4]; else // No alternation ? tempChar = characters[0][key_code.scan];
if(key_code.altKey3) // Uppercase if caps lock tempChar = toupper(tempChar); return tempChar; } Если заменить многомерный массив одномерным, то все нормально. А почему?
Сообщение отредактировал alux - Jun 13 2008, 08:15
|
|
|
|
|
Jun 13 2008, 08:04
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
...И вновь продолжается бой. Ребята, извините, пожалуйста, если достал уже этой проблемой. Напомню, что глюк проявляет себя в том, что портит скан-код четырех кнопок. Причем одинаково: кнопка "3" вместо скан-кода 2 дает 1, кнопка "ESC" вместо скан-кода 3 дает 1, кнопка "6" вместо скан-кода 10 дает 9, кнопка "UP" вместо скан-кода 11 дает 10. Может эта информация как-то наведет на мысли. Глюк появляется при входе в пункт меню ("Редактирование"). Вроде нашел причину: в функции convertKey() если заменить многомерный массив одномерным, то глюк пропадает. Ну, бог с ним, с многомерным массивом. Но следующее выходит за рамки моего понимания: если раскомментировать #define ALTKEYS , т.е. вызвать функцию void key_processAltKeys() , в которой просто XORятся биты флага, снова появляется этот злосчастный глюк. Код #ifdef ALTKEYS
void key_processAltKeys() { if (flags & ALTKEY0) flags ^= ALTKEY0; else if(flags & ALTKEY1) flags ^= ALTKEY1; else if(flags & ALTKEY2) flags ^= ALTKEY2; else if(flags & ALTKEY3) flags ^= ALTKEY3; } #endif Причем, для чистоты эксперимента переменные scan (скан-код) и flags сделал глобальными volatile unsigned char. Функцию scan_key() приводил в предыдущем посте. Воздействие ОС на глюк исключается,- функция вызывается в критической секции (TCritSect cs)
|
|
|
|
|
Jun 13 2008, 08:57
|

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

|
Цитата(alux @ Jun 13 2008, 12:04)  Код else if(flags & ALTKEY1) flags ^= ALTKEY1; else if(flags & ALTKEY2) flags ^= ALTKEY2; Так бегло alux а зачем инвертировать флаг в флаговом регистре ничего при этом не делая и не проверяя сканкод Выдержка из оригинала Код if ( key_code.scan == ALTKEY0 ) key_altState ^= (1<<0); else if( key_code.scan == ALTKEY1 ) key_altState ^= (1<<1); else if( key_code.scan == ALTKEY2 ) key_altState ^= (1<<2); else if( key_code.scan == ALTKEY3 ) key_altState ^= (1<<3); else if( key_code.scan == LCKKEY0 ) key_altState ^= (1<<4); else if( key_code.scan == LCKKEY1 ) key_altState ^= (1<<5); else if( key_code.scan == LCKKEY2 ) key_altState ^= (1<<6); else // Not alternation key ? { key_altState &= ALTLOCKMASK; // Clear one-shot key flags } ALTKEY как у Вас определены, може всё завязано на битовых сдвигах?
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Jun 13 2008, 09:39
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Код // Alternation key code #define ALTKEY 26 // '#' on test keypad
#define ALT0 0x01 #define ALT1 0x02 #define ALT2 0x04 #define ALT3 0x08 Проблема возникает если просто : Код void key_processAltKeys() { if(scan == ALTKEY) flags ^= ALT0; } Что здесь не так? Не вижу криминала. PS. Меня не покидает чувство, что виноват все-таки компилятор (v.5.10A). Где-то на форуме проскакивало сообщение, что компилятор 5.10 не правильно определяет CSTACK >= 0xC0. Уже качаю IAR v.5.11B.
|
|
|
|
|
Jun 13 2008, 17:42
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(alux @ Jun 13 2008, 14:04)  Код #ifdef ALTKEYS
void key_processAltKeys() { if (flags & ALTKEY0) flags ^= ALTKEY0; else if(flags & ALTKEY1) flags ^= ALTKEY1; else if(flags & ALTKEY2) flags ^= ALTKEY2; else if(flags & ALTKEY3) flags ^= ALTKEY3; } #endif Это что за ерунда такая? Раньше эта процедура сравнивала скан код нажатой клавиши с кодами альтернативных клавиш и устанавливала бит в key_altState. Даже если key_altState теперь называется flags, то ерунда тут. Исключающее ИЛИ с кодом клавиши? Зачем? В flags лежат коды клавиш? ЗЫ. Больше не буду искать ошибки, когда на обозрение выкладываются какие-то левые исходники, а потом оказывается что в реале что-то где-то поменяно и вообще хз что скомпилено.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 13 2008, 18:45
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(GetSmart @ Jun 13 2008, 20:42)  Раньше эта процедура сравнивала скан код нажатой клавиши с кодами альтернативных клавиш и устанавливала бит в key_altState. Раньше эта процедура была отключена препроцессором условной компиляцией. После включения #define ALTKEYS возникла проблема, и после этого я начал экспериментировать с флагами, думал, что это как-то связано с объединениями key_code.scan и битовым полем флага. Прошу прощения, если ввел в заблуждение. Просто не знаю где еще искать. Программа scan_key() правильно вычисляет скан-код. Проверял в симуляторе. Но по какой-то причине при определенных условиях, портится скан-код... Почему, не могу понять. PS. Наконец-то!!! Сделал следующее: т.к. у меня матрица 4х4, то сделал скан-код от 0 до 15. Ну и соответственно массив уменьшил в два раза : Код char __flash characters[16] = {...}; .......................... while(lineResult & 0x10) // Loop while row line high { lineResult >>= 1; // Next row line into LSB tempScan += 4; // Increment row part of scancode. Было tempScan += 8; } И убрал в функции scan_key() { // TCritSect cs; и глюк пропал. Наверно это связано с последней строкой в функции scan_key(): Код ENABLE_PCINT3; // Reenable pin change interrupt
Сообщение отредактировал alux - Jun 14 2008, 08:01
|
|
|
|
|
Jul 10 2008, 16:22
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Вот еще один пример до кучи. Вариация на тему "Вычисление дня недели". Найдено на microchip.com. Код __flash const unsigned char Table[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; unsigned int CurrentYear; unsigned char Month, Day;
/********************************************************* * Test Program for the routine GetDayofWeek() *********************************************************/ void main(void) { char Temp; CurrentYear = 1998; //Date : 21 September 1998 Month = 9; Day = 21; Temp = GetDayofWeek();// Result stored in Temp do{} while(1); }
/**************************************************************** * GetDayofWeek * This routine calculate the Day(Sunday, Monday,...Saturday) of * week when a Date(year, Month, Day) is given. * Input : Year, Month and Day which in this routine is used * as global variable. * Output Variable : 0 to 6(which correspond to Sunday to Saturdaday * respectively) if the input is acceptable, else a value 8 is return *****************************************************************/ unsigned char GetDayofWeek(void) { unsigned int TempYear; unsigned char AccValue; if(CheckValidInput(CurrentYear)!= OK) // Return Error if input not Valid return Error; TempYear = 1990; //Comparation start with year 1990 AccValue = 0; //Init AccValue to 0 // If TempYear is a leap year AccValue +2, else AccValue+1 while(TempYear != CurrentYear) { AccValue++; if(IsLeapYear(TempYear)) AccValue++; TempYear++; } if(Month > 2) { if(IsLeapYear(TempYear)==1) AccValue++; } AccValue += Table[Month]; AccValue += Day; AccValue= AccValue%7; return(AccValue); } /************************************************************************* * CheckValidInput * Return a '1' if the input is within the required range. Else * return a '0'. * * Input Variable : 16Bit Unsigned Int * Output Varible : '1' if input ranges between 1990 & 2099 inclusively ***************************************************************************/ unsigned char CheckValidInput(unsigned int Input) { if(Input >= 1990 && Input <= 2099) return OK; else return !OK; }
/************************************************************************* * IsLeapYear * Return a '1' if the input is a leap year. Else return a '0' * * Input Variable : 16Bit Unsigned Int * Output Varible : '1' if is a leap year, else '0'. ***************************************************************************/ unsigned char IsLeapYear(unsigned int Year) { Year=Year&0x0003; if(Year==0) return 1; else return 0; } /*************************************************************************/
|
|
|
|
|
Jul 12 2008, 10:32
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(sensor_ua) Код return( nWDay < 0 ? ( nWDay + 7 ) : ( nWDay % 7 ) ); Можно я упрощу? Вот: Код return( ( nWDay + 7 ) % 7 );
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jul 12 2008, 10:45
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Можно я упрощу? это к автору  - Regra de Zeller
--------------------
aka Vit
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|