Hjälp med assebmly program för AVR

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Hjälp med assebmly program för AVR

Inlägg av bachler »

Tjenare alla.


Tänkte att jag slänger upp en tråd om detta av 2 anledningar, dels att jag vill visa upp mitt lilla bygge och också för att få lite hjälp med programmeringen.
Jag skrev förut att jag hade problem med min hårdvaruprogrammering i största allmänhet.
För att råda bot på det så tänkte jag att jag bygger något simpelt.
Så förra söndagen så satt jag i hobbyrummet och klurade, så blev det något som kan likna en klocka eller äggtimer.
Eftersom att jag bara höftade och ville kunna bygga vidare/bygga om så byggde jag på ett sånt experimentkort med lödöar.
Det blev så simpelt som en 7805, attiny26, 4st 7segments led displayer, och lite motstånd och transistorer.
Senare tillkom 2st tryckknappar med någon tillhöftad avstudsning och ett pizero element.

Så nu försöker jag skriva någon sorts mjukvara till den här härvan av komponenter.
Jag problem med att få till något som "scannar" igenom alla 4 displayerna. Det är tanken att den rutinen ska ligga i interruptet för timer0 overflow. Nu har jag kommenterat raderna med engelska för att det känns lättare för mig att göra det pga att det ibland är svårt att hitta svenska ord som stämmer in.

keep in mind att det är mitt första assembly program.

Kod: Markera allt

; avr tiny26 clocka
; alexander bachler jansson
; PORTA
; PORTB

.nolist
.include "tn26def.inc"
.list
.device attiny26

.dseg
.org 0x0060
	segments: .byte 10		; holds the individial segment data for each number 0-9
	display: .byte 1		; holds count of witch display to drive 0-3
	data: .byte 4			; holds the nubmers to be displayed on each digit

.cseg
.org 0x0000
	rjmp main
	rjmp main				; External Interrupt 0
	rjmp main				; External Interrupt Request 0
	rjmp main				; Timer/Counter1 Compare Match 1A
	rjmp main				; Timer/Counter1 Compare Match 1B
	rjmp main				; Timer/Counter1 Overflow
	rjmp OVF0_interrupt		; Timer/Counter0 Overflow
	rjmp main				; USI Start
	rjmp main				; USI Overflow
	rjmp main				; EEPROM Ready
	rjmp main				; Analog Comparator
	rjmp main				; ADC Conversion Complete


; -----------------------------------------------------------------------------
; does some things
OVF0_interrupt:
	push r16
	push r17
	push r18
	push XH
	push XL
	push YH
	push YL
	push ZH
	push ZL

	ldi ZH, high(display)
	ldi ZL, low(display)

	ld r17, Z				; load witch display we are updating

	ldi YH, high(data)
	ldi YL, low(data)

	add YL, r17				; add display to YL to get address of data

	ld r18, Y				; load data to r18

	ldi XH, high(segments)
	ldi XL, low(segments)

	add XL, r18				; add data for display to segment offset	

	ld r16, X				; load it

	out PORTB, r16			; put it on display

	ldi r16, 0b0000_1110	;

	out PORTA, r16			; activate dispay

	pop ZL
	pop ZH
	pop YL
	pop YH
	pop XL
	pop XH
	pop r18
	pop r17
	pop r16
	reti
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; puts each numbers segment data into a table in ram 0-9
init_segments:
	push r16				; this is probably not needed since we
	push XH					; do this onec at the very beginning
	push XL					; of our program

	ldi XH, high(Segments)
	ldi XL, low(Segments)
	
	ldi r16, 0b0011_1111	; 0
	st X+, r16				; 0x0060

	ldi r16, 0b0000_0110	; 1
	st X+, r16				; 0x0061

	ldi r16, 0b0101_1011	; 2
	st X+, r16				; 0x0062

	ldi r16, 0b0100_1111	; 3
	st X+, r16				; 0x0063

	ldi r16, 0b0110_0110	; 4
	st X+, r16				; 0x0064

	ldi r16, 0b0110_1101	; 5
	st X+, r16				; 0x0065

	ldi r16, 0b0111_1101	; 6
	st X+, r16				; 0x0066

	ldi r16, 0b0000_0111	; 7
	st X+, r16				; 0x0067

	ldi r16, 0b0111_1111	; 8
	st X+, r16				; 0x0068

	ldi r16, 0b0110_1111	; 9
	st X, r16				; 0x0069
	
	pop XL
	pop XH
	pop r16

	ret
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; init port directions
init_ports:
	push r16				; also, probably not needed

	ldi r16, 0b1000_1111	; buzzer n/c button 2, button 1, digit 4, 3, 2, 1
	out DDRA, r16
	
	ldi r16, 0b0111_1111	; segments, g, f, e, d, c, b, a
	out DDRB, r16

	pop r16
	ret
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; init and start the timer
init_timer:
	push r16				; pobably not
	
	ldi r16, 0b0000_1101	; PSR0, CS02, CS00	// ck/1024
	out TCCR0, r16

	ldi r16, 0b0000_0010	; TOIE0
	out TIMSK, r16

	pop r16
	ret
