2 Программные решения

Программные решения, изложенные в данном разделе, пригодятся разработчикам и программистам, использующим AVR-ассемблер. AVR-архитектура позволяет создавать универсальные макросы, содержащие внутренние условные и безусловные переходы. Функциональная форма макросов, задаваемая директивой #define, сделала макросы наглядными формальными аналогами СИ-функций. Благодаря глобальной метке PC (Programm Counter), в функциональных макросах, так же как и в ассемблерных, можно делать условные и безусловные переходы. При наличии удобных для разработчика библиотек макросов ассемблер становится макроассемблером, который по скорости создания программ не уступает языку СИ. В подразделе 2.11 рассмотрены задачи управления знакосинтезирующими индикаторами, реализуемые в среде ОСРВ-ПА (см. раздел 1). Возможно, подраздел 2.11 кому-то поможет в освоении материалов раздела 1.

	
	

	
	
	
	
	

2.1 Об использовании ASM-макросов

2.1.1 Где-то в конце 90-х, начале 2000-х годов, я начал переходить с уровня микропрограммирования на уровень программирования на ассемблере и приступил к освоению "несравненного" AVR-ассемблера. Важнейшим отличием ассемблера от микроассемблера и настоящим открытием для меня (смешно и стыдно конечно), явились макросы с параметрами. Макросы AVR-ассемблера обеспечивают локальную видимость адресных меток внутри себя, поэтому допускают использование в своих макроопределениях внутренние условные и безусловные переходы и могут многократно использоваться в программе с различными значениями параметров. Правда эта особенность не так уж и восстребована, поскольку в AVR-ассемблере есть глобальная метка РС (Programm Counter), которая позволяет не "заморачиваться" с именами внутренних меток макросов и использовать для идентификации адресов внутренних переходов метку РС со смещением. Благо документация на AVR-микроконтроллеры содержит всю необходимую информацию о числе слов в памяти программ, занимаемых каждой командой AVR-ассемблера, и расчитать смещение для метки РС труда не составляет. Во всех моих библиотеках макросов внутренние переходы идентифицированы с помощью глобальной метки РС и расчитанных смещений. Наборы универсальных макросов, расширяющих функциональные возможности AVR-ассемблера сокращают тексты программ и делают их компактными и вполне удобочитаемыми. Признаюсь, что порой у меня даже пропадало желание осваивать и использовать СИ. Зачем тратить время, когда вот он кратчайший путь к решению всех проблем-макроассемблер собственной разработки. Нужна какая-то сложная функция, ну потрать 2-3 часа, а то и несколько минут, сделай макрос с подходящим именем, проверь на симуляторе и пользуйся. Никаких сомнений в качестве - все "со своего огорода". А необходимое отслеживание используемых регистров (в СИ это понятно не требуется) труда не составляет. 2.1.2 Очередная "революция" в моем сознании произошла с появлением функциональной или СИ-подобной формы макросов. Действительно, все эти обозначения параметров @0, @1 и т.д. затрудняют понимание кода макроса в макроопределении и требуют подробной расшифровки в комментариях. А вот функциональная форма просто идеальна для определения и вызова макроса. Кстати, в СИ функциональная форма макросов "конфликтует" с формой задания функций и требует особых начальных знаков в именах макросов, чтобы отличать их от функций. В AVR-ассемблере никаких "конфликтов" нет - увидел круглые скобки, значит макрос. Библиотеки макросов далее представлены как в традиционной классической форме с параметрами @0, @1 ..., так и в функциональной форме. В защиту классической формы макросов скажу, что в отличие от функциональной формы, она не требует использования в макроопределении обратного слэша (\) при переносе строк и допускает по тексту комментарии. Это немаловажно! Допускается использование в одном общем файле макросов двух указанных форм, но только лишь с разными именами. Должен сказать, что мои "труды" по расчету смещений относительно глобальной метки РС в макросах классической формы не пропали даром. В функциональных макросах метки имеют глобальную видимость и без глобальной метки РС в них обойтись невозможно. Все макросы функциональной формы созданы путем механического переноса кода из макроопределений классических макросов. 2.1.3 Еще обращаю внимание на следующее обстоятельство. Все опасения относительно использования в макросах сложных программных фрагментов и "гнездования" совершенно напрасны. Внутри макросов "гнездуются" как другие макросы, так и подпрограммы, также содержащие макросы - все прекрасно ассемблируется и работает. То есть делай что хочешь, если понимаешь что делаешь! И конечно, все надо тщательно проверять. 2.1.4 Используя "гнездование" ассемблерных макросов учитывайте, что если в макрос с условным именем например, MACRO_1 и параметрами @0, @1, @2, @3, как в "гнездо", вкладывается другой макрос с условным именем MACRO_2 и собственными параметрами, например @0, @1, необходимо выполнить следующие требования: - макроопределение макроса MACRO_2 должно быть сделано перед макроопределением макроса MACRO_1; - в тексте макроопределения MACRO_1 при вызове вложенного макроса MACRO_2 на позиции параметров @0, @1 макроса MACRO_2 должны быть записаны идентификаторы параметров макроса MACRO_1 - @0, @1, @2, @3 (понятно в любом сочетании). .MACRO MACRO2 SWAP @0 SWAP @1 .ENDMACRO .MACRO MACRO1 MOV R0,@0 MOV R1,@1 MOV R2,@2 MOV R3,@3 MACRO2 @3,@0 .ENDMACRO 2.1.5 С препроцессорными макросами функциональной формы точно такая же история. Вложенный макрос вызывается в тексте макроопределения основного макроса с идентификаторами параметров основного макроса. А вот последовательность макроопределений основного и вложенного функциональных макросов может быть произвольной. 2.1.6 Макросы, рассмотренные в подразделах 2.2, 2.3, 2.4, позволяют использовать ячейки и массивы ячеек памяти данных, памяти программ и EEPROM-памяти, так же как используются обычные рабочие регистры в командах ассемблера. 2.1.7 В подразделах 2.5, 2.6 представлены макросы сравнения и преобразования кодов, которыми мне приходилось пользоваться в своих рабочих программах. Возможно эти макросы также кому-то пригодятся. 2.1.8 В подразделах 2.7, 2.8 рассмотрены макросы условных переходов и макросы условных пропусков команд, которые позволяют при анализе условия перехода использовать как содержимое старшей группы регистров (R16...R31), так и содержимое младшей группы (R0...R15). Кроме того, они позволяют напрямую анализировать содержимое ячеек памяти данных и сравнивать его с содержимым других ячеек памяти данных и регистров. 2.1.9 Для сокращения объема программной памяти, необходимого программе, фрагменты кода часто используемых макросов, не содержащие параметров, могут быть оформлены как подпрограммы. 2.1.10 Имена макросов по мере возможности приближены к аббревиатурам команд AVR-ассемблера. При желании, любое имя может быть изменено на более понятное или правильное по мнению пользователя. Вполне допускаю, что можно оптимизировать и отдельные фрагменты кода макросов. 2.1.11 Все библиотеки макросов можно скачать одним архивом
MACROLIB-ALL.zip

2.2 Макросы для работы с памятью данных

