CodeVision AVR + большой проект = много глюков.

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

Здравствуйте Ув. Коты.

Еще два года начал начал освоение avr, и как для человека далекого посоветовали CodeVision. Использую версию 2.04, т.к. под ней есть библиотеку для 18b20, и работы с SD картой.

Так сложилось, что проект начат тогда - развивается уже 2 года. В устройстве есть графический экран 128х60, SD карта, датчики 18b20, часы ds1307, и работа с rs232, АЦП.

До недавнего времени все было хорошо, добавлялись новые возможности... Размер hex файла подходил до 50 кб. (мега 128). Потом начали появлять совсем странные глюки. Например:

Подпрограмма 1 (работа с СД картой)

Подпрограмма 2 (то же работа с СД).

Так вот, первая работает, вторая нет. Сделал подпрограммы АБСОЛЮТНО одинаковыми, только название сменил. Не работают. Методом тыка, узнал, что если инициализацию СД карты вынести в третью подпрограмму, и вызывать ее отдельно - все работает. Но никакой разницы быть не должно.
Ну и ладно, работает и хорошо.

Дальше, оказалось что при опросе пина Порта Е, можно получить изменения переменных в ОЗУ или ЕЕПРОМ! Т.е. опрашиваю пин порта Е - а у меня меняется яркость подсветки, которая храниться в ЕЕПРОМ!

Еще дальше - еще хуже. Отказался от работы с пином порта Е, и снова все кое- как работает.

Добавил снова подпрограмму, размер до шел до 64 кб.
Таперь при попытке работать с СД картой - просиходит вообще чудеса, может вызваться подпрограмма которая никак не может вызваться, может быть зависание, мусор на экране, а если чтение таки пройдет - то в прочитанных данных просто мусор. Порой это данные с карты только с других файлов, порой это данных с самого микроконтроллера.

Я понимаю, что прочитав это скорее всего пошлете искать ошибки в коде, но какие ошибки могут привести к таким проблемамм? Компиляция идет без ошибок, только пара предупреждений что было бы хорошо переменную вместо int сделать long, но глюки идут да же есть эту подрограмму никогда не вызывать. Так же пробовал исключить места где идет запись в массив, типа ререполняю его, и порчу что-то в ОЗУ. Все равно проблемы.
Сейчас полность отказала работа с SD картой.

Так же есть ошибка, предупреждение, что в одной из подпрограмм флаг определен, но не используется.
А он опрашивается типа if (флаг & флаг2) бла-бла.

Все это наводит на мысль, что компилятор "запутывается" в коде.
Встречал ли кто-то подобные проблемы? Может надо на что-то обратить внимание? Очень много переменных, очень много. Много флагов. Использую от char до long int.


Самое паршивое, что использую много встроенных библиотек от CodeVision. И перейти на другой компилятор не могу :(

Ув. Коты, посоветуйте хоть что-то разумное, посоветуйте в какую сторону двигаться.
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

Valentin44 писал(а):И перейти на другой компилятор не могу
Ну во-первых я бы не был столь категоричным. Всегда есть варианты, чужие наработки для других компиляторов. Но я думаю тут проблема не в компиляторе, а в коде.
Если возникают чудеса, но код не хочется выкладывать, то советую почитать про:
1) правильное использование #define
2) volatile
3) статические и глобальные переменные/функции
4) атомарный доступ
5) преобразование типов
Ставим плюсы: )
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

ibiza11 писал(а):Ну во-первых я бы не был столь категоричным. Всегда есть варианты, чужие наработки для других компиляторов.
Да, но адаптировать чужие библиотеки к своему проекту сложно. И не факт что при адаптации не наделаю других глюков, которые сольются уже имеющимися и проект вообще станет не рабочим.
Но я думаю тут проблема не в компиляторе, а в коде.Если возникают чудеса, но код не хочется выкладывать,
В коде 10 000 строк, и еще 13 файлов библиотек. Просто никто не станет копаться в этом коде.
Если у кого есть желание взглянуть - вышлю лично.

то советую почитать про:
1) правильное использование #define
2) volatile
3) статические и глобальные переменные/функции
4) атомарный доступ
5) преобразование типов
Я использую все кроме атомарного доступа, а может и использую, но пока что я не знаю что это такое.
Остальные пункты - использую, и читал о них когда изучал что это, но как они могут повлиять?
Тут еще, работа с SD картой начиналась с самого начала, и практически не менялась. А глюки стали проявляться просто при разростании проекта.

