Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование встроенных приложений Keil uvision

.pdf
Скачиваний:
127
Добавлен:
06.01.2021
Размер:
4.29 Mб
Скачать

СПБГУАП группа 4736 / Индустрия 4.0

9.Индикатор 32-битного числа. Побайтно циклически выводится на линейку светодиодов 32-битное число 0xf3798146. Смена байта происходит каждые 2 с начиная с 1 байта числа. Перед началом нового чикла следует выключить все светодиоды на 3 секунды.

10.Новогодняя гирлянда. Организовать включение случайного светодиода из линейки каждые 200 мс. Гирлянда должна иметь не менее 10 состояний. После смены всех состояний процесс происходит заново.

11.Четные светодиоды. Необходимо включать только четные светодиоды по одному в цикле каждую секунду. Новый цикл начинается с выключения всех светодиодов.

12.Нечетные светодиоды. Необходимо включать только нечетные светодиоды по одному в цикле каждую секунду. Новый цикл начинается с выключения всех светодиодов.

13.Сдвигающиеся огоньки. Сначала включаются 1, 2, 3 и 4 светодиоды. Спустя 1 с. они начинают сдвигаться вниз. При этом сдвиг включенных светодиодов происходит в верхние светодиоды. Так, через 1 с. будут включены 1, 2, 3 и 8 светодиоды. Далее еще через 1 с. 1, 2, 8 и 7 светодиоды. Программный цикл длится пока все 4 верхних светодиода не будут включены. После этого цикл начинается снова.

14.Индикатор 16-битного числа. Циклически выводить на линейку светодиодов побайтно 16-битное число 0x56bc. Смена байта происходит каждые 2 с, перед началом нового цикла следует выключить все светодиоды на 3 секунды.

15.Индикатор 32-битного числа. Циклически выводить на линейку светодиодов побайтно 32-битное число 0xfa1372bc. Смена байта происходит каждые 2 с, перед началом нового цикла следует выключить все светодиоды на 3 секунды.

16.Бинарный индикатор. Каждые 300 мс на линейке светоди-

одов высвечивается декрементирующийся байт. После достижения байтом значения 0, ему присваивается значение 255 и процесс повторяется снова.

17. Накопление огоньков. Каждые полсекунды происходит включение, а затем сдвиг светодиода, начиная с 1. Спустя 7 циклов сдвига должен быть включен 8 светодиод, далее запускается процесс сдвига нового светодиода, когда он пройдет 6 сдвигов должны быть включены уже 7 и 8 светодиоды. Процесс длится пока не будут включен все светодиоды. После этого все светодиоды выключаются и процесс начинается заново.

69

СПБГУАП группа 4736 / Индустрия 4.0

4.3. Применение битовых операций при создании программ для микроконтроллеров

Цель работы – освоение принципов использования битовых и логических операций языка С.

Задачи:

1)Создать новый проект в среде KEIL MDK-ARM;

2)Написать рабочий программный код с комментариями;

3)Проверить работоспособность программного кода;

4)Выполнить индивидуальные задания;

5)Написать отчёт о проделанной работе.

4.3.1. Введение

Одной из главных операций при программировании МК является операция манипулирования битами в регистрах. Зачастую требуется инвертировать определенный бит в регистре не изменяя другие биты, избавиться от старших или младших битов (разрядов) числа, записываемого в регистр или произвести битовый сдвиг одного или нескольких разрядов в регистре МК. Для реализации этого и используются битовые (поразрядные) логические операции.

Управление работой микроконтроллера в большинстве случаев сводится к следующему простому набору действий с его регистрами:

запись в регистр необходимого значения;

чтение значения из регистра;

установка в единицу нужных разрядов регистра;

сброс разрядов регистра в ноль;

проверка состояния разряда регистра;

изменение логического состояния разряда регистра на противоположное.

Во всех указанных действиях принимает участие оператор присваивания языка С, записываемый в виде знака равенства (прим. int a = 100). Принцип действия оператора сводится к записи в регистр или переменную расположенную слева от него, значения записанного справа [4].

70