2.2.1 Макроопределения ASM-макросов для работы с памятью данных содержится в файлах
MEMLIB-D.asm, MEMLIB-DF.asm и в архиве MACROLIB-ALL.zip Далее приведены имена макросов вместе с условными именами их формальных параметров, которые при вызове макроса должны заменяться фактическими параметрами - именами рабочих регистров, адресами или именами ячеек памяти данных, значениями констант. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. 2.2.2 Запись байта из регистра Rs в ячейку, адрес которой, смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd: STS_MDR M, Rd, Rs STS_MDR(M, Rd, Rs) Используются регистры R30, R31. 2.2.3 Запись байта из регистра Rs в массив из N ячеек (N=1… 255), начальный адрес которого смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd: STS_MDNR M, Rd, N, Rs STS_MDNR(M, Rd, N, Rs) Используются регистры R25, R30, R31. 2.2.4 Запись константы I (I=1… 255) в ячейку, адрес которой смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd: STS_MDI M, Rd, I STS_MDI(M, Rd, I) Используются регистры R25, R30, R31. 2.2.5 Запись константы I (I=1… 255) в массив из N ячеек (N=1… 255), начальный адрес которого смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd: STS_MDNI M, Rd, N, I STS_MDNI (M, Rd, N, I) Используются регистры R24, R25, R30, R31. 2.2.6 Запись константы I (I=1… 255)в ячейку M: STS_MI M, I STS_MI(M, I) Используются регистры R25, R30, R31. 2.2.7 Запись константы I (I=1… 255) в массив из N ячеек (N=1… 255) c начальным адресом М: STS_MNI M, N, I STS_MNI(M, N, I) Используются регистры R24, R25, R30, R31. 2.2.8 Копирование содержимого N ячеек массива с начальным адресом Ms в N ячеек массива с начальным адресом M (N=1… 255): STS_MMN M, Ms, N STS_MMN(M, Ms, N) Используются регистры R24,R25,R28,R29,R30,R31. 2.2.9 Копирование содержимого N ячеек массива с начальным адресом Ms в N ячеек массива, начальный адрес которого смещен с плюсом относительно адреса ячейки M на содержимое регистра Rd (N=1… 255): STS_MDMN M, Rd, Ms, N STS_MDMN(M, Rd, Ms, N) Используются регистры R24,R25,R28,R29,R30,R31. 2.2.10 Копирование содержимого N ячеек массива, начальный адрес которого смещен с плюсом относительно адреса ячейки Ms на содержимое регистра Rd, в N ячеек массива с начальным адресом М (N=1… 255): STS_MMDN M, Ms, Rd, N STS_MMDN(M, Ms, Rd, N) Используются регистры R24,R25,R28,R29,R30,R31. 2.2.11 Копирование содержимого N ячеек массива, начальный адрес которого смещен с плюсом относительно адреса ячейки Ms на содержимое регистра Rds, в N ячеек массива, начальный адрес которого смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd (N=1… 255): STS_MDMDN M, Rd, Ms, Rds, N STS_MDMDN(M, Rd, Ms, Rds, N) Используются регистры R24,R25,R28,R29,R30,R31. 2.2.12 Запись 8 байт ( B0 …B7 ) в массив из 8 ячеек с начальным адресом М: STS_MS8 M, B0,B1,B2,B3,B4,B5,B6,B7 STS_MDMDN(M, Rd, Ms, Rds, N) Используются регистры R25,R30,R31. 2.2.13 Чтение в регистр R содержимого ячейки памяти, адрес которой смещен с плюсом относительно адреса ячейки М на содержимое регистра Rd: LDS_RMD R, M, Rd LDS_RMD(R, M, Rd) 2.2.14 Маскирование N-байтной области памяти (N=1… 255) с начальным адресом, смещенным относительно адреса М на содержимое регистра Rd, N-байтной областью памяти с начальным адресом, смещенным относительно адреса Mm на содержимое регистра Rdm (побитное И байтов маскируемой и маскирующей областей памяти): MASK_MDMDN M,Rd,Mm,Rdm,N MASK_MDMDN(M,Rd,Mm,Rdm,N) Используются регистры R23, R24, R25, R28, R29, R30, R31. 2.2.15 Маскирование двух N-байтных областей памяти (N=1… 255) с начальными адресами М1 и М2 N-байтной областью памяти с начальным адресом Mm (побитное И байтов маскируемой и маскирующей областей памяти): MASK_MMMN M1,M2,Mm,N MASK_MMMN(M1,M2,Mm,N) Используются регистры R22, R23, R24, R25, R26, R27, R28, R29, R30, R31. 2.2.16 Маскирование двух N-байтных областей памяти (N=1… 255) третьей N-байтной областью памяти, с начальными адресами M1, M2, Mm, смещенными на содержимое регистров Rd1, Rd2, Rdm соответственно (побитное И байтов маскируемой и маскирующей областей памяти): MASK_MDMDMDN M1,Rd1,M2,Rd2,Mm,Rdm,N MASK_MDMDMDN(M1,Rd1,M2,Rd2,Mm,Rdm,N) Используются регистры R22, R23, R24, R25, R26, R27, R28, R29, R30, R31.

2.3 Макросы для работы с памятью программ

2.3.1 Макроопределения ASM-макросов для работы с памятью программ содержится в файлах
MEMLIB-P.asm, MEMLIB-PF.asm и в архиве MACROLIB-ALL.zip Далее приведены имена макросов вместе с условными именами их формальных параметров, которые при вызове макроса должны заменяться фактическими параметрами - именами рабочих регистров, адресами или именами ячеек памяти программ, значениями констант. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. 2.3.2 Чтение в регистр R байта информации из ячейки памяти программ, с байтовым адресом, смещенным относительно байтового адреса Р*2 на содержимое регистра Rd: LPM_RPD R, P, Rd LPM_RPD(R, P, Rd) Используются регистры R30, R31. 2.3.3 Чтение в регистр R байта информации из ячейки памяти программ, с байтовым адресом, смещенным относительно байтового адреса Р*2 на величину константы смещения С (C=0… 255): LPM_RPC R, P, C LPM_RPC(R, P, C) Используются регистры R25, R30, R31. 2.3.4 Чтение в регистр R байта информации из ячейки памяти программ, с байтовым адресом, смещенным относительно байтового адреса Z*2 на содержимое регистра Rd: LPM_RD R, Rd LPM_RD(R, Rd) Используются регистры R30, R31. 2.3.5 Чтение в регистр R байта информации из ячейки памяти программ, с байтовым адресом, смещенным относительно байтового адреса Z*2 на величину константы смещения С (C=0… 255): LPM_RC R,C LPM_RC(R,C) Используются регистры R25, R30, R31. 2.3.6 Чтение в регистр R байта информации из ячейки памяти программ, с байтовым адресом Z*2: LPM_R R LPM_R(R) Используются регистры R30, R31. 2.3.7 Чтение в регистры RL, RH слова из ячейки памяти программ с адресом, смещенным относительно адреса Р на содержимое регистра Rd: LPM_RRPD RL, RH, P, Rd LPM_RRPD(RL, RH, P, Rd) Используются регистры R30, R31. 2.3.8 Чтение в регистры RL, RH слова из ячейки памяти программ с адресом Р: LPM_RRP RL, RH, P LPM_RRP(RL, RH, P) Используются регистры R30, R31. 2.3.9 Чтение в регистры RL, RH слова из ячейки памяти программ с адресом, смещенным относительно адреса Z на содержимое регистра Rd: LPM_RRD RL, RH, Rd LPM_RRD(RL, RH, Rd) Используются регистры R30, R31. 2.3.10 Чтение в регистры RL, RH слова из ячейки памяти программ с адресом, смещенным относительно адреса Z на величину константы смещения С (C=0… 255): LPM_RRC RL,RH,C LPM_RRC(RL,RH,C) Используются регистры R25, R30, R31. 2.3.11 Чтение в регистры RL, RH слова из ячейки памяти программ с адресом Z: LPM_RR RL,RH LPM_RR(RL,RH) Используются регистры R30, R31.

2.4 Макросы для работы с EEPROM

2.4.1 Макроопределения ASM-макросов для работы с памятью EEPROM содержится в файлах
MEMLIB-E.asm, MEMLIB-EF.asm и в архиве MACROLIB-ALL.zip Далее приведены имена макросов вместе с условными именами их формальных параметров, которые при вызове макроса должны заменяться фактическими параметрами - именами рабочих регистров и адресами или именами ячеек EEPROM. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. 2.4.2 Запись содержимого регистра R в ячейку EEPROM с адресом Е: STE_ER E, R STE_ER(E, R) Используются регистры R30, R31. 7 циклов исполняются команды 2 цикла процессор блокируется Запись выполняется за 8450 циклов внутреннего генератора 1 МГц т.е. за 8,5 мсек. 2.4.3 Чтение содержимого ячейки EEPROM с адресом Е в регистр R: LDE_RE R,E LDE_RE(R,E) Используются регистры R30, R31. 6 циклов исполняются команды 4 цикла процессор блокируется В целом чтение занимает 10 циклов 2.4.4 Запись содержимого регистра R в ячейку EEPROM с адресом, смещенным относительно адреса Е на содержимое регистра Rd: STE_EDR E, Rd,R STE_EDR(E, Rd,R) Используются регистры R30, R31. 7 циклов исполняются команды 2 цикла процессор блокируется Запись выполняется за 8450 циклов внутреннего генератора 1 МГц т.е. за 8,5 мсек 2.4.5 Чтение в регистр R содержимого ячейки EEPROM с адресом, смещенным относительно адреса Е на содержимое регистра Rd: LDE_RED R,E,Rd LDE_RED(R,E,Rd) Используются регистры R30, R31. 6 циклов исполняются команды 4 цикла процессор блокируется В целом чтение занимает 10 циклов