; -----------------------------------------------------------------------------


main:
	ldi r16, low(RAMEND)	; init stack
	out SP, r16				; load to stack pointer
	
	rcall init_segments		; load segments data to ram
	rcall init_ports		; init ports directions
	rcall init_timer		; start the timer

	ldi XH, high(data)
	ldi XL, low(data)
	
	ldi r16, 2
	
	st X, r16

	ldi XH, high(display)
	ldi XL, low(display)
	
	ldi r16, 0
	
	st X, r16
	
	sei						; enable interrupts

loop:
	rjmp loop
IMAG0170.jpg
IMAG0165.jpg
edit:bilder
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med assebmly program för AVR

Inlägg av sodjan »

> Jag problem med att få till något som "scannar" igenom alla 4 displayerna.

Vad är "problemen" ??
Vad är det som inte händer som du tror ska hända ?
För övrigt är det inte mycket att kommentera eftersom
det inte finns några frågor igentligen.

En mindre sak bara som jag fastnade för...

> ldi r16, 0b0110_1101

Är det korrekt syntax med ett extra underscore där ?
Mycket möjligt, men det ser lite underligt ut...
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av bachler »

> För övrigt är det inte mycket att kommentera eftersom det inte finns några frågor igentligen.

Nej det är sant, jag har inte inte riktigt hunnit formulera dom än. Det kommer.

> Är det korrekt syntax med ett extra underscore där ?

Japp, det funkar i AVR Studio 4, jag tycker det blir mycket lättare att se vilka bitar som är på och av
om man delar upp det per nibbel istället för att skriva hela byten.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med assebmly program för AVR

Inlägg av sodjan »

> Nej det är sant, jag har inte inte riktigt hunnit formulera dom än. Det kommer.

Men då tycker jag att du borde vänta(t) till du har/hade allt klart.

> jag tycker det blir mycket lättare att se vilka bitar som är på och av

Absolut ! Det tycker jag med. Och fungerar det så fungerar det... :-)
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av bachler »

> Men då tycker jag att du borde vänta(t) till du har/hade allt klart.

Du har så rätt som en tokig :lol:

Dock tänkte jag att ifall någon har lust att kanske föreslå någon smart metod så är det juh fritt fram.

Jag tänkte att man skulle sätta en bit i ett på LSB positionen och sedan shifta den mot MSB tills den är på platsen för sista displayen bit 3 och då sätta 0 biten igen.

En annan grej är att jag inte riktigt förstått hur man gör för att maska av den låga nibbeln på porten.
Användarvisningsbild
stekern
Inlägg: 453
Blev medlem: 2 november 2008, 08:24:18
Ort: Esbo, Finland

Re: Hjälp med assebmly program för AVR

Inlägg av stekern »

En liten kommentar angående interruptvektorn.
Om du skulle råka slå på något av interrupten som inte används kommer koden som den ser ut nu bete sig lite underligt, eftersom den då hoppar till början av main.
Normalt brukar man bara ha en reti på de interrupts som är oanvända.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med assebmly program för AVR

Inlägg av sodjan »

> En annan grej är att jag inte riktigt förstått hur man gör för att maska av den låga nibbeln på porten.

Lämplig användning av AND och/eller OR instruktionerna. Busenkelt...

> Jag tänkte att man skulle sätta en bit i ett på LSB positionen och sedan shifta den
> mot MSB tills den är på platsen för sista displayen bit 3 och då sätta 0 biten igen.

För att göra *VADÅ* ??

Problemet är fortfarande att du inte har presenterat något problem eller någon fråga !
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av bachler »

@stekern: ja just de. så blir det ju såklart. då sättar jag reti där istället

>För att göra *VADÅ* ??
>Problemet är fortfarande att du inte har presenterat något problem eller någon fråga !

Hehe, i min enfald så tänker juh jag inte på att andra inte vet vad jag har i huvudet.

Mina 4 segmentdisplayer är alltså kopplade med en PNP trissa som driver common när den får en 0a från porten.
De fyra segmenten sitter på PORTA 0 till 3. Så jag vill för att uppdatera displayerna under intterupt rutinen, "scanna" igenom
den låga nibbeln av PORTA med en 0a. utan att röra den höga nibbeln.

så först så ser PORTA ut såhär
xxxx1110
nästa steg blir
xxxx1101
och nästa
xxxx1011
sista
xxxx0111
och sedan börjar man om från första steget igen