СПБГУАП группа 4736 / Индустрия 4.0

В языке программирования С существует шесть операторов для работы с битами которые можно применять к любым целочисленным знаковым или беззнаковым типам:

1)

сдвиг влево

<< ;

2)

сдвиг вправо

>> ;

3)

инверсия

~ ;

4)

ИЛИ

| ;

5)

И

& ;

6)

исключающее ИЛИ

^ .

4.3.2. Операции битовых сдвигов (<<, >>)

Сдвиг влево применяется для сдвига числа на n разрядов влево (в сторону старших разрядов). Старшие n разрядов при этом исчезают, а младшие n разрядов заполняются нулями. Операция сдвига влево на n разрядов эквивалентна умножению переменной на

2n.

/*------------------------------------------------------------

 

*/

uint8_t x = 0x03; /* объявление однобайтной беззнаковой перемен-

 

ной x и присвоение ей значения 3 = 0b00000011

*/

x = x << 1

/* перезапись переменной числом, получившимся

 

 

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

 

 

Теперь в переменной x хранится число 6 = 0b00000110

 

*/

 

/*------------------------------------------------------------

 

*/

Сдвиг вправо применяется для сдвига числа на n разрядов вправо (в сторону младших разрядов). Заполнение старших n разрядов зависит от типа переменной и ее значения. Старшие n разрядов заполняются нулями в двух случаях – если переменная беззнакового типа или если переменная знаковая и ее текущее значение положительное. Когда переменная знаковая и ее значение отрицательное – старшие разряды заполняются единицами. Операция сдвига вправо на n разрядов эквивалентна делению переменной на 2n.

71

СПБГУАП группа 4736 / Индустрия 4.0

/*------------------------------------------------------------

*/

uint8_t x = 0x03; /* объявление однобайтной беззнаковой переменной x

иприсвоение ей значения 3 = 0b00000011 */

x= x >> 1; /* перезапись значения переменной числом, получившимся

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

 

Теперь в переменной x хранится число 1 = 0b00000001 */

//--------------

 

uint8_t y = 0xf0;

/* объявление однобайтной беззнаковой переменной y

 

и присвоение ей значения 240 = 0b11110000 */

y = y >> 3;

/* перезапись значения переменной числом, получившимся

 

в результате сдвига вправо ее начального значения.

 

Теперь в переменной y хранится число 30 = 0b00011110 */

//--------------

 

int16_t z = 0xfef1; /* объявление двухбайтной знаковой переменной z

 

и присвоение ей значения -271 = 0b11111110 11110001

*/

 

z = z >> 4;

/* перезапись значения переменной числом, получившимся

 

в результате сдвига вправо ее начального значения.

Теперь в переменной z хранится число -17 = 0b11111111 111001111 */

/*------------------------------------------------------------

*/

72

СПБГУАП группа 4736 / Индустрия 4.0

4.3.3. Операция битовой инверсии ( ~ )

Поразрядно инвертирует число. Разряды, в которых были нули – заполняются единицами. Разряды, в которых были единицы

– заполняются нулями. Оператор поразрядной инверсии являются унарным оператором, то есть используется с одним операндом.

/*------------------------------------------------------------

*/

uint8_t x = 0x0f; /* объявление однобайтной беззнаковой

 

переменной x и присвоение ей знач. 16 = 0b00001111 */

x = ~ x;

/* перезапись переменной числом, получившимся

 

в результате инверсии ее начального значения.

Теперь в переменной x хранится число 240 = 0b11110000 */

 

//--------------

 

 

// запись числа x = 0b11110000 в регистр RXTX PORTA

 

MDR_PORTA->RXTX = x;

 

 

// инверсия бита № 8

в регистре, теперь в нем хранится значение

 

// 0b0111000

 

 

MDR_PORTA->RXTX = MDR_PORTA->RXTX & ~(1 << 7);

/*------------------------------------------------------------

 

*/

73

СПБГУАП группа 4736 / Индустрия 4.0

4.3.4. Операция поразрядного сложения (ИЛИ | )