2.5 Макросы сравнения кодов

2.5.1 Макросы, представленные в данном разделе, позволяют сравнивать содержимое ячеек памяти (RAM, FLASH, EEPROM) и рабочих регистров. Макроопределения макросов сравнения содержится в файлах
COMPLIB-1.asm, COMPLIB-1F.asm и в архиве MACROLIB-ALL.zip. Макросы практически применялись для сверки кодов, считанных с радиокарт, с кодами доступа, хранящимися либо в программной памяти, либо в EEPROM. К макросам сравнения кодов отнесены и два макроса поиска "новых единиц" (тревог), используемые при разработке программ для охранных систем. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. 2.5.2 Сравнение содержимого 4-х ячеек ОЗУ с двойным словом из памяти программ В Y -начальный адрес ОЗУ (M), В Z -начальный адрес памяти программ (P) В R25 записывается 1 при совпадении и 0 при несовпадении R24 используется как рабочий регистр CP_4MP M,P CP_4MP(M,P) 2.5.3 Сравнение содержимого 2 регистров (Ra,Rb) с байтами EEPROM (E,E+1) Байты EEPROM пишутся в в регистр R25 B R25 записывается 1 при совпадении и 0 при несовпадении CP_2RE Ra,Rb,E CP_2RE(Ra,Rb,E) 2.5.4 Сравнение содержимого 6 регистров (Ra,Rb,Rc,Rd,Re,Rf) с байтами EEPROM (E,E+1,...,E+5) байты EEPROM пишутся в в регистр R25 B R25 записывается 1 при совпадении и 0 при несовпадении CP_6RE Ra,Rb,Rc,Rd,Re,Rf,E CP_6RE(Ra,Rb,Rc,Rd,Re,Rf,E) 2.5.5 Сравнение содержимого 6 регистров (Ra,Rb,Rc,Rd,Re,Rf) с байтами EEPROM (E,E+1,...,E+5) смещенными на содержимое регистра DR Байты EEPROM пишутся в в регистр R25 B R25 записывается 1 при совпадении и 0 при несовпадении CP_6RED Ra,Rb,Rc,Rd,Re,Rf,E,DR CP_6RED(Ra,Rb,Rc,Rd,Re,Rf,E,DR) 2.5.6 Сравнение содержимого регистра R с байтом EEPROM E, смещенным на содержимое регистра DR. Байт EEPROM пишется в в регистр R25 B R25 записывается 1 при совпадении и 0 при несовпадении CP_RED R,E,DR CP_RED(R,E,DR) 2.5.7 Сравнение содержимого 2 регистров (Ra,Rb) с байтами ОЗУ (M,M+1) B R25 записывается 1 при совпадении и 0 при несовпадении CP_2RM Ra,Rb,M CP_2RM(Ra,Rb,M) 2.5.8 Сравнение содержимого 2-х регистров (Ra,Rb) С 2-мя байтами ОЗУ (M,M+1),смещенными на содержимое регистра DR B R25 записывается 1 при совпадении и 0 при несовпадении CP_2RMD Ra,Rb,M,DR CP_2RMD(Ra,Rb,M,DR) 2.5.9 Сравнение содержимого 4-х регистров с двойным словом из памяти программ Регистры Ra,Rb,Rc,Rd В регистре Ra - младший байт двойного слова(первый байт цепочки байтов) В регистре Rd - старший байт двойного слова(последний байт цепочки байтов) В Z -начальный адрес памяти программ (P) В R25 записывается 1 при совпадении и 0 при несовпадении CP_4RP Ra,Rb,Rc,Rd,P CP_4RP(Ra,Rb,Rc,Rd,P) 2.5.10 Сравнение содержимого 4-х регистров с двойным словом из памяти программ со словарным смещением из регистра DR Регистры Ra,Rb,Rc,Rd В регистре Ra - младший байт двойного слова(первый байт цепочки байтов) В регистре Rd - старший байт двойного слова(последний байт цепочки байтов) В Z -записываем начальный адрес памяти программ (P) В R25 записываем 1 при совпадении и 0 при несовпадении CP_4RPD Ra,Rb,Rc,Rd,P,DR CP_4RPD(Ra,Rb,Rc,Rd,P,DR) 2.5.11 Сравнение содержимого n байт ОЗУ (M1) с N байтами ОЗУ (M2) Смещения берутся из регистров (DR1) и (DR2) Используются R25,X,Y,Z - регистры B R25 записывается 1 при совпадении и 0 при несовпадении В ХL и ХH остаются последние сравниваемые значения CP_MDMDN M1,DR1,M2,DR2,N CP_MDMDN(M1,DR1,M2,DR2,N) 2.5.12 Сравнение содержимого N байт ОЗУ (M1) с N байтами ОЗУ (M2) Смещение для ОЗУ (M1) берется из регистра (DR1) Используются R25,X,Y,Z - регистры B R25 записывается 1 при совпадении и 0 при несовпадении В ХL и ХH остаются последние сравниваемые значения CP_MDMN M1,DR1,M2,N CP_MDMN(M1,DR1,M2,N) 2.5.13 Сравнение содержимого N байт ОЗУ (M1) с N байтами ОЗУ (M2) Смещение для ОЗУ (M2) берется из регистра (DR2) Используются R25,X,Y,Z - регистры B R25 записывается 1 при совпадении и 0 при несовпадении В ХL и ХH остаются последние сравниваемые значения CP_MMDN M1,M2,DR2,N CP_MMDN(M1,M2,DR2,N) 2.5.14 Сравнение содержимого N байт ОЗУ (M1) с N байтами ОЗУ (M2) Используются R25,X,Y,Z - регистры B R25 записывается 1 при совпадении и 0 при несовпадении В ХL и ХH остаются последние сравниваемые значения CP_MMN M1,M2,N CP_MMN(M1,M2,N) 2.5.15 Сравнение содержимого 2-х регистров (Ra,Rb) сo словом из памяти программ (P) со словарным смещением из регистра (DR) В регистре Ra - младший байт слова В регистре Rb - старший байт слова В R25 записывается 1 при совпадении и 0 при несовпадении CP_2RPD Ra,Rb,P,DR CP_2RPD(Ra,Rb,P,DR) 2.5.16 Сравнение содержимого 4-х регистров(Ra,Rb,Rc,Rd) с двойным словом из памяти программ(P) со словарным смещением из регистров (DRH,DRL) В регистре Ra - младший байт двойного слова(первый байт цепочки байтов) В регистре Rd - старший байт двойного слова(последний байт цепочки байтов) В R25 записывается 1 при совпадении и 0 при несовпадении CP_4RPDD Ra,Rb,Rc,Rd,P,DRH,DRL CP_4RPDD(Ra,Rb,Rc,Rd,P,DRH,DRL) 2.5.17 Сравнение содержимого 2-х регистров(Ra,Rb) сo словом из памяти программ(P) со словарным смещением из регистров (DRH,DRL) В регистре Ra - младший байт слова В регистре Rb - старший байт слова В R25 записываем 1 при совпадении и 0 при несовпадении CP_2RPDD Ra,Rb,P,DRH,DRL CP_2RPDD(Ra,Rb,P,DRH,DRL) 2.5.18 Поиск новых единиц Сравнение содержимого N байт ОЗУ (M1) с N байтами ОЗУ (M2) Смещения берутся из регистров (DR1) И (DR2) Используются R25,X,Y,Z - регистры B R25 записывается 1 при наличии новых единиц и 0 при отсутствии В ХL и ХH остаются последние сравниваемые значения Используется для регистрации новых тревог при сравнении нового и старого состояний шлейфов сигнализации (ШС) Операция AND инверсии старого байта и нового байта M1 - новые N байт M2 - старые N байт NEW1_MDMDN M1,DR1,M2,DR2,N NEW1_MDMDN(M1,DR1,M2,DR2,N) 2.5.19 Поиск новых единиц Сравнение содержимого N байт ОЗУ (M1) с N байтами ОЗУ (M2) Смещениe берется из регистра (DR2) Используются R25,X,Y,Z - регистры B R25 записывается 1 при наличии новых единиц и 0 при отсутствии В ХL И ХH остаются последние сравниваемые значения Используется для регистрации новых тревог при сравнении нового и старого состояний ШС Операция AND инверсии старого байта и нового байта M1 - новый байт M2 - старый байт NEW1_MMDN M1,M2,DR2,N NEW1_MMDN(M1,M2,DR2,N)