Om vi bara börjar med att maska bort den höga nibblen från outputen?
Hur skulle koden för att göra det se ut?

Kod: Markera allt

ldi r17, [här ska det vara segment]
andi r17, 0b0000_1111
out PORTA, r17
Är det rätt tänkt?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med assebmly program för AVR

Inlägg av sodjan »

Du skriver alltså alltid "0000" till höga delen av PORTA, är det det du vill ?

Eller vill du att den höga delen av PORTA *inte ska ändras* ?
I så fall får du först läsa in den, göra lite maskning så att höga delen
inte ändras och skriva tillbaka med samma höga del kombinerat med
dina nya låga delar. På en PIC hade man kanske kört bit-operationer
direkt på porten, men det kanske inte fungerar. Man kan även använda
ett "shadow-register" där amn gör allt bitfibblade som sedan skriva i sin
helhet ut till PORTA. Då man kanske shadow-registret ligga på en adress
där även bit-instruktionerna i AVR fungerar.

Men om "[här ska det vara segment]" är en konstant så kan den väl redan
ha den höga nibblen nollad. Eller är det något som läses någonannanstans ifrån ?
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av bachler »

> Du skriver alltså alltid "0000" till höga delen av PORTA, är det det du vill ?

Nej det ville jag inte.

> Eller vill du att den höga delen av PORTA *inte ska ändras* ?

Korrekt.

> I så fall får du först läsa in den, göra lite maskning så att höga delen
> inte ändras och skriva tillbaka med samma höga del kombinerat med
> dina nya låga delar.

> Men om "[här ska det vara segment]" är en konstant så kan den väl redan
> ha den höga nibblen nollad. Eller är det något som läses någonannanstans ifrån ?

Ja, tanken var att spara [här ska det vara segment(displayens nummer som skall vara aktiv för tillfället)] i sram
som ett nummer bara 0-3.

Kanske blir mera rätt om jag gör såhär?

Kod: Markera allt

; ovan bör finnas kod som inte finns ännu
; för att få in min xxxx1110, xxxx1101.. osv i r17
in r16, PINA
and r16, r17
out PORTA, r16
Om man tar en sak i taget såhär så blir det lättare ;)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med assebmly program för AVR

Inlägg av sodjan »

Läs in PORTA/PINA/INA (eller vad det nu heter) till ett tmp register.

AND tmp med 1111_0000 för att "nolla" låga delen och behålla höga delen.
Or med (t.ex) 0000_1110 för att sätta låga delen till önskat segment.
OUT till PORTA av tmp registret.

Gör om för alla segment, d.v.s med 0000_1101, 0000_1011 och 0000_0111.
Användarvisningsbild
bachler
EF Sponsor
Inlägg: 189
Blev medlem: 23 december 2003, 13:58:24
Skype: alexander.bachler.jansson
Ort: Sala
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av bachler »

Sådär nu tror jag att jag har kommit halvvägs med display rutinen, eller lite längre än halvvägs tillochmed.

Det funkar nu och den uppdaterar displayen och hämtar varje displays siffra från sram. :bravo:

Tack för hjälpen sodjan

Kod: Markera allt

; avr tiny26 clocka
; alexander bachler jansson
; PORTA
; PORTB

.nolist
.include "tn26def.inc"
.list
.device attiny26

.dseg
.org 0x0060
	segments: .byte 10		; holds the individial segment data for each number 0-9
	display: .byte 1		; holds count of witch display to drive 0-3
	data: .byte 4			; holds the nubmers to be displayed on each digit

.cseg
.org 0x0000
	rjmp main
	reti					; External Interrupt 0
	reti					; External Interrupt Request 0
	reti					; Timer/Counter1 Compare Match 1A
	reti					; Timer/Counter1 Compare Match 1B
	reti					; Timer/Counter1 Overflow
	rjmp OVF0_interrupt		; Timer/Counter0 Overflow
	reti					; USI Start
	reti					; USI Overflow
	reti					; EEPROM Ready
	reti					; Analog Comparator
	reti					; ADC Conversion Complete


; -----------------------------------------------------------------------------
; does some things
OVF0_interrupt:
	push r16
	push r17
	push r18
	push XH
	push XL
	push YH
	push YL
	push ZH
	push ZL

	ldi ZH, high(display)
	ldi ZL, low(display)

	ld r17, Z				; load the display we are updating

	ldi YH, high(data)
	ldi YL, low(data)

	add YL, r17				; add display to YL to get address of data

	ld r18, Y				; load data to r18

	ldi XH, high(segments)
	ldi XL, low(segments)

	add XL, r18				; add data for display to segment offset	

	ld r16, X				; load it

	out PORTB, r16			; put segments on display port


	ser r16

	ldi r18, 0

	lsl r16	
	cp r17, r18
	breq skip
