Sida 1 av 1

AVR assembler nybörjar hjälp

Postat: 25 oktober 2007, 15:46:02
av sebbe
Hej!

jag har precis börjat microprocessorteknink i skolan och vi har börjat använda en ATmega8515 med STK500 labbplatta grejen

jag har lyckats blinka och fladdra runt med lysdioder och sånt så nu skulle jag vilja testa använda en extern interrupt så jag funderar lite på hur man gjör

jag kan visa min kod och förklara vad jag vill göra

Kod: Markera allt

.include "8515def.inc"

.org 0x0000
rjmp reset
rjmp START
.org 0x0009

.def Temp =r16
.def Temp2 =r17
.def Delay2 =r18

RESET:
	ldi Temp, 0xFF
	out DDRB,Temp
	 ldi Temp, 0x00
	out DDRD,Temp
	ldi Temp, 0xff
	out PINB,Temp 


START:

ldi Temp2, low(RAMEND)
out SPL, Temp2
ldi Temp2, high(RAMEND)
out SPH, Temp2
ldi Temp , 0b10001111
out MCUCR, Temp

sei

		ldi Temp, 0b11111111
		out PORTB,Temp

		sbis PIND,6
		rjmp rakna	
		sbis PIND,7
		rjmp LOOP
		sbis PIND,5
		rjmp snurr
			
		rjmp START





rakna:
		ldi Temp, 0b11101111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11010111
		out PORTB,Temp 
		rcall delay_05
		ldi Temp, 0b11000111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b01010101
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b01000101
		out PORTB,Temp 
		rcall delay_05
		ldi Temp, 0b00010001
		out PORTB,Temp 
		rcall delay_05
		rcall delay_05
		rjmp START
snurr:
		ldi Temp, 0b11111101
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11111011
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11101111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b10111111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11011111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b10111111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b01111111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b10111111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11101111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11111011
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11110111
		out PORTB,Temp
		rcall delay_05
		ldi Temp, 0b11111011
		out PORTB,Temp
		rcall delay_05
		rjmp START


LOOP:


pett:	sbic PIND,1
		rjmp ptva
		rjmp ett
ptva:	sbic PIND,1
		rjmp ptre
		rjmp tva
ptre:	sbic PIND,1
		rjmp pfyra
		rjmp tre
pfyra:	sbic PIND,1
		rjmp pfem
		rjmp fyra
pfem:	sbic PIND,1
		rjmp psex
		rjmp fem	
psex:	sbic PIND,1
		rjmp LOOP
		rjmp sex
		

	
	
	

ett:
ldi Temp, 0b11101111
out PORTB,Temp 
rjmp pett

tva:
ldi Temp, 0b11010111
out PORTB,Temp 
rjmp ptva
tre:
ldi Temp, 0b11000111
out PORTB,Temp 
rjmp ptre

fyra:
ldi Temp, 0b01010101
out PORTB,Temp 
rjmp pfyra

fem:
ldi Temp, 0b01000101
out PORTB,Temp 
rjmp pfem

sex:
ldi Temp, 0b00010001
out PORTB,Temp 
rjmp psex



delay_05:
ldi Temp2, 8
outer_loop:
 
ldi r24, low(3037)
ldi r25, high(3037)
delay_loop:
adiw r24, 1
brne delay_loop
 
dec Temp2
brne outer_loop
ret


den funkar så att först kommer man till start och där får man välja med knappar vilket "program" man vill köra på pinne 7 kommer man till en tärning och på pinne 6 kommer man till en program som räknar upp till sex och på 5an är det bara lite fladder på dioderna

det jag skulle vilja göra är att ha en knapp som man trycker på och den ska avbryta allt och gå till "huvud menyn"
och vad jag har förståt så måste man ha en interrupt knapp för de.

jag har läst lite i databladet men förstår inte riktigt hur man gör
av det jag har förstod så måste man aktivera int1 för att få en "igång" och det gör man i SREG och GICR eller nåt?

så nu till det oluddiga :P
hur gör man en "avbryt knapp" = en interrupt

det här kanske vart jätte luddigt hoppas ni förstår :D

mvh
Sebastian

Postat: 25 oktober 2007, 17:27:59
av sodjan
Jag tror ingen kommer att läsa över 100 rader okommenterad kod...

Postat: 25 oktober 2007, 20:21:17
av Illuwatar
Du kan få en liten hint gällandes interrupt:

hoppvektor för INT0 är $0001, INT1 är $0002

Lägg en hoppinstruktion till en subrutin på någon av dessa. Koppla din tryckknapp till motsvarande ingång. Aktivera global interrupt med SEI. I subrutinen som körs måste man sluta med RETI. För att stänga av global interrupt använder man CLI.

