Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Чт апр 30, 2015 12:22:03
По кускам кода сложно что-то сказать. А дописывать (и домысливать) код самому чтобы погонять в симуляторе и понять что не так как-то лень 
Здесь можно немножко помяукать :)
https://radiokot.ru:443/forum/
Код: Выделить всё
.include "C:\Program Files (x86)\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRAssembler\2.1.51.64\avrassembler\include\m48def.inc"
.def Second=R16
.def Minute=R17
.def Hour=R18
.def BCDL=R1 ;Регисторы, в которые будут сохраняться значения чисел, выводимых на дисплей, при переводе 8ми битного значения в десятичные числа
.def BCDH=R2
.def BinVal=R3 ;Регистр, который является посредником при переводе 8ми битного числа в 2 десятичных
.def XOR=R5
.def Temp=R19
.def Temp1=R20
.def Display=R21 ; Сюда загружается значение, которое будет выведено на индикатор
.def BlinkStatusReg=R22 ; Установка битов с 0 по 5 включает мигание сегментов в таком же порядке, справа налево
.equ HH=5; ||HH
.equ HL=4; |||HL
.equ MH=3; ||||MH -
.equ ML=2; |||||ML -
.equ SH=1; ||||||SH -
.equ SL=0; |||||||SL -
; 76543210
.def DotStatusReg=R23 ; Установка битов с 0 по 5 включает точки сегментов в таком же порядке, справа налево
.equ BOL=7; BOL - Если установлен, активируется длинный пик динамика
.equ BOS=6; |BOS - Если установлен, активируется короткий пик динамика
.equ dHH=5; ||dHH
.equ dHL=4; |||dHL
.equ dMH=3; ||||dMH -
.equ dML=2; |||||dML -
.equ dSH=1; ||||||dSH -
.equ dSL=0; |||||||dSL -
; 76543210
.def GameStatus=R24 ; Регистр, бит 0 показывает, в какую сторону будет считать счётчик. При 0 - с числа до 0, при 1 - с нуля до числа. Бит 1 - за какую команду идёт отсчёт. 0 - за первую. 1 - за вторую.
.equ T1S=2 ; Флаги просмотра статистики для первой и второй команды
.equ T2S=3
.equ SP=7 ; - SecondPassed - флаг взводится при проходе очередной секунды
.equ II=6 ; - InterruptInversion bit. Бит инвентируется в прерывании по таймеру. В такт с ним мигают сегменты индикатора
.def BF=R25 ; Флаг работы с кнопками
;***************************************************************************************************
;*
;* Присвоение имён портов
;*
;***************************************************************************************************
.equ PORT_CA=PORTC;0x08;PORTC
.equ PORT_SEG=PORTD;0x0b;PORTD
;***************************************************************************************************
;*
;* Значения, которые необходимо вывести в порт, чтобы включить соответствующий сегмент индикатора
;* ATmega48 имеет 7 портов в PC, но седмой порт - reset, поэтому запись ведётся в размере 6 бит
;*
;***************************************************************************************************
.equ SLSegment=0b101111 ;PC4, active low
.equ SHSegment=0b011111 ;PC5, active low
.equ MLSegment=0b110111 ;PC3, active low
.equ MHSegment=0b111011 ;PC2, active low
.equ HLSegment=0b111101 ;PC1, active low
.equ HHSegment=0b111110 ;PC0, active low
;Бит, используемый командой SBR, для включения точки
.equ Dot=0b00100000
;***************************************************************************************************
;*
;* Присвоение имён портам кнопок
;* Присвоение имён портам диодов кнопок, Active low
;*
;* Button_1 (RED) = PORT
;*
;*
;*
;*
;***************************************************************************************************
;***************************************************************************************************
;*
;* Константы счётчиков
;*
.equ F_CPU=8000000 ; Тактовая частота процессора
.equ F_ClockResonator=32768; Тактовая частота часового кварца
;***** Значения для TimerCounter1(16bit)
.equ TC1_Prescaler=1024 ; Предделитель
.equ Second_ScalerA16=5 ; Число, обозначающее долю секунды, по проходу которой будет вызвано прерывание по совпадению
.equ TC1_16bit_CompareA=(F_CPU/1024)/Second_ScalerA16 ; Число, с которым будет сравниваться 16 битный счётчик. 1563
;***** Значения для TimerCounter2(8 bit) ЧАСОВОЙ
.equ TC2_Prescaler=128 ; Предделитель
.equ Second_ScalerA=3 ; Число, обозначающее долю секунды, по проходу которой будет вызвано прерывание по совпадению
.equ Second_ScalerB=2
.equ TC2_8_bit_CompareA=(F_ClockResonator/TC2_Prescaler)/Second_ScalerA ; Число, с которым будет сравниваться
.equ TC2_8_bit_CompareB=(F_ClockResonator/TC2_Prescaler)/Second_ScalerB
;Порт и пин диода на красной кнопке
.equ RBLP=PortB
.equ RBLPin=1
;Порт и пин диода на зелёной кнопке
.equ GBLP=PortB
.equ GBLPin=3
;Порты и пины кнопок
.equ RBLPi=PinB
.equ GBLPi=PinB
.equ B1P=PinB
.equ B1Pin=2
.equ B2P=PinB
.equ B2Pin=0
.equ BUZZER_PORT=PORTB
.equ BUZZER_PIN=5
.equ BUZZER_Pi=PinB ; Для SBIC, SRIS
.equ SYREN_PORT=PORTD
.equ SYREN_PIN=1
.equ BFE=0
.equ BFD=1
.equ BFS=2
.equ BFM=3
.equ FDM=4
.equ FDE=5
.equ BDM=6
.equ IIF=7
.equ B2L=5
.equ BDE=6
.equ SCF=7
;Загрузка ячеек оперативной памяти
.dseg
buttonsflag: .byte 1 ; Флаг состояний кнопок
;
; |
; || -
; ||| -
; ||||B2E - Разрешение выполнения кода по нажатию второй кнопки 1 - разрешено выполнение
; |||||B1E - Разрешение выполнения кода по нажатию первйо кнопки 1 - разрешено выполнение
; ||||||B2P - Нажатие второй кнопки 1 - нажата
; |||||||B1P - Нажатие первой кнопки 1 - нажата
; 76543210
;**********************************************************************************************************************
;*
;* Данные, которые будут выводиться на дисплей в режиме использования подпрограммы DICTM
FirstSegment: .byte 1 ; Значение, которое будет выведено в младший разряд секунд, при выполнении функции DICTM
SecondSegment: .byte 1 ; Значение, которое будет выведено в старший разряд секунд, при выполнении функции DICTM
ThirdSegment: .byte 1 ; Значение, которое будет выведено в младший разряд минут, при выполнении функции DICTM
FothSegment: .byte 1 ; Значение, которое будет выведено в сташий разряд минут, при выполнении функции DICTM
FifthSegment: .byte 1 ; Значение, которое будет выведено в младший разряд часов, при выполнении функции DICTM
SixthSegment: .byte 1 ; Значение, которое будет выведено в старший разряд часов, при выполнении функции DICTM
;**********************************************************************************************************************
;*
;* Переменные, в которые будут сохранены значения времени, которо необходимо досчитать в режиме отсчёта от 0 до числа
SecondComparator: .byte 1
MinuteComparator: .byte 1
HourComparator: .byte 1
;**********************************************************************************************************************
;*
;* Переменные, в которые будут сохранены значения времени, которо отсчтитываются для разных команд
SecondTeam1: .byte 1
MinuteTeam1: .byte 1
HourTeam1: .byte 1
SecondTeam2: .byte 1
MinuteTeam2: .byte 1
HourTeam2: .byte 1
;**********************************************************************************************************************
;*
;* Переменные, в которые будет записываться время захвата контроля надо точкой
SRAMCounter1: .byte 1
SRAMCounter2: .byte 1
Team1: .byte 200
Team2: .byte 200
.cseg
.org 0
rjmp reset
.org INT0addr ; External Interrupt Request 0
rjmp INT0_IRQ
.org INT1addr ; External Interrupt Request 1
rjmp INT1_IRQ
.org PCI0addr ; Pin Change Interrupt Request 0
rjmp PCI0_IRQ
.org PCI1addr ; Pin Change Interrupt Request 0
rjmp PCI1_IRQ
.org PCI2addr ; Pin Change Interrupt Request 1
rjmp PCI2_IRQ
.org WDTaddr ; Watchdog Time-out Interrupt
rjmp WDT_IRQ
.org OC2Aaddr ; Timer/Counter2 Compare Match A
rjmp OC2A_IRQ
.org OC2Baddr ; Timer/Counter2 Compare Match A
rjmp OC2B_IRQ
.org OVF2addr ; Timer/Counter2 Overflow
rjmp OVF2_IRQ
.org ICP1addr ; Timer/Counter1 Capture Event
rjmp ICP1_IRQ
.org OC1Aaddr ; Timer/Counter1 Compare Match A
rjmp OC1A_IRQ
.org OC1Baddr ; Timer/Counter1 Compare Match B
rjmp OC1B_IRQ
.org OVF1addr ; Timer/Counter1 Overflow
rjmp OVF1_IRQ
.org OC0Aaddr ; TimerCounter0 Compare Match A
rjmp OC0A_IRQ
.org OC0Baddr ; TimerCounter0 Compare Match B
rjmp OC0B_IRQ
.org OVF0addr ; Timer/Couner0 Overflow
rjmp OVF0_IRQ
.org SPIaddr ; SPI Serial Transfer Complete
rjmp SPI_IRQ
.org URXCaddr ; USART Rx Complete
rjmp URXC_IRQ
.org UDREaddr ; USART, Data Register Empty
rjmp UDRE_IRQ
.org UTXCaddr ; USART Tx Complete
rjmp UTXC_IRQ
.org ADCCaddr ; ADC Conversion Complete
rjmp ADCC_IRQ
.org ERDYaddr ; EEPROM Ready
rjmp ERDY_IRQ
.org ACIaddr ; Analog Comparator
rjmp ACI_IRQ
.org TWIaddr ; Two-wire Serial Interface
rjmp TWI_IRQ
.org SPMRaddr ; Store Program Memory Read
rjmp SPMR_IRQ
;Векторы прерываний
INT0_IRQ:
INT1_IRQ:
PCI0_IRQ:
PCI1_IRQ:
PCI2_IRQ:
WDT_IRQ:
;OC2A_IRQ:
;OC2B_IRQ:
;OVF2_IRQ:
ICP1_IRQ:
;OC1A_IRQ:
OC1B_IRQ:
OVF1_IRQ:
OC0A_IRQ:
OC0B_IRQ:
OVF0_IRQ:
SPI_IRQ:
URXC_IRQ:
UDRE_IRQ:
UTXC_IRQ:
ADCC_IRQ:
ERDY_IRQ:
ACI_IRQ:
TWI_IRQ:
SPMR_IRQ:
reti
reset:
RAM_Flush: LDI ZL,Low(SRAM_START) ; Адрес начала ОЗУ в индекс
LDI ZH,High(SRAM_START)
CLR R16 ; Очищаем R16
Flush: ST Z+,R16 ; Сохраняем 0 в ячейку памяти
CPI ZH,High(RAMEND+1) ; Достигли конца оперативки?
BRNE Flush ; Нет? Крутимся дальше!
CPI ZL,Low(RAMEND+1) ; А младший байт достиг конца?
BRNE Flush
CLR ZL ; Очищаем индекс
CLR ZH
; очистка регистров
LDI ZL, 30 ; Адрес самого старшего регистра
CLR ZH ; А тут у нас будет ноль
DEC ZL ; Уменьшая адрес
ST Z, ZH ; Записываем в регистр 0
BRNE PC-2
;STACK
ldi Temp, high(RamEnd); Установка указателя стека в начало ОЗУ Set Stack Pointer to top of RAM
out SPH, Temp;
ldi Temp, low(RamEnd);
out SPL, Temp;
;STACK
/***** - Порты
PB0 - SupplyControl - 1 is ON | PD0 - UART | PC0 - !!! - в этой версии платы используется эта нога, тк нога PC1 оторвалась
PB1 - | PD1 - UART | PC1 - ADC
PB2 - | PD2 - Button_1 | PC2 -
PB3 - | PD3 - | PC3 -
PB4 - Button_2 | PD4 - | PC4 -
PB5 - | PD5 - ReadData | PC5 -
PB6 - | PD6 - ShowData | PC6 -
PB7 - Data | PD7 -
*/
;Настройка портов
ldi Temp, 0b00111010 ; //Порт сегментов
out DDRB, Temp
ldi Temp, 0b111111
out DDRC, Temp
ldi Temp, 0b11111111
out DDRD, Temp
ldi Temp, 0b00001010
out PortB, Temp
ldi Temp, 0b111111
out PortC, Temp
ldi Temp, 0b11111111
out PortD, Temp
;Настройка портов
;*****************************************************************************************************************************************
;*
;Конфигурация счётчика TimerCounter1(16bit)
;*Предделитель 1024, прерывание по совпадению с OCR1A, примерно 1\5 секунды
;*
;***** Настройка регистра сравнения OCR1A
;*
ldi ZH, High(4000); Загрузка числа, с которым будет сравниваться счётчик
ldi ZL, Low(4000) ; Значение смотреть в DefEqu
STS OCR1AH, ZH
STS OCR1AL, ZL
;***** Настройка предделителя
;*
ldi Temp, 0b00000101; // Prescaler 1024
STS TCCR1B, Temp
;***** Настройка прерываний
;*
ldi Temp, 0b00000010; //Прерывание по совпадению OCR1A
STS TIMSK1, Temp
;*****************************************************************************************************************************************
;*
;Конфигурация счётчика TimerCounter2(8 bit) ЧАСОВОЙ
;*
/*
a. Disable the Timer/Counter2 interrupts by clearing OCIE2x and TOIE2.
b. Select clock source by setting AS2 as appropriate.
c. Write new values to TCNT2, OCR2x, and TCCR2x.
d. To switch to asynchronous operation: Wait for TCN2xUB, OCR2xUB, and TCR2xUB.
e. Clear the Timer/Counter2 Interrupt Flags.
f. Enable interrupts, if needed.
*/
;**********************************************************************************************************************************
;*
;* Включение ассинхронного режима
;*
;***** a. Отключение прерываний
CLR Temp
STS TIMSK2, Temp
;***** b. Включение тактирования от внешнего кварца
ldi Temp, 0b00100000
STS ASSR, Temp
;***** c. Заново настраиваем TCNT2, OCR2x, и TCCR2x.
;***** Настройка регистра сравнения OCR2A, на прерыван
;* Используется как счётчик короткого пика динамика
;*
ldi Temp, TC2_8_bit_CompareA ; Загрузка числа, с которым будет сравниваться счётчик А
STS OCR2A, Temp
;***** Настройка регистра сравнения OCR2A, на прерыван
;* Используется как счётчик длинного пика динамика
;*
ldi Temp, TC2_8_bit_CompareB ; Загрузка числа, с которым будет сравниваться счётчик B
STS OCR2B, Temp
;***** Настройка предделителя
;*
ldi Temp, 0b00000101 ; 128, при 32.768\128 = 256 = 1 тик в секунду при переполнении
STS TCCR2B, Temp
;***** Сброс счётного регистра
;*
CLR Temp
STS TCNT2,Temp
;***** d. Ожидание, пока применятся все настройки
;*
waiting_for_TC2_AS_applys_settings:
LDS Temp,ASSR
SBRC Temp, TCN2UB
rjmp waiting_for_TC2_AS_applys_settings
SBRC Temp, OCR2AUB
rjmp waiting_for_TC2_AS_applys_settings
SBRC Temp, TCR2AUB
rjmp waiting_for_TC2_AS_applys_settings
;***** e. Очистка флагов прерываний
;*
ldi Temp,0b00000111 ;В TIFR2 записываются единицы, так сбрасываются флаги
STS TIFR2,Temp
CLR DotStatusReg ; НЕ ЗНАЮ КАК, НО ЗНАЧЕНИЕ В ПРЕДЫДУЩЕМ TEMP ПОПАДАЕТ В DotStatusReg, что включает точки О_о
;***** Настройка прерываний (Это закомментировано, потому что пока это не нужно)
;*
/*ldi Temp, 0b00000111; //Прерывание по совпадению OCR2A и переполнению.
STS TIMSK2, Temp ; A - выключение динамика при коротком пике
; B - Выключение динамика при длинном пике
; Overflow - переполнение счётчика, проход одной секунды*/
; == ;IncTime SecondMinuteLow - Макрос, который уменьшает младший разряд минут или минут - не используется подпрограмма, т.к. это нужно только при вводе натсроек
.Macro IncTimeSML
cpi @0,9
brne IncSML
clr @0
rjmp OverSML
IncSML:
inc @0
OverSML:
.ENDM
; == IncTime SecondMinuteLow - Макрос, который увеличивает старший разряд секунд или минут - не используется подпрограмма, т.к. это нужно только при вводе настроек
.Macro IncTimeSMH
;if (a>=b)
CPI @0,50
brcs IncTimeSMHelse
SUBI @0,50
rjmp IncTimeSMHover
IncTimeSMHelse: SUBI @0, (-10)
IncTimeSMHover:
.ENDM
; == IncTime SecondMinuteLow - Макрос, который уменьшает младший разряд часов - не используется подпрограмма, т.к. это нужно только при вводе натсроек
.Macro IncTimeHL
cpi @0,99
brne IncHL
clr @0
rjmp OverHL
IncHL:
inc @0
OverHL:
.ENDM
; == IncTime SecondMinuteLow - Макрос, который увеличивает старший разряд часов - не используется подпрограмма, т.к. это нужно только при вводе настроек
.Macro IncTimeHH
;if (a>=b)
CPI @0,90
brcs IncTimeHHelse
SUBI @0,90
rjmp IncTimeHHover
IncTimeHHelse: SUBI @0, (-10)
IncTimeHHover:
.ENDM
ldi Second,1
ldi Minute,2
ldi Hour,3
looooop:
;* Записываем в оперативку очередное время
ldi ZL, LOW(Team1)
ldi ZH, HIGH(Team1)
LDS Temp, SRAMCounter1
CLR Temp1
add ZL,Temp
adc ZH,Temp1
ST Z+,Minute
ST Z,Hour
cpi Temp,197
brne keepgo1
ldi Temp,254 ;* Следующая команда обнулит Temp
keepgo1:
SUBI Temp,(-2)
STS SRAMCounter1,Temp
;* Чтение из оперативки
cpi Second,99
brne keepgo3
ldi Second,255
ldi ZL, LOW(Team1)
ldi ZH, HIGH(Team1)
keepgo3:
LD Minute,Z+
LD Hour,Z+
inc Second
rjmp looooopКод: Выделить всё
looooop:
;* Записываем в оперативку очередное время
ldi ZL, LOW(Team1)
ldi ZH, HIGH(Team1)
LDS Temp, SRAMCounter1
CLR Temp1
add ZL,Temp
adc ZH,Temp1
ST Z+,Minute
ST Z,Hour
cpi Temp,197
brne keepgo1
ldi Temp,254 ;* Следующая команда обнулит Temp
keepgo1:
SUBI Temp,(-2)
STS SRAMCounter1,Temp
;* Чтение из оперативки
cpi Second,99
brne keepgo3
ldi Second,255
ldi ZL, LOW(Team1)
ldi ZH, HIGH(Team1)
keepgo3:
LD Minute,Z+
LD Hour,Z+
inc Second
rjmp looooopЭээ... Чаго?ILYAUL писал(а):Free timer c двумя прерываниями OCR
Код: Выделить всё
;**************************************************
;* ;;/Initialization TIMER1;;* *
;**************************************************
outi OCR1BH, high(7)
outi OCR1BL,low(7)
ldi temp,1<<OCIE1A|1<<OCIE1B
outr TIMSK1,temp
ldi temp,1<<CS11|1<<CS10
outr TCCR1B,temp Код: Выделить всё
;-Задержка на 40us(25кгц) для Xtal 110592MHz
;******************************************
Wait40us:
sbi TIFR1,OCF1A
inr temp,TCNT1L
inr temp1,TCNT1H
subi temp,(low(-6+1))
sbci temp1,(high(-6+1))
outr OCR1AH,temp1
outr OCR1AL,temp
sbis TIFR1,OCF1A
rjmp PC-1
ret
;**************************************
;- Задержка на 1,5ms
;**************************************
Wait1_5ms:
sbi TIFR1,OCF1B
inr temp,TCNT1L
inr temp1,TCNT1H
subi temp,(low(-259+1))
sbci temp1,(high(-259+1))
outr OCR1BH,temp1
outr OCR1BL,temp
sbis TIFR1,OCF1B
rjmp PC-1
ret
;**************************************
;- Задержка на 20 ms
;**************************************
Wait20ms:
sbi TIFR1,OCF1A
inr temp,TCNT1L
inr temp1,TCNT1H
subi temp,(low(-3456+1))
sbci temp1,(high(-3456+1))
outr OCR1AH,temp1
outr OCR1AL,temp
sbis TIFR1,OCF1A
rjmp PC-1
retКод: Выделить всё
sbi TIFR1,OCF1A
;
;
sbis TIFR1,OCF1AПодъебалakl писал(а):А можно спросить, для какого камня(ей) работают конструкции типа