Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Какова логика работы компилятора Atmel studio
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
mozg12342
Добрый день!!!
Решил вот опробовать Atmel studio 7. Столкнулся со следующими странностями:
Если в поле условия оператора if вставить любую логическую операцию, то компилятор отказывается выполнять её и просто пропускает. Если к примеру выполню необходимую операцию, запишу в переменную и переменную вставлю в поле условия, то работает как надо.
Раньше писал код в Code Vision? там так делать можно было. Можно ли в студии так делать или прийдется каждый раз использовать промежуточную переменную?
Написал простой код для примера:
Код
#define F_CPU 8000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

unsigned char r;

int main(void)
{
    DDRB=0b11111111;
    PORTB=0b00000000;
    DDRC=0b00000000;
    PORTC=0b00000001;
    DDRD=0b00000000;
    PORTD=0b00000000;
    ACSR=0x80;
    //------------------------------------------------
    while (1)
    {
        if(~(PINC|0b11111110))      //если bit 0 порта С равен нулю, то выполнить условие
        {
         PORTB=0xFF;
         }
         r=(~(PINC|0b11111110));         
     }
}


Дизасемблер показывает:
Код
00000013  CLR R1        Clear Register
00000014  OUT 0x3F,R1        Out to I/O location
00000015  LDI R28,0x5F        Load immediate
00000016  LDI R29,0x04        Load immediate
00000017  OUT 0x3E,R29        Out to I/O location
00000018  OUT 0x3D,R28        Out to I/O location
--- No source file -------------------------------------------------------------
00000019  LDI R18,0x00        Load immediate
0000001A  LDI R26,0x60        Load immediate
0000001B  LDI R27,0x00        Load immediate
0000001C  RJMP PC+0x0002        Relative jump
0000001D  ST X+,R1        Store indirect and postincrement
0000001E  CPI R26,0x61        Compare with immediate
0000001F  CPC R27,R18        Compare with carry
00000020  BRNE PC-0x03        Branch if not equal
00000021  RCALL PC+0x0003        Relative call subroutine
00000022  RJMP PC+0x0015        Relative jump
00000023  RJMP PC-0x0023        Relative jump
--- C:\STUDIOmk\transmitter\transmitter\Debug/.././main.c ----------------------
{
    DDRB=0b11111111;
00000024  SER R24        Set Register
00000025  OUT 0x17,R24        Out to I/O location
    PORTB=0b00000000;
00000026  OUT 0x18,R1        Out to I/O location
    DDRC=0b00000000;
00000027  OUT 0x14,R1        Out to I/O location
    PORTC=0b00000001;
00000028  LDI R24,0x01        Load immediate
00000029  OUT 0x15,R24        Out to I/O location
    DDRD=0b00000000;
0000002A  OUT 0x11,R1        Out to I/O location
    PORTD=0b00000000;
0000002B  OUT 0x12,R1        Out to I/O location
    ACSR=0x80;
0000002C  LDI R24,0x80        Load immediate
0000002D  OUT 0x08,R24        Out to I/O location
         PORTB=0xFF;
0000002E  SER R25        Set Register
        if(~(PINC|0b11111110))      //если bit 0 порта С равен нулю, то выполнить условие
0000002F  IN R24,0x13        In from I/O location а
         PORTB=0xFF;
00000030  OUT 0x18,R25        Out to I/O location
        r=(~(PINC|0b11111110));         
00000031  IN R24,0x13        In from I/O location
00000032  ORI R24,0xFE        Logical OR with immediate
00000033  COM R24        One's complement
00000034  STS 0x0060,R24        Store direct to data space
00000036  RJMP PC-0x0007        Relative jump
--- No source file -------------------------------------------------------------
00000037  CLI         Global Interrupt Disable
00000038  RJMP PC-0x0000        Relative jump
Harvester
Цитата(mozg12342 @ Mar 31 2018, 18:07) *
Код
if(~(PINC|0b11111110))      //если bit 0 порта С равен нулю, то выполнить условие

Для проверки бита нужно использовать оператор "логическое И" (&). А для логического отрицания - оператор "!".
В вашем исполнении условие всегда истинно, поэтому компилятор его выкидывает.
k155la3
А если внимательно почитать warn, то скорее всего там есть упоминание об это факте.
dimka76
Код
if( (PINC & (1 << 0)) == 0 )      //если bit 0 порта С равен нулю, то выполнить условие
aiwa
Цитата(mozg12342 @ Mar 31 2018, 17:07) *
Можно ли в студии так делать или прийдется каждый раз использовать промежуточную переменную?

Причина не в переменной. По стандарту языка компилятор перед выполнением операции расширяет байт до целого нулями. Которые после инвертирования превращаются в "непредвиденные" единицы.



Сергей Борщ
QUOTE (aiwa @ Apr 1 2018, 00:32) *
Которые после инвертирования превращаются в "непредвиденные" единицы.
Да там и до расширения после "ИЛИ" единиц хватает.
k155la3
Цитата(dimka76 @ Mar 31 2018, 22:54) *
Код
if( (PINC & (1 << 0)) == 0 )      //если bit 0 порта С равен нулю, то выполнить условие


Код
if( (PINC & 0x01) ^ 0x01 ) . . .   //если bit 0 порта С равен нулю, то выполнить условие


Код
if( (PINC & 0x10) ^ 0x10 ) . . .   //если bit 7 порта С равен нулю, то выполнить условие

//если bit 7 bit 4 порта С равен нулю, то выполнить условие

Код
#define IS_BIT_NULL(PORT, BIT_MASK)    ( (PORT & BIT_MASK) ^ BIT_MASK )
adnega
Цитата(k155la3 @ Apr 1 2018, 15:33) *
Код
if( (PINC & 0x10) ^ 0x10 ) . . .   //если bit 7 порта С равен нулю, то выполнить условие

может, маска "bit 7" равна 0x80 ?
Зачем себя путать, отказываясь от (((PINC >> n) & 1) == 0/1) ?
k155la3
Цитата(adnega @ Apr 1 2018, 17:30) *
может, маска "bit 7" равна 0x80 ?

Вах ! подловили "двоечника" sm.gif
Цитата
. . . Зачем себя путать, отказываясь от (((PINC >> n) & 1) == 0/1) ?

Когда надо "просчитать" несколько битов сразу (в одном условии), использовать сдвиг можно, но менее компактно. IMHO.
Если маски изначально забиты в виде имен-макросов, то ошибки маловероятны.

ps
для проверки одного бита на 1 достаточно
if( PINC & ONE_BIT_MASK ) . . . . .

на 0
if( ~PINC & ONE_BIT_MASK ) . . . . .

естественно, эти выражения несовместимы с лог. операторами && итд.
mozg12342
Цитата(Harvester @ Mar 31 2018, 18:20) *
Для проверки бита нужно использовать оператор "логическое И" (&). А для логического отрицания - оператор "!".
В вашем исполнении условие всегда истинно, поэтому компилятор его выкидывает.

Моя логика такая:
если бит 0 порта С равен еденице, то

0b00000001 поразрядное или
0b11111110
__________
0b11111111 поразрядное отрицание
__________
0b00000000

если бит 0 порта С равен нулю то

0b00000000 поразрядное или
0b11111110
__________
0b11111110 поразрядное отрицание
__________
0b00000001
adnega
Цитата(k155la3 @ Apr 1 2018, 17:33) *
Вах ! подловили "двоечника" sm.gif

Ага. В пределах байта это сразу бросилось в глаза, а вот в 32 битной маске уже без листочка и ручки не смогу.

Цитата(k155la3 @ Apr 1 2018, 17:33) *
Когда надо "просчитать" несколько битов сразу (в одном условии), использовать сдвиг можно, но менее компактно. IMHO.

В боевом коде выглядит довольно компактно и понятно
Код
    if(TIM3->SR & (1 << TIM_SR_CC1IIF))

Конечно же никаких магический чисел быть не должно.
Цитата(k155la3 @ Apr 1 2018, 17:33) *
Если маски изначально забиты в виде имен-макросов, то ошибки маловероятны.

Я везде использую не маски, а номера битов.
Да, в условиях появляется лишние (1 <<,
зато инициализация удобная
Код
    TIM3->CCMR1    = 0
        | (OC_MODE_PWM1 << TIM_CCMR1_OC1M)
        | (OC_MODE_PWM1 << TIM_CCMR1_OC2M);
    TIM3->CCER    = (1 << TIM_CCER_CC1E);
    TIM3->DIER    = 0
        | (1 << TIM_DIER_CC1IE)
        | (0 << TIM_DIER_CC2IE)
        | (1 << TIM_DIER_UIE);
jcxz
Цитата(mozg12342 @ Apr 1 2018, 17:45) *
Моя логика такая:

Прочитайте про типы данных в языке си. И про приведения (расширения) типов.
и про типы операций, что такое "побитовое И", а что такое "побитовое ИЛИ".
adnega
Цитата(mozg12342 @ Apr 1 2018, 17:45) *
поразрядное и

Это называется "или".
jcxz
Цитата(adnega @ Apr 1 2018, 17:50) *
В боевом коде выглядит довольно компактно и понятно
Код
    if(TIM3->SR & (1 << TIM_SR_CC1IIF))

Скобки-то зачем? Приоритет операций никто не отменял.
mozg12342
Цитата(dimka76 @ Mar 31 2018, 20:54) *
Код
if( (PINC & (1 << 0)) == 0 )      //если bit 0 порта С равен нулю, то выполнить условие

Прекрасно!!! эта комбинация работает!, ровно как и комбинация if(~PINC&(1<<0)). А я видимо немного на мудрил. Хотя по логике и на бумаге вроде все верно
Спасибо!
adnega
Вообще, в AVR для битовых условий есть всякие sbrc|sbrs|sbic|sbis.
Как на С лучше всего помочь компилятору задействовать эти инструкции?
mozg12342
Цитата(aiwa @ Mar 31 2018, 23:32) *
Причина не в переменной. По стандарту языка компилятор перед выполнением операции расширяет байт до целого нулями. Которые после инвертирования превращаются в "непредвиденные" единицы.

Я понял, но этот ноль должен был операцией или установиться в единицу и затем инвертироваться
adnega
Цитата(jcxz @ Apr 1 2018, 17:53) *
Скобки-то зачем? Приоритет операций никто не отменял.

Для однообразности. Иногда TIM_SR_CC1IIF не простая константа.
Кста, она тоже что-то типа
Код
#define    TIM_SR_CC1IIF                    (1UL)

Я не хвастаюсь, но скобочками у меня удобрено сильно.
mozg12342
Цитата(adnega @ Apr 1 2018, 15:53) *
Это называется "или".

Упс. исправил.
jcxz
Цитата(adnega @ Apr 1 2018, 18:01) *
Для однообразности. Иногда TIM_SR_CC1IIF не простая константа.

Все "непростые" должны быть записаны в виде:
#define TIM_SR_CC1IIF (...)
Если у Вас не так, то Вам следует сильно задуматься о своём стиле. laughing.gif

Цитата(adnega @ Apr 1 2018, 18:01) *
Я не хвастаюсь, но скобочками у меня удобрено сильно.

Когда надо разобраться в каком-то коде и вижу лес (да даже не лес, а чащу) типа:
if (((a)+(x)) | (((y)+((d)*(e))) << 1))
то сначала выкашиваю этот бурелом, иначе в этих скобочках теряется логика выражения.
Это как с шевелюрой - пока её не сбрить, операцию на мозге не выполнить качественно. cool.gif
mozg12342
Всем отзывчивым большое спасибо!!!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.