Итак, скачиваем проект generator_IAR.rar, распаковываем его и открываем в IARe.
Создаем новый файл File > New > File.
Называем его encoder.asm и сохраняем в папке проекта.
Подключаем этот файл к проекту Project > Add Files..
Сишный файл encoder.c удаляем из проекта Project >Remove
Сохраняем проект.
Для работы с энкодером у нас три функции:
void ENC_InitEncoder(void)
void ENC_PollEncoder(void)
unsigned char ENC_GetStateEncoder(void)
void ENC_SetStateEncoder(unsigned char var)
Сейчас мы напишем ассемблерные аналоги этих функций. Сразу вас предупрежу, синтаксис IAR`овского ассемблера несколько отличается от AVR`овского. Взять хотя бы такую простую вещь — в IAR`e ассемблерные команды должны писаться с отступом. Если этого не сделать, компилятор выдаст ошибку.
Структура ассемблерного модуля
Ассемблерные подпрограммы должны находиться внутри модуля. Модуль имеет следующую структуру:MODULE имя_модуля
//подключение заголовочных файлов
RSEG DATA //сегмент данных
//здесь можно объявить переменные
RSEG CODE //сегмент кода
//здесь будут ассемблерные подпрограммы
ENDMOD
END
Жирным шрифтом выделены директивы.
END – директива, обозначающая конца файла. Все что находится после нее, компилятор игнорирует.
Назовем наш модуль encoder и напишем его каркас.
MODULE encoder
#include
#include "encoder.h"
RSEG NEAR_Z
RSEG CODE
//инициализация порта
ENC_InitEncoder:
ret
//опрос энкодера
ENC_PollEncoder:
ret
//возвращает значение буфера
ENC_GetStateEncoder:
ret
//загружает значение в буфер
ENC_SetStateEncoder:
ret
ENDMOD
END
ioavr.h мы подключили, потому что в программе используются имена регистров AVRа.
NEAR_Z — это название области памяти данных (ОЗУ) используемой для статических и глобальных переменных инициализируемых нулем.
Дальше вроде все понятно - 4 пустых подпрограммы.
RSEG NEAR_Z
stateEnc DS 1
bufEnc DS 1
…
stateEnc – название переменной, DS – директива для резервирования оперативной памяти под байтовую переменную, 1 — количество резервируемых байтов.
Заметьте, никаких адресов ОЗУ мы не указываем - за нас это сделает компилятор.
Для того чтобы наши подпрограммы были доступны в других модулях нужно добавить еще одно объявление:
MODULE encoder
#include
#include "encoder.h"
PUBLIC ENC_InitEncoder
PUBLIC ENC_PollEncoder
PUBLIC ENC_GetStateEncoder
PUBLIC ENC_SetStateEncoder
...
Теперь нужно наполнить ассемблерные подпрограммы/функции содержимым.
Функция инициализации
ENC_InitEncoder:
cbi DDR_Enc, Pin1_Enc
cbi DDR_Enc, Pin2_Enc
sbi PORT_Enc, Pin1_Enc
sbi PORT_Enc, Pin2_Enc
ret
DDR_Enc, PORT_Enc … это макроопределения из файла encoder.h
Функция записи в буфер

ENC_SetStateEncoder:
sts bufEnc, r16
ret
Функция чтения буфера
Для возврата значений компилятор IAR использует регистры R16 – R19. В табличке ниже расписаны варианты для разных типов данных.
ENC_GetStateEncoder:
lds r16, bufEnc
clr r17
sts bufEnc, r17
ret
Функция опроса энкодера
Эта функция ничего не возвращает и не принимает, но зато делает самую главную работу — опрашивает энкодер. Для выполнения различных операций "внутри" функции IAR использует регистры R0–R3, R16–R23 и R30–R31 (так называемые scratch registers).ENC_PollEncoder:
clr r16 //очищаем R16 потому что он нам понадобится ниже
sbic PIN_Enc, Pin1_Enc //записываем состояние выводов энкодера в r16
sbr r16, 1
sbr r16, (1<<1)
lds r17, stateEnc //считываем переменную, в которой хранятся старые
andi r17, b'00000011 //состояния энкодера и выделяем последнее
cp r16, r17 //сравниваем с текущим
breq Exit //если равны, значит ничего не изм. — выходим
lds r17, stateEnc //если не равны, считываем stateEnc,
lsl r17 //сдвигам влево на 2 разряда
lsl r17 //чтобы добавить текущее состояние
or r16, r17 //добавляем с помощью операции ИЛИ
sts stateEnc, r16 //сохраняем в ОЗУ
cpi r16, b'11100001 //сравниваем получившуюся последовательность
breq LeftSpin //с константами, переходим если равно
cpi r16, b'11010010
breq RightSpin
ret
LeftSpin:
ldi r16, LEFT_SPIN //если вращение влево, записываем в r16 константу
rjmp LoadToRam // LEFT_SPIN и прыгаем на метку
RightSpin:
ldi r16, RIGHT_SPIN //если вправо, записываем в r16 RIGHT_SPIN
LoadToRam:
sts bufEnc, r16 //сохраняем r16 в буфер
Exit:
ret
Последний штрих - нужно сообщить компилятору, что используемые нами функции находятся в другом модуле и указать, что вызов функций должен осуществляться старым методом. Для этого используются ключевые слова extern и __version_1 соответственно. Добавляем перед main`ом.
extern void ENC_InitEncoder(void);
extern void ENC_PollEncoder(void);
extern unsigned char ENC_GetStateEncoder(void);
__version_1 extern void ENC_SetStateEncoder(unsigned char val);
Запускаем компиляцию и сборку - F7.... Грузим прошивку в микроконтроллер и проверяем ее работоспособность... Все работает. Продолжение следует...


[code] [/code]