PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATtiny13 und Studio4 in Assembler



hegewald
18.12.2011, 07:49
Hallo Leute,
seit einem halben Jahr habe ich von Bascom zu AVR-Studio4 in Assembler gewechselt.
Es ist schon eine Umstellung.
Ein Tiny13 ist mit Bascom als Ortungspieper programmiert.
Dazu dienen 3 DIP-Schalter mit der Bezeichnung "sw1 | sw2 | sw3" für verschiedene Zeiten.

Die Schalter wurden in Bascom mit Alias den Ports zugewiesen.
sw1 Alias Pinb.4 (oder PINB,PB4)
sw2 Alias Pinb.1
sw3 Alias Pinb.2
Ich lese nun schon in allen möglichen Büchern, um sowas auch im Assembler zu realisieren.
In den Direktiven gibt es den Befehl .DEF...aber damit kann ich nur den Arbeitsregistern R0-R31
einen Namen zuweisen, keinen Port-Register.
Hat jemand von Euch eine Idee?

Grüße

Rolf

Hubert.G
18.12.2011, 09:09
Vielleicht hilft dir das hier: http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen

oberallgeier
18.12.2011, 09:38
... von Bascom zu AVR-Studio4 in Assembler gewechselt ...
... in Bascom mit Alias ... sw1 Alias Pinb.4 (oder PINB,PB4) ... sowas auch im Assembler zu realisieren ...Und das geht in Assem bler nicht? Hmmmm. Ich hatte in Assem bler viel mit #define-s gearbeitet, z.B. hieß das Allzweckregister r16 öfters kurz "a", ein einzelner Pin z.B. servo1 und so. WENN das Register r16 a heissen kann, warum sollten dann Portregister nicht auch benannt werden können? Leider hatte ich auf die Schnelle in meinen Quellen dazu kein Beispiel mit Port-Alias gefunden.