Оператор | осуществляет операцию логического ИЛИ между соответствующими битами двух операндов. Результатом операции ИЛИ между двумя битами будет 0 только в случае, если оба бита равны 0. Во всех остальных случаях результат будет 1. Это показано в таблице истинности (таблице 6).

Таблица 6. Таблица истинности оператора ИЛИ

/*------------------------------------------------------------

*/

uint8_t a = 0x01;

/* объявление однобайтной беззнаковой перемен-

 

ной a и присвоение ей знач. 1 = 0b00000001 */

uint8_t b = 0x04;

/* объявление однобайтной беззнаковой перемен-

 

ной b и присвоение ей знач. 4 = 0b00000100 */

uint8_t c = a | b; /* объявление однобайтной беззнаковой перемен

 

ной c и присвоение ей результата сложения

 

(битовой операции ИЛИ) переменных a + b = 5 =

 

0b00000101 */

//--------------

MDR_PORTA->RXTX = с; //запись числа с = 0b00000101 в регистр RXTX

//PORTA

//запись результат сложения значения регистра с числом 0xf0, теперь в регистре хранится значение 0xf5 = 0b11110101

 

MDR_PORTA->RXTX = MDR_PORTA->RXTX | 0xf0;

/*------------------------------------------------------------

*/

Операция ИЛИ часто используется для установления определенного бита в регистре микроконтроллера. Это очень удобно, когда требуется установить в логическую единицу конкретный бит регистра не изменяя состояние других битов этого регистра.

74

СПБГУАП группа 4736 / Индустрия 4.0

/*------------------------------------------------------------

*/

MDR_PORTA->RXTX = 0x20; // инициализируем порт числом 0b00100000

//установка 8 и 1 битов регистра не изменяя значения других его битов,

//теперь содержимое регистра RXTX PORTA = 0b10100100

MDR_PORTA->RXTX = MDR_PORTB->RXTX | (1 << 7) | (1 << 2);

 

/*------------------------------------------------------------

*/

4.3.5. Операция поразрядного умножения ( И & )

Оператор & осуществляет операцию логического И между соответствующими битами двух операндов. Результатом операции логического И между двумя битами будет 1 только в том случае, если оба бита равны 1. Во всех других случаях результат будет 0. Это показано в таблице истинности. (таблица 7).

Таблица 7. Таблица истинности оператора И

/*------------------------------------------------------------

 

 

 

 

 

*/

uint8_t a = 0x01;

/* объявление однобайтной беззнаковой

переменной a

 

и присвоение ей значения

1

=

0b00000001

*/

uint8_t b = 0x05;

/* объявление однобайтной беззнаковой

переменной b

 

и присвоение ей значения

4

=

0b00000101

*/

uint8_t c = a & b; /* объявление однобайтной беззнаковой переменной c присвоение ей значения результата умножения

(битовой операции И) переменных a * b = 1 = 0b00000001

*/

 

/*------------------------------------------------------------

*/

Оператор & обычно применяют, чтобы обнулить один или несколько битов с помощью битовой маски. Создается ситуация, когда битовая маска подбирается таким образом, чтобы условие таблицы истинности оператора И не выполнилось и сбросились (обнулились) определенные биты переменной или регистра.

75

СПБГУАП группа 4736 / Индустрия 4.0

/*------------------------------------------------------------

*/

MDR_PORTA->RXTX = 0x33;

// инициализация регистра RXTX PORTA числом

0b00110011

 

// сброс старшего полубайта регистра с помощью битовой маски и операции битового умножения, теперь в регистре хранится значение 0x03 = 0b00000011

MDR_PORTA->RXTX = MDR_PORTA->RXTX & 0x0f;

0b00110011

// начальное значение

&

 

 

0b00001111

//

битовая маска

----------

 

 

0b00000011

//

результат операции

// сброс первого бита регистра с помощью

другой битовой маски, теперь в

регистре хранится значение 0x01 =

0b00000010

MDR_PORTA->RXTX = MDR_PORTA->RXTX

& 0x02;

 

/*------------------------------------------------------------

 

*/

