Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Повторный вызов функции
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Георгий
Вопрос по повторному вызову функций. Есть такой алгоритм:
читается с линии байт и по результатам чтения устанавливается ПРИЗНАК_А и РЕЗУЛЬТАТ_А. В зависимости от ПРИЗНАК_А производятся разные действия, одно из которых теперь уже в зависимости от РЕЗУЛЬТАТ_А может потребовать прием второго байта с линии. Так вот, когда второй байт принимаю, он всегда равен первому принятому байту. Я уже продублировал функцию приема с линии и для приема второго байта использую другую функцию с другими переменными. Но результат тот же. Это же алгоритм отлично работает на ассемблере. Причем когда идут однобайтовые команды, они принимаются нормально, при двухбайтовых происходит этот глюк. Код, к сожалению, выложить не могу, привожу условно. Хотелось бы теоретических рекомендаций, где я криво написал.
Код
РЕЗУЛЬТАТ_А = func_receive(); // тут же формируется через глобальную переменную ПРИЗНАК_А

switch (ПРИЗНАК_А)
{
case 1: func1;
    break;
case 2: func2(РЕЗУЛЬТАТ_А);
    break;
default: func3;
    break;
}

void func2(unsigned char РЕЗУЛЬТАТ_А)
{
switch (РЕЗУЛЬТАТ_А)
  {
   case 1: func1_1;
           break;
   case 2: РЕЗУЛЬТАТ_Б = func_receive_2(); // РЕЗУЛЬТАТ_Б = РЕЗУЛЬТАТ_А всегда!
        if ((РЕЗУЛЬТАТ_Б & 2) == 0)
        PORTD &= 0xBF;
        else PORTD |= 0x40;
    break;
  }
}
Alex11
Если это не дурацкая ошибка в строке if (РЕЗУЛЬТАТ_Б & 2) - здесь же не сравнение со значением 2, а проверка бита, то все остальное правильно. Варианты ошибки могут быть или в работе оптимиизатора IAR - он очень любит выбросить половину компилируемого текста, или в функции func_receive() - по какой-то причине она не дожидается приема второго байта и читает из регистра приемника еще раз предыдущий.
Первая рекомендация - выключить напрочь оптимизатор.
Георгий
Это была не ошибка, это я не дописал, сейчас исправил, проверяю я именно это бит, из-за этого злополучного бита и вся бодяга. А оптимизатор я отключал напрочь, не помогло. Регистра приемника нет, функция func_receive читает прямо с линии и выдает результат, только когда чтение упешно прошло. Я проверял, ошибки при приеме второго байта не возникает, значит байт принимается и где-то в недрах компилятора подменивается на предыдущий результат.
Посмотрел еще раз листинги, возникло такое предположение - проверка условий на Си занимает больше времени, чем на Ассемблере, и программа просто не успевает вовремя дать подтверждение приема, источник не получив подтверждения еще раз высылает первый байт команды, который я благополучно принимаю за второй.
Вечером проверю.
rezident
А func_receive_2() как-то опрашивает готовность приемника? А то может второй байт вовсе и не принят еще к тому времени как его читает func_receive_2().
Георгий
Если бы вы внимательно прочитали, то увидели, у меня нет приемника, или регистра приемник, процедуры func_receive и и ее копия func_receive2 читают прямо с линии. Линия естественно проверяется на старт стоп паузу и т .п. Пока вечером копался, накопал еще хуже.
1. Результат, возвращаемый функцией, зависит от начального состояния переменной, которая загоняется в return.
2. Если принудительно возвращать нужный результат в return, программа все равно после отработки либо погасит, либо включит светодиод, в зависимости от начального состояния переменной РЕЗУЛЬТАТ_Б, даже если в самой функции эта переменная изменяется.
Чем лучше дизассемблировать результатный HEX, чтобы посмотреть, что на самом деле наворачивает компилятор?
Георгий
Нашел глюк компилятор, взгляните на куски листинга:
(в процедуре приема func_receive)
Код
     56             if ((PIND & 4) > 0) Paritet++;
   \   0000003E   9982               SBIC    0x10, 0x02
   \   00000040   9513               INC     R17
     57            delay40mks;
   \                     ??inbyte_4:
   \   00000042   EA20               LDI     R18, 160
   \   00000044   952A               DEC     R18
   \   00000046   F7F1               BRNE    $-2


(в процедуре приема func_receive2)
Код
   128             if ((PIND & 4) > 0) Paritet2++;
   \   00000038   B300               IN      R16, 0x10
    129            delay40mks;
   \   0000003A   EA00               LDI     R16, 160
   \   0000003C   950A               DEC     R16
   \   0000003E   F7F1               BRNE    $-2

Поэтому второй байт всегда принимается с ошибкой. Чем победить, пока не знаю. Упорно ставит IN
Георгий
Разнес процедуры в разные модули - глюк исчез. А разочарование осталось. Решил продолжать писать на ассемблере, по крайней мере полный контроль над процессом. С глюками Си быстрее не получается.
KSN
Попробуйте к критичным переменным применить идентификатор volatile
Георгий
А какую роль играет модификатор volatile?

Пробую еще перестроить программу. Не оставляет мысль, что я где-то виноват. Практика показывает, что в 90% виноват человеческий фактор, и только в остальном глюки, ошибки системы и т. п.
IgorKossak
Георгий , может вместо
Код
if ((PIND & 4) > 0) и т. д.
лучше попробовать
Код
if (PIND_Bit2) и т. д.
?
Я допускаю, что Вы работаете в среде IAR v4.11.
Георгий
Так, конечно, понятнее и красивее, но конечный код не изменился. Я все-таки склонен думать, что где-то я плюшку допускаю, переводя с ассемблера. Сижу сейчас, копаю глубоко.
vet
Кстати, в программе так и написано?
case 1: func1;

Это к тому, что в Си идентификатор функции без скобок означает просто её адрес. Чтобы вызвать функцию, обязательно добавлять скобки, даже если параметров у неё нет. В отличие от того же Паскаля.
Георгий
case 1: func1();
break;
Про скобки я помню, для простоты не указал сразу.
KSN
идентификатор volatile сообщает компилятору, что эту переменную нельзя оптимизировать. Такой переменной гарантировано размещение в памяти, а не в регистре(размещение переменных в регистрах является одним из видов оптимизации). В основном этот идентификатор применяют к переменным, которые используются в обработчиках прерываний и в тоже время могут изменяться в основной программе.
Лучше конечно поглядеть на исходный текст программы, может что и броситься сразу в глаза.
Георгий
Посмотрел осцилограммы и убедился, что глюк у меня был от недооценки Cи. Я решил, что после Си код будет медленней работать и уменьшал задержки. В результате код ответа практически накатывался на код приема первого байта и передатчик его просто не воспринимал. А не получив ответ, передатчик посылал снова код первого байта и так несколько раз. А я грешил, что не успеваю ответить.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.