Обсуждаем контроллеры компании Atmel.
Ответить

Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 11:48:40

Есть следующий кусок кода:
Код:
if(flag_TIMER1 == ON)
      {
         flag_TIMER1 = OFF;
         TCCR1B &= ~((1<<CS10)|(1<<CS12)); // anti-bounce timer stop   
         uint8_t buttonState = 0; // буфер для текущего состояния кнопок         
         buttonState = PINB ^ 0x07; // проверяем какая кнопка нажата
         switch(buttonState)
         {
            case BACK: {direct = DIR_BACK; step = 0xFFFF; flag_ROLLBACK = OFF; TCCR0B |= (1<<CS00)|(1<<CS02);} break; // back
            case FORWARD: {direct = DIR_FORWARD; step = 0xFFFF; flag_ROLLBACK = OFF; TCCR0B |= (1<<CS00)|(1<<CS02);} break;   // forward
            case STEP_FWRD: {direct = DIR_FORWARD; step = val_step_fwrd; flag_ROLLBACK = ON; TCCR0B |= (1<<CS00)|(1<<CS02);} break; // step forward
            case 0: step = 0; break;
         }
         GIFR |= (1<<PCIF1); // Flag External Interrupt clear
         GIMSK |= (1<<PCIE1);   //  External Interrupt  Pin Change Interrupt Enable 1
         stepper_motor();
      }            

Проблема в локальной переменной buttonState. При включении оптимизации, компилятор начинает игнорировать ее и, соответственно swith не отрабатывает. Подскажите, как побороть?
Изображение
Последний раз редактировалось Land Вс ноя 06, 2022 12:51:28, всего редактировалось 1 раз.

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:00:34

flag_TIMER1 объявить volatile.

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:02:09

Код:
uint8_t buttonState = 0; // буфер для текущего состояния кнопок         
         buttonState = PINB ^ 0x07; // проверяем какая кнопка нажата
         switch(buttonState)

может отличаться от
Код:
switch(PINB ^ 0x07)

только в одном случае: если перед switch сработало прерывание и за время обработки прерывания изменилось состояние порта. Если это так, то используйте volatile как указание компилятору не трогать переменную. Если нет - то пишите изначально логичный код без лишних переменных

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:07:26

[code] используйте volatile как указание компилятору не трогать переменную.

пробовал. Не проходит фокус. Ну и само-собой, флаг выставляется в обработчике прерывания.
АП. А, рекомендуете вообще выбросить эту переменную. Логично, спасибо.

ААП А хрен там. Компилятор тогда игнорирует swith :o

Добавлено after 49 seconds:
flag_TIMER1 объявить volatile.

Вы не поняли. Флаг обрабатывается корректно. А вот с локальной переменной при обработке этого флага -- проблема.
Последний раз редактировалось Land Вс ноя 06, 2022 12:12:44, всего редактировалось 2 раз(а).

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:12:03

зачем нужна buttonState ?

Добавлено after 1 minute 21 second:
и найдите разницу между
Код:
uint8_t buttonState = 0; // буфер для текущего состояния кнопок         
         buttonState = PINB ^ 0x07; // проверяем какая кнопка нажата

и
Код:
uint8_t buttonState = PINB ^ 0x07; // буфер для текущего состояния кнопок // проверяем какая кнопка нажата


Добавлено after 2 minutes 31 second:
ну и ^ тоже вызывает сомнения

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:16:24

зачем нужна buttonState ?
и найдите разницу между

Уже пройденный этап. Ни в том ни в том варианте не работает. просто swith (PINB^0x07) тоже не работает.
Проблема не в самом коде, на уровне комплиляции для дебаггинга все работает корректно. Трабл вылезает при включении оптимизации О3

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:20:47

Вы не поняли. Флаг обрабатывается корректно.
Ну не поня так не понял. Только из-за локальной переменной проблемы не может быть, а вот глобальная изменяемая в прерывании должна быть volatile.

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:21:46

А может проблема в программисте, который использует XOR для проверки состояния бита?

Добавлено after 46 seconds:
Land писал(а):Трабл
это что?

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 12:50:54

Только из-за локальной переменной проблемы не может быть, а вот глобальная изменяемая в прерывании должна быть volatile.