Detta är taget från ATmega8515-databladet (gamla 8515 finns inte i listan längre):

Kod: Markera allt

Address Labels Code Comments
$000 rjmp RESET ; Reset Handler
$001 rjmp EXT_INT0 ; IRQ0 Handler
$002 rjmp EXT_INT1 ; IRQ1 Handler
$003 rjmp TIM1_CAPT ; Timer1 Capture Handler
$004 rjmp TIM1_COMPA ; Timer1 Compare A Handler
$005 rjmp TIM1_COMPB ; Timer1 Compare B Handler
$006 rjmp TIM1_OVF ; Timer1 Overflow Handler
$007 rjmp TIM0_OVF ; Timer0 Overflow Handler
$008 rjmp SPI_STC ; SPI Transfer Complete Handler
$009 rjmp USART_RXC ; USART RX Complete Handler
$00a rjmp USART_UDRE ; UDR0 Empty Handler
$00b rjmp USART_TXC ; USART TX Complete Handler
$00c rjmp ANA_COMP ; Analog Comparator Handler
$00d rjmp EXT_INT2 ; IRQ2 Handler
$00e rjmp TIM0_COMP ; Timer0 Compare Handler
$00f rjmp EE_RDY ; EEPROM Ready Handler
$010 rjmp SPM_RDY ; Store Program memory Ready Handler
$011 RESET: ldi r16,high(RAMEND); Main program start
$012 out SPH,r16 ; Set Stack Pointer to top of RAM
$013 ldi r16,low(RAMEND)
$014 out SPL,r16
$015 sei ; Enable interrupts
$016 <instr> xxx
... ... ...

Postat: 26 oktober 2007, 10:15:35
av sebbe
okej men hur gör man det då ?

typ

Kod: Markera allt

.include "8515def.inc" ;includera lite bajs

.org 0x0000  ;börja på 0000 registrert reset reg
rjmp RESET  ;om reset hoppa till RESET ???
rjmp START ;om INT0 är satt hoppa till START ????
.org 0x0009 ;gå tillbaks till rätt ställe


RESET:
	ldi Temp, 0xFF
	out DDRB,Temp
	 ldi Temp, 0x00
	out DDRD,Temp    ;sätt pinnarna till rätt
	ldi Temp, 0xff
	out PINB,Temp 


START:

sei ;aktivera global interrupt

*MENYN*

rjmp START ;gå till start eller måste man ha reti här??
är det typ så man ska göra ? men måste man inte aktivera i GCRI och MCUCR registret??

Mvh
Sebastian

Postat: 26 oktober 2007, 10:53:02
av B1n4ry
Du kan göra din "återgå" knapp på (minst) tre sätt...

Absolut enklast men inte så snyggt är ju att den knappen bara gör en reset. Alltså jorda reset-pinnen så kommer ditt program att börja om i menyn igen.

Alternativ två är mest krångligt och det är att använda interupt. Saken är ju den att när interuptyen kommer så hinner du inte avsluta det du håller på med utan programmet kommer att lämna tända lysdioder på m.m. och bara fortsätta vid din interuptfunktion. Går ju iofs att ta hand om men kräver ändå en del pyssel och interupt är inte enklaste saken att lära sig.

Tredje alternativet som jag tycker är rätt enkelt är att i dina "nyttofunktioner" (blinkandet och tärningen) med jämna mellanrrum läsa av knappen och se om den är intryckt. Är den det så avslutar du det du håller på med och återgår till menyn. Jag hade definierat en variabel kallad "exitflagga", sedan gjort en liten procedur som kollar knappen och om knappen är tryckt sätter "exitflagga" till 1. Sedan i alla loopar anropar man då och då proceduren och sedan kollar man oxå då och då om exitflaggen är satt och är den det så avslutar man snyggt och återgår till menyn...

//B1N4RY

Postat: 26 oktober 2007, 11:28:08
av sebbe
jo det är klart =) men det är ju inte lika kul :P

nä men jag skulle vilja lära mig använda interrupts så det är lite därför jag tänkte använda det

mvh
sebastian

Postat: 26 oktober 2007, 11:50:05
av ucadv
håller med B1n4ry. det är inte så "interrupt" är tänkt att användas

Postat: 26 oktober 2007, 15:29:48
av sebbe
nä det är det säkert inte men det känns som en bra grej och testa på så man får ungifär ett hum om hur det funkar

mvh
sebastian

Postat: 26 oktober 2007, 18:37:26
av Illuwatar
Man kan låta interruptet sätta en flagga som huvudprogrammet läser av i main-loopen. På så sätt är det ingen risk att man missar tryck, även om man befinner sig i en lång delayslinga.