Система команд мікроконтролера AVR MEGA128

Базовий набір команд мови ASSEMBLER для мікроконтролерів AVR містить 120 інструкцій, які можна розділити на 4 групи: команди пересилання даних; арифметичні й логічні команди; інструкції для роботи з бітами; команди керування ходом виконання програми.

Команди пересилання даних. Група команд пересилання даних містить у собі інструкції із завантаження значень констант, пересилання даних типу регістр - регістр, регістр - пам'ять, регістр - порт вводу/виводу. Команди даної групи є двух-операндными, причому першим операндом є приймач даних, а другим - джерело даних.

Команда завантаження констант ldi R, K застосовується для запису безпосереднього значення К у регістр – приймач R. Як регістр - приймач можуть використовуватися регістри загального призначення R16 - R31. Якщо константа представлена у двійковій або шістнадцятковій системах числення, то перед значенням константи K необхідно вказати специфікатор системи числення 0b - для двійкової, 0х - для шістнадцяткової відповідно. Приклади:

ldi R16, 125 завантаження в R16 десяткового числа 125;

ldi R20, 0xFF завантаження в R20 шістнадцяткової константи FFh;

ldi R23, 0b11011001 завантаження в R23 двійкової константи 11011001;

Команда пересилання даних між регістрами mov Rd, Rs використається для пересилання значення з регістра-джерела Rsу регістр-приймач Rd. Операнды в команді є винятково регістрами загального призначення R0 - R31.

Приклади:

mov R16, R0 завантаження в R16 значення з регістра R0;

mov R17, R20 завантаження в R17 значення з регістра R20;

У командах пересилання даних між регістром і коміркою пам'яті використовується механізм непрямої адресації, при якому адреса комірки пам'яті заноситься в один з 16-розрядних регістрів Х,Y,Z (cм. рисунок 1.3). Формати команд:

ld R8, (R16) – завантаження даних з комірки пам'яті, адреса якої перебуває в 16-розрядному регістрі R16, у регістр загального призначення R8

st (R16), R8 – завантаження даних з регістра загального призначення R8 у комірку пам'яті, адреса якої перебуває в 16-розрядному регістрі R16 ,

ldd R8, (R16+Q) – завантаження даних у регістр загального призначення R8 з комірки пам'яті, адреса якої перебуває як сума значення, що перебуває в 16-розрядному регістрі R16 , і зсуву Q,.

std (R16+Q), R8 – завантаження даних з регістра загального призначення R8 у комірку пам'яті, адреса якої перебуває як сума значення, що перебуває в 16-розрядному регістрі R16 , і зсуву Q,.

Приклади:

ld R2, X завантаження в R2 значення з пам'яті за адресою, зазначеному в Х;

st Y, R5 завантаження значення з регістра R5 в пам'ять за адресою,

зазначеній в Y.

ldd R5, Z+1 завантаження в R5 байта з пам'яті за адресою Z+1;

std Y+4, R7 завантаження байта з регістра R7 в пам'ять за адресою Y+4.

Для звертання до портів вводу/виводу в мікропроцесорі передбачені спеціальні команди in і out:

in R, P ввід даних з порту з адресою Р у регістр загального призначення R;

out P, R вивід даних з регістра загального призначення R у порт із адресою Р;

Приклади:

in R10, 0x15 ввід даних з порту з адресою 15h у регістр загального призначення R10;

out 0x2F, R8 вивід даних з регістра загального призначення R8 у порт із адресою 2Fh;

Арифметичні й логічні команди. Для роботи із цілими двійковими числами цілочисельне АЛУ мікроконтролера AVR MEGA128 підтримує більше десятка арифметичних і логічних команд.

Основними арифметичними командами є інструкції додавання, вирахування й множення. Операндами в командах даної групи можуть бути тільки регістри загального призначення. Результат операції (крім множення) записується за адресою першого операнда.

Основні команди для виконання операцій додавання, вирахування й множення (для чисел без знака):

add Rd, Rs команда додавання (addition), дія: Rd=Rd+Rs;

sub Rd, Rs команда вирахування (subtraction), дія: Rd=Rd–Rs.