ну не может, значит не может. Спасибо.

Добавлено after 3 minutes 39 seconds:
А может проблема в программисте, который использует XOR для проверки состояния бита?
?

Угу. Именно из-за этого переменная игнорируется компилятором. Мне, само-собой, до такого уровня программиста, как до бога.

Добавлено after 3 minutes 49 seconds:
Только из-за локальной переменной проблемы не может быть, а вот глобальная изменяемая в прерывании должна быть volatile.

ну не может, значит не может. Спасибо.

Добавлено after 3 minutes 39 seconds:
А может проблема в программисте, который использует XOR для проверки состояния бита?
?

Угу. Именно из-за этого переменная игнорируется компилятором. Мне, само-собой, до такого уровня программиста, как до бога.


Воистину, задай вопрос на русском форуме и тебе быстро объяснят, какой ты мудак.
Вынес переменную в глобальные, все заработало. Но непонятки и осадочек остался.
тема ЗАКРЫТА.

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 13:01:14

Дак там, вероятно, проблема не в игнорировании переменной, а в том, что после XOR с состоянием входов всего порта ее значение не соответствует ни одному из вариантов case. Достаточно, чтобы хотябы один из входов порта, не относящийся к кнопкам, изменился, и после XOR число уже будет совсем другим. Таблица истинности XOR - впомощь!
Обычно делают не через XOR, а через AND: state = PORT & 0x07. Или сразу в switch(PORT & 0x07). Таблица истинности AND гласит, что все биты вне единичной маски обнуляются. А значит, число, поступившее на switch, будет в диапазоне 0 - 7 при любом раскладе.
В варианте с XOR при значении 1 напрмер в 5-м бите, на switch уже поступит число в диапазоне 32- 39. И включение оптимизации тут наверно просто чисто случайно приводит к такому эффекту на входе порта.
У автора эта тема "закрыта" ровно до следующего случайного (или неслучайного) совпадения обстоятельств.

--- PS ---
Автору нужно в swhtch после всех case дописать default: с каким-либо действием, типа зажигания контрольного светодиода, чтобы визуально было видно, когда значение в switch не попадает ни в один вариант case и тогда будет выполнен вариант default, что и будет сигнализировать о работе switch как таковом.
Последний раз редактировалось MLX90640 Вс ноя 06, 2022 13:49:12, всего редактировалось 1 раз.

Re: Компилятор "убивает" локальную переменную

Вс ноя 06, 2022 13:25:31

Воистину, задай вопрос на русском форуме и тебе быстро объяснят, какой ты мудак.

Кто-то запрещает спрашивать на англоязычных?

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 13:27:37

Ага, особенно сейчас :))) Спроси на чешском или польском форуме, специально написав в профиле "from Russia". :))) Посмотрим, насколько "немудаком" там назовут.

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 17:48:16

TIMER_1 слишком жирно использовать для опроса кнопок, клавиатуры. Я использую этот таймер для более важных вещей. О своих подходах я рассказывал (конечные автоматы, программные таймеры), если сложно, можно упростить.

Совет первый. Никаких магических чисел. Сразу прописываем входы и выходы. Это полезно тем, что библиотечки можно таскать из проекта в проект, меняя определения в одном месте, а не по всему проекту. Также, плюс предлагаемого примера - кнопки могут быть разбросаны по разным портам. В scan_keys все кнопки упаковываются в одной переменной, над которой уже совершать разные действия.

Специально урезал под использовании в прерывании.

Спойлер
Код:
//==================
#ifdef __IOTINY13_H
#define ST_TCNT         TCNT0
#define ST_TIMSK        TIMSK0
#define ST_OCIE         OCIE0A
#define ST_OCR          OCR0A
#define ST_TCCR         TCCR0B
#define ST_CS0          CS00
#define ST_CS1          CS01
#define ST_CS2          CS02

#define ST_TIFR         TIFR0
#define ST_OCF          OCF0A
#endif

#ifdef __IOTINY13A_H
#define ST_TCNT         TCNT0
#define ST_TIMSK        TIMSK0
#define ST_OCIE         OCIE0A
#define ST_OCR          OCR0A
#define ST_TCCR         TCCR0B
#define ST_CS0          CS00
#define ST_CS1          CS01
#define ST_CS2          CS02