2.6 Макросы преобразования кодов

2.6.1 Макроопределения макросов преобразования кодов содержится в файлах
CONVLIB-1.asm, CONVLIB-1F.asm и в архиве MACROLIB-ALL.zip Далее приведены имена макросов вместе с условными именами их формальных параметров, которые при вызове макроса должны заменяться фактическими параметрами - именами рабочих регистров, адресами или именами ячеек памяти данных. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. 2.6.2 Преобразование двухразрядного десятичного ASCII числа в упакованный BCD-код R-регистр результата RsH-регистр старшего разряда числа ASCII RsL-регистр младшего разряда числа ASCII R24,R25-рабочие регистры Исходные регистры не меняются Можно использовать R24,R25 в качестве регистров старшего и младшего разрядов ASCII-кода соответственно (RsH,RsL), а также любой из них в качестве регистра результата R FORM_BCD_ASCII R,RsH,RsL FORM_BCD_ASCII(R,RsH,RsL) 2.6.3 Преобразование упакованного BCD-кода в двухразрядное десятичное ASCII число RH-регистр старшего разряда числа ASCII RL-регистр младшего разряда числа ASCII Rs-регистр исходного упакованного BCD-кода R25-рабочий регистр Исходный регистр не меняется Можно использовать R25 в качестве RL FORM_ASCII_BCD RH,RL,Rs FORM_ASCII_BCD(RH,RL,Rs) 2.6.4 Преобразование упакованного BCD-кода в двоичный R-регистр результата (двоичное число) Rs-регистр исходного упакованного BCD-числа R0,R1 используются при умножении R25 используется как рабочий регистр Использовать R0,R1,R25 в качестве R или Rs нельзя FORM_BIN_BCD R,Rs FORM_BIN_BCD(R,Rs) 2.6.5 Преобразование двоичного кода в упакованный BCD-код R-регистр результата (упакованное BCD-число) Rs-регистр исходного двоичного числа R24 используется как рабочий регистр R25 используется как рабочий регистр R25 можно использовать только как Rs FORM_BCD_BIN R,Rs FORM_BCD_BIN(R,Rs) 2.6.6 Преобразование двухразрядного десятичного ASCII числа в двоичный код R-регистр результата RsH-регистр старшего разряда RsL-регистр младшего разряда R0,R1,R24,R25-рабочие регистры Исходные регистры не меняются R0,R1,R24,R25 можно использовать в качестве R FORM_BIN_ASCII R,RsH,RsL FORM_BIN_ASCII(R,RsH,RsL) 2.6.7 Преобразование двоичного кода в двухразрядное десятичное ASCII число RH-регистр старшего разряда результата RL-регистр младшего разряда результата Rs-регистр исходного двоичного кода R24,R25-рабочиe регистры Исходный регистр Rs не меняется R24 можно использовать в качестве RH R25 можно использовать в качестве Rs FORM_ASCII_BIN RH,RL,Rs FORM_ASCII_BIN(RH,RL,Rs) 2.6.8 Преобразование 4-х байтного НЕХ-числа в 8-ми байтное ASCII число M-имя области памяти для записи результата Rs3-регистр двух старших разрядов исходного НЕХ-кода Rs2,Rs1-регистры четырех средних разрядов исходного НЕХ-кода Rs0-регистр двух младших разрядов исходного НЕХ-кода R24,R25-рабочиe регистры(использовать нельзя) Исходныe регистры Rs0-Rs3 не меняются FORM_ASCII8_HEX4 M,Rs3,Rs2,Rs1,Rs0 FORM_ASCII8_HEX4(M,Rs3,Rs2,Rs1,Rs0)

2.7 Макросы ближних и дальних условных переходов

