AVR. Учебный курс. Макроассемблер
Автор DI HALT
Опубликовано 05 июля 2008
Рубрики: AVR. Учебный курс
Метки: Assembler, AVR, Макро язык
Перед изучением системы команд микроконтроллера надо бы разобраться в инструментарии. Плох тот плотник который не знает свой топор. Основным инструментом у нас будет компилятор. У компилятора есть свой язык — макроассемблер, с помощью которого жизнь программиста упрощается в разы. Ведь гораздо проще писать и оперировать в голове командами типа MOV Counter,Default_Count вместо MOV R17,R16 и помнить что у нас R17 значит Counter, а R16 это Default_Count. Все подстановки с человеческого языка на машинный, а также многое другое делается средствами препроцессора компилятора. Его мы сейчас и рассмотрим.
Комментарии в тексте программы начинаются либо знаком “;“, либо двойными слешами “//“, а еще AVR Studio поддерживает Cишную нотацию комментариев, где коменты ограничены “колючей проволокой” /* коммент */.
Оператор .include позволяет подключать в тело твоей программы кусок кода из другого текстового файла. Что позволяет разбить большую исходник на кучу мелких, чтобы не загромождать и не мотать туда сюда огромную портянку кода. Считай куда ты воткнул .include туда и вставился кусок кода из другого файла. Если надо подключать не весь файл, а только его часть, то тебе поможет директива .exit дойдя до которой компилятор выйдет из файла.
Оператор .def позволяет привязать к любому слову любое значение из ресурсов контроллера — порт или регистр. Например сделал я счетчик, а считаемое значение находится в регистре R0, а в качестве регистра-помойки для промежуточных данных я заюзал R16. Чтобы не запутаться и помнить, что в каком регистре у меня задумано я присваиваю им через .def символические имена.
1 2 | .def schetchik = R0 .def pomoika = R16 |
И теперь в коде могу смело использовать вместо официального имени R0 неофицальную кличку schetchik
Одному и тому же регистру можно давать кучу имен одновременно и на все он будет честно откликаться.
Также есть оператор .undef после которого компилятор напрочь забывает, что данной переменной что либо соответствовало. Иногда бывает удобно. Когда одно и то же символическое имя хочется присвоить разным ресурсам.
1 | .undef pomoika |
Оператор .equ это присвоение выражения или константы какой либо символической метке.
Например, у меня есть константа которая часто используется. Можно, конечно, каждый раз писать ее в коде, но вдруг окажется, что константа выбрана неверно, а значит придется весь код шерстить и везде править, а если где-нибудь забудешь, то получишь такую махровую багу, что задолбаешься потом ее вылавливать. Так что нафиг, все константы писать надо через
.equ! Кроме того, можно же присвоить не константу, а целое выражение. Которое при компиляции посчитается препроцессором, а в код пойдет уже исходное значение. Надо только учитывать, что деление тут исключительно целочисленное. С отбрасыванием дробной части, без какого-либо округления, а значит 1/2 = 0, а 5/2 = 2
1 2 3 | .equ Time = 5 .equ Acсelerate = 4 .equ Half_Speed = (Accelerate*Time)/2 |
Директивы сегментации. Как я уже рассказывал в посте про архитектуру контроллера AVR память контроллера разбита на независимые сегменты - данные (ОЗУ), код (FLASH), EEPROM
Чтобы указать компилятору, что где находится применяют директивы сегментации и адресации.
.CSEG сегмент кода, он же флеш. После этой директивы идет тело программы, комманды процессора. Тут же можно засунуть какие нибудь данные которые не меняются, например таблицу с заранее посчитаными значениями, статичный текст или таблицу символов для знакогенератора.
В сегменте кода уместны директивы:
Адресная метка. Любое слово, не содержащее пробелов и не начинающееся с цифры, главное, чтобы после него стояло двоеточие.
1 2 3 | .CSEG label: LDI R16,'A' RJMP label |
В итоге, после компиляции вместо label в код подставится адрес команды перед которой стоит эта самая метка, в данном случае адрес команды LDI R16,’A’
Адресными метками можно адресовать не только код, но и данные, записанные в любом сегменте памяти. Об этом чуть ниже.
.ORG address означет примерно следующее “копать отсюда и до обеда”, т.е. до конца памяти. Данный оператор указывает с какого адреса пойдет собственно программа. Обычно используется для создания таблицы прерываний.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | .CSEG .ORG 0x0000 RJMP Start ;перепрыгиваем таблицу векторов. .ORG INT0addr ; External Interrupt0 Vector Address RJMP INT0_expection .ORG INT1addr ; External Interrupt1 Vector Address RETI .ORG OC2addr ; Output Compare2 Interrupt Vector Address RJMP PWM_1 .ORG OVF2addr ; Overflow2 Interrupt Vector Address RETI .ORG ICP1addr ;Input Capture1 Interrupt Vector Address RETI .ORG 0х0032 ; Начало основной программы Start: LDI R16,0x54 ; и понеслась |
Статичные данные пихаются в флеш посредством операторов
.db массив байтов.
.dw массив слов - два байта.
.dd массив двойных слов - четыре байта
.dq массив четверных слов - восем байт.
1 2 3 | Constant: .db 10 ; или 0хAh в шестнадцатеричном коде Message: .db "Привет лунатикам" Words: .dw 10, 11, 12 |
В итоге, во флеше вначале будет лежать число 0А, затем побайтно будут хекскоды символов фразы “привет лунатикам”, а дальше 000A, 000B, 000С.
Последнии числа, хоть сами и невелики, но занимают по два байта каждое, так как обьявлены как .dw.
.DSEG сегмент данных, оперативка. Те самые жалкие считанные байты. Сюда не зазорно пихать перменные, делать тут буффера, тут же находится стек.
Тут действует оператор .BYTE позволяющий указать на расположение данных в памяти.
1 2 | var1: .BYTE 1 table: .BYTE 10 |
В первом случае мы указали переменную var1 состоящую из одного байта.
Во втором случае у нас есть цепочка из 10 байт и переменная table указывающая на первый байт из цепочки. Адрес остальных вычисляется смещением.
Указывать размеры перменных нужно для того, чтобы компилятор их правильно адресовал и они не налезали друг на друга.
.EESEG сегмент EEPROM, энергонезависимая память. Можно писать, можно считывать, а при пропаже питания данные не повреждаются.
Тут действуют те же директивы что и в flash — db, dw, dd, dq.
MACRO - оператор макроподстановки. Вот уж реально чумовая вещь. Позволяет присваивать имена целым кускам кода, мало того, еще параметры задавать можно.
1 2 3 4 | .MACRO SUBI16 ; Start macro definition subi @1,low(@0) ; Subtract low byte sbci @2,high(@0) ; Subtract high byte .ENDM ; End macro definition |
@0, @1, @2 это параметры макроса, они нумеруются тупо по порядку. А при вызове подставляются в код.
Вызов выглядит как обычная команда:
1 | SUBI16 0x1234,r16,r17 |
После имени через запятую передаются параметры, которые подставятся в код.
Макросы позволяют насоздавать себе удобных команд на все случаи жизни, по сути создать свой язык. Но надо помнить, что каждый макрос это тупо кусок кода, поэтому если макрос получается большой, то его лучше оформить в виде процедуры или функции - будет резкая экономия места в памяти, но выполняться будет чуток медленней.
Макроассемблер это мощнейшая штука. По ходу пьесы я буду вводить разные макросы и показывать примеры работы макроопределений.
Комментарии
85 комментариев на «AVR. Учебный курс. Макроассемблер»
Оставьте свой отзыв
Вы должны войти, чтобы оставлять комментарии.





1. Не понял про директиву .ORG Можно поподробнее?
2. В коде
Message: .db “Привет инопланетные придурки
по всей видимости упущена закрывающая кавычка.
3. Не понтно про
var1: .BYTE 1 - зачем это нужно? как можно применить?
4. Самое главное :). Рискуя показаться не в меру наглым, прошу сообщить мне свой e-mail, что бы я вам надоедал всякими вопросами, которые не получается приткнуть ни в одной теме на этом сайте. Просто мне не у кого больше спросить.
Если не хотите выкладывать свой адрес здесь, можно просто написать мне письмо. Мой адрес: мой_ник@gmail.com
Обещаю сильно не надоедать. :)
Мыло твоё уже нашёл. Буду писать. :)
директива ORG говорит компилятору - Копать отсюда и до конца.
Т.е. у тебя память идет последовательно 0..1..2..3..4..5 и так до самого конца. Если ничего не указывать, то компилер команды забьет начиная с нуля. А если сказать, что у нас ORG 5 то уже будут записываться начиная с 5го адреса.
Да, кавычку забыл. Надо будет поправить.
Для того, чтобы у тебя в ОЗУ был зарезервирован байт и был адрес на него. А уж что с этим байтом ты будешь делать тебе решать. Я как переменные использую.
А… с var1: .BYTE 1 понятно.
Просто в обычном ассемблере х86 я под переменные использовал
Name: .db 10, 156,34
а здесь так делать нельзя, т.к. память раздельная… Упустил этот момент.
отправь куданибудь, где можно толково почитать про обычный ассемблер, т.к. подразумевается, что читатель его уже знает. Желательно попроще, сам 2 курс и знаком только с приплюснутым…
Обычный это какой?
Хм, глупость сморозил. На николаев.орг нашел все. Буду разбираться, не шибко страшно вроде. :[
Хм, глупость сморозил. На николаев.орг нашел все. Буду разбираться, не шибко страшно вроде. :[ а имелось ввиду основы, регистры и прочее, команды…
WP Ajax Edit Comments - не работает почему-то ( пишет “загружаем” и все…
Купил давеча ATmega16-16PU и чёт нигде не могу найти что означает маркировка 16PU…
16Мгц максимальная частота. Корпус PDip, коммерческий температурный диапазон (-5…40С)
Благодарю!
не понятно с директивой .equ. вот кусок кода, который не работает должным образом:
;+Установка времени следующего срабатывания Timer0
; Параметры: @0 - число тиков, через которое сработает таймер
; Модифицирует: R16
.MACRO st0of
outi TCNT0, $FF-@0
.ENDMACRO
.equ XTAL = 8000000 ; Частота МК
.equ t0_divider = 256 ; Предделитель timer0
.equ impulse_time = 1200; ; Время в микросекундах
.equ t0_ticks = (XTAL*impulse_time)/(t0_divider*1000000) ; Время в тиках
st0of t0_ticks ; Задаем время до срабатывания (в тиках)
если поставить
st0of 37
то все работает на ура
Гхм, может слишком много вложенных макросов?
У тебя в макросе St0of макрос outi плюс сложная макроподстановка. Попробуй вынести FF-@0 в отдельный EQU
Да, кстати, результат вычисления какой получается? Целый?
неа. дробный, но мне целое число нужно. пофиг как округленное
В принципе задал значение 1152 вместо 1200 чтобы при любых (>=2MHz) частотах XTAL был целый результат (хочу сделать универсально) - все заработало, но вопрос остался - Как макросредствами делать целочисленное деление?
Странно, но вот такой код работает на ура даже с учетом того, что дробное значение получается
ХЗ. В Хелпе к студии есть описание макроязыка. По моему там получается как с типом int - т.е. дробная часть просто теряется.
А ну так тут ты явно привел все к однобайтному результату взяв сразу Low байт и все дела. А там ты пытался напрямую сложить в однобайтный регистр двубайтное (или более) число, вот компилятор и не понял, что ты пытался ему скормить.
Че то я не совсем понял, чем отличаются директивы .def и .equ
equ означает что “Теперь вот это слово равно/эквивалентно этому числу и вместо числа может быть слово”
def означает что “Теперь этот регистр можно обозвать еще и таким словом ”
Регистру мы можем присвоить кучу разных имен и это не будет ошибкой (варнинг будет, но на него можно забить)
А вот заэквивалентить одному слову несколько чисел уже нельзя (наоборот, разным словам одно число - запросто, без проблем).
т.е. как дефайн в си
.def OPA r16
.def OPA r17
А вот equ, это что-то вроде макро константы
а моджете прикрепить в конце статьи http://www.atmel.ru/Articles/Atmel11.htm для более глубоко ознакомления.. или не требуется?
В принципе, не проблема. Чуть позже добавлю.
жду инфу про арифметические (ну и про логические операции) на асм
и если можно то и комбинации арифметических операций например для вычисления синуса (макросом или процедурой\функцией?)
спасибо
Функции в подавляющем большинстве случаев, проще задавать таблицей. Вычислять их - дикий расход памяти и быстродействия.
Вычислять их - дикий расход памяти и быстродействия.
—-
ну да.. в ряд тейлора (циклом) до необходимой точность.. это мучительно для проца и памяти МК
задавать таблицей в томто и дело и неподходит…
ладно раскужу что хочу
хочеца сделать чтото типа мидиконтроллер - тоесть контроллер генерирующий звук при подключенной к нему некоторой клавиатуре… -но т.к. миди то нужно хранить семплы гдето например в ееprom- но памяти этой в МК будет очень мало (надо “допаивать” 24хх)
тогда яже свел задачу к генерации.. формулами - это экономит ROM память но предпожил что процессор потянет вычисления.. я так понял из ваших слов непотянет..
да и самое сложное в моей идее - это подбор формул легче семплами
допустим выбрал метод семплы.. а вот нет идеи как их ээ микшировать\сумировать(когда нажаты две и более кнопки на клавиатуре)? (повидимум програмно но как.. прирывания - нет имхо, акакже)
Ну почему не потянет - потянет, только сожрет много ПЗУ.
А что из себя представляет сэмпл?
впринципе как ты и сказал “проще задавать таблицей”
впринципе семпл wav файл (а в реале миди семпл я незнаю, но возможно также)
тоесть мидиконтроллером управляем семплами: изменить скорость воспроизведения(нота), продолжительность, громкость… и т.д.
но семплы не мало занимают места как уже понятно…
например если делать семплы wav то каждый будет весить гдето по 4-8КБ
только сожрет много ПЗУ.
—-
может ОЗУ?
кстати очееень жду статейку про подключение к МК озу
для тех МК в которых это поддерживается (типа мега8515 ) и для тех кто не поддерживает но можно(если можно) реализовать програмно
а также про dram (валяется планка сим.. думаю какбы примостырить к МК)
впринципе как ты и сказал “проще задавать таблицей”
—-
так и называют wavetable
Можно использовать синтезаторы типа YM3812 или аналогичные. Синтезировать качественно многоканальный звук из сэмплов или функционально с помощью 8разрядного МК задача если и решимая, то с качеством звука как из китайских говорящих кукол.
Здравствуйте! DI HALT, не могли ли вы написать (может быть макрос) как из переменной table (table:.BYTE 10) считать побайтно символы?
Заранее благодарен за ответ!
ПОбайтно? Хм.
Проще вот так:
LDS R16,Table ; первый байт
LDS R16,Table+1 ; второй байт ну и так далее.
Если надо программно выбирать значение, то тут есть другой подход.
LDI XL,low(table)
LDI XH,High(table)
LD R16,X
; считать первый байт или
LD R16,X+
;считать первый байт и после увеличить Х на 1
Ну или вручную складывать регистровую пару Х с константой-смещением. Вариантов тьма. Что что, а инструментарий работы с ОЗУ у AVR очень богатый.
А можно по подробней об ОПЕРАТОРАХ .equ .def !? К примеру, возможно ли присвоить имя не регистру, а скажем порту или даже лучше конкретному пину порта!? Возможно, ли определенным ИМЕНАМ присвоить значение?!
Очень хочется статейки по различным интерфейсам, и самое главное про библиотеки, и по подробней!
можно.
def работает ТОЛЬКО с регистрами. А вот имена портов это не более чем equ под имя порта, все они прописаны в inc файле соответствующего мк.
вот у меня обычно такая ботва:
.def COK = R26
.def SEDOK = R27
.def Catch = R28
.def Armed = R29
.equ R_ON = 6
.equ R_ON_P = PORTB
.equ R_ON_D = DDRB
.equ R_EN = 7
.equ R_EN_P = PORTB
.equ R_EN_D = DDRB
То есть получается (.equ R_ON = 6) R_ON 6-ой пин неизвестного пора ; (.equ R_ON_P = PORTB) R_ON_P все пины портаВ. А совместить не как не получится? К примеру, я хочу управлять 4 пином ddrC, 5 пином ddrC по отдельности и каждому присвоить свое имя, допустим scl ddrC,4; sda ddrC,5 и потом уже в коде так
Sbi sda
Sbi scl
Cbi sda
Sbrc sda
Не, не получится.
Только SBI IIC_PORT,SDA
Но никто не мешает сделать тебе макрос, например:
.MACRO SBI_SDA
SBI IIC_PORT,SDA
.ENDM
И юзать в своей программе
SBI_SDA как одну команду. Тока макросы тогда уже удобней звать, например так:
SDA_H
SDA_L
Di Halt, я не понял как кусок проги или всю её сделать как макрос и юзать. Например вот я не давно изучал динамическую индикацию, вот как всю её или часть забахать макрос и как задавать параметры то есть заюзать:
; Выполняемые функции: Динамическая индикация
;__________________________________________________________________________
.device ATtiny2313
.nolist
.include “d:\avr\def\tn2313def.inc”
.list
;=====================================================================
; Объявления:
.def temp1=r1
.def temp2=r2
.def n_digit=r3
.def counter=r4
.def digit_out=r5
.def n_point=r6
.def temp=r16
.equ crystal=6000000 ;частота кварца
.equ Sciler=1024 ;предделитель таймера
.equ N_TC0_2500uc=255-crystal/(Sciler*400);число тиков таймера ТС0 для организации
;задержи при динамической индикации
.equ amount_digit=4 ;маска, нужно ввести количество разрядов индикатора
;в данном случае 4-х разрядный индикатор
;======================================================================
; Начало программы:
.dseg
Digit: .byte 4
Point: .byte 1
.cseg
.org 0
rjmp RESET ;Reset Handler
nop ;rjmp INT0 ;External Interrupt0
nop ;rjmp INT1 ;External Interrupt1
nop ;rjmp ICP1 ;Input capture interrupt 1
nop ;rjmp OC1A ;Timer/Counter1 Compare Match A
nop ;rjmp OVF1 ;Overflow1 Interrupt
rjmp OVF0 ;Overflow0 Interrupt
nop ;rjmp URXC0 ;USART0 RX Complete Interrupt
nop ;rjmp UDRE0 ;USART0 Data Register Empty Interrupt
nop ;rjmp UTXC0 ;USART0 TX Complete Interrupt
nop ;rjmp ACI ;Analog Comparator Interrupt
nop ;rjmp PCINT ;Pin Change Interrupt
nop ;rjmp OC1B ;Timer/Counter1 Compare Match B
nop ;rjmp OC0A ;Timer/Counter0 Compare Match A
nop ;rjmp OC0B ;Timer/Counter0 Compare Match B
nop ;rjmp USI_START ;USI start interrupt
nop ;rjmp USI_OVF ;USI overflow interrupt
nop ;rjmp ERDY ;EEPROM write complete
nop ;rjmp WDT ;Watchdog Timer Interrupt
; for compatibility purpose
;======================================================================
; Инициализация
RESET:
ldi temp,low (RAMEND) ;Определение начала стека
out SPL,temp
ldi temp,0b0001111 ;Конфигурирование портов
out DDRD,temp ;Порт D вход\выход
ser temp
out DDRB,temp ;Порт B выход
out PIND,temp ;Команда для отладчика
out PORTD,temp ;Включаем подтягивающие резисторы
out PORTB,temp ;Выключаем матрицу
ldi temp,15 ;Инициализация сторожевого таймера
out WDTCR,temp
rcall TNCT_0 ;Инициализация таймера ТС0
;======================================================================
; для проверки работы индикатора выводит на индикатор число 4321
; запятая во втором знакоместе
ldi Temp,4
sts Digit ,Temp ;загрузка начальных значений число 4321
ldi Temp,3
sts Digit+1,Temp
ldi Temp,2
sts Digit+2,Temp
ldi Temp,1
sts Digit+3,Temp
ldi Temp,1
sts Point,Temp ;загрузка номера разряда запятой 2-й разряд
clr counter
;======================================================================
; Основной блок программы
main:
wdr ;”Бросим кость собаке”
rjmp main ;Начинаем всё сначала
;=======================================================================
; Инициализация таймеров
TNCT_0:
cli ;запрещаем прерывания
ldi temp,N_TC0_2500uc ; инициализируем таймер Т\С0 на Т=0,0025 с
out TCNT0,temp
ldi temp,0b00000000
out TCCR0A,temp
ldi temp,(1<<CS02)+(1<<CS00) ;прескайлер таймера 1024
;ldi temp,(1<<CS00) ;прескайлер таймера 1 для отладки
out TCCR0B,temp
ldi temp,(1<<TOIE0) ;прерывания Т\С0 по переполнению
out TIMSK,temp
sei
reti
;========================================================================
; Обработчик прерываний
OVF0:
rcall TNCT_0 ;Инициализация таймера ТС0
ldi ZL,Low(Digit) ;инициализация массива
ldi ZH,High(Digit)
clr temp2
add ZL,counter ;выбираем нужный номер ячейки
adc ZH,temp2
ld digit_out,Z ;загружаем ячейку
lds n_point,Point
rcall Decoder_n_digit
rcall Decoder
out PORTD,n_digit
out PORTB,digit_out
inc counter ;увеличиваем номер разряда
mov temp,counter
andi temp,(amount_digit-1) ;отсекаем количество разрядов по маске
mov counter,temp
reti
;=========================================================================
; Подпрограммы
Decoder:
;преобразует десятичную цифру разряда в 7-ми сегментный код индикатора
clr temp
ldi ZL,Low(DcMatrix*2) ;инициализация массива перекодировки
ldi ZH,High(DcMatrix*2)
clr Temp2 ;прибавление переменной
add ZL,digit_out ;к 0-му адресу массива
adc ZH,Temp2
lpm ;загрузка значения 7-ми сегментного кода индикатора
mov digit_out,r0
clr temp
cp n_point,temp ;проверяем номер разряда зяпятой если
breq PC+6 ;если он равен 0 то выходим из подрограммы
cp counter,n_point ;если он не равен нулю сравниваем с
brne PC+4 ;номером разряда вкл в данный момент
mov temp,digit_out
andi temp,0b01111111 ;если равен зажигаем зяпятую иначе
mov digit_out,temp
ret ;выходим из подпрограммы
DcMatrix:
;массив - таблица истинности декодера
; hgfedcba hgfedcba
.db 0b11000000,0b11111001 ;0;1
.db 0b10100100,0b10110000 ;2;3
.db 0b10011001,0b10010010 ;4;5
.db 0b10000010,0b11111000 ;6;7
.db 0b10000000,0b10010000 ;8;9
Decoder_n_digit:
ldi ZL,Low(DnMatrix*2) ;инициализация массива
ldi ZH,High(DnMatrix*2)
clr Temp2 ;прибавление переменной
add ZL,counter ;к 0-му адресу массива
adc ZH,Temp2
lpm ;загрузка значения
mov n_digit,r0
ret
DnMatrix:
;массив - таблица истинности декодера разряда
.db 0b11111110,0b11111101 ;0;1
.db 0b11111011,0b11110111 ;2;3
Всю прогу макросом нельзя. Да и ни к чему это.
А небольшие кусочки - прочитай статью еще раз.
Вопрос по .DSEG
Если взять структуру исходных файлов, как, например, в прогах ADCsoftFilter, UARTundSoftADC, в каком месте нужно её указывать, или это все равно - компилятор сам разберётся?
“var1: .BYTE 1″ А как задать 2-х байтную переменную в ОЗУ, var1: .BYTE так?
И отсюда же следующий вопрос - как задать массив 2-х байтных чисел в ОЗУ. Может быть надо уазать var1: .BYTE 8 - это массив из 4-х двухбайтовых значений, правильно? Ну и соответственно, работать с ними, подразумевая, что каждый следующий элемент идёт через 2 байта.
DSEG везде где не CSEG :) Я обычно перед CSEG ставлю. Сразу после инклюдников обычно.
вроде бы .WORD можно определить, не помню уже. ПОзырь в описаниях макроязыка.
Собственно, я поставил в vectors.asm, но тоже получается перед .CSEG. Надо мне будет, наверное, завести отдельный фалик только с переменными ОЗУ и записать их все туда :) И подключить includе’ом в нужном месте
Кстати, в данном конкретном примере “Сразу после инклюдников” получится уже после .CSEG. Ну это так, к слову.
А как задать 2-х байтную переменную в ОЗУ, var1: .BYTE 2 - опечатался
А запись var1: .BYTE 8 я имею ввиду рассматривать как “массив из 4-х двухбайтовых значений”, хотя ассемблеру, возможно, мои мысли и неведомы и он подразумевает просто последовательность данных в ОЗУ
А нет, вру. это не из той оперы. Тут только отожрать нужное количество байт. ВСе равно ты не можешь их инициализировать на уровне компилятора. Так что пофиг чем ты их задаешь, также тебе адреса придется вручную считать для каждого элемента массива.
Инициализировать-то потом не проблема. Главное правильно мне их задать. А “адреса придется вручную считать” это в смысле подразумевается 1-и 2-х байтовый элемент - это адрес 0-го + 2 ? Ну это тоже не очень большая проблема. Ведь в программе же я оперирую символьным имененм, и следующий элемент массива находится по вышеприведённому способу исходя из размера элемента массива.
И опять вопрос по оператору (.BYTE) .
Если мы выделили массив с меткой Variablе:
как установить указатель допустим Z на метку массива
ldi Zh,high(Variablе)
ldi Zh,low(Variablе)
а считывать массив
st Z+,r16
st Z+,r17
и т.д.
Или я ошибаюсь?
Именно так, только
ldi ZH,high(Variablе)
ldi ZL,low(Variablе)
А чтение это не st (это сохранение), а ld
DI HALT Спасибо ошибки замелил сам но отредактировать не смог не поддерживается у вас чтоли.
Но самое главное суть понял а позже буду внимательней уж извини.
И еще вопрос по .include .Вставлять я так понял этот оператор мона где угодно хоть посреди кода а помещать в прикрепляемый файл как куски того же кода так и подпрограммы (даже обработчики прерывания).
И еще расширение у файла должно быть асм. или произвольное и помещать его нуна в папку текущего проекта?
Я так понимаю что любой отлаженный кусок кода (инициализация портов) или подпрограмму просто вырезаем и сохраняем как отдельный файл с расширением асм. в папке проекта
а в том месте пишем .include имя файла.asm или я не прав?
Да. Расишерие может быть любым. Главное чтобы это был текстовый файл. Быть он может тоже где угодно, но длинные пути и пути с русскими буквами плохо отрабатываются.
Проверил расширение только asm катит.Иначе студия матерится.
Я могу ошибаться, но в статье косяк: надо не .EESEG, а .ESEG.
Не пойму, проект на основе Atmega48, при компиляции запнулось повидимому на макросе OUTI с такой ошибкой: macro.asm(6): error: Operand 1 out of range: 0xc4 И указывает на вторую строчку макроса, т.е. OUT @0,R16. И еще куча подобных ошибок, где этот макрос встречается. Мой проект http://slil.ru/28665386
Да, все верно. Открывай файл m48def.inc и смотри карту ио регистров. Те из них что помечены как memory mapped недоступны для команды OUT|IN которая используется в макросе OUTI. Загрузка/выгрузка в них идет как в ячейку памяти по командам STS/LDS
т.е. меняем OUT на STS и все работает.
Сделай еще один макрос OUTIm такого вида и юзай его для мемори маппед регистров.
Опа, никто не упомянул о таких дьявольских штуках, как .if\.endif, .ifdef\.endif :)
С их помощью можно создать почти свой язык программирования :)
Точно. Совсем про них забыл. Надо добавить. Кстати, а AVRassebler1 их поддерживает? В доке про них нет ни слова.
Все поддерживает, искать надо лучше ;) Help - AVR Tool User guide - AVR assembler - User’s guide - Directives. сам ведь не знал о их оффициальном существовании! О_о
Охрененно. Вот жеж надо было закопать О_о а я ведь там два раза ходил и не заметил.
Общие макросы переношу из проекта в проект и подключаю через:
.include “MACROS.MAC”
(кстати, кто-то жаловался что только расширение “.asm”)
Вот примерчик, работающий на разных AVR8
Насчет первой версии не знаю, но во второй всё охрененно пашет. Я рад: создал скрипты инициализации таймеров, USART, ADC и других нудных вещей - и не паришся!
Это как Сишная вставка посреди ассемблерного поля :)
Добрый день.
Подскажите пожалуЙста, можно ли в макросе, в качестве параметра”@” ставить ссылку на подпрограму?
Например:
,MACRO CALC_1
ldi @1, @2
cp r16, @2
BREQ @3
И тогда при вызове макроса написать:
CALC_1 r17,r18,METKA
где “METKA” будет являтся той ссылкой, на которую с макроса пойдет контроллер.
Думаю проблем не составит. Макропроцессору то без проблем что подсунуть.
Большое спасибо.
Сейчас пробовал макрос забабахать. Супер, все работает. Реально удобно. Уже начал использовать в деле. Только вот хочется узнать, откуда у DIHALTA слева в редакторе появился столбец с цифрами, то есть нумерация строк. У меня в AVR STUDIO нет такой фишки. Не подскажете кто, как такую себе сделать?
У меня тоже нет, а с чего ты взял, что у меня в АВР студио есть нумерация?
Ну вот, когда ты вверху показываешь пример кода. У тебя в редакторе слева есть нумерация строк. Да и сам редактор привлекательный. Попривлекательнее чем в AVR. Просто думал ты какой нибудь плагин доставил к проге. Значит это не AVR STUDIO. А что же это за редактор?
Это Wordpress syntax hilighter - плагин к движку сайта который сам код подкрашивает.
OK! Понятно.
Мы тоже хотим красиво в коментах писать,
а то сваливается все в кучу….
И можно-ли редактировать свое сообщение?
DI HALT в придложении
>В итоге, во флеше вначале будет лежать число 0А, затем побайтно будут хекскоды символов
>фразы “привет лунатикам”, а дальше 000A, 000B, 000F.
>Последнии числа, хоть сами и невелики, но занимают по два байта каждое, так как .dw.
несостыковка с примером идущим сверху в котором нет описи “dw”.
Это при условии что я ничего не пропустил :)
ой точно куда то кусок примера отвалился :) Спасибо щас поправлю
пока не видно
Еще упущена “.SET” (про “.IF”, “.IFDEF”, “.IFNDEF” уже вспоминалось)
Вот кусок из программы:
ну Блин!
Уже и вертикальную черточку поставил, чтоб не сплюскивало, так автоматика сайта пробелы сократила. Компьютер и так прохавает, а я людям для наглядности форматировал. Для восприятия лучше…
- - - - - - - - - - - -
Может программка есть какая?
Написал в ней, отформатировал, сюда вставил и все красиво.
А если нету - то надо на сайте что-то менять.
Ну напрягает… тексты программ в комментариях ко всем статьям - просто каша.
я то разберусь, но начинающие могут упустить(не понять) много полезного.
Глянул на местный форум — ситуация та же… код-лист == каша.
Даааа уж… Видимо не все так просто.
Удивительно! Обсуждения концепций OS и каменный век — рядом!
Я не хтмл программист. А готовый плагин который бы мог это делать я не нашел.
Спасибо, вижу ты облагородил сообщение “апреля 24, 2010 at 4:26″
Еще и в “24 Апр 2010 4:45″ желательно убрать передующие “|” и сдвиги добавить. Плиз…
лень
Я думал ты сидишь на готовом движке сайта. А если все сам…
Ну может кто поможет/подскажет DI HALT-у доработать/переработать обработку сообщений на сайте, а то и сайт перемастырить.
Ему над уроками надо мозговать, а он тратит время на редактирование наших текстов.
На готовом и сижу. Потому и не могу взять и что то там подкрутить если этого нет в настройках.
После установки AvrStudio4, запустить файлик помощи:
AVRTools\Help\AVRASM.chm
Там в закладке “Содержание” выбираем (раскрываем)
-> “AVR Assembler” -> “User’s Guide” -> “Directives”
И вот здесь, в разделе “Assembler directives”, внимательно рассматриваем/изучаем директивы и примерчики (как раз по нашему учебному курсу).
DI HALT привет. А что означает выражение: макрос - лучше оформить в виде процедуры или функции? У тебя на сайте это где-то объясняется? Я бы почитал.
Имеется в виду, что макрос в этом случае использовать не стоит, а лучше сразу написать процедуру и вставить ее в код.
Constant: .db 10 ; или 0хAh в шестнадцатеричном коде
Message: .db “Привет лунатикам”
Words: .dw 10, 11, 12
В итоге, во флеше вначале будет лежать число 0А, затем побайтно будут хекскоды символов фразы “привет лунатикам”, а дальше 000A, 000B, 000F.
А разве последняя строчка не равна 000A,000B,000C?
ОПечатка, конечно же 000с