Оператор & часто используют для проверки установлен ли определенный бит в регистре. Для этого требуется обнулить все биты, кроме проверочного, а потом сравнить полученное значение с нулем.

/*------------------------------------------------------------

*/

// блок будет выполняться только если установлен 4 бит регистра if ( (MDR_PORTB->RXTX & (1 << 4) != 0)

{

MDR_PORTA->RXTX = 0x00; // выкл. светодиода PA0 при нажатии на кнопку

}

// этот код запись можно сократить до вида:

if ( (MDR_PORTB->RXTX & (1 << 4)1 ) MDR_PORTA->RXTX = 0x01;2

//1) при проверке на равенство единице допускается сокращенная запись

//условия оператора if

//2) при наличии единственной операции в теле оператора if, фигурные

//скобки тела оператора можно не использовать

//--------------

// проверку на равенство нулю можно сделать двумя способами:

if

( (MDR _ PORTB - >RXTX & (1 << 4) == 0) MDR _ PORTA - >RXTX =

0x01;//способ

1

if

( !(MDR _ PORTB - >RXTX & (1 << 4))

MDR_PORTA->RXTX =

0x01;//способ

2

/*------------------------------------------------------------

 

*/

76

СПБГУАП группа 4736 / Индустрия 4.0

4.3.6. Операция поразрядного исключающего ИЛИ ( ^ )

Оператор ^ осуществляет операцию логического исключающего ИЛИ между соответствующими битами двух операндов. Результатом операции логического исключающего ИЛИ будет 0 в случае равенства битов. Во всех остальных случаях результат будет 1. Это проиллюстрировано в таблице истинности (таблица 8).

Таблица 8. Таблица истинности оператора ИЛИ

.

Оператор ^ применяется не так часто как остальные битовые операторы. С помощью него можно инвертировать один или несколько битов переменной.

/*------------------------------------------------------------

 

*/

uint8_t a = 0x07;

// объявление переменной a = 7 = 0b00000111

a = a ^ 0x04;

// инверсия 3 бита переменной а

0b00000111

// начальное значение

^

 

 

0b00000100

// битовая маска

----------

 

 

0b00000011

// результат операции

/*------------------------------------------------------------

 

*/

Из результата видно, что третий бит изменил свое значение на противоположное, а остальные биты остались без изменений.

77

СПБГУАП группа 4736 / Индустрия 4.0

4.3.7. Сокращенные записи битовых операций и полезные конструкции

В процессе написания программ для МК часто используются сокращенные записи битовых операций. Рассмотрим на конкретных примерах ниже.

/*------------------------------------------------------------

*/

//__________________ ЛОГИЧЕСКОЕ ИЛИ __________________

MDR_PORTA->RXTX = 0x01; // инициализируем PORTA числом 0b00000001

// установим 3 бит регистра в единицу не изменяя состояние других битов

MDR_PORTA->RXTX = MDR_PORTA->RXTX | 0x04;

MDR_PORTA->RXTX |= 0x04; // сокращенная запись этой операции

//результат - 0b00000101

//теперь установим в единицу 7 и 6 биты регистра не другие

MDR_PORTA->RXTX = MDR_PORTA->RXTX | (1 << 7) | (1 << 6);

MDR_PORTA->RXTX |= (1 << 7) | (1 << 6); // сокращенная запись этой операции

// результат - 0b11000101

//__________________ ЛОГИЧЕСКОЕ И __________________

MDR_PORTA->RXTX = 0x72; // инициализируем PORTA числом 0b01110010

// сбросим 6 бит регистра не изменяя другие с помощью битовой маски

MDR_PORTA->RXTX = MDR_PORTA->RXTX & 0x5f;

0b01110010

// начальное значение

&

 

0b10111111

// битовая маска

----------

 

0b00110010

// результат операции

MDR_PORTA->RXTX &= 0x5f; // сокращенная запись этой операции

/*------------------------------------------------------------

*/

При работе с целочисленными переменными различной разрядности важным правилом является приведение типов. Это необходимо для того, чтобы избежать ошибочных значений при сохранении переменных.

78