#define ST_TIFR         TIFR0
#define ST_OCF          OCF0A
#endif

#ifdef __IOM8A_H
#define ST_TCNT         TCNT2
#define ST_TIMSK        TIMSK
#define ST_TIFR         TIFR
#define ST_OCIE         OCIE2
#define ST_OCR          OCR2
#define ST_TCCR         TCCR2
#define ST_CS0          CS20
#define ST_CS1          CS21
#define ST_CS2          CS22

#define ST_TIFR         TIFR
#define ST_OCF          OCF2
#endif


//==================

//==================
#define SYS_TICK        (F_CPU/64/1000)
//==================


Спойлер
Код:
//==================
#ifdef __ST_INTERRUPT__
#pragma vector = TIMER2_COMP_vect
__interrupt void SysTimerComp (void)
{
   static u08 cnt;

   ST_OCR += SYS_TICK;
   sys_tick++;

   if (cnt++ >= 30) // Подавление дребезга.
   {
      cnt = 0;
      kbd_drv ();
   }
}
#endif
//==================

//==================
void Init_Soft_Timers (void)
{
   sys_tick = 0;
   ST_TCNT = 0;
   ST_OCR = SYS_TICK;

#ifdef __IOTINY13_H
   ST_TCCR |= ((1<<ST_CS1) | (1<<ST_CS0));
#endif

#ifdef __IOTINY13A_H
   ST_TCCR |= ((1<<ST_CS1) | (1<<ST_CS0));
#endif

#ifdef __IOM8A_H
   ST_TCCR |= (1<<ST_CS2);
#endif

#ifdef __ST_INTERRUPT__
   set_bit (ST_TIMSK, ST_OCIE);
#endif
}


Спойлер
Код:
//==================
#ifndef KBD_DRV_H

#define KBD_DRV_H

#include "kbd_drv.h"

#include "main_def_func.h"
//==================

//==================
#ifdef __PROJECT_MODE_WORK__
#define DEBOUNCE_DELAY 30
//#define DEBOUNCE_DELAY 3
#endif

#ifdef __PROJECT_MODE_DEBUG__
#define DEBOUNCE_DELAY 3
#endif
//==================

//==================
#define KEY_1_PIN PINB
#define KEY_1     0
#define KEY_1_BIT (1<<0)

#define KEY_2_PIN PINB
#define KEY_2     1
#define KEY_2_BIT (1<<1)

#define KEY_3_PIN PINB
#define KEY_3     2
#define KEY_3_BIT (1<<2)
//==================

//==================
//#define KEY1_PRESSED() ((KEYS1_PIN & (1<<BIT_KEY1) == 0)
//#define KEY1_UNPRESSED() ((KEYS1_PIN & (1<<BIT_KEY1) == 1)

#ifdef __IOTINY13_H
#define Set_Is_Key_Pressed()   check_bit (KEY_PIN, KEY)    // High level.
#define Set_Is_Key_UnPressed() !(check_bit (KEY_PIN, KEY)) // Low level.
#endif

#ifdef __IOTINY13A_H
#define Set_Is_Key_Pressed()   check_bit (KEY_PIN, KEY)    // High level.
#define Set_Is_Key_UnPressed() !(check_bit (KEY_PIN, KEY)) // Low level.
#endif

#ifdef __IOM8A_H
#define check_key_1()   (!(check_bit (KEY_1_PIN, KEY_1))) // Low level. |
#define check_key_2()   (!(check_bit (KEY_2_PIN, KEY_2))) // Low level. |- Общий плюс.
#define check_key_3()   (!(check_bit (KEY_3_PIN, KEY_3))) // Low level. |
#endif

// При работе с буфером входов (расширение ввода-вывода):
// #define Set_Is_Key_Stop_Pressed()   check_bit (inputs_buf [0], KEY_STOP)
//==================

//==================
typedef enum _kbd_drv
{
   KBD_DRV_NONE = 0,
   KBD_DRV_WAIT_DOWN,
   KBD_DRV_DOWN,
   KBD_DRV_WAIT_UP,
} kbd_drv_t;
//==================

