Ярлыки

_GetPixelIndex (1) _SetPixelIndex (1) 3-phase (1) 800x480 (1) АЦП (1) генератор (1) синхронный усилитель (2) структура (1) учебный курс (1) шаговый двигатель (1) ШИМ (2) accert (1) AD7608 (1) AD8429 (1) ADC (5) amplifer (1) arccos (1) arcsin (1) arctang (2) arctg (3) ARM (2) arm_sqrt_q15 (2) assembler (6) ASSERT (1) atan (2) bit (1) Bitband (1) boot (3) bootlloader (1) BUTTON (1) C (5) C# (1) CAN (2) CC2530 (5) CMSIS (4) command (1) Cordic (1) Core746I (1) CubeMX (4) DBGMCU (2) debug (2) debug.ini (1) delegate (1) Digital Potentiometers (1) DigitalPOT (1) Discovery (1) DMA (9) DMA2D (1) DSP (1) DSP library (1) DWT (1) EFM32 (5) EmWin (9) EXTI (1) FATFS (1) FMC (2) FreeRTOS (2) gl868-dual cmux (1) GPIO (4) GUI (2) GUIBuilder (1) GUIDRV_CompactColor_16 (1) HAL (3) HappyGecko (1) Hard Fault (2) heap (1) I2C (1) ID (1) ILI9320 (1) ILI9325 (1) Initialisation (1) InitLTDC (1) Instrumentithion (1) Interrupt (4) ITR (1) JTAG (1) Keil (5) LCDConf (2) lock-in (1) LTCD (1) LTDC (3) main (1) memory (1) MINI_STM32 Revision 01 (1) nBoot0 (1) NVIC (1) OnePulse (2) OSAL (4) pack (1) phase (1) printf (3) Pulse (1) PWM (12) RCC (2) RCR (1) Register (1) RESET (2) RS232 (3) RSS (1) RTC (3) RTOS-RTX (1) RTT (1) RTX-RTOS (1) SDCard (1) SDRAM (6) Segger (2) SPI (3) sqrt (3) SSD1298 (1) SSD1963 (1) Standart Peripherial Library (3) STANDBAY (1) startup (1) STemWin (8) stepper motor (1) STlink (2) STM32 (17) STM32429ZI (1) STM32Cube (1) STM32DBG.IN (1) STM32F (28) STM32F0 (4) STM32F1 (13) STM32F4 (10) STM32F4 Discovery (1) STM32F407ZG (1) STM32F429 (2) STM32F746 (1) STOP (1) string (1) struct (1) SWD (1) SWD JTAG (1) Synhronization (1) system_stm32f4xx.c (1) SystemInit (1) SysTick (1) task (4) telit (1) TIM (27) typedef (1) UART (1) USART (9) viewer (2) WM_PAINT (1) Z-stack (5) ZigBee (5)

суббота, 3 мая 2014 г.

Битовые операции

 Установка битов регистров
Язык Си не имеет в своём составе команд непосредственного сброса или установки разрядов переменной, однако присутствуют побитовые логические операции "И" и "ИЛИ", которые успешно используются для этих целей.
      Оператор побитовой логической операции "ИЛИ" записывается в виде вертикальной черты - "|" и может выполнятся между двумя переменными, а так же между переменной и константой. Напомню, что операция "ИЛИ" над двумя битами даёт в результате единичный бит, если хотя бы один из исходных битов находится с состоянии единицы. Таким образом для любого бита логическое "ИЛИ" с "1" даст в результате "1", независимо от состояния этого бита, а "ИЛИ" с логическим "0" оставит в результате состояние исходного бита без изменения. Это свойство позволяет использовать операцию "ИЛИ" для установки N-ого разряда в регистре. Для этого необходимо вычислить константу с единичным N-ным битом по формуле 2^N, которая называется битовой маской и выполнить логическое "ИЛИ" между ней и регистром, например для установки бита №7 в регистре SREG:
      (SREG | 128) — это выражение считывает регистр SREG и устанавливает в считанном значении седьмой бит, далее достаточно изменённое значение снова поместить в регистр SREG:
SREG = SREG | 128; // Установить бит №7 регистра SREG
Такую работу с регистром принято называть "чтение - модификация - запись", в отличие от простого присваивания она сохраняет состояние остальных битов без именения.
      Приведённый программный код, устанавливая седьмой бит в регистре SREG, выполняет вполне осмысленную работу - разрешает микроконтроллеру обработку программных прерываний. Единственный недостаток такой записи — в константе 128 не легко угадать установленный седьмой бит, поэтому чаще маску для N-ного бита записывают в следующем виде:  (1<<N) - это выражение на языке Си означает, число один, сдвинутое на N разрядов влево, это и есть маска с установленным N-ным битом. Тогда предыдущий код в более читабельном виде:
SREG = SREG | (1<<7)
   или ещё проще с использование краткой формы записи языка Си:
 SREG |= (1<<7);
которая означает - взять содержимое справа от знака равенства, выполнить между ним и регистром слева операцию, стоящую перед знаком равенства и записать результат в регистр или переменную слева.

Сброс битов в регистрах

Ещё одна логическая операция языка Си – побитовое "И", записывается в виде символа "&". Как известно, операция логического "И", применительно к двум битам даёт единицу тогда и только тогда, когда оба исходных бита имеют единичное значение, это позволяет применять её для сброса разрядов в регистрах. При этом используется битовая маска, в которой все разряды единичные, кроме нулевого на позиции сбрасываемого. Её легко получить из маски с установленным N-ным битом, применив к ней операцию побитного инвертирования:  ~(1<<N) в этом выражении символ "~" означает смену логического состояния всех битов маски на противоположные. Так, например, если (1<<3) в двоичном представлении – 00001000b,  то ~(1<<3) уже 11110111b. Сброс седьмого бита в регистре SREG будет выглядеть так:
SREG = SREG & (~ (1<<7));  или кратко: SREG &= ~ (1<<7);
В упомянутом ранее заголовочном файле для конкретного микроконтроллера приведены стандартные имена разрядов регистров специального назначения, например:
#define OCIE0 1
здесь #define – указание компилятору заменять в тексте программы сочетание символов "OCIE0" на число 1, то есть стандартное имя бита OCIE0, который входит в состав регистра TIMSK микроконтроллера Atmega64 на его порядковый номер в этом регистре. Благодаря этому установку бита OCIE0 в регистре TIMSK можно нагляднее записывать так:
TIMSK|=(1<<OCIE0);

Пример управления выводом NSS (CS) для режима мастер SPI шины
SPI1->CR1 |= SPI_CR1_SPE;                             //Enable the SPI1 by setting the SPE bit to 1
HAL_SPI_TransmitReceive(&hspi1, SPI1_Tx, SPI1_Rx,6,10);
SPI1->CR1 &= ~SPI_CR1_SPE;                       //Disable the SPI1  by setting the SPE bit to 0


Устанавливать или сбрасывать несколько разрядов регистра одновременно можно, объединяя битовые маски в выражениях оператором логического "ИЛИ":
     PORTA |= (1<<1)|(1<<4); // Установить выводы 1 и 4 порта A в единицу;
     PORTA&=~((1<<2)|(1<<3)); // Выводы 2 и 3 порта A сбросить в ноль

Проверка разрядов регистра на ноль и единицу.

Регистры специального назначения микроконтроллеров содержат в своём составе множество битов-признаков, так называемых "флагов”, уведомляющих программу о текущем состоянии микроконтроллера и его отдельных модулей. Проверка логического уровня флага сводится к подбору выражения, которое становится истинным или ложным в зависимости от того установлен или сброшен данный разряд в регистре. Таким выражением может служить логическое "И” между регистром и маской с установленным разрядом N на позиции проверяемого бита :
(REGISTR & (1<<N))
в этом выражении операция "И” во всех разрядах кроме N-ного даст нулевые значения, а проверяемый разряд оставит без изменения. Таким образом возможное значения выражения будут или 0 или 2^N, например для второго бита регистра SREG:

                                        если bit2=1                         если  bit2=0
SREG                      1  0  1  1  0  1  1  1                1  0  1  1  0  0  0  0
(1<<2)                    0  0  0  0  0  1  0  0                0  0  0  0  0  1  0  0
SREG&(1<<2)           0  0  0  0  0  1  0  0                0  0  0  0  0  0  0  0


Приведённое выражение можно использовать в условном операторе if (выражение) или операторе цикла while (выражение), которые относятся к группе логических, то есть воспринимают в качестве аргументов значения типа истина и ложь. Поскольку язык Си, приводя числовые значения к логическим, любые числа не равные нулю воспринимает как логическую истину, значение (REGISTR & (1<<N)) равное 2^N в случае установленного бита, будет воспринято как "истина".

     Если появляется необходимость при установленном бите N получить для нашего выражения логическое значение «ложь», достаточно дополнить его оператором логической инверсии в виде восклицательного знака - !(REGISTR & (1<<N)). Не следует путать его с похожим оператором побитовой инверсии (~) меняющим состояние битов разряда на противоположное. Логическая инверсия работает не с числовыми значениями, а с логическими, то есть преобразует истинное в ложное и наоборот. Такая конструкция приводится в DataSheet на Atmega как пример для ожидания установки бита UDRE в регистре UCSRA, после которого можно отправлять данные в UART:
while ( !( UCSRA & (1<<UDRE)) ) { } // Ждать установки UDRE
Здесь при сброшенном бите UDRE выражение ( UCSRA & (1<<UDRE)) даст значение ”ложь”, инвертированное  !( UCSRA & (1<<UDRE)) — ”истину”, и пока это так, программа будет выполнять действия внутри фигурных скобок, то есть не делать ничего (стоять на месте). Как только бит UDRE установится в единицу, программа перейдёт к выполнению действий следующих за конструкцией while(), например займётся отправкой данных в UART.

Изменение состояния бита регистра на противоположное.

Эту, с позволения сказать, проблему с успехом решает логическая операция побитного "ИСКЛЮЧАЮЩЕГО ИЛИ” и соответствующий ей оператор Си, записываемый в виде символа " ^ ”. Правило "исключающего или" с двумя битами даёт "истину” тогда и только тогда, когда один из битов установлен, а другой сброшен. Не трудно убедиться, что этот оператор, применённый между битовой маской и регистром, скопирует в результат биты стоящие напротив нулевых битов маски без изменения и инвертирует расположенные напротив единичных. Например, если: reg=b0001 0110 и mask=b0000 1111, то reg^mask=b0001 1001. Таким способом можно менять состояние светодиода, подключенного к пятому биту порта A:
#define LED 5 // Заменять в программе сочетание символов LED на число 5 (вывод светодиода).
     …
     PORTA ^=(1<< LED); // Погасить светодиод, если он светится и наоборот.

2 комментария:

  1. Почему всегда срабатывает foo, независимо установлен нулевой бит в FLAGS или нет?

    uint32_t FLAGS = 0;
    ...
    void SysTick_Handler() {
    GPIOB->ODR ^= (1 << PIN11) ;
    if (FLAGS & 0x00000001) foo();
    return;
    }

    ОтветитьУдалить
  2. Вот про возможность инверсии ^= не знал, спасибо.

    ОтветитьУдалить