2.7.1 Макроопределения ASM-макросов ближних и дальних условных переходов содержится в файлах
BRANCHLIB-1.asm, BRANCHLIB-2.asm, BRANCHLIB-1F.asm, BRANCHLIB-2F.asm и в архиве MACROLIB-ALL.zip Ближние условные переходы выполняются в пределах диапазона словарных адресов программной памяти от -2К до +2K (от 0 до 4К для микроконтроллеров с программной памятью 8 Кбайт и менее) с использованием команды RJAMP. Дальние условные переходы выполняются в пределах полного диапазона словарных адресов программной памяти от 0 до 4М с использованием команды JAMP. Далее приведены имена макросов условных переходов и условные имена формальных параметров этих макросов. При вызове макросов формальные параметры должны заменяться фактическими параметрами - именами рабочих регистров, адресами или именами ячеек памяти данных, метками или фактическими значениями адресов программной памяти, значениями констант. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. Имена макросов дальних условных переходов дополнены отличительной цифрой 2. Обычно я пользуюсь макросами ближних условных переходов. Если при ассемблировании выдается ошибка "out of reach", вставляю 2 в имя макроса. Макросы с условным ассемблированием как-то "не пошли", во-первых, из-за "громоздкости", а во-вторых, из-за того, что микроконтроллеры с программной памятью до 8 Кбайт напрямую не вписываются в макроопределения, содержащие директивы условного ассемблирования (требуется дополнительный анализ типов микроконтроллеров). 2.7.2 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого регистра R (R=R16…R31) с константой I (I=0…255). Содержимое Rd не изменяется. регистра R (R=R16…R31) с константой I (I=0…255). Содержимое R не изменяется. Переход по неравенству R и I: BRIF_NEQI R, I, ADR BRIF_NEQI(R, I, ADR) BRIF2_NEQI R, I, ADR BRIF2_NEQI(R, I, ADR) Переход по равенству R и I: BRIF_EQI R, I, ADR BRIF_EQI(R, I, ADR) BRIF2_EQI R, I, ADR BRIF2_EQI(R, I, ADR) Переход, если R равен или больше I: BRIF_SHI R, I, ADR BRIF_SHI(R, I, ADR) BRIF2_SHI R, I, ADR BRIF2_SHI(R, I, ADR) Переход, если R меньше I: BRIF_LOI R, I, ADR BRIF_LOI(R, I, ADR) BRIF2_LOI R, I, ADR BRIF2_LOI(R, I, ADR) Переход, если R меньше или равен I: BRIF_SLI R, I, ADR BRIF_SLI(R, I, ADR) BRIF2_SLI R, I, ADR BRIF2_SLI(R, I, ADR) Переход, если R больше I: BRIF_HII R, I, ADR BRIF_HII(R, I, ADR) BRIF2_HII R, I, ADR BRIF2_HII(R, I, ADR) 2.7.3 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого регистра R (R=R0…R24, R26…R31) с константой I (I=0…255). Содержимое R не изменяется. Используется R25. Переход по неравенству R и I: BRIF_RNEQI R, I, ADR BRIF_RNEQI(R, I, ADR) BRIF2_RNEQI R, I, ADR BRIF2_RNEQI(R, I, ADR) Переход по равенству R и I: BRIF_REQI R, I, ADR BRIF_REQI(R, I, ADR) BRIF2_REQI R, I, ADR BRIF2_REQI(R, I, ADR) Переход, если R равен или больше I: BRIF_RSHI R, I, ADR BRIF_RSHI(R, I, ADR) BRIF2_RSHI R, I, ADR BRIF2_RSHI(R, I, ADR) Переход, если R меньше I: BRIF_RLOI R, I, ADR BRIF_RLOI(R, I, ADR) BRIF2_RLOI R, I, ADR BRIF2_RLOI(R, I, ADR) Переход, если R меньше или равен I: BRIF_RSLI R, I, ADR BRIF_RSLI(R, I, ADR) BRIF2_RSLI R, I, ADR BRIF2_RSLI(R, I, ADR) Переход, если R больше I: BRIF_RHII R, I, ADR BRIF_RHII(R, I, ADR) BRIF2_RHII R, I, ADR BRIF2_RHII(R, I, ADR) 2.7.4 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого регистра Ra (Ra=R0…R31) с содержимым регистра Rb (Rb=R0…R31). Переход по неравенству Ra и Rb: BRIF_RNEQR Ra, Rb, ADR BRIF_RNEQR(Ra, Rb, ADR) BRIF2_RNEQR Ra, Rb, ADR BRIF2_RNEQR(Ra, Rb, ADR) Переход по равенству Ra и Rb: BRIF_REQR Ra, Rb, ADR BRIF_REQR(Ra, Rb, ADR) BRIF2_REQR Ra, Rb, ADR BRIF2_REQR(Ra, Rb, ADR) Переход, если Ra равен или больше Rb: BRIF_RSHR Ra, Rb, ADR BRIF_RSHR(Ra, Rb, ADR) BRIF2_RSHR Ra, Rb, ADR BRIF2_RSHR(Ra, Rb, ADR) Переход, если Ra меньше Rb: BRIF_RLOR Ra, Rb, ADR BRIF_RLOR(Ra, Rb, ADR) BRIF2_RLOR Ra, Rb, ADR BRIF2_RLOR(Ra, Rb, ADR) Переход, если Ra меньше или равен Rb: BRIF_RSLR Ra, Rb, ADR BRIF_RSLR(Ra, Rb, ADR) BRIF2_RSLR Ra, Rb, ADR BRIF2_RSLR(Ra, Rb, ADR) Переход, если Ra больше Rb: BRIF_RHIR Ra, Rb, ADR BRIF_RHIR(Ra, Rb, ADR) BRIF2_RHIR Ra, Rb, ADR BRIF2_RHIR(Ra, Rb, ADR) 2.7.5 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого ячейки М памяти данных с константой I (I=0…255). Содержимое М не изменяется. Используется R25. Переход по неравенству М и I: BRIF_MNEQI M, I, ADR BRIF_MNEQI(M, I, ADR) BRIF2_MNEQI M, I, ADR BRIF2_MNEQI(M, I, ADR) Переход по равенству М и I: BRIF_MEQI M, I, ADR BRIF_MEQI(M, I, ADR) BRIF2_MEQI M, I, ADR BRIF2_MEQI(M, I, ADR) Переход, если М равна или больше I: BRIF_MSHI M, I, ADR BRIF_MSHI(M, I, ADR) BRIF2_MSHI M, I, ADR BRIF2_MSHI(M, I, ADR) Переход, если М меньше I: BRIF_MLOI M, I, ADR BRIF_MLOI(M, I, ADR) BRIF2_MLOI M, I, ADR BRIF2_MLOI(M, I, ADR) Переход, если М меньше или равна I: BRIF_MSLI M, I, ADR BRIF_MSLI(M, I, ADR) BRIF2_MSLI M, I, ADR BRIF2_MSLI(M, I, ADR) Переход, если М больше I: BRIF_MHII M, I, ADR BRIF_MHII(M, I, ADR) BRIF2_MHII M, I, ADR BRIF2_MHII(M, I, ADR) 2.7.6 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого ячейки М памяти данных с содержимым регистра R (R=R0…R24, R26…R31). Содержимое R не изменяется. Используется R25. Переход по неравенству М и R: BRIF_MNEQR M, R, ADR BRIF_MNEQR(M, R, ADR) BRIF2_MNEQR M, R, ADR BRIF2_MNEQR(M, R, ADR) Переход по равенству М и R: BRIF_MEQR M, R, ADR BRIF_MEQR(M, R, ADR) BRIF2_MEQR M, R, ADR BRIF2_MEQR(M, R, ADR) Переход, если М равна или больше R: BRIF_MSHR M, R, ADR BRIF_MSHR(M, R, ADR) BRIF2_MSHR M, R, ADR BRIF2_MSHR(M, R, ADR) Переход, если М меньше R: BRIF_MLOR M, R, ADR BRIF_MLOR(M, R, ADR) BRIF2_MLOR M, R, ADR BRIF2_MLOR(M, R, ADR) Переход, если М меньше или равна R: BRIF_MSLR M, R, ADR BRIF_MSLR(M, R, ADR) BRIF2_MSLR M, R, ADR BRIF2_MSLR(M, R, ADR) Переход, если М больше R: BRIF_MHIR M, R, ADR BRIF_MHIR(M, R, ADR) BRIF2_MHIR M, R, ADR BRIF2_MHIR(M, R, ADR) 2.7.7 Данные макросы обеспечивают условные переходы на метку ADR по результату сравнения содержимого регистра R (R=R0…R24, R26…R31) с содержимым ячейки М памяти данных. Содержимое R не изменяется. Используется R25. Переход по неравенству R и M: BRIF_RNEQM R, M, ADR BRIF_RNEQM(R, M, ADR) BRIF2_RNEQM R, M, ADR BRIF2_RNEQM(R, M, ADR) Переход по равенству R и M: BRIF_REQM R, M, ADR BRIF_REQM(R, M, ADR) BRIF2_REQM R, M, ADR BRIF2_REQM(R, M, ADR) Переход, если R равен или больше M: BRIF_RSHM R, M, ADR BRIF_RSHM(R, M, ADR) BRIF2_RSHM R, M, ADR BRIF2_RSHM(R, M, ADR) Переход, если R меньше M: BRIF_RLOM R, M, ADR BRIF_RLOM(R, M, ADR) BRIF2_RLOM R, M, ADR BRIF2_RLOM(R, M, ADR) Переход, если R меньше или равен M: BRIF_RSLM R, M, ADR BRIF_RSLM(R, M, ADR) BRIF2_RSLM R, M, ADR BRIF2_RSLM(R, M, ADR) Переход, если R больше M: BRIF_RHIM R, M, ADR BRIF_RHIM(R, M, ADR) BRIF2_RHIM R, M, ADR BRIF2_RHIM(R, M, ADR)

2.8 Макросы условных пропусков команд

2.8.1 Макроопределения ASM-макросов условных пропусков однословных и двухсловных команд содержится в файлах
SKIPLIB-1.asm, SKIPLIB-2.asm, SKIPLIB-1F.asm, SKIPLIB-2F.asm и в архиве MACROLIB-ALL.zip Далее приведены имена макросов условных пропусков команд и условные имена формальных параметров этих макросов. При вызове макросов формальные параметры должны заменяться фактическими параметрами - именами рабочих регистров, адресами или именами ячеек памяти данных, метками или фактическими значениями адресов программной памяти, значениями констант. Макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. Имена макросов условных пропусков двухсловных команд дополнены отличительной цифрой 2. 2.8.2 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого регистра R (R=R16…R31) с константой I (I=0…255). Содержимое R не изменяется. Пропуск команды по неравенству R и I: SKIF_NEQI R, I, ADR SKIF_NEQI(R, I, ADR) SKIF2_NEQI R, I, ADR SKIF2_NEQI(R, I, ADR) Пропуск команды по равенству R и I: SKIF_EQI R, I, ADR SKIF_EQI(R, I, ADR) SKIF2_EQI R, I, ADR SKIF2_EQI(R, I, ADR) Пропуск команды, если R равен или больше I: SKIF_SHI R, I, ADR SKIF_SHI(R, I, ADR) SKIF2_SHI R, I, ADR SKIF2_SHI(R, I, ADR) Пропуск команды, если R меньше I: SKIF_LOI R, I, ADR SKIF_LOI(R, I, ADR) SKIF2_LOI R, I, ADR SKIF2_LOI(R, I, ADR) Пропуск команды, если R меньше или равен I: SKIF_SLI R, I, ADR SKIF_SLI(R, I, ADR) SKIF2_SLI R, I, ADR SKIF2_SLI(R, I, ADR) Пропуск команды, если R больше I: SKIF_HII R, I, ADR SKIF_HII(R, I, ADR) SKIF2_HII R, I, ADR SKIF2_HII(R, I, ADR) 2.8.3 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого регистра R (R=R0…R24, R26…R31) с константой I (I=0…255). Содержимое R не изменяется. Используется R25. Пропуск команды по неравенству R и I: SKIF_RNEQI R, I, ADR SKIF_RNEQI(R, I, ADR) SKIF2_RNEQI R, I, ADR SKIF2_RNEQI(R, I, ADR) Пропуск команды по равенству R и I: SKIF_REQI R, I, ADR SKIF_REQI(R, I, ADR) SKIF2_REQI R, I, ADR SKIF2_REQI(R, I, ADR) Пропуск команды, если R равен или больше I: SKIF_RSHI R, I, ADR SKIF_RSHI(R, I, ADR) SKIF2_RSHI R, I, ADR SKIF2_RSHI(R, I, ADR) Пропуск команды, если R меньше I: SKIF_RLOI R, I, ADR SKIF_RLOI(R, I, ADR) SKIF2_RLOI R, I, ADR SKIF2_RLOI(R, I, ADR) Пропуск команды, если R меньше или равен I: SKIF_RSLI R, I, ADR SKIF_RSLI(R, I, ADR) SKIF2_RSLI R, I, ADR SKIF2_RSLI(R, I, ADR) Пропуск команды, если R больше I: SKIF_RHII R, I, ADR SKIF_RHII(R, I, ADR) SKIF2_RHII R, I, ADR SKIF2_RHII(R, I, ADR) 2.8.4 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого регистра Ra (Ra=R0…R31) с содержимым регистра Rb (Rb=R0…R31). Пропуск команды по неравенству Ra и Rb: SKIF_RNEQR Ra, Rb, ADR SKIF_RNEQR(Ra, Rb, ADR) SKIF2_RNEQR Ra, Rb, ADR SKIF2_RNEQR(Ra, Rb, ADR) Пропуск команды по равенству Ra и Rb: SKIF_REQR Ra, Rb, ADR SKIF_REQR(Ra, Rb, ADR) SKIF2_REQR Ra, Rb, ADR SKIF2_REQR(Ra, Rb, ADR) Пропуск команды, если Ra равен или больше Rb: SKIF_RSHR Ra, Rb, ADR SKIF_RSHR(Ra, Rb, ADR) SKIF2_RSHR Ra, Rb, ADR SKIF2_RSHR(Ra, Rb, ADR) Пропуск команды, если Ra меньше Rb: SKIF_RLOR Ra, Rb, ADR SKIF_RLOR(Ra, Rb, ADR) SKIF2_RLOR Ra, Rb, ADR SKIF2_RLOR(Ra, Rb, ADR) Пропуск команды, если Ra меньше или равен Rb: SKIF_RSLR Ra, Rb, ADR SKIF_RSLR(Ra, Rb, ADR) SKIF2_RSLR Ra, Rb, ADR SKIF2_RSLR(Ra, Rb, ADR) Переход, если Ra больше Rb: SKIF_RHIR Ra, Rb, ADR SKIF_RHIR(Ra, Rb, ADR) SKIF2_RHIR Ra, Rb, ADR SKIF2_RHIR(Ra, Rb, ADR) 2.8.5 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого ячейки М памяти данных с константой I (I=0…255). Содержимое М не изменяется. Используется R25. Пропуск команды по неравенству М и I: SKIF_MNEQI M, I, ADR SKIF_MNEQI(M, I, ADR) SKIF2_MNEQI M, I, ADR SKIF2_MNEQI(M, I, ADR) Пропуск команды по равенству М и I: SKIF_MEQI M, I, ADR SKIF_MEQI(M, I, ADR) SKIF2_MEQI M, I, ADR SKIF2_MEQI(M, I, ADR) Пропуск команды, если М равна или больше I: SKIF_MSHI M, I, ADR SKIF_MSHI(M, I, ADR) SKIF2_MSHI M, I, ADR SKIF2_MSHI(M, I, ADR) Пропуск команды, если М меньше I: SKIF_MLOI M, I, ADR SKIF_MLOI(M, I, ADR) SKIF2_MLOI M, I, ADR SKIF2_MLOI(M, I, ADR) Пропуск команды, если М меньше или равна I: SKIF_MSLI M, I, ADR SKIF_MSLI(M, I, ADR) SKIF2_MSLI M, I, ADR SKIF2_MSLI(M, I, ADR) Пропуск команды, если М больше I: SKIF_MHII M, I, ADR SKIF_MHII(M, I, ADR) SKIF2_MHII M, I, ADR SKIF2_MHII(M, I, ADR) 2.8.6 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого ячейки М памяти данных с содержимым регистра R (R=R0…R24, R26…R31). Содержимое R не изменяется. Используется R25. Пропуск команды по неравенству М и R: SKIF_MNEQR M, R, ADR SKIF_MNEQR(M, R, ADR) SKIF2_MNEQR M, R, ADR SKIF2_MNEQR(M, R, ADR) Пропуск команды по равенству М и R: SKIF_MEQR M, R, ADR SKIF_MEQR(M, R, ADR) SKIF2_MEQR M, R, ADR SKIF2_MEQR(M, R, ADR) Пропуск команды, если М равна или больше R: SKIF_MSHR M, R, ADR SKIF_MSHR(M, R, ADR) SKIF2_MSHR M, R, ADR SKIF2_MSHR(M, R, ADR) Пропуск команды, если М меньше R: SKIF_MLOR M, R, ADR SKIF_MLOR(M, R, ADR) SKIF2_MLOR M, R, ADR SKIF2_MLOR(M, R, ADR) Пропуск команды, если М меньше или равна R: SKIF_MSLR M, R, ADR SKIF_MSLR(M, R, ADR) SKIF2_MSLR M, R, ADR SKIF2_MSLR(M, R, ADR) Пропуск команды, если М больше R: SKIF_MHIR M, R, ADR SKIF_MHIR(M, R, ADR) SKIF2_MHIR M, R, ADR SKIF2_MHIR(M, R, ADR) 2.8.7 Данные макросы обеспечивают условные пропуски команд по результату сравнения содержимого регистра R (R=R0…R24, R26…R31) с содержимым ячейки М памяти данных. Содержимое R не изменяется. Используется R25. Пропуск команды по неравенству R и M: SKIF_RNEQM R, M, ADR SKIF_RNEQM(R, M, ADR) SKIF2_RNEQM R, M, ADR SKIF2_RNEQM(R, M, ADR) Пропуск команды по равенству R и M: SKIF_REQM R, M, ADR SKIF_REQM(R, M, ADR) SKIF2_REQM R, M, ADR SKIF2_REQM(R, M, ADR) Пропуск команды, если R равен или больше M: SKIF_RSHM R, M, ADR SKIF_RSHM(R, M, ADR) SKIF2_RSHM R, M, ADR SKIF2_RSHM(R, M, ADR) Пропуск команды, если R меньше M: SKIF_RLOM R, M, ADR SKIF_RLOM(R, M, ADR) SKIF2_RLOM R, M, ADR SKIF2_RLOM(R, M, ADR) Пропуск команды, если R меньше или равен M: SKIF_RSLM R, M, ADR SKIF_RSLM(R, M, ADR) SKIF2_RSLM R, M, ADR SKIF2_RSLM(R, M, ADR) Пропуск команды, если R больше M: SKIF_RHIM R, M, ADR SKIF_RHIM(R, M, ADR) SKIF2_RHIM R, M, ADR SKIF2_RHIM(R, M, ADR)

2.9 Макросы безусловных переходов

2.9.1 Макроопределения макросов безусловных переходов содержится в файлах
JMPLIB-1.asm, JMPLIB-1F.asm и в архиве MACROLIB-ALL.zip. Понятно, что безусловные переходы выполняются по командам AVR-ассемблера RJMP и JMP. Однако при совместном использовании с макросами условных переходов с аббревиатурой BRIF для безусловных переходов больше подходит аббревиатура BRELSE, поддерживающая СИ-стиль. Макросы, заменяющие команды RJMP и JMP, представлены в п.2.9.2. В п.2.9.3 представлен макрос безусловного косвенного перехода, позволяющий строить программные дешифраторы состояний и ветвиться по множеству направлений с минимальными затратами времени. 2.9.2 Ближний и дальний безусловные переходы на адрес ADR при невыполнении условия: BRELSE ADR BRELSE(ADR) BRELSE2 ADR BRELSE2(ADR) 2.9.3 Безусловный переход на адрес ADR со словарным смещением из регистра DR: JMP_PD ADR,DR JMP_PD(ADR,DR)

2.10 Программные дешифраторы в обработчиках прерываний

2.10.1 В устройствах обработки информации, работающих в режиме реального времени, к обработчикам прерываний обычно предъявляются жесткие требования по времени обработки прерывания. В обработчиках недопустимо выполнять многошаговый анализ значений состояний с целью ветвления по множеству направлений. Поэтому даже при написании СИ-программ такой анализ и ветвление целесообразно выполнять на ассемблере с использованием команды косвенного безусловного перехода IJMP, а точнее - макроса JMP_PD (см.п.2.9.3). По сути, такие АСМ-программы являются аналогами аппаратных дешифраторов состояний. Основу программного дешифратора образует проименованный блок команд безусловных переходов RJMP (или JMP), аналогичный блоку векторов прерываний. Число команд в блоке соответствует максимальному значению дешифрируемого состояния плюс 1. При использовании макроса JMP_PD в регистр смещения DR записывается значение состояния (умноженное на 2 для блоков команд JMP) и осуществляется безусловный переход на адрес, определяемый как сумма адреса метки указанного блока и словарного смещения из регистра DR. Далее в каждой ветке выполняется специфическая обработка состояния, после чего значение состояния изменяется и осуществляется возврат из прерывания по команде RETI. 2.10.2 Наибольшее применение программные дешифраторы нашли в обработчиках прерываний от USART-ов, входящих в состав микроконтроллеров, которые, в свою очередь, являются основой периферийных контроллеров наших систем. Напомню, что периферийные контроллеры в наших системах работают под управлением центрального системного контроллера (мастера). В качестве основного протокола обмена информацией мы используем протокол ViTa RS-485FD с фиксированным форматом кодограмм, представленным на рис.2.1. Рисунок 2.1 Размер кодограммы (14 байт) определяется размером буфера FIFO (16 байт) стандартного СОМ-порта РС-совместимого компьютера. По приему 14 байт микросхема приемо-передатчика СОМ-порта может при соответствующей настройке вырабатывать запрос на прерывание процессора РС-совместимого компьютера, что позволяет не отвлекать процессор на прием каждого байта, а принимать всю кодограмму целиком. В периферийных контроллерах с USART-ми такой возможности нет и прерываться приходится по приему каждого байта. В связи с этим, один из рабочих регистров периферийного контроллера определяется в качестве регистра состояния интерфейса RS-485FD. Ему мы обычно присваиваем имя SRS. В регистр SRS записывается в двоичном коде номер состояния интерфейса RS-485FD для данного периферийного контроллера: 0-исходное состояние (ожидание @) 1-принята @ (ожидание А1) 2-принят старший знак адреса A1(ожидание А0) 3-принят младший знак адреса A0(ожидание С) 4-принята своя команда С(ожидание D7) 5-принят 1-й свой байт D7 в буфер(ожидание D6) 6-принят 2-й свой байт D6 в буфер(ожидание D5) ... 12-принят 8-й свой байт D0 в буфер(ожидание S) 13-принята своя верная контрольная сумма S(ожидание *) 14-принята своя * (ожидание программного переключения в состояние 27) 15-принят старший знак чужого адреса A1 16-принят младший знак чужого адреса A0 17-принята чужая команда или ответ C 18-принят 1-й чужой байт D7 19-принят 2-й чужой байт D6 ... 25-принят 8-й чужой байт D0 26-принята чужая контрольная сумма S 27-передана @ ответа на команду C 28-передан старший знак своего адреса A1 29-передан младший знак своего адреса A0 30-передан код ответа C 31-передан 1-й байт данных D7 32-передан 2-й байт данных D6 ... 38-передан 8-й байт данных D0 39-передана контрольная сумма S 40-передана * Периферийный контроллер в процессе круглосуточной работы непрерывно "держит фазу" как по байтам, передаваемым в интерфейсе RS-485FD, так и по кодограммам, причем и своим и чужим. При таком подходе подключение и отключение контроллера допускается выполнять "на горячую" и при этом работа системы в целом не нарушается. Каждое из состояний имеет свою ветку обработки, выход на которую осуществляется с помощью макроса JMP_PD(DECSRS,SRS) через блок команд безусловных переходов c меткой DECSRS. Для состояний с 15 по 26 в блоке DECSRS вместо команд безусловного перехода могут записываться команды RETI (или пары команд RETI NOP), поскольку никакой обработки такие прерывания не требуют. 2.10.3 При желании, состояния приема и передачи байтов данных можно объединять в отдельные обобщенные состояния с параметром отсчета принятых и переданных байтов (N). Параметр N мы используем при реализации протокола ViTa RS-485VD с переменным форматом кодограмм. Согласно этому протоколу одна кодограмма может содержать от 0 до 224 байт информации. Параметр N, определяющий число принимаемых и передаваемых в периферийное устройство по интерфейсу RS-485VD информационных байтов, включен отдельным байтом в формат кодограммы протокола, как показано на рис.2.2. Рисунок 2.2 По протоколу ViTa RS-485VD мы реализуем работу с такими периферийными устройствами как модемы дальней низкоскоростной проводной связи. В канал связи через модем отправляется только информационная часть D0 ... D(N-1) кодограммы рис.2.2. Соответственно, принятый модемом из канала связи информационный пакет включается на правах составной части D0 ... D(N-1) в кодограмму рис.2.2 и отправляется по интерфейсу RS-485VD в центральный системный контроллер. При реализации обработчиков прерываний интерфейса RS-485VD, также как и интерфейса RS-485FD, используется программный дешифратор состояния интерфейса с тем же макросом JMP_PD(DECSRS,SRS). 2.10.4 Еще одной "сферой" применения программных дешифраторов, связанной с обработчиками прерываний, являются так называемые программные прерывания. В ассемблере IBM PC программные прерывания реализуются с помощью специальной команды INT с числовым параметром Db, по которому вычисляется адрес обработчика программного прерывания. В AVR-ассемблере такой команды нет, но тем не менее, в документации предлагается реализовывать программные прерывания используя один из физических входов/выходов микроконтроллера. Изменению сигнала на этом выводе в блоке векторов прерываний микроконтроллера должен соответствосать отдельный вектор прерывания, обеспечивающий переход к обработчику, например по адресу EXT_INT0 или EXT_INT1. Программа может инициировать запрос на прерывание и переход на указанный вектор путем изменения уровня сигнала на данном входе/выходе. При начальной настройке микроконтроллера данный вход/выход устанавливается в режим выхода, что не мешает схеме прерываний реагировать на изменения сигналов на этом входе/выходе. Программное прерывание предлагаю реализовывать с помощью макроса PINT: .MACRO PINT LDI ZH,HIGH(@0) LDI ZL,LOW(@0) ADIW ZH:ZL,@1 SBI @2,@3 .EMDMACRO @0 - метка блока векторов программных прерываний (массива безусловных переходов на обработчики программных прерываний); @1 - числовой идентификатор программного прерывания (0,1....63); @2 - имя порта ввода/вывода (PORTA,PORTB,PORTC,PORTD,PORTE); @3 - номер бита прерывания 0,1 ...7. Общий обработчик программных прерываний, размещенный по адресу EXT_INT0 или EXT_INT1, может состоять из единственного макроса PINTHANDLER, который сбрасывает в 0 уровень сигнала на входе/выходе программного прерывания и выполняет безусловный косвенный переход на вектор программного прерывания, соответствующий числовому идентификатору прерывания: .MACRO PINTHANDLER CBI @0,@1 IJMP .EMDMACRO @0 - имя порта ввода/вывода (PORTA,PORTB,PORTC,PORTD,PORTE); @1 - номер бита прерывания 0,1 ...7. Каждый индивидуальный обработчик программного прерывания должен заканчиваться командой возврата из прерывания RETI, как и обычный обработчик аппаратного прерывания. В заключение хочу отметить, что программное прерывание, также как подпрограмма и макрос, является одним из возможных способов задания функции в АСМ-программах. У этого способа есть свои особенности - приоритет исполнения функции и автоматическое (аппаратное) управление флагом разрешения/блокировки прерываний. Полагаю, что в определенных случаях это может пригодиться.

2.11 Управление знакосинтезирующими индикаторами

2.11.1 Затрудняюсь судить об актуальности задач управления знакосинтезирующими индикаторами. При современном уровне микроэлектроники и повсеместном внедрении сенсорных экранов модули индикации DV-16110 и DV-40400, об управлении которыми я хочу рассказать, некоторым покажутся "динозаврами", вроде вакуумных ламп. Но тем не менее, мы достаточно широко применяли их в удаленных от центрального системного контроллера пультах ввода и отображения информации, и никаких замечаний от потребителей в части "несовременности" не получали. А уж встроенный в эти модули контроллер KS0066U до сих пор мне представляется чуть ли не верхом совершенства. Думаю, что подобные модули еще послужат на благо человечества. В подразделе 3.5 рассмотрены схемы управления указанными модулями индикации. Эти схемы реализованы на микроконтроллере ATmega162, который выбран прежде всего из-за наличия двух USART-ов - один требовался для связи с центральным системным контроллером, а другой для связи со считывателем радиокарт. Кроме того, микроконтроллер ATmega162 обрабатывал и сигналы подключенной к нему клавиатуры, в общем - все как положено в удаленных пультах. 2.11.2 Конечно, программное обеспечение микроконтроллера реализовывалось в среде ОСРВ-ПА (см.раздел 1), поскольку микроконтроллер должен был одновременно выполнять несколько задач. Среди них есть и задачи управления индикатором. Алгоритмические схемы задач управления индикаторами представлены на рис.2.3, 2.4, 2.5, 2.6, 2.7. Алгоритмические схемы представлены в форме системы функциональных блоков в соответствии с идеологией операционной среды ОСРВ-ПА(п.1.6). О каждой из этих схем скажу несколько слов. 2.11.3 Задача 1, алгоритмическая схема которой представлена на рис.2.3, предназначена для инициализации контроллеров KS0066U, управляющих индикаторами. Индикатор DV-16110 содержит один такой контроллер, а DV-40400 - два. Для управления первым контроллером индикатора DV-40400, также как и для управления контроллером индикатора DV-16110, используется синхросигнал WR_1, а для управления вторым контроллером - синхросигнал WR_2 (см. п.3.5.1). Других отличий в кодах и алгоритмах программ управления первым и вторым контроллерами индикатора DV-40400 нет. Рисунок 2.3 Функциональный блок FB2_1 задачи 1 устанавливает индикаторы в так называемый двухстрочный режим, который позволяет выводить знаки на индикацию "восьмерками", то есть по восемь знаков. После вывода восьмого знака 8-ки на индикатор выдается начальный адрес следующей 8-ки. Именно такой способ управления был нами использован для различных индикаторов серии DV. Главное - не ошибаться с адресом 8-ки и все получится. Не сомневаюсь, что есть и другие, более "правильные" способы управления, но этот достаточно "прозрачен" и главное - работает. Период активизации функциональных блоков задач индикации, в том числе и задачи 1, выбран равным системному кванту - 1 мс. Эта величина значительно превышает время исполнения индикаторами большинства команд. Но есть команды, требующие больше времени на исполнение. Так например, команда очистки дисплея, посылаемая на индикатор при активизации FB4_1, требует для своего исполнения не менее 1,53 мс. Для выполнения этого требования переход к следующему функциональному блоку FB5_1 в блоке FB4_1 должен выполняться с использованием макроса перехода с задержкой на 2 мс - DNEXT(FB5_1,2). Данный макрос применяется и в других задачах управления, в которых используются операции очистки или начальной установки окна дисплея. 2.11.4 Задача 2 ( рис.2.4 ) используется для вывода на индикатор стандартного сообщения фиксированной длины, хранящегося в памяти программ в виде строки знаков. Для индикатора DV-16110 длина стандартного сообщения составляет 16 байт. Сообщению присваивается метка-имя, по которому осуществляется последовательная выборка кодов знаков и передача их в индикатор. Задача 2 с незначительными изменениями, и понятно под другим номером, используется также для вывода на индикатор сообщений, сформированных логически в буфере RAM. Рисунок 2.4 Непосредственный вывод знаков осуществляет функциональный блок FB2_2. Этот блок имеет 3 выхода: - сам на себя для вывода знаков одной 8-ки; - на FB3_2 для перехода к выводу знаков следующей 8-ки; - на FB5_2 для завершения задачи 2. Два входа блока FB2_2 идентифицируются значением счетчика переданных знаков R. В СИ-программах, работающих в среде ОСРВ-ПА "КВАНТОС", функциональные блоки вызываются по своему имени, то есть имеют единственный явный вход (в нашем случае FB2_2). Далее, используя значения контекста задачи (счетчика переданных знаков R), программа разветвляется, образуя неявные входы, идентифицируемые значениями этого счетчика. В АСМ-программах переходы выполняются непосредственно на отдельные входы функционального блока, имеющие собственные метки-имена FB2_2_R0 и FB2_2_RN. 2.11.5 Еще одной полезной задачей управления индикатором является задача вывода знака на индикацию в заданное знакоместо индикатора. Алгоритмическая схема такой задачи представлена на рис.2.5. В блоках FB2_3 и FB4_3 заданный номер знакоместа постоянно сравнивается с числом сдвигов курсора и при положительном результате сравнения выполняется вывод знака на индикацию. Рисунок 2.5 2.11.6 Для вывода стандартного сообщения на отдельную строку или на пару строк индикатора DV-40400, наиболее сложного из всей серии индикаторов DV, применяется алгоритм, представленный на рис.2.6, подобный алгоритму задачи 2, рассмотренной в п.2.11.4. В используемом нами двухстрочном режиме работы индикаторов, начальные адреса восьмерок первой и второй строк индикатора DV-40400, так же как и начальные адреса третьей и четвертой строк, образуют последовательность 0, 8, 16, 24, 32, 64, 72, 80, 88, 96. Первые пять начальных адресов последовательности относятся к первой(третьей) строке индикатора, а вторые - ко второй(четвертой) строке. По завершению вывода знаков каждой 8-ки на индикатор передается адрес следующей 8-ки. Рисунок 2.6 2.11.7 Вывод текста на все 4 строки индикатора DV-40400 реализуется задачей 5, алгоритмическая схема которой представлена на рис.2.7. В качестве знака завершения индицируемого текста мы используем знак "=" ( 0х3D ). Для индикации текстов, превышающих 160 знаков, не сложно сделать и построчный сдвиг индикации с освобождением нижней строки. Рисунок 2.7 2.11.8 Бесспорно, алгоритмические схемы при создании программ как минимум полезны, а в ряде случаев просто необходимы, но за работоспособность устройств отвечают все же программные фрагменты, скрытые внутри функциональных блоков. Для реализации этих программных фрагментов были разработаны специальные макросы. Они обеспечивают стандартные операции записи команд и данных(знаков) в индикаторы. Их макроопределения приведены в файлах
INDLIB-1.asm и INDLIB-1F.asm. 2.11.9 Далее приведены имена и формы вызова макросов управления индикацией. Как обычно, макросы представлены в двух формах - классической ассемблерной форме и функциональной СИ-подобной форме. Запись команды C (Используется регистр R16): INDWRC C INDWRC(C) Запись команды из регистра R (R=R0...R31): WRC R WRC(R) Запись знака D (Используется регистр R16): INDWRD D INDWRD(D) Запись знака из регистра R (R=R0...R31): WRD R WRD(R) Вызов сообщения из программной памяти по имени P. Макрос переписывает из программной памяти адрес первого слова сообщения в ячейки RAM - INDPAR1, INDPAR2 и сбрасывает счетчик знаков CHARCNT: IND P IND(P) Вызов сообщения из буфера RAM по имени M. Макрос записывает адрес первого знака сообщения в ячейки RAM - ВINDPAR1,ВINDPAR2 и сбрасывает счетчик знаков ВCHARCNT. Длина сообщения записывается в ячейку CHARLEN: BIND M BIND(M) 2.11.10 Из приведенных в пп. 2.11.3 - 2.11.7 алгоритмов задач управления индикаторами можно видеть, что все они заканчиваются макросом самоостанова. Следовательно эти задачи должны вызываться и вызываются из других задач управления, более высокого уровня. В таких задачах часто используются специализированные функциональные блоки, обеспечивающие выдержку(фиксацию) индицируемой информации на индикаторе в течение нескольких секунд, а также блоки захвата индикатора, используемого несколькими различными задачами управления высшего уровня. 2.11.11 Фиксация индикации выполняется путем многократного перезапуска блока выдержки с помощью макроса выхода из функционального блока с задержкой - DNEXT (см.раздел 1). 2.11.12 Для захвата индикатора задачей управления используется одна или несколько флажковых ячееек RAM. Если индикатором, как общим ресурсом пользуются две задачи, достаточно одной флажковой ячейки. Для трех задач необходимо две и т.д. Допустим, что индикатор совместно используют три задачи, и мы определили две флажковых ячейки - FLAGIND_1 и FLAGIND_0. Перед выводом информации на индикатор каждая из трех задач проверяет состояние флажковых ячеек, FLAGIND_1 и FLAGIND_0. По результатам проверки задача выполняет следующие действия: 00 - индикатор свободен, очередь пуста; Задача захватывает индикатор, устанавливая состояние ячеек 01; 01 - индикатор занят, но очередь пуста; Задача занимает очередь на захват индикатора, устанавливая состояние ячеек 11, и повторяет попытку захвата индикатора через таймаут; 10 - индикатор свободен, но в очереди стоит задача; Если в очереди стоит сама задача, то она захватывает индикатор и устанавливает состояние ячеек 01; В противном случае задача повторяет попытку захвата индикатора или записи в очередь через таймаут; 11 - индикатор занят и в очереди стоит задача; Задача повторяет попытку захвата индикатора или записи в очередь через таймаут. По завершению индикации задача сбрасывает ячейку FLAGIND_0.