Вот одна из подпрограмм. На бит NeedRead - пишет что локальная переменная установлена, но не используется.
Строка где в комментарии много восклицательных знаков. Как же она не используется? Она используется на строку выше!
Вот и думаю, может таки компилятор запутался в моем коде :) Хотя уверен что писали его очень умные люди.
Но как объяснить этот момент?

Код: Выделить всё

void DK_view (void){
unsigned char number;
unsigned int OborWiew;                          // Обороты для показа, или реальные, или с сетки оборотов
unsigned int RashodWiev;                        // Расдод для показа, или реальный, или табличный
unsigned char temp_index;                       // вреенная для расчета индекса
bit NeedRead=1;                                 // Флаг что надо прочитать что там у нас! (1- для первого просотра надо же читать)


Nachalo:

 if (NeedRead==1 & DK_W_I) {                    // Если режим редактированние (просмотра)==1  и надо прочитать
 NeedRead=0;                                    // Сбросили флаг необходимости чтения.           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 DK_init();                                     // Читаем с СД карты то что
 };
 
  if (ObSovpad) {sprintf (lcd_buf, "<RPM>"); }
 else { sprintf (lcd_buf, "     "); };
  LcdString(16,5,1);
 if (RasSovpad) {sprintf (lcd_buf, "<ДАД>" );}
 else {sprintf (lcd_buf, "     " ); };
  LcdString(16,6,1);

 if (DK_Log_Create) {                           // Если логирование -
 OborWiew=Obor;                                 // показываем реальные обороты.
 #ifdef MaYa
 RashodWiev=InfoPack.Flow;                    // Показываем реальный расход 
 #endif
 #ifdef Invent 
 RashodWiev=InfoPack.Rashod;                    // Показываем реальный расход   
 #endif

 RashodWiev=RashodWiev*10/16;                   // Пересчитываем для отображения с десятичными НЕ МЕНЯТЬ! Иначе криво считает.
 }
 else {
 OborWiew=OborotRaboch[TabObIndex];             // показывае обороты из сетки оборотов
 RashodWiev=NamRas;                             // показываем расход
 RashodWiev=RashodWiev*10;                      // пересчитывае для отображения, НЕ МЕНЯТЬ! иначе криво будет
 ObSovpad=0;                                    // сбрасываем флаги совпадения, чтобы потушить надписи совпадение!
 RasSovpad=0;                                   // сбрасываем флаги совпадения, чтобы потушить надписи совпадение!
 }; 

/*-----показываем обороты---------*/
number=OborWiew/1000;
LcdTah(number, 1);                              // показываем картинку 
number=(OborWiew-(OborWiew/1000*1000))/100;
LcdTah(number, 2);                              // показываем картинку 
number=(OborWiew-(OborWiew/100*100))/10;
LcdTah(number, 3);                              // показываем картинку 
number=OborWiew-(OborWiew/10*10);
LcdTah(number, 4);                              // показываем картинку 


/*--------------- показываем Расход  -------------------------------*/  
//LcdUOZ (10, 1);                                 // Показываем надпись УОЗ это цифра 10
number=RashodWiev/100;
LcdUOZ(number, 2);                              // показываем картинку
number=(RashodWiev-(RashodWiev/100*100))/10;
LcdUOZ(number, 3);                              // показываем картинку 
number=RashodWiev-(RashodWiev/10*10);
LcdUOZ(number, 4);                              // показываем картинку



/*---------- значение в бедной и богатой таблице----------*/

temp_index=(NamRas-1)*16+TabObIndex;                       // Расчитали индекс в массиве.

sprintf (lcd_buf, "Lo:%3u", buffer_SD_0[temp_index] ); LcdString(10,7,0);
sprintf (lcd_buf, "Hi:%3u", buffer_SD_1[temp_index] ); LcdString(10,8,0);


/*---------- Показывае режим инфоэкран или просмотр таблицы---------*/
 if (DK_W_I) {                                  // Если режим редактированние (просмотра)==1 
   
  
  
  // Обработка кнопок
  
  key_set_zero();   
  keys();
  
    if (KEY_MENU){                                // Если нажали МЕНЮ
     DK_W_I=0;                                    // Переходим с режима редактирования в инфо
    };
    if (KEY_ENTER){                               // если нажали кнопку Enter
    };
            
    if (KEY_UP){                                  // если нажали кнопку верх
     if (NamRas>1) NamRas--;                      // Ходим по меню вверх              
    };    
           
    if (KEY_DOWN){                                // ходим по меню вниз
     if (NamRas<16) NamRas++;                      
    };
            
    if (KEY_LEFT){                                // если нажали кнопку влево
     if (TabObIndex>0) TabObIndex--;              // ходим по сетку оборотов
    };    
           
    if (KEY_RIGHT){                               // если нажали кнопку вправо
     if (TabObIndex<18) TabObIndex++;             // ходим по сетке оборотов
    }; 
       
   
  goto Nachalo;                                 // В режие редактирования - валим в начало! 
 };   
 

}
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

