ATmega8 - Werte [SRAM] zeitweise in ein anderes [SRAM] laden

Jonas

Neues Mitglied
04. März 2010
3
0
0
Sprachen
Hallo zusammen,

meine Projektgruppe und ich haben folgendes Problem Wir haben einen ATmega8 und eine Multiplexanzeige mit vier Stellen. Unser Programm(MY AVR) was ich gleich anhängen werde, zählt hoch im ms Takt über den Timer_1 und wird über den Timer_0 auf die Multiülexanzeige ausgegeben. Soweit so gut. Wir wollen die vergangene Zeit messen die über ein und den selben Sensor erfasst werden soll. Unser problem ist, dass wir die Werte die ins SRAM geschrieben werden, solange bei der ersten Routine in ein Zwischenspeicher zuladen um die bei der nächsten gemessen Routine vergangene Zeit ins Zwischenregister zu speichern um den ersten Wert aus dem Zwischenspeicher zuladen. D.h. das wir fortlaufend Werte umladen.

So... Viel gequatscht und vielleicht schwer beschrieben, aber ich hänge euch mal das Pro(blem)gramm an.




PROGRAMM:


CodeBox ASM

.include<m8def.inc>
.cseg
.org 0x000
rjmp reset
.org 0x008
rjmp tim1_ovf
.org 0x009
rjmp tim0_ovf
;*************************************************************************
.org 0x020
reset:
ldi r16,LOW(RAMEND)
out spl,r16
ldi r16,HIGH(RAMEND)
out sph,r16
ldi r16,0x00
out ddrc,r16
ldi r16,0xff
out ddrb,r16
out ddrd,r16
out portc,r16
ldi r16,0b00000011
out tccr0,r16 ;interner Takt Timer0 - Frequenz CLK/64
ldi r16,0000000001
out tccr1b,r16 ;interner Takt - kein Vorteiler
ldi r17,0xf1 ;timer highbyte zuerst initialisieren
ldi r18,0xb4 ;timer lowbyte initialisieren
out tcnt1h,r17
out tcnt1l,r18
ldi r16,0b00000001
out timsk,r16 ;timer0 interrupt ermöglichen
ldi zl,0x60 ;zeiger auf ausgabewerte
ldi zh,0x00
ldi r16,0x00
sts stelle,r16 ;stellenzähler
ldi r16,0x00
sts einer,r16
ldi r16,0x00
sts zehner,r16
ldi r16,0x00
sts hunderter,r16
ldi r16,0x00
sts tausender,r16
ldi r20,0x00
sei

start:
sbis pinc,0
rjmp start

st1:
ldi r16,0x00
sts stelle,r16 ; stellenzähler
sts einer,r16 ; `0` ---> einer
sts zehner,r16 ; `0` ---> zehner
sts hunderter,r16 ; `0` ---> hunderter
sts tausender,r16 ; `0` ---> tausender
ldi r16,0b00000101 ; timer 1\0 interrupt ermöglichen
out timsk,r16
st2:
; rcall zeit
sbic pinc,0
rjmp st2
st3:
ldi r16,0b00000001 ;timer0 interuppt ermöglichen
out timsk,r16
; rcall zeit
rjmp start

tim0_ovf:
sei ;interrupts zulassen
push r16 ;register retten
push r17
push r18
push r19
in r16,sreg ;statusregister sichern
ld r18,z+ ;ausgabewert holen
lds r19,stelle ;stelle holen
swap r19 ;nibbles tauschen
out portb,r18 ;wert ausgeben
out portd,r19 ;stelle ausgeben
swap r19 ;stelle zurücktauschen
inc r19
sts stelle,r19 ;und sichern
cpi r19,0x04
brlo t0_1
ldi zl,0x60
ldi zh,0x00
ldi r19,0x00
sts stelle,r19

t0_1:
out sreg,r16 ;statusregister wieder herstellen
pop r19 ;register wieder herstellen
pop r18
pop r17
pop r16
reti

tim1_ovf:

push r16
push r17
push r18
in r16,sreg
lds r16,einer ;einerstelle holen
inc r16 ;und inkrementieren
cpi r16,0x0a
brsh s2 ;wenn einer > 9
sts einer,r16 ;sonst einer sichern
rjmp t1_end ;und wiederholen
s2: ldi r16,0x00
sts einer,r16 ;einer zurücksetzen
lds r16,zehner
inc r16 ;zehner inkrementieren
cpi r16,0x0a
brsh s3 ;wenn zehner > 9
sts zehner,r16 ;sonst zehner sichern
rjmp t1_end ;und wiederholen
s3: ldi r16,0x00
sts zehner,r16 ;zehner zurück setzen
lds r16,hunderter
inc r16 ;hunderter inkrementieren
cpi r16,0x0a
brsh s4 ;wenn hunderter > 9
sts hunderter,r16 ;sonst hunderter sichern
rjmp t1_end ;und wiederholen
s4: ldi r16,0x00
sts hunderter,r16 ;hunderter zurücksetzen
lds r16,tausender
inc r16 ;tausender inkrementieren
cpi r16,0x0a
brsh s5 ;wenn tausender > 9
sts tausender,r16 ;tausender sichern
rjmp t1_end ;und wiederholen
s5: ldi r16,0x00
sts tausender,r16 ;tausender zurücksetzen

t1_end:
ldi r17,0xf1
ldi r18,0xb4
out tcnt1h,r17 ;timerwert zurücksetzen
out tcnt1l,r18
out sreg,r16 ;statusregister wiederherstellen
pop r18
pop r17
pop r16
reti

zeit: push r16
push r17
push r18
lds r16,sreg
push r16
ldi r16,0x02
zeit1: ldi r17,0xcd
zeit2: ldi r18,0x1d
zeit3: dec r18
brne zeit3
dec r17
brne zeit2
dec r16
brne zeit1
pop r16
sts sreg,r16
pop r18
pop r17
pop r16
ret

.dseg

einer: .byte 1
zehner: .byte 1
hunderter: .byte 1
tausender: .byte 1
stelle: .byte 1



ICH WÄRE SO DANKBAR ÜBER JEDE HILFESTELLUNG !!!
 
Hallo Jonas,

so ganz verstehe ich euer Projekt noch nicht, bzw. weiß nicht wo eure Probleme liegen und ich vermute anderen Usern geht es ähnlich, so dass du bisher noch keine Antwort erhalten hast.

Ich schreibe einfach mal kurz hin, wie ich euer Projekt verstehe, du kannst mich ja berichtigen oder etwas ergänzen.
  • Mikrocontroller ist ein ATmega8
  • ISR von Timer0 multiplext eine vierstellige Anzeige
  • ISR von Timer1 inkrementiert den Inhalt eines Registers alle 1ms
ab jetzt habe ich Verständnisprobleme
  • ihr messt mit einem angeschlossenen Sensor und erhaltet Daten
  • die Daten werden im SRAM abgelegt
  • die Zeit von Start bis Ende der Messung soll ermittelt werden?
  • wenn neu gemessen wird, sollen die zuvor gemessenen Daten in einem anderen Bereich des SRAMs abgelegt werden?
  • wieviele Daten sind es jedesmal?
  • was passiert mit den Daten von den vorhergehenden Messungen?
  • und wo liegt genau das Problem?
Wenn wir mehr Infos bekommen, können wir vielleicht besser weiterhelfen.

Gruß,
Dirk
 
hallo dirk,

also du hast unser problem auf jedenfall richtig interpritiert. wir messen mit einem sensor und um genau zu sein mit einem sensor, der von einem fahrradtacho ist. dieser sensor ist an eine scheibe angebracht. dieser ja prinziepiell alle 360° tangiert wird weil sich die scheibe dreht. das haben wir getestet und er ist fähig dazu ein programm zu starten. unser ziel ist es die zeit zwischen start und ende (nach einer umdrehung) über die interrupt routine hochzuzählen und auf die mux-anzeige auszugeben.

unser hauptproblem besteht primär darin, dass wir über den timer_1 (1ms takt) inkrementierten wert beim ersten mal in einen zwischenspeicher ablegen müssen, weil man den ersten gemessenen wert wenn man ihn direkt ausgeben würde nur kurz sieht , weil der sensor sozusagen die werte wieder auf null legt. das bedeutet ja das wir den ersten gemessenen wert speichern müssen und erst wenn der zweite wert gemessen worden ist, der erste wert ausgegeben werden kann usw.

