Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Осторожно цикл do - while
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
sKWO
Написал примерный код когда этот нюанс возникает.
Допустим нужно сосчитать данные с порта, сначала старший нибл ,
потом младший в некую временную переменную по четырёхбитному интерфейсу.
Потом необходимо проанализировать её значение (в коде наличие установки битика),
если определённый битик установлен, то повтор цикла иначе выход.
Отлаживал с АВР Студией, код ИАР 5.10А - полная, атмега8535
Код
// TWI Bit Rate Register (TWBR) объявлен как System_Flags
// К сожалению в меге 8535 нету GPIO регистров, поэтому такое решение
#define System_Flags TWBR  
#define DATA_SHIFT 0       // Коефиц сдвига данных
#define DATA_MASK 0x0f     // Маска данных
enum
    {
        BUSY_TIMEOUT_FLAG = (1 << 0),// таймаут ожидания
        _fail             = (1 << 1),// Cбой
        busy_bit          = (1 << 7)//
    };

void Port_check(void) { // ожидаем готовности
volatile uint8_t temp =0;
    do {
        System_Flags &= ~BUSY_TIMEOUT_FLAG;
        // строб упущен
        temp |= ((PINC << ( 4 - DATA_SHIFT)) & 0xF0);
        // строб упущен
        temp |= ((PINC >> DATA_SHIFT) & DATA_MASK);
        if (temp &(busy_bit)) System_Flags |= BUSY_TIMEOUT_FLAG;
                #ifdef _TIMER_ESCAPE_
        // аварийный выход по таймеру
        if (TIFR & (1<<TOV2)) break;
                #endif
    } while (System_Flags & BUSY_TIMEOUT_FLAG);
    if (System_Flags & BUSY_TIMEOUT_FLAG)
        System_Flags |= _fail;
        else System_Flags &= ~_fail;
}
int main( void ){for(;;){
Port_check();}}

При вызове функции Port_check в цыкле единожды считанные значения заносятся в
конкретном примере в регистр №17, и не изменяются при зацикливании!!!!
Хотя в отладчике видно что рабочий регистр №16 считывает значения но не обновляет
регистр №17. Зацикливание поизводится когда в отладчике проимитировать установление
битика3 PINC. Уровень оптимизации не имеет значение. Такой же вариант происходит
если вместо переменной temp использовать регистр №24, только код хуже.
Код
// Доступ к регистру 24
#define r24 (*(char*)24) // Это только для примера!

Выходит переменная и (или) регистр в цыкле не обновляются!!!!
в цикле проверяется только флаг BUSY_TIMEOUT_FLAG.
Вариант рабочей функции, без локальной переменной
Код
void Port_check(void) { // ожидаем готовности
    do {
        System_Flags &= ~BUSY_TIMEOUT_FLAG;
                // строб упущен
// нужно просто анализировать бит7 который мы получаем после первого строба
                if (((PINC << ( 4 - DATA_SHIFT)) & 0xF0) &busy_bit)
                System_Flags |= BUSY_TIMEOUT_FLAG;
                // строб упущен
        // аварийный выход по таймеру упущен
    } while (System_Flags & BUSY_TIMEOUT_FLAG);
    if (System_Flags & BUSY_TIMEOUT_FLAG)
        System_Flags |= _fail;
        else System_Flags &= ~_fail;
}

варианты откомпилированного кода с листингами прикрепляю
diper
...не вникая в суть вопроса: volatile ?
sKWO
Цитата(diper @ May 12 2008, 13:40) *
...не вникая в суть вопроса: volatile ?

нет, volatile это просто указать компилятору чтобы он переменную не оптимизировал, дабы показать что уровень оптимизации здесь непричём
rezident
Цитата(sKWO @ May 12 2008, 16:56) *
нет, volatile это просто указать компилятору чтобы он переменную не оптимизировал, дабы показать что уровень оптимизации здесь непричём
volatile это запрет для компилятора оптимизировать обращение к переменной. Т.е. значение переменной типа volatile он обязан обновлять каждый раз, когда к ней происходит обращение. Что в вашем случае и не происходит.
diper
"...Хотя в отладчике видно что рабочий регистр №16 считывает значения но не обновляет регистр №17..." явный признак того что компилятор что то выкинул и нужен volatile.
sKWO
Цитата(rezident @ May 12 2008, 14:44) *
volatile это запрет для компилятора оптимизировать обращение к переменной. Т.е. значение переменной типа volatile он обязан обновлять каждый раз, когда к ней происходит обращение. Что в вашем случае и не происходит.

Впринципе я это и имел ввиду, не оптимизировал переменную а обращение к ней, дабы компилятор
небыл не вчём уверен и каждый раз считывал её значение в цикле

Цитата(diper @ May 12 2008, 15:04) *
"...Хотя в отладчике видно что рабочий регистр №16 считывает значения но не обновляет регистр №17..." явный признак того что компилятор что то выкинул и нужен volatile.

я ещё для примера сказал что пробовал вместо локальной переменной исспользовал 24-й регистр,
суть дела таже.
Rst7
Компилятор сделал то, что Вы хотели. Ошибка у Вас.

Код
volatile uint8_t temp =0;
    do {


замените на

Код
volatile uint8_t temp;
    do {
          temp=0;
sKWO
Цитата(Rst7 @ May 12 2008, 15:47) *
Компилятор сделал то, что Вы хотели. Ошибка у Вас.
замените на
Код
volatile uint8_t temp;
    do {
          temp=0;

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


Не за что. Но в следующий раз - ищите ошибку у себя потщательнее wink.gif

Кстати, volatile перед temp там не нужно, это локальная переменная, применение этого модификатора только резко ухудшит выходной код.
sKWO
Цитата(Rst7 @ May 18 2008, 12:16) *
Не за что. Но в следующий раз - ищите ошибку у себя потщательнее wink.gif
Кстати, volatile перед temp там не нужно, это локальная переменная, применение этого модификатора только резко ухудшит выходной код.

Согласен,volatile перед temp ненужно. Просто код писал без книги (взяли почитать), а с этим циклом никогда раньше не работал, так приблизительно по памяти и посмотрел ваш пост №87 ну и написал не особо заморачиваясь. Цикл не заработал как надо , думал оптимизация, но она как уже известно тут непричём. Другого компилятора под рукой небыло а версия новая, не проверенная мной, вот и такая штука

PS: у Вас всё правильно
defunct
Цитата(sKWO @ May 19 2008, 13:47) *
Согласен,volatile перед temp ненужно.

В добавок к удалению volatile, еще хорошо бы во избежание других глюков порт читать единожды.
да и вместо жутких конструкций с "4 - DATA_SHIFT" не проще ли применить макрос

Код
#define  SWAP( x )  ((char)((x) << 4) | ((x) >> 4))
..
        temp =  PINC;
        temp = SWAP(temp);
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.