На бит NeedRead - пишет что локальная переменная установлена, но не используется.
Правильно он пишет, т.к. смысла в условии if (NeedRead==1 нет никакого, т.к. NeedRead всегда будет = 1.
Реклама
Эиком - электронные компоненты и радиодетали
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

Простите, почему?

Код: Выделить всё

Nachalo:

 if (NeedRead==1 & DK_W_I) {                    // Если режим редактированние (просмотра)==1  и надо прочитать
 NeedRead=0;                                             // Сбросили флаг необходимости чтения.           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 DK_init();                                                   // Читаем с СД карты то что
 };
Условие выполняется, и следующей строкой флаг сбрасывается в 0. Дальше идет выполнение программы, и в конце переходит на метку Nachalo.
И флаг NeedRead уже сброшен в 0. И условие больше не выполняется. Т.е. при это условие надо выполнить ОДНОКРАТНО. Выполнили - сняли флаг.
Что тут не верно?
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

Если уж пишете на Си, то пишите правильно. Чтобы компилятор Вас понимал.

Код: Выделить всё

Nachalo:
   ...
goto Nachalo 
заменить на

Код: Выделить всё

while(1)
{
   ....
}
Ставим плюсы: )
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

Переход в начало происходит если выполняется условие.

Код: Выделить всё

Nachalo:
   ...

if (условие)  goto Nachalo
В начало надо переходить в определенном случае! Как тут поставить While? Вполне логично переходить по goto.
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

Без всяких goto
Спойлер

Код: Выделить всё