lslloop:
	lsl r16
	sbr r16, 0b0000_0001
	dec r17
	brbc 1, lslloop
skip:

	in r17, PORTA			; read PINA to r16	

	andi r17, 0b1111_0000	; clear lower nibble of r17
	andi r16, 0b0000_1111	; clear high nibble of r16

	or r16, r17

	out PORTA, r16			; activate dispay

	ld r17, Z				; load the display we are updating

	inc r17
	cpi r17, 4
	brne hopp
	ldi r17, 0
	hopp:

	st Z, r17

	ldi r16, 160
	out TCNT0, r16

	pop ZL
	pop ZH
	pop YL
	pop YH
	pop XL
	pop XH
	pop r18
	pop r17
	pop r16
	reti
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; puts each numbers segment data into a table in ram 0-9
init_segments:
	push r16				; this is probably not needed since we
	push XH					; do this once at the very beginning
	push XL					; of our program

	ldi XH, high(Segments)
	ldi XL, low(Segments)
	
	ldi r16, 0b0011_1111	; 0
	st X+, r16				; 0x0060

	ldi r16, 0b0000_0110	; 1
	st X+, r16				; 0x0061

	ldi r16, 0b0101_1011	; 2
	st X+, r16				; 0x0062

	ldi r16, 0b0100_1111	; 3
	st X+, r16				; 0x0063

	ldi r16, 0b0110_0110	; 4
	st X+, r16				; 0x0064

	ldi r16, 0b0110_1101	; 5
	st X+, r16				; 0x0065

	ldi r16, 0b0111_1101	; 6
	st X+, r16				; 0x0066

	ldi r16, 0b0000_0111	; 7
	st X+, r16				; 0x0067

	ldi r16, 0b0111_1111	; 8
	st X+, r16				; 0x0068

	ldi r16, 0b0110_1111	; 9
	st X, r16				; 0x0069
	
	pop XL
	pop XH
	pop r16

	ret
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; init port directions
init_ports:
	push r16				; also, probably not needed

	ldi r16, 0b1000_1111	; buzzer n/c button 2, button 1, digit 4, 3, 2, 1
	out DDRA, r16
	
	ldi r16, 0b0111_1111	; segments, g, f, e, d, c, b, a
	out DDRB, r16

	pop r16
	ret
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; init and start the timer
init_timer:
	push r16				; pobably not
	
	ldi r16, 0b0000_1011	; PSR0, CS02, CS00	// ck/1024
	out TCCR0, r16

	ldi r16, 0b0000_0010	; TOIE0
	out TIMSK, r16

	ldi r16, 100
	out TCNT0, r16

	pop r16
	ret
; -----------------------------------------------------------------------------


main:
	ldi r16, low(RAMEND)	; init stack
	out SP, r16				; load to stack pointer
	
	rcall init_segments		; load segments data to ram
	rcall init_ports		; init ports directions
	rcall init_timer		; start the timer

	ldi XH, high(data)
	ldi XL, low(data)
	
	ldi r16, 4				; set data for display 0 to 2
	
	st X+, r16
	dec r16
	st X+, r16
	dec r16
	st X+, r16
	dec r16
	st X, r16

	ldi XH, high(display)
	ldi XL, low(display)
	
	ldi r16, 0				; we are updating display 1 next
	
	st X, r16
	
	sei						; enable interrupts

loop:
	rjmp loop
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Hjälp med assebmly program för AVR

Inlägg av Swech »

Att lägga en tabell i SRAM så som det är gjort är lite "gå över bäcken för att hämta vatten"
Det är mycket lättare och smidigare att lägga tabeller direkt i programminnet (FLASH)

Sen använder du dig av Z för att läsa från tabellen.

Kod: Markera allt


;  > R16:= POSITION I TABELL ATT LÄSA AV

   LDI    ZL,LOW(MY_TABLE*2)    ;Z:=PEKAR PÅ TABELL
   LDI    ZH,HIGH(MY_TABLE*2)
   ANDI  R16,15                         ;MAX 16 POSITIONER I TABELLEN

   LDI    R17,0                           
   ADD   ZL,R16
   ADC   ZH,R17
   
   LPM   R16,Z                      ;R16:=TABELLVÄRDE
   RET

MY_TABLE:
.DB      0b0011_1111,0b0000_0110    ;0,1
.DB      0b0101_1011,0b0100_1111    ;2,3
.DB      0b0110_0110,0b0110_1101 
.DB      0b0111_1101,0b0000_0111   
.DB      0b0111_1111,0b0110_1111 
.DB      0,0
.DB      0,0
.DB      0,0

Swech
Skriv svar