//==================
typedef enum kbd_codes
{
   KEY_NULL_COD = 0,
   KEY_1_COD,
   KEY_2_COD,
   KEY_3_COD,
} kbd_codes_t;
//==================

//==================
void kbd_drv (void);
void Set_Key_Cod (void);
kbd_codes_t Get_Key_Code (void);
//==================

#endif



Спойлер
Код:
//==================
#include "kbd_drv.h"
//==================

//==================
static u08 prev_keys;
static u08 curr_keys;

static kbd_codes_t keys_buf;
//==================

//==================
void scan_keys (void)
{
   curr_keys = 0;

   if (check_key_1())
      set_bit (curr_keys, 0);

   if (check_key_2())
      set_bit (curr_keys, 1);

   if (check_key_3())
      set_bit (curr_keys, 2);
}
//==================

//==================
void kbd_drv (void)
{
   static kbd_drv_t _kbd_drv;
//   static soft_timer_t ST_KBD;

   scan_keys ();

   switch (_kbd_drv)
   {
      case KBD_DRV_NONE:
         if (curr_keys)
         {
            prev_keys = curr_keys;

//            set_soft_timer (ST_KBD, DEBOUNCE_DELAY);
            _kbd_drv = KBD_DRV_WAIT_DOWN;
         }
         break;

      case KBD_DRV_WAIT_DOWN:
//         if (handle_soft_timer (ST_KBD)) // Таймер подавления дребезга.
//         {
            if (curr_keys && (prev_keys == curr_keys))
            {
               Set_Key_Cod ();

//               Set_Event (EV_ID_KEY_PRESSED, USER_EVENT);
               _kbd_drv = KBD_DRV_DOWN;
            }
            else
               _kbd_drv = KBD_DRV_NONE;

            prev_keys = curr_keys;
//         }
         break;

      case KBD_DRV_DOWN:
         if (!curr_keys)
         {
//            set_soft_timer (ST_KBD, DEBOUNCE_DELAY);
            _kbd_drv = KBD_DRV_WAIT_UP;
         }
         break;

      case KBD_DRV_WAIT_UP:
//         if (handle_soft_timer (ST_KBD)) // Таймер подавления дребезга.
//         {
            if (!curr_keys)
            {
               Set_Event (EV_ID_KEY_UNPRESSED, USER_EVENT);
               _kbd_drv = KBD_DRV_NONE;
            }
            else
               _kbd_drv = KBD_DRV_DOWN;

            prev_keys = curr_keys;
//         }
         break;
   }
}
//==================

//==================
void Set_Key_Cod (void)
{
   switch (curr_keys)
   {
      case KEY_1_BIT:
         keys_buf = KEY_1_COD;
         break;

      case KEY_2_BIT:
         keys_buf = KEY_2_COD;
         break;

      case KEY_3_BIT:
         keys_buf = KEY_3_COD;
         break;

      default:
         keys_buf = KEY_NULL_COD;
   }
}

kbd_codes_t Get_Key_Code (void)
{
   return keys_buf;
}
//==================

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:21:07

Demiurg, Ваш код для отслеживания другими слишком "запутан" (+ г. транслейт) :). Личное мнение.
Спойлернапр.:
#define check_key_1() (!(check_bit (KEY_1_PIN, KEY_1))) // Low level. |
#define check_key_2() (!(check_bit (KEY_2_PIN, KEY_2))) // Low level. |- Общий плюс.
#define check_key_3() (!(check_bit (KEY_3_PIN, KEY_3))) // Low level. |
...
void scan_keys (void)
{
curr_keys = 0;

if (check_key_1())
set_bit (curr_keys, 0);

if (check_key_2())
set_bit (curr_keys, 1);

if (check_key_3())
set_bit (curr_keys, 2);
}

С одной общей проверкой и одним общим решением действия код будет короче, по крайней мере, как программа.
Если взять "зашифровать" скан (напр. в одно число) и проверить действие напр. по байтам, то может уместиться в несколько строк.
Последний раз редактировалось veso74 Вс ноя 06, 2022 18:25:27, всего редактировалось 3 раз(а).

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:22:57

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

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:35:02

Это мнение я слышал уже не раз. "Слишком запутан", "слишком сложно". Я отталкиваюсь от целесообразности. Использование инструмента.

Далеко не всегда в программировании просто - это просто. И далеко не всегда первое мнение правильное.

Добавлено after 1 minute 2 seconds:
if лишние. Таймер почему-то жирно, а условиями разбрасывать не жирно...

Предметно и конструктивно. Критикуешь, предложи альтернативу. Как сам видишь.

А вот выхлоп не сложный...
Спойлер
Код:
     12          //==================

   \                                 In  segment CODE, align 2, keep-with-next
     13          void scan_keys (void)
   \                     scan_keys:
     14          {
     15             curr_keys = 0;
   \   00000000   E000               LDI     R16, 0
     16         
     17             if (check_key_1())
   \   00000002   9BB0               SBIS    0x16, 0x00
     18                set_bit (curr_keys, 0);
   \   00000004   E001               LDI     R16, 1
     19         
     20             if (check_key_2())
   \                     ??scan_keys_0:
   \   00000006   9BB1               SBIS    0x16, 0x01
     21                set_bit (curr_keys, 1);
   \   00000008   6002               ORI     R16, 0x02
     22         
     23             if (check_key_3())
   \                     ??scan_keys_1:
   \   0000000A   9BB2               SBIS    0x16, 0x02
     24                set_bit (curr_keys, 2);
   \   0000000C   6004               ORI     R16, 0x04
   \                     ??scan_keys_2:
   \   0000000E   9300....           STS     (prev_keys + 1), R16
     25          }
   \   00000012   9508               RET
   \   00000014                      REQUIRE _A_PINB
     26          //==================


Добавлено after 8 minutes 23 seconds:
veso74 специально для тебя повторяю. Плюс такого подхода в том, что входы могут быть разбросаны по разным портам. Давай, покажи, что у тебя короче. При этом условии.
Последний раз редактировалось Demiurg Вс ноя 06, 2022 18:35:29, всего редактировалось 1 раз.

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:35:15

В варианте с XOR при значении 1 например в 5-м бите...

XOR - это побитная инверсия. Единица разряда маски инвертирует (ноль не инвертирует) этот разряд во втором операнде. Ну или наоборот. Такшта наш ТС тупо инвертирует три младших разряда, не маскируя в ноль ничего.

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:44:55

Не говорю: менять код. Просто высказываю свое мнение: смотрю на код 1..2..30 сек ... и закрываю страницу. Легче написать новое сравнение на случай, если мне нужно будет что-то изменить в Вашем коде. С етими #define -> const -> функции "одина в другой" сложно для внешнего пользователя. Но если это для Вас, как привыкли, то нормально - ничего не меняйте и не слушайте внешние "раздражители" :). (+транслейт)

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:47:32

veso74, Я не просто так спрашиваю. Какая у вас специальность? Опыт в программировании, c МК AVR? Пример хорошего кода по вашему мнению.

Re: Компилятор "убивает" локальную переменную. ЗАКРЫТО.

Вс ноя 06, 2022 18:54:06

Предметно и конструктивно. Критикуешь, предложи альтернативу. Как сам видишь.

Я вижу, что установка единицы проверкой единицы в большинстве случаев лишнее действие.
А ещё вижу, что предлагать свои частные решения для общих случаев, притом, когда их не спрашивают - это не нужно.
У меня вот вообще нет какого-то универсального подхода к кнопкам, потому что сегодня они висят на шине дисплея, завтра мк всё время спит и кнопки будят его как внешнее прерывание, послезавтра что-то ещё. Кроме того, мне не составляет труда активно работать и с железом, и если есть возможность, то повесить кучу кнопок на один порт, например. И тогда нафига эти "если кнопка 1 нажата, то поставим в переменной бит 1", когда я могу просто глянуть состояние порта? А ещё может нехватить ног и тогда начнет работать ацп, расширитель портов или ещё какая идея, например, отказаться от кнопок :))
В общем, всё - субъективно.

Если что - то моя специальность: "старший электрик по ремонту и хранению стратегических ракет", плотник и оператор строительно-монтажного пистолета ПЦ-84
Ответить