void DK_view (void)
{
   unsigned char number;
   unsigned int OborWiew;                          // Обороты для показа, или реальные, или с сетки оборотов
   unsigned int RashodWiev;                        // Расдод для показа, или реальный, или табличный
   unsigned char temp_index;                       // вреенная для расчета индекса
   bit NeedRead=1;                                 // Флаг что надо прочитать что там у нас! (1- для первого просотра надо же читать)
   unsigned char OneMoreTime = 1;                  // устанавливаем флаг для первоначального входа в цикл
   
   while(OneMoreTime)
   {
      OneMoreTime = 0;                             // сбрасываем флаг, чтобы больше не входить в цикл без требования 
      if (NeedRead==1 & DK_W_I)                    // Если режим редактированние (просмотра)==1  и надо прочитать
      {
         NeedRead=0;                                    // Сбросили флаг необходимости чтения.           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         DK_init();                                     // Читаем с СД карты то что
      }
   
      if (ObSovpad) {sprintf (lcd_buf, "<RPM>"); }
      else { sprintf (lcd_buf, "     "); };
      LcdString(16,5,1);
   
      if (RasSovpad) {sprintf (lcd_buf, "<ДАД>" );}
      else {sprintf (lcd_buf, "     " ); };
      LcdString(16,6,1);

      if (DK_Log_Create)                            // Если логирование -
      {
         OborWiew=Obor;                                 // показываем реальные обороты.
         #ifdef MaYa
         RashodWiev=InfoPack.Flow;                    // Показываем реальный расход 
         #endif
         #ifdef Invent 
         RashodWiev=InfoPack.Rashod;                    // Показываем реальный расход   
         #endif
         RashodWiev=RashodWiev*10/16;                   // Пересчитываем для отображения с десятичными НЕ МЕНЯТЬ! Иначе криво считает.
      }
      else
      {
         OborWiew=OborotRaboch[TabObIndex];             // показывае обороты из сетки оборотов
         RashodWiev=NamRas;                             // показываем расход
         RashodWiev=RashodWiev*10;                      // пересчитывае для отображения, НЕ МЕНЯТЬ! иначе криво будет
         ObSovpad=0;                                    // сбрасываем флаги совпадения, чтобы потушить надписи совпадение!
         RasSovpad=0;                                   // сбрасываем флаги совпадения, чтобы потушить надписи совпадение!
      }

      /*-----показываем обороты---------*/
      number=OborWiew/1000;
      LcdTah(number, 1);                              // показываем картинку 
         number=(OborWiew-(OborWiew/1000*1000))/100;
      LcdTah(number, 2);                              // показываем картинку 
      number=(OborWiew-(OborWiew/100*100))/10;
      LcdTah(number, 3);                              // показываем картинку 
      number=OborWiew-(OborWiew/10*10);
      LcdTah(number, 4);                              // показываем картинку 

      /*--------------- показываем Расход  -------------------------------*/  
      //LcdUOZ (10, 1);                                 // Показываем надпись УОЗ это цифра 10
      number=RashodWiev/100;
      LcdUOZ(number, 2);                              // показываем картинку
      number=(RashodWiev-(RashodWiev/100*100))/10;
      LcdUOZ(number, 3);                              // показываем картинку 
      number=RashodWiev-(RashodWiev/10*10);
      LcdUOZ(number, 4);                              // показываем картинку

      /*---------- значение в бедной и богатой таблице----------*/

      temp_index=(NamRas-1)*16+TabObIndex;                       // Расчитали индекс в массиве
   
      sprintf (lcd_buf, "Lo:%3u", buffer_SD_0[temp_index] ); LcdString(10,7,0);
      sprintf (lcd_buf, "Hi:%3u", buffer_SD_1[temp_index] ); LcdString(10,8,0);
   
      /*---------- Показывае режим инфоэкран или просмотр таблицы---------*/
      if (DK_W_I)                                  // Если режим редактированние (просмотра)==1 
      {
         OneMoreTime = 1;                          // Взводим флаг для повторного входа в цикл
         // Обработка кнопок
         key_set_zero();   
         keys();
      
         if (KEY_MENU)                                // Если нажали МЕНЮ
         {
            DK_W_I=0;                                    // Переходим с режима редактирования в инфо
         }
         if (KEY_ENTER)                               // если нажали кнопку Enter
         {
         }
      
         if (KEY_UP)                                  // если нажали кнопку верх
         {
            if (NamRas>1) NamRas--;                      // Ходим по меню вверх              
         }
      
         if (KEY_DOWN)                                // ходим по меню вниз
         {
            if (NamRas<16) NamRas++;                      
         }
      
         if (KEY_LEFT)                                // если нажали кнопку влево
         {
            if (TabObIndex>0) TabObIndex--;              // ходим по сетку оборотов
         }
      
         if (KEY_RIGHT)                               // если нажали кнопку вправо
         {
            if (TabObIndex<18) TabObIndex++;             // ходим по сетке оборотов
         }
      }
   }
}
Ставим плюсы: )
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

Я такого решения не встречал, попробую заменить в этом случае goto.
Но, почему применить While таким образом правильнее, чем применить goto?
В чем преимущество?

Открыл ссылку по valitile, прочел и понял что я ничего не понял. Раньше с считал что это запрещает компиляторы оптимизировать размещение переменных в памяти, в частности применял при определении переменных в ЕЕПРОМ памяти.
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 15, 2010 23:48:09
Откуда: Украина, Кривой Рог

Сообщение Valentin44 »

Заменил goto на while по вашему предложению.
Ругаться на флаг NeedRead перестал!

Спасибо :)

Вообще, у меня много где используется goto, не считал это криминальным раньше.
Тем более хотелось бы узнать, чем while посущественнее goto.
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Valentin44 писал(а):Вообще, у меня много где используется goto, не считал это криминальным раньше. Тем более хотелось бы узнать, чем while посущественнее goto.
Действительно, ничего криминального нет в этом, сам иногда использую goto..... Но только в том случае если по другому ну ни как..... Обычно можно обойтись без него.
Вот тоже интересные мысли насчет goto отсюда http://ru.wikipedia.org/wiki/GOTO
Код с goto трудно форматировать, так как он может нарушать иерархичность выполнения (парадигму структурного программирования) и потому отступы, призванные отображать структуру программы, не всегда могут быть выставлены правильно. goto также мешает оптимизации компиляторами управляющих структур

Доводы против оператора goto оказались столь серьёзны, что в структурном программировании его стали рассматривать как крайне нежелательный. Это нашло отражение при проектировании новых языков программирования. Например, goto был запрещён в Java и Ruby.

Формально доказано (теорема Бёма — Якопини), что применение goto не является обязательным, то есть не существует такой программы с goto, которую нельзя было бы переписать без него с полным сохранением функциональности
Ответить

Вернуться в «AVR»