im grunde genommen bauen wir ja das selbe prinzip nach eines fahhradtacho?!

wie die timer funktionieren und auslösen usw. das habe ich verstanden, aber um ehrlich zu sein habe ich noch schwierigkeiten mit den werten im sram beschreiben und werte daraus zu verarbeiten,zeiger etc.

naja vielleicht kann man das irgendwie in das obige programm einbauen damit es für mein verständnis einleuchtener wird...

besten dank schon mal !
 
Hallo Jonas,

in der Interruptserviceroutine vom Timer0Overflow-Event tim0_ovf macht ihr eine relative Adressierung um auf den Ausgabewert zuzugreifen. Das ist soweit schon richtig, allerdings würde ich hier keine feste SRAM-Adresse angeben sondern den Assembler die Adresse wählen lassen.

AusgabeWert: .byte 4
Stelle: .byte 1


Das Z-Register enthält ja die aktuelle Adresse von AusgabeWert, initialisieren könnt ihr Z so:

ldi zl, low(AusgabeWert)
ldi zh, high(AusgabeWert)


also nicht mehr so

ldi zl,0x60
ldi zh,0x00




Den Timer0Overflow-Interrupt und den Timer1Overflow-Interrupt würde ich am Anfang in der Initialisierung kurz vor sei freigeben. Zuvor noch AusgabeWert und Stelle initialisieren

ldi r16, 0
sts AusgabeWert, r16
sts AusgabeWert+1, r16
sts AusgabeWert+2, r16
sts AusgabeWert+3, r16
sts Stelle, r16


Ab jetzt im Hauptprogramm Stelle nicht mehr verändern. Das macht nur noch die ISR vom Timer0.

Hauptprogramm:
Wenn nun PINC0 auf high geht, startet ihr die Zählung. Hier initialisiert ihr die BCD-Zahl:

ldi r16,0x00
cli ; Interrups global sperren
sts einer,r16 ; `0` ---> einer
sts zehner,r16 ; `0` ---> zehner
sts hunderter,r16 ; `0` ---> hunderter
sts tausender,r16 ; `0` ---> tausender
sei ; Interrupts global freigeben


Geht danach PINC0 wieder auf low, ist die Messung beendet. Jetzt kann man die anzuzeigende Zahl updaten, das geht zum Beispiel so:

cli ; Interrupts global freigeben
lds r16, einer
sts AusgabeWert, r16
lds r16, zehner
sts AusgabeWert+1, r16
lds r16, hunderter
sts AusgabeWert+2, r16
lds r16, tausender
sts AusgabeWert+3
sei ; Interrupts global sperren


Nun wird die Zeit in Millisekunden angezeigt.
Ihr springt jetzt nun wieder zum Start des Hauptprogramms und wartet bis PINC0 auf high geht.


Das sind nur noch Verbesserungsvorschläge:

Verbessern könnt ihr das Programm noch, indem ihr einen externen Interrupt verwendet, um auf die Tachoscheibe zu reagieren.
Besser wäre es auch, wenn ihr in der Timer1 ISR eine 16Bit Zahl inkrementiert und diese erst dann im Hauptprogramm in eine 4 Stellige BCD Zahl wandelt, wenn die anzuzeigende Zahl aktuelisiert werden soll, also wenn PINC0 auf low geht. Vorteil ist, die ISR von Timer1 wird einfacher.

Achtung, in der Timer0 ISR gebt ihr sofort wieder die Interrupts global frei, das wird bei euch jetzt nicht schlimm sein, kann aber, wenn das Programm einmal durch andere ISR erweitert wird, zu Problemen führen, hier muss man aufpassen.

Ich hoffe, ich konnte euch ein bisschen weiterhelfen.

Gruß,
Dirk
 
hallo dirk,

echt super das du dir die zeit genommen hast und uns wirklich unter die arme greifen konntest. das programm funktioniert nun. 1000 dank !!

grüße

jonas
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)