Перейти к содержанию
    

Какова логика работы компилятора Atmel studio

Добрый день!!!

Решил вот опробовать 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

if(~(PINC|0b11111110))      //если bit 0 порта С равен нулю, то выполнить условие

Для проверки бита нужно использовать оператор "логическое И" (&). А для логического отрицания - оператор "!".

В вашем исполнении условие всегда истинно, поэтому компилятор его выкидывает.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если внимательно почитать warn, то скорее всего там есть упоминание об это факте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

if( (PINC & (1 << 0)) == 0 )      //если bit 0 порта С равен нулю, то выполнить условие

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно ли в студии так делать или прийдется каждый раз использовать промежуточную переменную?

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

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Которые после инвертирования превращаются в "непредвиденные" единицы.
Да там и до расширения после "ИЛИ" единиц хватает.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

может, маска "bit 7" равна 0x80 ?

Зачем себя путать, отказываясь от (((PINC >> n) & 1) == 0/1) ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

может, маска "bit 7" равна 0x80 ?

Вах ! подловили "двоечника" :)

. . . Зачем себя путать, отказываясь от (((PINC >> n) & 1) == 0/1) ?

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

Если маски изначально забиты в виде имен-макросов, то ошибки маловероятны.

 

ps

для проверки одного бита на 1 достаточно

if( PINC & ONE_BIT_MASK ) . . . . .

 

на 0

if( ~PINC & ONE_BIT_MASK ) . . . . .

 

естественно, эти выражения несовместимы с лог. операторами && итд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для проверки бита нужно использовать оператор "логическое И" (&). А для логического отрицания - оператор "!".

В вашем исполнении условие всегда истинно, поэтому компилятор его выкидывает.

Моя логика такая:

если бит 0 порта С равен еденице, то

 

0b00000001 поразрядное или

0b11111110

__________

0b11111111 поразрядное отрицание

__________

0b00000000

 

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

 

0b00000000 поразрядное или

0b11111110

__________

0b11111110 поразрядное отрицание

__________

0b00000001

Изменено пользователем mozg12342

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вах ! подловили "двоечника" :)

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

 

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

В боевом коде выглядит довольно компактно и понятно

    if(TIM3->SR & (1 << TIM_SR_CC1IIF))

Конечно же никаких магический чисел быть не должно.

Если маски изначально забиты в виде имен-макросов, то ошибки маловероятны.

Я везде использую не маски, а номера битов.

Да, в условиях появляется лишние (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);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Моя логика такая:

Прочитайте про типы данных в языке си. И про приведения (расширения) типов.

и про типы операций, что такое "побитовое И", а что такое "побитовое ИЛИ".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В боевом коде выглядит довольно компактно и понятно

    if(TIM3->SR & (1 << TIM_SR_CC1IIF))

Скобки-то зачем? Приоритет операций никто не отменял.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

if( (PINC & (1 << 0)) == 0 )      //если bit 0 порта С равен нулю, то выполнить условие

Прекрасно!!! эта комбинация работает!, ровно как и комбинация if(~PINC&(1<<0)). А я видимо немного на мудрил. Хотя по логике и на бумаге вроде все верно

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...