Mal ein Beispiel aus meinem Code für (m)einen Servotester (klick) (https://www.roboternetz.de/community/threads/44919-Servo-tester-mit-ATiny13?p=430092&viewfull=1#post430092) mit einem tiny13, siehe die Aliase servo1, msmin und msges. Vielleicht hilft Dir das? (Oder diese Beiträge? - klick) (https://www.roboternetz.de/community/threads/31164-läuft-Code-Servotest-an-ATtiny13-läuft-nicht)


;================================================= ==================================
; Speicherbelegung
;r14 low-Byte der ADC-Wandlung (lsb)
;r15 high-Byte der ADC-Wandlung: Beide ergeben einen Wert zwischen 0...1023
;r16 Mehrzweck, high-Byte in Pausen "pause_an", "pause_aus", "led_ende" u.ä.
;r17 low-Byte in Pausen, s.o.
;
;r18 -- --
;r19 -- --
;r20 -- --
;
;r21 Byte Steuerbyte. Es werden nur Bits ausgewertet
; "Rampe" an-aus, 1=Rampe an, bit 1 = Servo 1 , bit 5 = Servo 2
; Übernahme Rampenwert, 1=Daten wurden noch nicht übernommen vom
; Hauptprogramm in die ISR, 0=ISR hat Daten abgeholt und zwar
; bit 2 = Servo 1 , bit 6 = Servo 2
;r22 1/2 Word lsb Zeitwert Rampe aus auf-ab-Rechnerei im Hauptprogramm
;r23 1/2 Word msb zu r26
;r24 1/2 Word LSB Zeitwert Rampe aus ADC/Poti im Hauptprogramm
;r25 1/2 Word MSB wird vom r14/15 geholt und zurechtgerechnet
;
;r26 1/2 Word LSB GESAMTDAUER Servoimpuls MUSS in r26/27 sein wegen sbiw
;r27 1/2 Word MSB Zeitwert für GESAMTDAUER Servoimpuls, etwa 500 Takte ?
;
;r28 1/2 Word lsb LSB RampenCOUNTER Servo1, wird in ISR runtergezählt
;r29 1/2 Word msb MSB Counter stammt vom ADC
;r30 1/2 Word lsb LSB Auf-ab-COUNTER Servo2, wird in ISR runtergezählt
;r31 1/2 Word msb MSB
;
;================================================= ==================================
; ..................
;================================================= ==================================
; Deklarationen für den Praeprozessor
; Konstanten ####### evtl. auch keine Konstanten definiert
;
#define a r16 ;Kurzbezeichung für Allzweckregister r16
;
; Anschlussbelegung, vgl. srv-adc+pwm-x29b.asm
#define servo1 3 ;Servo 1 auf Port PB3
#define potiadc 2 ;Poti 1 am Port PB4 geht auf ADC-Kanal 2
;
;Festwerte und div. Daten für adcdat etc ====>
#define adcpsc 7 ; =7 ==> Clock/128, 9,6 MHz werden 75 kHz, vgl. doc, S93
;#define adcdat 3 ;Dummywert vom ADC ###>>> "Nur" 8Bit-Wandlung ! ? !
#define msges 5000 ;Gesamtzeit der Rampe: 5000 ISR-Zyklen sind 20 ms
#define mstest 1000 ;Test ergibt mit mstest 500 und tmprs 40: für 2,0 ms
; das heisst: 4 µs Interrupt-Abstand (Fehler +4%)
#define msmin 100 ;Minimalwert für Rampe: 0,5 ms
#define tmrprs 38 ;Preset im Timer-Register (hoffentlich für CTC)
;
;================================================= ==================================
; Hauptprogramm
;================================================= ==================================
;
anfang:
; .......
;================================================= ==================================
;
;
isr_ctc: ;=== Immer wieder Veränderungen
;
sbiw r27:r26,1 ;Pointer von 5000 runterzählen
; für EINEN Servoimpuls von 20 ms
breq i_neu ; .. und Spezialfall "null" ==> Daten umschaufeln
; und Rampe einschalten. WENN keine neuen Daten da
; sind, dann alte Daten nehmen :(
;
; Jetzt wird nachgesehen, ob eine der Rampen ausgeschaltet werden muss. Das steht
; im Portbit ddrb
;
isr_nn: ;=== Zähler der ISR steht nicht auf Null
s1_pran: ;=== Servo1: Prüfe, ob Rampe ist an
in r20,portb
sbrs r20,servo1 ;Ist Rampe von servo1 an?
rjmp i_raus ;Wenn Rampe nicht an ist, dann gleich raus
;
sbiw r29:r28,1 ;Decrementiere Rampenwert
brne i_raus ;weiter, wenn noch nicht Null zu servo2
cbi portb,servo1 ; Sonst Lösche Rampe für Servo1
;
rjmp i_raus sbiw r29:r28,1
breq i_neu
rjmp i_raus
i_neu: ;Daten neu in Register und port servo1 umschalten
ldi r28,low(msmin)
ldi r29,high(msmin)
; mov r17,r15 ;Es ist adlar gesetzt, das ADCLH ist in r15
ldi r18,0
add r28,r15
adc r29,r18
;Und ADC-Wert gleich nochmal draufaddieren
; aber nur die Hälfte
clc ;Clear carry für anschliessende Division /2
ror r15 ;
add r28,r15
adc r29,r18
;
ldi r26,low(msges) ;Loopgrenzen für Gesamtloop 20 msec
ldi r27,high(msges)
sbi portb,servo1 ; Und setze Rampe für Servo1. FERTIG
;
i_raus:
reti ;=====----->>>>>
;
;================================================= ==================================
; Ende des Quellcodes
;================================================= ==================================

hegewald
19.12.2011, 08:00
Hallo Hubert und Oberallgeier,
danke für Eure Hilfe!
zu Hubert...habe schon das halbe AVR - Tutorial gelesen, aber zu den Vorschlag von Oberallgeier

#define sw1 PINB,PB4
stand nichts! Auch in meinen Buch zum AVR-Assembler war nichts zu lesen.
Und es funktioniert tadellos.
Schlau geworden bin ich auch, wie ich die PULLUP-Widerstände am Portb setze.
Nun werde ich über Timer0 3 Zeiten von 20 / 30 / 40 Minuten aufbauen.

Grüße

Rolf

Besserwessi
19.12.2011, 16:14
Viele der Tutorials und Bücher sind noch für den alten Assembler. Der kann den Befehl #define noch nicht. Da hat man so etwas per .equ Direktive gemacht. Bei AVR Studio4 kann man zwischen der alten und neuen Version des Assemblers wählen.

hegewald
20.12.2011, 11:55
Hallo Leute,
ich hänge mit den Tiny13 auf dem Schlauch...und habe schon das Datenblatt studiert.
Anfangsteile vom Quelltext und Aufruf der ISR am Ende:

.INCLUDE "tn13def.inc" ; Deklarationen für Tiny13
.EQU takt = 1000000 ; Systemtakt 1 MHz
#define test PINB,PB3
#define sw1 PINB,PB4
#define sw2 PINB,PB1
#define sw3 PINB,PB2
rjmp start ; Reset-Einsprung
.ORG OVF0addr ; Interupt-Vektoren
rjmp TIM0_OVF ; Sprung zur ISR

start: ldi r16,LOW(RAMEND) ; Stapel anlegen
out SPL,r16

ldi r16,0x01 ; Bitmuster 0000 0001
out DDRB,r16 ; PortB (PB0 ist Ausgang)
ldi r16,0b00011110 ; PB1-PB4 = PULLUP
out PORTB,r16

;Interrupt-ISR
TIM0_OVF: push r16
in r16,SREG
dec r17
pop r16
out SREG,r16
reti
Der Compiler vom Studio4 gibt Fehlermeldung "TIM0_OVF" undefiniertes Symbol.
Beim Tiny2313 läuft das anstandslos...ich weiß nicht mehr weiter.
Auch wenn ich in der loop-Schleife "rcall zeit4" eingebe, und die Routiene mit ret beende,
kommt die Fehlermeld. zeit4 undef. Symbol

Grüße

Rolf

hegewald
20.12.2011, 12:34
Sorry, hab den Fehler gefunden!

Vor der ISR und den Aufrufen der Zeiten stand ein ".EXIT", und das hat mich 4 Stunden gekostet.

oberallgeier
20.12.2011, 12:45
... ein ".EXIT", und das hat mich 4 Stunden gekostet.Ein langsamer Ausgang . . . *ggg*. Aber besser ein .exit in der Software als der .exitus des Controllers.

Searcher
20.12.2011, 12:55
;Interrupt-ISR
TIM0_OVF: push r16
in r16,SREG
dec r17
pop r16
out SREG,r16
reti


Hallo,
ich bin Anfänger in ASM, aber könnte es sein, daß das grüne push fehlt oder das rote pop zuviel ist?

;Interrupt-ISR
TIM0_OVF: push r16
in r16,SREG
push r16
dec r17
pop r16
out SREG,r16
pop r16
reti


Gruß
Searcher

MagicWSmoke
20.12.2011, 13:44
..., aber könnte es sein, daß das grüne push fehlt oder das rote pop zuviel ist?
Nein, nur vertauscht, richtig wär's so:

TIM0_OVF:
push r16
in r16,SREG
dec r17
out SREG,r16
pop r16
reti
Der Originalcode:

pop r16
out SREG,r16
stellt dagegen SREG mit einem Wert wieder her, den R16 beim Aufruf des Interrupts hatte, was für kreatives Verhalten des Codes sorgt.

hegewald
20.12.2011, 17:52
Hallo Macig,
den Cod
TIM0_OVF:
push r16
in r16,SREG
dec r17
out SREG,r16
pop r16
reti
hatten mir die Provis vom www.mikrocontroller.net vorgegeben, und daran habe ich mich dann gehalten.
SREG ist doch ein Register (Bit7=I) =sei, wenn gesetzt, läuft der Overflow ständig.
Was mich nun beschäftigt, die Zeiten von 20 | 30 | 40 Minuten zu realisieren...das wird noch an Zeit kosten.
Toleranzen sehe ich mit +/- 5%

Grüße

Rolf

MagicWSmoke
20.12.2011, 18:39
Hallo Hegewald,

TIM0_OVF:
push r16
in r16,SREG
dec r17
out SREG,r16
pop r16
reti
hatten mir die Provis vom www.mikrocontroller.net (http://www.mikrocontroller.net/) vorgegeben, und daran habe ich mich dann gehalten.
Dieser Code jetzt entspricht dem von mir berichtigten.

Vergleich' dazu Dein Post Nr. 6 dieses Threads:
;Interrupt-ISR
TIM0_OVF: push r16
in r16,SREG
dec r17
pop r16
out SREG,r16
reti
Nur darum ging's, das ist falsch.
Betrachte genau wo R16 gepoppt wird und wo in's SREG heschrieben wird.

hegewald
21.12.2011, 07:40
Hallo Macig,
hast Recht, hier war ein Dreher, in meinen Quelltext habe ich es nochmal kontrolliert.
Habe mich mit den PUSH / POP nochmal über Bücher informiert.
Danach würde doch der Ablauf so aussehen:
push r16 ; push kopiert den Inhalt von r16 auf die durch den Stapelzeiger SP adressierte SRAM Speicherstelle
; und vermindert den SP um 1
Nun steht hier weiter für den Mega8:
Der Stapelzeiger (das ist doch eine Adresse im SRAM-Bereich,oder?) wird sofort nach dem Start des Programms
auf die höchste SRAM Adresse gesetzt. In der Deklarationsdatei m8def.inc vordefiniert auf Adresse RAMEND=$045F.
Wie das beim Tiny13 aussieht, kann ich nicht erkennen, oder Datenblatt ranholen.

pop r16 ; pop erhöht erst den Stapelzeiger SP um 1 und lädt dann r16 mit dem adressierten SRAM-Byte

Interessant ist auch, daß die Befehle rcall / icall / call und Inter. die aus 2 Bytes besteh. Rücksprungadresse
auf den Stapel legen, und automatisch durch ret bzw. iret wieder entfernt werden.
Wie gesagt, man schreibt im Quelltext notorisch so viele Befehlsabläufe und wies eigentlich garnicht, was da so
richtig passiert. Alles ist natürlich auch eine Zeitfrage um sich mit der Materie zu beschäftigen.
Ich als Rentner habe die Zeit, und der Geist bleibt dadurch in Bewegung.

Das wars erst mal, hoffentlich langweilt Dich dieses Thema nicht.

Grüße

Rolf

MagicWSmoke
21.12.2011, 08:45
das ist doch eine Adresse im SRAM-Bereich,oder?
Ja. Variablen wachsen von niedriger Adresse nach hoher Adresse, der Stack von hoher nach niedriger Adresse.
Wenn der Stackverbrauch zu groß wird, z.B. durch rekursiven Code, dann wächst er in die Variablen hinein und es gibt Datensalat.

Wie das beim Tiny13 aussieht, kann ich nicht erkennen, oder Datenblatt ranholen.
RAMEND ist je nach Prozessortyp und dessen SRam-Größe an anderer Adresse, das Prinzip bleibt zumindest bei den hier besprochenen Prozessoren immer gleich.

Interessant ist auch, daß die Befehle rcall / icall / call und Inter. die aus 2 Bytes besteh. Rücksprungadresse
auf den Stapel legen, und automatisch durch ret bzw. iret wieder entfernt werden.
Der Stack arbeitet nach dem LiFo-Prinzip, last in, first out.

Das wars erst mal, hoffentlich langweilt Dich dieses Thema nicht.
Nein, sonst hätte ich ja nicht geantwortet. Wobei Du mir zur Funktion aber sicher nix Neues sagen kannst :D