mul Rd, Rs команда множення (multipl.), дія: R1, R0=Rd*Rs;

Команди змінюють прапори переносу С, переповнення V, знака N, S, і нуля Z. При виконанні операції множення n -значних чисел місцезнаходження результату розрядністю 2n фіксовано й не вказується в команді: при множенні двох байтів результат розміром у слово заноситься в регістрову пару (R1, R0), в R0 – молодше слово, в R1 – старше слово.

Приклади:

add R10, R15 R10 = R10 + R15;

sub R2, R7 R2 = R2 – R7;

mul R5, R16 R1,R0 = R5 * R16.

Команди позитивного й негативного збільшення (інкремента й декремента):

inc R інкремент (increment), дія R=R + 1;

dec R декремент (decrement), дія R=R – 1;

У якості операнда в цих командах допускається використати тільки регістр загального призначення.

Приклади:

inc R20 дія R20 = R20 + 1;

dec R16 дія R16 = R16 – 1;

Основними логічними командами мікроконтролера AVR MEGA128 є:

or Rd, Rs логічне “або”; дія: Rd = Rd or Rs;

and Rd, Rs логічне “і”; дія: Rd = Rd and Rs;

eor Rd, Rs “ щовиключає або”; дія: Rd = Rd eor Rs.

Дані команди виконують операції поразрядного логічного “або”, логічного “і”, “ щовиключає або” (див. таблицю 1.2) над операндами, що перебувають у регістрах загального призначення, причому результат записується за адресою першого операнда. Приклади:

or R7, R11 дія: R7 = R7 or R11;

and R10, R11 дія: R10 = R10 and R11;

eor R25, R30 дія: R25 = R25 eor R30.

 

Таблиця 1.2 - Таблиці істинності логічних операцій or, end, eor

оr (або) and (і) eor (виключ. або)
Вхід Вихід Вхід Вихід Вхід Вихід
А В Q A B Q А В Q
                 
                 
                 
                 

 

Зазначені команди використовуються для виконання операцій порозрядного маскування: or – для установки одиниць у заданих розрядах, and – для установки нулів, еor – для з'ясування збігів значень битов першого операнда з маскою. Команди змінюють прапори нуля, Z, знака N і переповнення V. Приклади порозрядних логічних операцій, що ілюструють застосування механізму маскування бітів, приводяться в таблиці 1.3.

Таблиця 1.3 - Приклади порозрядних логічних операцій

Приклад порозрядного маскування or Приклад порозрядного маскування and Приклад порозрядного маскування eor
Rd хххххххх Rd хххххххх Rd  
Rs   Rs   Rs  
Rd=Rd or Rs ххх1хх1х Rd=Rd and Rs х0хх0х0х Rd=Rd eor Rs  

 

Команда порозрядного інвертування:

com R логічне заперечення; дія: R = 0b11111111 – R,

виконує зміну значень двійкових розрядів операнда (регістр загального призначення) на протилежні.

Приклад:

com R3 дія: R3 = 0b11111111 – R3.

Повний перелік арифметичних і логічних команд мікроконтролера AVR MEGA128 приводиться в Додатку 2.

 

Команди для роботи з бітами. Доповнюють сукупність логічних операцій команди скидання, установки й перевірки значень окремих бітів.

Команди скидання cbi P, n і установки sbi P, n бітів призначені для присвоювання значень 0 і 1 окремим бітам портів вводу/виводу. Першим операндом у цих командах є адреса порту вводу/виводу, другим - номер біта (від 0 до 7).

Приклади:

cbi 0x17, 5 дія: 0x175 = 0;

sbi 0x40, 1 дія: 0x401 = 1.

Команда логічного зсуву lsl R здійснює зсув вліво на одну позицію всіх битов операнда, а в молодший розряд додається нуль. Старший біт операнда надходить у прапор переносу С. У якості операнда можуть використовуватися тільки регістри загального призначення. Команда lsr R виконує зсув вправо на одну позицію всіх бітів операнда, а в старший розряд додається нуль. Молодший біт операнда надходить у прапор переносу С. Механізм роботи й синтаксис аналогічний команді lsl. Приклади використання команд логічного зсуву:

lsl R17 виконати логічний зсув вліво всіх розрядів в R17;
lsr R9 виконати логічний зсув вправо всіх розрядів в R9.

Поміняти місцями молодшу й старшу тетрады байта, завантаженого в регістр загального призначення, можна за допомогою команди swap R. Наступний фрагмент ілюструє дію команди swap:

ldi R19, 0b01001101 Завантажити константу 0b01001101 у регістр R19;

swap R19 У результаті виконання команди swap у регістрі R19 буде збережене значення 0b11010100.

Доповнюють перелік команд для роботи з бітами інструкції для скидання/установки значень прапорових розрядів у регістрі стану SREG, опис яких приводиться в Додатку 2.

Команди порівняння, умовного й безумовного переходу. Команда порівняння cp Rd, Rs – здійснює дію Rd–Rs і встановлює прапори нуля Z, негативного результату N, переповнення V, переносу C і додаткового переносу H. Результат не зберігається за адресою першого операнда, а тільки формуються прапори. Операндами можуть бути тільки регістри загального призначення.

Команди умовного переходу викликаються відразу після команд порівняння (або інших інструкцій, що викликають зміни бітів регістра стану SREG) і на основі аналізу прапорів здійснюють перехід по зазначеній адресі (мітці) у пам'яті команд.

Найпоширенішими серед команд цієї групи є:

breq M перехід на М, якщо дорівнює;

brne M перехід на М, якщо нерівно;

brlo M перехід на М, якщо менше;

brsh M перехід на М, якщо більше або дорівнює.

 

Приклад спільного використання команд порівняння й умовного переходу:

cp R1, R5 зрівняти значення в регістрах R1 і R5;

breq lbl1 виконати перехід на мітку lbl1, якщо значення в регістрах R1 і R5 рівні (R1–R5=0).

Команда rjmp М здійснює безумовний перехід по зазначеній 8-розрядній адресі (мітці, label) у пам'яті команд. Приклад:

rjmp lbl2 безумовний перехід на мітку lbl2.

Команда jmp М здійснює безумовний перехід по зазначеній 16-розрядній адресі (мітці, label) у пам'яті команд. Приклад:

rjmp lbl3 безумовний перехід на мітку lbl3.

Повний перелік команд порівняння й переходу приводиться в Додатку 2.

 

1.1.4. Синтаксис і основні оператори мови С.

Складні програмні проекти можна більш компактно описувати (у порівнянні з мовою Assembler) за допомогою мови програмування С, що має можливості мов низького й високого рівня, а так само великою бібліотекою функцій.

Алфавіт мови С складається з рядкових і заголовних букв латинського алфавіту, цифр (0 - 9) і спеціальних символів. Причому, при записі ідентифікаторів і ключових слів необхідно враховувати регістр символів. Так, ідентифікатори sysreg і Sysreg не є однаковими. Всі ключові слова повинні бути набрані малими літерами. Роздільником між операторами є символ; Закомментованні рядки починаються з розміщених підряд двох символів //.

Константи в мові З декларуються за допомогою директиви #define у відповідність із синтаксисом:

#define ім'я константи значення;

При роботі з апаратними засобами зручно записувати константи у двійковій і шістнадцятковій формах. Перед значенням констант ставляться символи 0b і 0x для двійкового й шістнадцяткового подань відповідно. Регістр символів при записі шістнадцяткових констант не має значення. Приклади оголошення констант:

#define k 25; // оголошена десяткова константа k=25;

#define KX 0x5; // оголошена шестнадцатеричная константа KX=F5h;

#define k2 0x6e; // оголошена шестнадцатеричная константа k2=6Eh;

#define KB 0b1010; // оголошена двійкова константа KB=0b1001;

Базовими цілими типами даних у мові С є: сhar (розмір 1 байт, діапазон значень – 128 ¸ 127) і int (розмір 2 байти, діапазон значень – 32768 ¸ 32767). Модифікатор unsigned, записывыемый перед ім'ям базового типу, дозволяє інтерпретувати значення наведених вище типів даних як числа без знака: unsigned сhar (розмір 1 байт, діапазон значень 0 ¸ 255), unsigned int (розмір 2 байти, діапазон значень 0 ¸ 65535). При цьому старший розряд є бітом даних, а не знаковим бітом числа.

