Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Чт фев 03, 2011 15:43:06
ага, т.е. тупо взять с даташита и подставить свои метки для перехода... ок, поняв... я просто первый раз пишу.. пасиб, буду знать!
Здесь можно немножко помяукать :)
https://radiokot.ru:443/forum/
Да, в даташитах описано много готовых примеров (правда, не всегда верно =). Плюс ко всему, много интересного можно посмотреть в АппНотах.DJ_Kiridza писал(а):ага, т.е. тупо взять с даташита и подставить свои метки для перехода... ок, поняв... я просто первый раз пишу.. пасиб, буду знать!
Код: Выделить всё
;--------------------------------------------------------------------------
; инициализация аппартного юарта на прием - передачу
; вход: Y - символьная константа
; ресурс: r16
; 9600 бод
; формат ответа модема ”<\r><\n><response><\r><\n>”
;--------------------------------------------------------------------------
INIT_HUART:
; Set baud rate
ldi YL, low (51)
ldi YH, high (51)
sts UBRR0L, YL
sts UBRR0H, YH
; Enable receiver and transmitter
; инициализируем прерывания на прием и передау данных
ldi r16, (1<<TXCIE0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<RXEN0)
sts UCSR0B, r16
; Set frame format: 8data, 1stop bit
ldi r16, (3<<UCSZ00)
sts UCSR0C, r16
cbi FLAGS, HU_COM_FLG ; инициализируем прием
retГы, вы его обнуляете, а прерывание-то по опустошениюRuslan-maniak писал(а):и даже принудительно обнуляю UDR
Код: Выделить всё
;Прога делает следующее. Управляет скоростью мигания светика(PD6), путём переноса числа из буфера ЮСАРТа в регистры 16-битного таймера№1.
.device ATmega16
.nolist
.include "D:\Program Files\Atmel\AVR Studio\Appnotes\m16def.inc"
.list
;********************************
;определяем переменные
;рабочие:
.def work=r16
.def work1=r17
.def h_part=r19
.def l_part=r20
.def t_count1_L=r21
.def count1_symbol=r22
.def t_count0=r23
.def t_count1_H=r24
.def speed_value=r25
;порты:
;PORTD
.equ UH=PD6
.equ ADC0_ram=0x0 ;0x1
.equ ADC1_ram=0x14;
.equ ADC2_ram=0x28
.equ ADC3_ram=0x3C
.equ ADC4_ram=0x50
.equ ADC_count_ram=0x0;0x2
.equ TMR1_ram=0x2
.equ byte_count=0x4
;********************************
.cseg
.org 0x0010
;*****************************
jmp RESET ; Reset Handler
jmp EXT_INT0 ; IRQ0 Handler
jmp EXT_INT1 ; IRQ1 Handler
jmp TIM2_COMP ; Timer2 Compare Handler
jmp TIM2_OVF ; Timer2 Overflow Handler
jmp TIM1_CAPT ; Timer1 Capture Handler
jmp TIM1_COMPA ; Timer1 CompareA Handler
jmp TIM1_COMPB ; Timer1 CompareB Handler
jmp TIM1_OVF ; Timer1 Overflow Handler
jmp TIM0_OVF ; Timer0 Overflow Handler
jmp SPI_STC ; SPI Transfer Complete Handler
jmp USART_RXC ; USART RX Complete Handler
jmp USART_UDRE ; UDR Empty Handler
jmp USART_TXC ; USART TX Complete Handler
jmp ADC ; ADC Conversion Complete Handler
jmp EE_RDY ; EEPROM Ready Handler
jmp ANA_COMP ; Analog Comparator Handler
jmp TWSI ; Two-wire Serial Interface Handler
jmp EXT_INT2 ; IRQ2 Handler
jmp TIM0_COMP ; Timer0 Compare Handler
jmp SPM_RDY ; Store Program Memory Ready Handler
EXT_INT0:ret
EXT_INT1:ret
TIM2_COMP:ret
TIM2_OVF:ret
TIM1_CAPT:ret
TIM1_COMPA:ret
TIM1_COMPB:ret
;TIM1_OVF:
TIM0_OVF:ret
SPI_STC:ret
;USART_RXC:
USART_UDRE:ret
USART_TXC:
ldi YH,0x2;извлекаем значение счётчика
ldi r28,byte_count
ld work,Y+
cpi work,1
breq USART_TXC_exit
inc work
ldi YH,0x2
ldi r28,byte_count
st Y+, work
;cbi UCSRA,TXC
ldi YH,0x1
ldi r28,ADC0_ram
ld work,Y+
ld work1,Y+
sbi PORTC, PC7
nop
nop
out UDR,work1
nop
nop
nop
nop
out UDR,work
reti
USART_TXC_exit:
cbi PORTC, PC7
;---clear byte_count
clr work
ldi YH,0x2
ldi r28,byte_count
st Y+,work
;---
cbi UCSRA,TXC
cbi UCSRB,TXCIE
reti
;ADC:ret
EE_RDY:ret
ANA_COMP:ret
TWSI:ret
EXT_INT2:ret
TIM0_COMP:ret
SPM_RDY:ret
;****************************
; ///TMR1 OVF///
;****************************
TIM1_OVF:
;запретить прерывания по переполнению
;извлекаем номер периода и продолжаем счёт
clr work
out TCCR1B,work;останов таймера
out TCNT1H,work;сбросить таймер-счётчик
out TCNT1L,work
ser work
out TIFR,work;cбросить флаги таймеров
main:
ldi YH,0x2
ldi r28,TMR1_ram
ld work1,Y+
mov t_count1_H,work1;записать число с компа в реги.
;ldi work1,10
mov t_count1_L,work1
exit_1:
ldi work,0b00000011
out TCCR1B,work;пуск таймера 1 с преддел.
out TCNT1H,t_count1_H;записать число с компа в реги таймера
out TCNT1L,t_count1_L
clr work1
sbis PORTD,UH;светик вкл?
rjmp led_on;
rjmp led_off;тогда вырубить
exit:
;sbi ADCSR,ADSC
;sbi UCSRB,TXCIE
reti
;-------------------
led_on:
sbi PORTD,UH
rjmp exit
led_off:
cbi PORTD,UH
rjmp exit
;****************************
; ///USATR RXC///
;****************************
USART_RXC:
sbi UCSRB,TXCIE
;cbi UCSRA,TXC
ldi work,0b00000000;stop timer1
out TCCR1B,work;
cbi PORTC, PC7
nop
nop
in work1,UDR;cчитываем байт
ldi YH,0x1
ldi r28,TMR1_ram
st Y,work1
sbi PORTC, PC7
nop
nop
out UDR,work1
nop
nop
ldi work,0b00000011;предделитель
out TCCR1B,work
reti
ADC:
;cbi ADCSR,ADEN
clr work
out TCCR1B,work;останов таймера
;----///извлекаем значение счётчика///
ldi YH,0x2
ldi r28,ADC_count_ram
ld work,Y
;-------------------
cpi work,0
breq ADC_0
cpi work,1
breq ADC_1
cpi work,2
breq exit_ADC
ADC_0:
ldi YH,0x1
in work,ADCL
in work1,ADCH
ldi r28,ADC0_ram
st Y+,work;ADC0H
st Y+,work1;ADC0L,
rjmp exit_ADC
ADC_1:
in work,ADCL
in work1,ADCH
ldi YH,0x1
ldi r28,ADC1_ram
st Y+,work
st Y+,work1
exit_ADC:
ldi YH,0x2
ldi r28,ADC_count_ram
ld work,Y+
inc work
ldi YH,0x2
ldi r28,ADC_count_ram
st Y+,work
;ldi work,0b00000011
;out TCCR1B,work;останов таймера
cpi work,2
breq clear_ADC_count_ram
rjmp exit_ADC1
exit_ADC1:
ldi work,0b00000011
out TCCR1B,work;останов таймера
reti
clear_ADC_count_ram:
clr work
ldi YH,0x2
ldi r28,ADC_count_ram
st Y,work
rjmp exit_ADC1
RESET:
ldi r16,high(RAMEND) ; Main program start
out SPH,r16 ; Set stack pointer to top
ldi r16,low(RAMEND)
out SPL,r16
sei ; Enable interrupts
; ///PORTA///
ldi work,0b10001111
out DDRA,work
clr work
out PORTA,work
; ///PORTD///
ldi work,0b11111111
out DDRD,work
ldi work,0b01000000;светик на РД6
out PORTD,work
; ///PORTD///
ldi work,0b00011111
out DDRB,work
; ///PORTC///
ldi work,0b10000000
out DDRC,work
;***********************************
; ///настройка таймера 1 на прерывание по переполнению///
ldi work,0b00000000;stop timer1
out TCCR1B,work;
ldi t_count1_H,0x00;
ldi t_count1_L,0x00;
out TCNT1H,t_count1_H;clr TCNT
out TCNT1L,t_count1_L;clr TCNT1
ldi work,0b00000100;разрешить прерывание по переполн. таймера1
out TIMSK,work
;***********************************
; ///настройка USART///
; Set baud rate
ldi work,23;предделитель для 19200бодов при частотe 7.3728МГц
out UBRRL,work
; Enable receiver and transmitter
ldi work,(1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(0<<UDRIE);разрешить П/П, разрешить прерывание по принятому байту в UDR
out UCSRB,work
; Set frame format: 8data, 1 stop bit, no parity
ldi work,0b10000110;(URSEL, UCSZ1, UCSZ0)
out UCSRC,work
ldi work,0b00001110;(URSEL=0) - доступ к записи UBRRH
out UCSRC,work
clr work;
out UBRRH,work;в книгах не видел, но на форумах читал что надо очищать его.
;out UCSRA,work
cbi UCSRB,RXCIE;запрет на прерывание по принятому байту.
sbi UCSRB,TXCIE
;***********************************
; ///настройка АЦП///
;*настройка опорного напряжения, смещения, выбор кол-ва входов*
ldi work,0b00000000
out ADMUX,work;5 каналов АЦП, смещение вправо, 5 входов
;*вкл/выкл АЦП опорного напряжения, смещения, выбор кол-ва входов*
ldi work,0b11001110
out ADCSR,work
;*****************************
;main loop
;*****************************
main_loop:
ldi work,0b00000011;предделитель
out TCCR1B,work
out TCNT1H,t_count1_H;заряжем таймер первым значением
out TCNT1L,t_count1_L
sbi UCSRB,RXCIE;разрешаем прерывание "байт с компа в буфере"
;---------///clr SRAM///----------
clear_SRAM:
clr work1
clr work
;---------clr ADC0_ram
ldi YH,0x1
ldi r28,ADC0_ram
clear_ADC0_ram:
inc work1
st Y+,work
cpi work1,20
brne clear_ADC0_ram
clr work1
;---------clr ADC1_ram
ldi YH,0x1
ldi r28,ADC1_ram
clear_ADC1_ram:
inc work1
st Y+,work
cpi work1,20
brne clear_ADC1_ram
clr work1
;---------clr ADC2_ram
ldi YH,0x1
ldi r28,ADC2_ram
clear_ADC2_ram:
inc work1
st Y+,work
cpi work1,20
brne clear_ADC2_ram
clr work1
;---------clr ADC3_ram
ldi YH,0x1
ldi r28,ADC3_ram
clear_ADC3_ram:
inc work1
st Y+,work
cpi work1,20
brne clear_ADC3_ram
clr work1
;---------clr ADC4_ram
ldi YH,0x1
ldi r28,ADC4_ram
clear_ADC4_ram:
inc work1
st Y+,work
cpi work1,20
brne clear_ADC4_ram
clr work1
;---------clr ADC_count_ram
clr work
ldi YH,0x2
ldi r28,ADC_count_ram
st Y,work
;---------clr TMR1_ram
ldi YH,0x2
ldi r28,TMR1_ram
st Y,work
main_loop_1:
sbi ADCSR,ADSC
rjmp main_loop_1
И что бы это значило...?;********************************
.cseg
.org 0x0010
;*****************************
jmp RESET ; Reset Handler
;..................
Код: Выделить всё
.org 0x0000
jmp RESET ; Reset Handler
.org 0x0002
jmp EXT_INT0 ; IRQ0 Handler
.org 0x0004
jmp EXT_INT1 ; IRQ1 Handler
.org 0x0006
jmp TIM2_COMP ; Timer2 Compare Handler
.org 0x0008
jmp TIM2_OVF ; Timer2 Overflow Handler
..
............
Код: Выделить всё
.org 0x0000
jmp RESET ; Reset Handler
.org 0x0002
reti ; jmp EXT_INT0 ; IRQ0 Handler
.org 0x0004
reti ; jmp EXT_INT1 ; IRQ1 Handler
...
..............
Код: Выделить всё
.cseg
.org 0x0000
rjmp RESET
.org 0x001A
rjmp USART_TXC ; USART TX Complete Handler
;***************************************
.org INT_VECTORS_SIZE
USART_TXC:
;Ваш код обработки прерывания USART
reti
;***************************************
RESET:
;Отсуда начинается ваша программа
ldi r16, Low(RAMend)
out SPL, r16
ldi r16, High(RAMend)
out SPH, r16
;Далее настраиваете порты, USART и все остальное.
sei ;Разрешим прерывания и едем далее по своей программе.
Уже начинались танцы с бубном, но всё без толкуИ что бы это значило...?
Код: Выделить всё
.cseg
.org 0x0000
jmp RESET ;От суда мы идем в начало программы, после подачи питания.
.org 0x0010
jmp TIM1_OVF ;От суда мы идём в обработку прерывания по переполнению таймера 1
.org 0x0016
jmp USART_RXC ;От суда мы идём в обработку прерывания приёма данных с USART
.org 0x001C
jmp ADC ;От суда мы идём в обработку прерывания АЦП
.org INT_VECTORS_SIZE ;Это указывает на конец таблицы векторов прерываний
;**********************************************
; Тут наши обработчики прерываний
;**********************************************
TIM1_OVF:
; Код обработчика по переполнению таймера 1
reti
;-------------------------------------------
USART_RXC:
; Код обработчика по приёму данных с USART
reti
;-------------------------------------------
ADC:
; Код обработчика АЦП
reti
;**********************************************
; Тут наша основная программа (начало)
;**********************************************
RESET:
ldi r16, Low(RAMend)
out SPL, r16
ldi r16, High(RAMend)
out SPH, r16
................
.........
.............
Ага.Я как понял, Вы недавно начали осваивать МК?
Благодарю за совет!Чтобы правильно их расставить, существует директива .org (address) Каждый вектор располагается в своём порядке. Когда срабатывает прерывание, то рабочую точку программы бросает на соответствующий адрес. Там лежит команда jmp куда-то. Если вектор не нужен, то можно сразу записать туда reti. Или записать только используемые вектора, расположив их директивами .org
Например, из всех векторов нам нужны только прерывание TIM1_OVF , USART_RXC и ADC
Тогда поступим так: