Автор Тема: Непонятное поведение массивов в Си  (Прочитано 9413 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Уважаемвые программисты, есть один вопрос по массивом в Си.

Есть программа

Цитировать
int main (void){

init_device ();
rs232_init (9600);      // Инициализация COM порта

//Главный цикл
while(1){

      work (POLL,1 );
}


void work (const BYTE *massiv, BYTE init_bill){
BYTE  timeout = 0;
BYTE  crc = 0;
BYTE  cik = 0;
for  (cik=0; cik!=255;   cik++){W_W.Main_Buffer [cik]=0;}  //Обнуление массива

while(1){
          wdt_reset();
          send_command(massiv);
            timeout = rs232_wait_byte();
                      if (timeout==1){бла бал
                                             }
                                       }
                           else {
                                 crc=GetCRC16();   //вычисляем коннтольню сумму
                                  if (crc==0){
                                       //Ошибка CRC
                                 
                                 
                                       }
                                else{
                                          //что то делаем
                                    }

                                }
     }
}


BYTE GetCRC16()
{
      BYTE sizeData=W_W.Main_Buffer[2];
      BYTE j, i;
      unsigned int CRC = 0;
      unsigned int TMP = 0;
     for(i=0; i != sizeData-1; i++){
      CRC ^= W_W.Main_Buffer;
       for(j=0; j < 8; j++){
          if(CRC & 0x0001) {CRC >>= 1; CRC ^= POLYNOMIAL;}
             else CRC >>= 1;
         }
      }
     TMP = W_W.Main_Buffer[sizeData] << 8 | W_W.Main_Buffer[sizeData-1] ;
     //SendWord(TMP);
return TMP == CRC;
}



BYTE rs232_wait_byte(){

      BYTE cik = 0;
      BYTE i = 255;

      Config_And_Start_TimeOut_Timer();

      for  (cik=0; cik!=i ;  cik++){
             while ( W_W.flag_reciv_byte!=1 && W_W.TimeOut!=1);
               W_W.flag_reciv_byte=0;
               W_W.Main_Buffer [cik] = W_W.reciv_byte;
                if (cik==2){
                      i=W_W.reciv_byte;
                                       }
            if(W_W.TimeOut==1)return 1;
      }
      Stop_TimeOut_Timer;
      Reset_TimeOut_Timer;
  return 0;
}





Так проблема в том, что если не очистишь массив, выдаст ошибку CRC, причем при количетве принятых    элементов больше 6-и. И часто замечал если массив  или строку передашь по указателю в функцию и потом сразу передашь ее в другую, передается полная лажа, будто указатель не возвращается на место, хотя должен, так как имя массива и есть указатель на первый элемент. Приходится массив обнулять или еще как извращатся, поясните, пожалуйста в чем дело...
« Последнее редактирование: 14 Августа 2013, 03:11:54 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
А где там очистка массива? Как объявлена W_W и как она соотносится с massiv? Она глобальная?
Короче, пока ничего не понял. Завтра гляну, а то поздно уже.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Обнуление массива в самом начале функции Work -
for  (cik=0; cik!=255;   cik++){W_W.Main_Buffer [cik]=0;}  //Обнуление массива

Без этого обнуления - ошибка crc.

W_W.Main_Buffer - глобальная перемненная в структуре, я все глобальные переменные в структуру загоняю, иногда они сильно упрощают код. Это массив на 256 байт. Объявлен так:

Цитировать
typedef struct  {
       BYTE Flag_Service_mode;
       BYTE Pointer_Save;
       unsigned int Time;
       unsigned int Kredit;
       volatile BYTE TimeOut;                        //Тайм аут, 0 - нет таймаута, 1 есть таймаут
       volatile BYTE flag_reciv_byte;
       volatile BYTE reciv_byte;
       unsigned char Main_Buffer[256];                        //Буфер текущей команды
} Type_Global_Var;

#define BYTE unsigned char

Type_Global_Var W_W;
библиотеке - extern  Type_Global_Var W_W;

*massiv - это отправляемая команда, жестко лежит во флеше как константа, в WINAVR объялвяется так:
Цитировать
const BYTE POLL         [] PROGMEM = {0x02 , 0x03 , 0x06 , 0x33 , 0xDA , 0x81}; //Постоянный запрос сотояния
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
W_W.Main_Buffer передавал в функции через указетель и просто как глобальную переменную, разницы нет.

Приведенный код рабочий, интересует именно поведение массивов.
« Последнее редактирование: 15 Августа 2013, 02:32:10 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
"выдаст ошибку CRC" - что имеется в виду? Неверный расчет CRC или Runtime error ?


1. Вообще, структура Main_Buffer какая, и для чего нужен W_W.reciv_byte?
2. Первые два байта (Main_Buffer[0] и Main_Buffer[1]) - заголовок, а в третьем (Main_Buffer[2]) хранится длина всего фрейма, включая заголовок и себя самого?
3. Заголовок и поле длины фрейма (то есть три первых байта) тоже участвуют в расчете CRC?
4. Значение в третьем байте (длина фрейма) включает в себя байты с CRC, который пришел в хвосте буфера (из которого ты TMP делаешь) или нет? А то у тебя половина TMP входит (Main_Buffer[sizeData-1]), а половина за пределами (Main_Buffer[sizeData]), по-ходу здесь проблема, в старшем байте.
« Последнее редактирование: 15 Августа 2013, 17:11:32 от pumpkin »

Форум проекта "Минилаб-Мастер"


Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
1. W_W.reciv_byte изменяется в обработчике прерывания приема ком порта, поэтому и volatile. В нее падатет принятый байт. Обработчик:
 ISR(USART1_RX_vect)
{
      W_W.reciv_byte=UDR1;
      W_W.flag_reciv_byte=1;
}

2. CRC должно вычислятся - вся длинна сообщения кроме последних двух байт, которые и есть собственго CRC. Длинна сообщения (3-й байт ) включает CRC. То есть да.

3. Да.

4.  TMP = W_W.Main_Buffer[sizeData] << 8 | W_W.Main_Buffer[sizeData-1] ;
Смысл этой операции - сделать из двух байт из конца сообщения число INT, чтобы сравнить его с вычесленным CRC. И да, фигня получается. Хотя отлаживал этот код, проблем небыло, CRC сходилось и сейчас сходится, буду проверять.
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Если sizeData включает CRC, тогда TMP должен создаваться так: TMP = W_W.Main_Buffer[sizeData-1] << 8 | W_W.Main_Buffer[sizeData-2]

Так как у тебя W_W.Main_Buffer[sizeData] лежит за пределами сообщения, то в старший байт TMP попадает мусор, а когда ты обнуляешь массив, в старший байт попадает 0.
« Последнее редактирование: 16 Августа 2013, 05:18:35 от pumpkin »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Так, если у тебя в расчете участвуют все байты, кроме последнего (for(i=0; i != sizeData-1; i++)) и при обнулении массива (то есть когда TMP = W_W.Main_Buffer[sizeData-1]) CRC сходится с вычисленным, то может у тебя там восьмибитный CRC?

Попробуй сделать  TMP = W_W.Main_Buffer[sizeData-1] и убрать обнуление массива и проверить.
« Последнее редактирование: 16 Августа 2013, 05:31:46 от pumpkin »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Цитировать
BYTE GetCRC16()
{
     BYTE sizeData=W_W.Main_Buffer[2];
     BYTE j, i;
     unsigned int CRC = 0;
     unsigned int TMP = 0;
     for(i=0; i != sizeData-1; i++){
      CRC ^= W_W.Main_Buffer;   
       for(j=0; j < 8; j++){
          if(CRC & 0x0001) {CRC >>= 1; CRC ^= POLYNOMIAL;}
             else CRC >>= 1; 
         }
      }
     TMP = W_W.Main_Buffer[sizeData] << 8 | W_W.Main_Buffer[sizeData-1] ;
     //SendWord(TMP);
return TMP == CRC;
}

Чему равен POLYNOMIAL ?
Если POLYNOMIAL - байт, то у переменной CRC изменяется только младший байт, и тогда действительно, CRC восьмибитный.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
#define POLYNOMIAL 0x08408

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

Цитировать
TMP = W_W.Main_Buffer[sizeData-1] << 8 | W_W.Main_Buffer[sizeData-2]

Да-да я понял, все верно, буду от этого и плясать.

Цитировать
(for(i=0; i != sizeData-1; i++))
не ошибаешся ли ты? Цикл дойдет до sizeData-2 и остановится по условию.
« Последнее редактирование: 16 Августа 2013, 07:27:59 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Форум проекта "Минилаб-Мастер"


Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Непонятное поведение массивов в Си
« Ответ #10 : 16 Августа 2013, 07:33:46 »
Стоп, гоню, цикл должен быть (for(i=0; i < sizeData-1; i++))
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Непонятное поведение массивов в Си
« Ответ #11 : 16 Августа 2013, 07:41:19 »
Так как два последних байта, в которых пришел CRC имеют индексы sizeData-2 и sizeData-1, то чтоб их не захватить при расчете цикл должен быть for(i=0; i < sizeData-2; i++).

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Непонятное поведение массивов в Си
« Ответ #12 : 16 Августа 2013, 08:03:55 »
Ок, попробую, отпишусь.
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Непонятное поведение массивов в Си
« Ответ #13 : 19 Августа 2013, 03:31:00 »
Все заработало как по писаному, спасибо. Осталось со строками разобратся, чуть позже приведу пример.
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Непонятное поведение массивов в Си
« Ответ #14 : 21 Августа 2013, 18:08:26 »
 Ok [smiley=thumbsup.gif]

Форум проекта "Минилаб-Мастер"

Re: Непонятное поведение массивов в Си
« Ответ #14 : 21 Августа 2013, 18:08:26 »