Всі змінні повинні бути декларовані до їхнього використання в програмі. При записі імен змінних необхідно враховувати регістр символів. Формат оголошення змінної:

тип даних ім'я змінної [=початкове значення];

Якщо змінні мають однаковий тип даних, то при оголошенні їхні ідентифікатори можна перелічити через кому. Початкове значення змінної можна не вказувати. Приклади:

char A=10;

int B, C, D;

unsigned int E, F;

Розглянемо основні оператори мови С.

Оператор присвоювання має наступний синтаксис:

ідентифікатор = вираження;

У вираженнях над операндами можуть використовуватися наступні арифметичні й логічні операції мови С:

Арифметичні операції:

+ додавання;

– віднімання;

* множення,

/ ділення.

Логічні операції:

|| логічне АБО;

&& логічне І;

! логічне НЕ;

| побітова операція АБО;

& побітова операція І;

^ побітова операція виключаюче АБО;

~ побітова операція НЕ;

<< логічний зсув вліво;

>> логічний зсув вправо.

Мова С відноситься до строго типізованих мов програмування: змінним одного типу не можна безпосередньо привласнювати значення іншого типу даних. Для однозначного визначення пріоритету операцій у вираженнях необхідно використати круглі дужки (). Приклад оператора присвоювання:

A = (B+C)*D;

Оператор умови if/else дозволяє виконувати одне із двох дій залежно від умови. Синтаксис оператора:

if (умова) вираження1

[ else вираження2];

Умова являє собою вираження, задане за допомогою операцій відношення:

== дорівнює;

!= не дорівнює;

< менше;

<= менше або дорівнює;

> більше;

>= більше або дорівнює.

Якщо умова істинно, то виконується вираження1, якщо ложно – те виконується вираження2. Частина else може бути відсутня. Якщо, залежно від умови необхідно виконати фрагмент програми, що складається з декількох операторів, то їх необхідно помістити у фігурні дужки { }. Приклад використання оператора умови:

if (A==B) {C=D+E; I=N+5}

else {C=D–E; I=N–5;}

Оператор вибору switch/case дозволяє вибірково виконати фрагмент програмного коду, залежно від значення вираження. Формат оператора:

switch (цілочисельне вираження) {

case константа1: вираження1;

break;

case константа2: вираження2;

break;

...

case константа: выражение;

break;

[ default: дії за замовчуванням;] }

Оператор break повинен перебувати у всіх галузях, у противному випадку порушиться вибіркове виконання команд у галузях після case. Галузь default можна не вказувати. Приклад використання оператора вибору:

switch (num) {

case 0: A=B+C; C=D+2;

break;

case 1: A=B–C; C=D+10;

break;

case 5: A=B*C; C=D+15;

break; }

Оператор циклу з параметром for використовується в тих випадках, коли заздалегідь відома кількість ітерацій циклу. Синтаксис оператора циклу for наведений нижче:

for (ініціалізуюче вираження; умовне вираження; вираження, що модифікує)

{

оператори тіла циклу;

}

Розглянемо роботу циклу for: ініціалізуюче вираження при першому запуску циклу привласнює початкове значення лічильнику циклу; потім аналізується умовне вираження (цикл виконується поки умова істинна). Щораз після всіх рядків тіла циклу виконується вираження, що модифікує, у якому відбувається зміна лічильника циклу. Вихід із циклу відбудеться, як тільки умовне вираження одержить значення false. Приклад оператора циклу:

s=0;

m = 1;

for (i=1; i<=10; i++)

{ s=s+i;

m=m*i; }

Оператор циклу із передумовою while застосовується, коли число повторень невідомо, але необхідно виконати деяку умову. Формат оператора наведений нижче:

while (умовне вираження)

{

оператори тіла циклу;

}

Оператор починається із ключового слова while, за яким іде логічне вираження, що повертає значення false або true. Оператори, укладені у фігурних дужках, утворять тіло циклу. Приклад використання оператора циклу while:

a=0;

while (a<10)

{ b=(c+d)*a-f;

a=a+2; }

Підпрограми мовою С оформляються у вигляді функцій. Опис функції має наступний синтаксис:

[Тип повертаємого значення,] ім'я функції ([список параметрів])

{

[декларації локальних змінних]

оператори тіла функції;

[ return вираження;]

}

Якщо функція не повертає значення, то тип повертаємого значення, не вказується й секція return не використовується. При відсутності параметрів після імені функції обов'язково вказуються порожні круглі дужки (). Тіло функції заключається у фігурні дужки { }. Змінні, оголошені в тілі функції, є локальними (видимими тільки в межах тіла функції). Функції, що повертають значення, можна використати в правій частині операторів присвоювання.

Розглянемо приклад декларації функції, повертаюча, залежно від значення аргументу С, суму або різницю двох цілих чисел:

int sum (int A, int B, char C)

{

if (C>=0) return A+B;

else return A-B;

}

Приклад функції, що не має аргументів і не повертає значення:

init_data () {

A=10;

B=100+А; }

 

При програмуванні мікроконтролера часто виникає необхідність використати ассемблерний код у програмі, написаної мовою С. У цьому випадку фрагмент програми, складений з ассемблерних операторів, міститься в операторних дужках:

#asm

оператори мови асемблер

#endasm;

Приклад фрагмента програми мовою Assembler:

#asm

mov r1,r5

ldi r17,0xf5

#endasm;

Одиночний ассемблерний оператор у тілі С – программмы, може бути записаний у вигляді директиви #asm("Оператор мови Assembler”);.

Приклад:

#asm ("out 0x12,r16"); // виконати команду out 0x12,r16.

Функції, написані на асемблері, повертають значення через регістр R30 для типів char і unsigned char, і регістрову пару (R31, R30) для типів int і unsigned intR31 – старший, а в R30 – молодший байти). Параметри функції передаються через стек, на вершину якого вказує регістр Y, причому старший байт слова записується по старшій адресі. Механізми виклику й повернення з функції здійснюються засобами компілятора С. Директива #pragma warn- забороняє компіляторові генерувати попередження про те, що функція не повертає результат стандартним способом (за допомогою оператора return).

Як приклад розглянемо ассемблерну функцію, що виконує підсумовування двох цілих чисел і повертає значення типу int (пояснення до ассемблерного коду додаються):

int summa (int A, int B)

{

#asm

ldd R27, Y+3 завантажити старший байт параметра А;

ldd R26, Y+2 завантажити молодший байт параметра А;

ldd R25, Y+1 завантажити старший байт параметра В;

ld R24, Y; завантажити молодший байт параметра В;

add R24, R26 виконати підсумовування молодших байтів А и В;

adc R25, R27 виконати підсумовування старших байтів А и В

c обліком прапора переносу С;

mov R30, R24 записати молодший байт суми в регістр R30;

mov R31, R25 занести старший байт суми в регістр R31;

#endasm

}

Виклик даної функції може здійснюватися в такий спосіб:

...

int С;

C=summa (10, 15);

...

Часто в ассемблерних підпрограмах виникає необхідність одержати доступ до значень змінних, оголошених у С-програмі. Розміщення змінних (у регістрах процесора або пам'яті даних) можна визначити з файлу з розширенням *.map, ім'я якого збігається з ім'ям файлу вихідного коду програми. Даний файл генерується компілятором і перебуває в одному каталозі з вихідним модулем програми.

Розглянемо структуру програми на С. Текст вихідного модуля програми починається з директив препроцесора #include <ім'я файлу.h>, за допомогою яких у програмний код проекту довантажуються файли заголовків, що містять оголошення різних констант, ідентифікаторів і прототипи функцій. Приклад використання даної директиви, яка завантажує заголовний файл mega128.h:

#include <mega128.h>

Далі випливають оголошення констант (за допомогою директив #define) і глобальних змінних.

Потім записуються декларації функцій, використовуваних у тексті головної програми, розташованої в тілі функції main(), з операторів якої починається виконання програми. Тіло функції main() розташовано усередині фігурних дужок {}.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: