Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Сб июл 06, 2013 15:35:26
Единственное что понял так это УМВР = "У Меня Всё Работает". Остальное, кажется, написано в ответ не на эту тему...
Здесь можно немножко помяукать :)
https://radiokot.ru/forum/
Код: Выделить всё
;=========================
; Плавное зажигание 10 светодиодов
;
;=========================
;
; 10led.asm
;
; Copyright 2011 ploop <ploopgm@gmail.com>
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
; MA 02110-1301, USA.
;
;=========================
.device ATtiny2313
;-------------------------------------------------------------------------------
; Определения портов
;-------------------------------------------------------------------------------
.equ led0_port = PORTB
.equ led1_port = PORTB
.equ led2_port = PORTB
.equ led3_port = PORTB
.equ led4_port = PORTB
.equ led5_port = PORTB
.equ led6_port = PORTB
.equ led7_port = PORTB
.equ led8_port = PORTD
.equ led9_port = PORTD
.equ led0_bit = 7
.equ led1_bit = 6
.equ led2_bit = 5
.equ led3_bit = 4
.equ led4_bit = 3
.equ led5_bit = 2
.equ led6_bit = 1
.equ led7_bit = 0
.equ led8_bit = 6
.equ led9_bit = 5
.equ btn_pause_inc_port = PORTD
.equ btn_pause_inc_pin = PIND
.equ btn_pause_inc_bit = 1
.equ btn_pause_dec_port = PORTD
.equ btn_pause_dec_pin = PIND
.equ btn_pause_dec_bit = 0
.equ btn_pow_inc_port = PORTA
.equ btn_pow_inc_pin = PINA
.equ btn_pow_inc_bit = 1
.equ btn_pow_dec_port = PORTA
.equ btn_pow_dec_pin = PINA
.equ btn_pow_dec_bit = 0
; Для gavrasm
.def XH = R27
.def XL = R26
.def YH = R29
.def YL = R28
.def ZH = R31
.def ZL = R30
.def counter = r25 ; счетчик
.def max_l = r24 ; максимальная яркость
.def null = r23 ; ноль
.def delay = r22 ; задержка
.def btn_tsk = R8 ; регистр задач по нажатию кнопок.
;|7|6|5|4|3|2|1|0|
;| | 3-0 действие по нажатию
;|7-4 действие по отпусканию
.def btn_press = R7 ; регистр состояния кнопок (3-0 нажаты)
;
.equ btn_pause_inc = 3
.equ btn_pause_dec = 2
.equ btn_pow_inc = 1
.equ btn_pow_dec = 0
;=========================
; EEPROM
;=========================
.ESEG ; Хранение настроек
.org 0
e_bright:
.db 0 ; яркость
e_delay:
.db 1 ; задержка
;=========================
; RAM
;=========================
.DSEG
del_buf: .byte 10 ; буфер переменных сравнения для 10 каналов
;-------------------------------------------------------------------------------
.cseg
;-------------------------------------------------------------------------------
; Векторы прерываний
;-------------------------------------------------------------------------------
.org 0x0000
rjmp RESET ; Reset Handler
.org 0x0001
reti ;rjmp INT0 ; External Interrupt0 Handler
.org 0x0002
reti ;rjmp INT1 ; External Interrupt1 Handler
.org 0x0003
reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler
.org 0x0004
reti ; Timer1 CompareA Handler
.org 0x0005
reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler
.org 0x0006
reti ;rjmp TIM0_OVF ;rjmp TIM0_OVF ; Timer0 Overflow Handler
.org 0x0007
reti ; USART0 RX Complete Handler
.org 0x0008
reti ;rjmp USART0_DRE ; USART0,UDR Empty Handler
.org 0x0009
reti ;rjmp USART0_TXC ; USART0 TX Complete Handler
.org 0x000A
reti ;rjmp ANA_COMP ; Analog Comparator Handler
.org 0x000B
reti ;rjmp PCINT ; Pin Change Interrupt
.org 0x000C
reti ;rjmp TIMER1_COMPB ; Timer1 Compare B Handler
.org 0x000D
rjmp TIMER0_COMPA ; Timer0 Compare A Handler
.org 0x000E
reti ;rjmp TIMER0_COMPB ; Timer0 Compare B Handler
.org 0x000F
reti ;rjmp USI_START ; Usi Start Handler
.org 0x0010
reti ;rjmp USI_OVERFLOW ; USI Overflow Handler
.org 0x0011
reti ;rjmp EE_READY ; EEPROM Ready Handler
.org 0x0012
reti ;rjmp rjmp WDT_OVERFLOW ; Watchdog Overflow Handler
.org 0x0013
;-------------------------------------------------------------------------------
; Прерывание по переполнению
;-------------------------------------------------------------------------------
TIMER0_COMPA:
set ; устанавливаем флаг срабатывания таймера
reti
;-------------------------------------------------------------------------------
; Инициализация
;-------------------------------------------------------------------------------
reset:
ldi null,0
ldi max_l,0
ldi r16,low(RAMEND)
out spl,r16
ldi r16,$FF
out DDRB,r16
out PORTB,null
ldi r16,0b01100000
out DDRD,R16
ldi r16,0b00000011
out PORTD,R16
ldi r16,0b00000000
out DDRA,r16
ldi r16,0b00000011
out PORTA,r16
;-------- таймер ---------
ldi r16,(1<<WGM01)
out TCCR0A,r16
ldi r16,250
out OCR0A,r16
ldi r16,(1<<OCIE0A) ; прерывание по совпадению
out TIMSK,r16
ldi r16,(1<<CS00)|(1<<CS02) ; 1/1024
out TCCR0B,r16
;=========================
; Старт программы
;=========================
start:
rcall upd_max_light ; заполняем буфер минимальными значениями
ldi r17,e_bright ; Чтение настроек яркости и задержки
rcall EERead
mov max_l,r16
ldi r17,e_delay
rcall EERead
mov delay,r16
rcall big_delay ; задержка
;-------------------------------------------------------------------------------
; основной цикл
clr counter
clr r17 ; В r17 указатель на текущий светодиод
clt
sei
ldi r19,15 ; счетчик проходов,
main_loop: ; чтобы скорость не зависила от яркости
brtc no_timer ; Если флаг T не установлен, значит таймер не сработал
clt ; иначе сбрасываем его
dec r19
breq next_diode ; Если счетчик циклов =0 - следующий диод
cp r19,max_l ; проверим, не меньнше ли счетчик проходов максимального
brcs no_timer ; если меньше - зацикливаем
ldi YH,high(del_buf) ; берём значение яркости
ldi YL,low(del_buf)
add YL,r17
adc YH,null
ld r18,Y
dec r18 ; уменьшаем (увеличиваем яркость)
st Y,r18
rjmp no_timer
next_diode:
ldi r19,15
inc r17 ; если максимальная, увеличиваем счетчик светодиодов
cpi r17,10 ; если светодиод последний - выходим
breq exit_loop
no_timer:
rcall pwm
rjmp main_loop
;-------------------------------------------------------------------------------
; простой цикл после прохода эффекта
;-------------------------------------------------------------------------------
exit_loop:
rcall pwm ; ШИМ
rcall btn_test ; Опрос кнопок
rcall btn_set ; Реакция на кнопки
rjmp exit_loop
;=========================
; цикл прохода ШИМ по 10 каналам
;=========================
pwm:
ldi XH,high(del_buf)
ldi XL,low(del_buf)
ld r16,X+ ; загружаем значение сравнения 0-го канала
cp r16,counter ; сравниваем со счетчиком
brne pwm_1
sbi led0_port,led0_bit ; если равны - включаем канал
pwm_1:
ld r16,X+
cp r16,counter
brne pwm_2
sbi led1_port,led1_bit
pwm_2:
ld r16,X+
cp r16,counter
brne pwm_3
sbi led2_port,led2_bit
pwm_3:
ld r16,X+
cp r16,counter
brne pwm_4
sbi led3_port,led3_bit
pwm_4:
ld r16,X+
cp r16,counter
brne pwm_5
sbi led4_port,led4_bit
pwm_5:
ld r16,X+
cp r16,counter
brne pwm_6
sbi led5_port,led5_bit
pwm_6:
ld r16,X+
cp r16,counter
brne pwm_7
sbi led6_port,led6_bit
pwm_7:
ld r16,X+
cp r16,counter
brne pwm_8
sbi led7_port,led7_bit
pwm_8:
ld r16,X+
cp r16,counter
brne pwm_9
sbi led8_port,led8_bit
pwm_9:
ld r16,X+
cp r16,counter
brne pwm_x
sbi led9_port,led9_bit
pwm_x:
inc counter ; инкрементируем счетчик
sbrc counter,4 ; и проверяем на переполнение
rjmp ch_off
ret
ch_off: ; если переполнился - сбравываем счетчик и все порты
clr counter
out PORTB,null
cbi PORTD,6
cbi PORTD,5
ret
;=========================
; заполнение буфера значениями яркости
;=========================
upd_max_light:
ldi XL,low(del_buf)
ldi XH,high(del_buf)
ldi r16,10
ldi r17,16
l0:
st X+,r17
dec r16
brne l0
ret
upd_light:
ldi XL,low(del_buf)
ldi XH,high(del_buf)
ldi r17,10
l1:
st X+,r16
dec r17
brne l1
ret
;=========================
; Подпрограмма опроса кнопок
;=========================
btn_test:
mov r16,btn_press
mov r17,btn_tsk
sbic btn_pause_inc_pin,btn_pause_inc_bit
rjmp bt01 ; если кнопка нажата
sbrc r16,3 ; проверяем, была ли она нажата ранее
rjmp bt02 ; если да - выходим
ori r17,(1<<3) ; если нет - устанавливаем действие по нажатию
ori r16,(1<<3) ; и факт нажатия
rjmp bt02
bt01: ; если не нажата
sbrs r16,3 ; и не была нажата ранее
rjmp bt02 ; выходим
andi r16,~(1<<3) ; иначе сбрасываем факт нажатия
ori r17,(1<<7) ; ставим действие по отпусканию
bt02:
;--------------
sbic btn_pause_dec_pin,btn_pause_dec_bit
rjmp bt03 ; если кнопка нажата
sbrc r16,2 ; проверяем, была ли она нажата ранее
rjmp bt04 ; если да - выходим
ori r17,(1<<2) ; если нет - устанавливаем действие по нажатию
ori r16,(1<<2) ; и факт нажатия
rjmp bt04
bt03: ; если не нажата
sbrs r16,2 ; и не была нажата ранее
rjmp bt04 ; выходим
andi r16,~(1<<2) ; иначе сбрасываем факт нажатия
ori r17,(1<<6) ; ставим действие по отпусканию
bt04:
;--------------
sbic btn_pow_inc_pin,btn_pow_inc_bit
rjmp bt05 ; если кнопка нажата
sbrc r16,1 ; проверяем, была ли она нажата ранее
rjmp bt06 ; если да - выходим
ori r17,(1<<1) ; если нет - устанавливаем действие по нажатию
ori r16,(1<<1) ; и факт нажатия
rjmp bt06
bt05: ; если не нажата
sbrs r16,1 ; и не была нажата ранее
rjmp bt06 ; выходим
andi r16,~(1<<1) ; иначе сбрасываем факт нажатия
ori r17,(1<<5) ; ставим действие по отпусканию
bt06:
;--------------
sbic btn_pow_dec_pin,btn_pow_dec_bit
rjmp bt07 ; если кнопка нажата
sbrc r16,0 ; проверяем, была ли она нажата ранее
rjmp bt08 ; если да - выходим
ori r17,(1<<0) ; если нет - устанавливаем действие по нажатию
ori r16,(1<<0) ; и факт нажатия
rjmp bt08
bt07: ; если не нажата
sbrs r16,0 ; и не была нажата ранее
rjmp bt08 ; выходим
andi r16,~(1<<0) ; иначе сбрасываем факт нажатия
andi r16,~(1<<0) ; иначе сбрасываем факт нажатия
ori r17,(1<<4) ; ставим действие по отпусканию
bt08:
;--------------
mov btn_press,r16
mov btn_tsk,r17
ret
;=========================
; Действия при нажатии кнопок
;=========================
btn_set:
mov r20,btn_tsk
; сбросим все биты
mov r17,btn_tsk
andi r17,0b11110000
mov btn_tsk,r17
; условные переходы
sbrc r20,btn_pause_inc
rcall pause_inc
sbrc r20,btn_pause_dec
rcall pause_dec
sbrc r20,btn_pow_inc
rcall pow_inc
sbrc r20,btn_pow_dec
rcall pow_dec
ret
;=========================
; Подпрограмма записи в EEPROM (r17 - адрес, r16 - данные)
;=========================
EEWrite:
sbic EECR,EEWE ; Ждем готовности памяти к записи. Крутимся в цикле
rjmp EEWrite
cli ; запрещаем прерывания.
out EEAR,r17 ; Загружаем адрес нужной ячейки
out EEDR,r16 ; и сами данные из rx1
sbi EECR,EEMWE ; взводим предохранитель
sbi EECR,EEWE ; записываем байт
sei ; разрешаем прерывания
ret
;=========================
; Подпрограмма чтения в EEPROM (r17 - адреса, r16 - данные)
;=========================
EERead:
sbic EECR,EEWE ; Ждем пока будет завершена прошлая запись.
rjmp EERead
out EEAR, r17 ; загружаем адрес нужной ячейки
sbi EECR,EERE ; Выставляем бит чтения
in r16,EEDR ; Грузим из регистра данных результат
ret
;=========================
; увеличение задержки
;=========================
pause_inc:
cpi delay,251 ; проверка на максимум
breq exit_pause_inc
subi delay,-10 ; увеличение задержки и запись в EEPROM
mov r16,delay
ldi r17,e_delay
rcall EEWrite
rjmp reset
exit_pause_inc:
ret
;=========================
; уменьшение задержки
;=========================
pause_dec:
cpi delay,1 ; проверка на минимум
breq exit_pause_dec
subi delay,10 ; уменьшение задержки и запись в EEPROM
mov r16,delay
ldi r17,e_delay
rcall EEWrite
rjmp reset
exit_pause_dec:
ret
;=========================
; увеличение яркости
;=========================
pow_inc:
cpi max_l,0 ; проверка на ноль. 0 - максимальная яркость
breq exit_pow_inc
dec max_l ; увеличение яркости и запись в EEPROM
mov r16,max_l
ldi r17,e_bright
rcall EEWrite
rcall upd_light
exit_pow_inc:
ret
;=========================
; уменьшение яркости
;=========================
pow_dec:
cpi max_l,14 ; проверка на 15. 15 - минимальная яркость
breq exit_pow_dec
inc max_l ; увеличение яркости и запись в EEPROM
mov r16,max_l
ldi r17,e_bright
rcall EEWrite
rcall upd_light
exit_pow_dec:
ret
;=========================
; задержка
;=========================
big_delay:
ldi r16,0
ldi r17,0
mov r18,delay
del_loop:
dec r16
brne del_loop
dec r17
brne del_loop
dec r18
brne del_loop
ret
Код: Выделить всё
set_io SPL, low(RAMEND)
; установить порты ввода-вывода
set_io DDRB, 0b00011111 ; 1 - выход, 0 - вход.
; настройка таймера
;прескалер выставить на 8, Fast PWM частота будет 4.8Мгц/(8*512) ~ 1.1кГц
set_io TCCR0A, 0b10110001 ; режим таймера 01 - PWM(Phase Correct). Clear OC0A on Compare Match when up-counting.
; Set OC0A on Compare Match when down-counting.
; Set OC0B on Compare Match when up-counting.
; Clear OC0B on Compare Match when down-counting.
set_io TCCR0B, 0b00000010 ; Счетчик работает c предделителем = 8.Код: Выделить всё
.macro set_led
set_reg ledv, R16 ; Копия в текущее значение, для последующих плавных переходов.
OUT OCR0A, R16
OUT OCR0B, R16
.endmacroКод: Выделить всё
.DEF LEDV = R1 ; Текущая Яркость
.DEF tmp = R11
; Счетчики в регистрах
.DEF cyclecount = R16
.DEF target = R17
.DEF speed = R18
.macro trans_light
LDI target, @0
LDI speed, @1
rcall tr_light
.endmacro
.macro actualize_led
mov accum, ledv
OUT OCR0A, ACCUM
OUT OCR0B, ACCUM
.endmacro
tr_light:
clr tmp // будет выполнять роль суб-счетчика, который будет наполнятся speed
// и по переполнению выполнятся инкремент/декремент главного значения.
tr_loop:
CP ledv, target
BREQ tr_end // значение уже равно необходимому, выходим наф
BRLO tr_inc // target оказался больше чем ledv, нужен инкремент.
tr_dec: // остался только вариант ledv > target, нужен декремент
add tmp, speed
BRCC tr_no // нет переполнения субсчетчика - не меняем яркость
DEC ledv
actualize_led
rjmp tr_no
tr_inc:
add tmp, speed
BRCC tr_no
INC ledv
actualize_led
tr_no:
rcall delay_step
rjmp tr_loop
tr_end:
RET
Код: Выделить всё
.include "tn2313def.inc" ; Используем ATtiny2313
.equ Vpwr_mV = 5000 ; Питание = 5000 mV
.equ Vout_mV = 3000 ; Выход = 0 - 5000 mV
; ROM ===============
.CSEG ; ROM
.org $000
rjmp RESET ; External Pin, Power-on Reset, Brown-out Reset and Watchdog Reset
reti ; INT0 Внешнее прерывание 0
reti ; INT1 Внешнее прерывание 1
reti ; TIMER1 CAPT Захват таймера/счетчика Т1
reti ; TIMER1 COMPA Совпадение «А» таймера/счетчика Т1
reti ; TIMER1 OVF Переполнение таймера/счетчика Т1
reti ; TIMER0 OVF Переполнение таймера/счетчика Т0
reti ; USART,RX USART, прием завершен
reti ; USART,UDRE Регистр данных USART пуст
reti ; USART,TX USART, передача завершена
reti ; ANA_COMP Аналоговый компаратор
reti ; PCINT Pin Change Interrupt
reti ; TIMER1 COMPB Совпадение «В» таймера/счетчика Т1
reti ; TIMER0 COMPA Timer/Counter0 Compare Match A
reti ; TIMER0 COMPB Timer/Counter0 Compare Match B
reti ; USI START USI Start Condition
reti ; USI OVERFLOW USI Overflow
reti ; EE READY EEPROM, готово
reti ; WDT OVERFLOW Watchdog Timer Overflow
; -------------------- R E S E T ---------------------------------------
.ORG INT_VECTORS_SIZE ; Конец таблицы прерываний
RESET:
cli
ldi r16, RAMEND ; Set Stack Pointer to top of RAM
out SPL, r16 ;
; --------------- M A I N P R O G R A M M ------------------------
PORTS_Init:
ldi r16, 0b00001000
out DDRB, r16
PWM_16_A_Init:
ldi r16, low(Vout_mV) ;
ldi r17,high(Vout_mV) ;
out OCR1AH, r17 ;
out OCR1AL, r16
ldi r16, low(Vpwr_mV) ;
ldi r17,high(Vpwr_mV) ;
out ICR1H, r17 ;
out ICR1L, r16
ldi r16, (0b10<<WGM10) ; Set PWM, Phase Correct mode with resolution ICR1.
ldi r17, (0b10<<WGM12) ; Set PWM, Phase Correct mode with resolution ICR1.
ori r16, (0b10<<COM1A0); Clear OC1A on Compare Match, set OC1A at ICR1
ori r17, (0b001<<CS10) ; Prescaler 001=1:1
out TCCR1A, r16 ;
out TCCR1B, r17 ; Enable TCNT1
sei
MAIN_loop:
in r16,MCUCR
ori r16, (1<<SE)
out MCUCR, r16
sleep ; Отдыхаем пока не началось
rjmp MAIN_loop ; Go again
Код: Выделить всё
ldi r17, 0b11111111
out ddrb, r17 ; Порт В на выход
ldi r16, 0b00000000
out ddrc, r16 ; Порт С на вход
out PortC, r17 ; Подтяжка порта С
Main:
sbic pinc, 4 ; Проверим состояние входа кнопки РС4
rjmp LEDOff ; Переход, если не нажата (на РС4 высокий уровень)
out PortB, r17 ; Включим светодиод
RJMP Main
LEDOff:
out PortB, r16 ; Выключим светодиод
rjmp MainКлассические вилы. Порт С по дефолту работает на жтаг и потому те выводы его , что служат жтагу (TDI TDO ЕСЛ TMS) не могут использоваться как порт. Жтаг можно отключить либо фуз битами. Либо поправив регистр MCUCSR поставив там бит JTD
Регистр bitcount - R21, 8-ми битный, а переменная - 16-ти. При компиляции в АВР студио 6.0 выпадает ошибка:ldi bitcount,CRC16poly>>8 ;do bitcount CRC polynom - vrchny byte
eor temp1,bitcount ;a urob XOR zo zvyskom a CRC polynomom - vrchny byte
ldi bitcount,CRC16poly ;do bitcount CRC polynom - spodny byte
eor temp0,bitcount ;a urob XOR zo zvyskom a CRC polynomom - spodny byte
а почему так происходит? я запутался в етих out и sts. если не сложно обясните пжл. если нет, даите хотсябы ссылку где детально про это написано. спасибоzero648 писал(а):Потому что когда OUT, то EIMSK=0x1d
а когда используете STS, то EIMSK должен быть 0x3d, т.е. +0x20.
Потому что младшие 32 байта области данных выделены под РОН, за ними идут РВВ, за ними — SRAM.Dessp писал(а):а почему так происходит?