www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 24 bit Timer


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!!!

Ich bin blutiger Anfänger was Assembler und µC angeht. Ich benutzte das 
AVR Studio 4 und einen ATmega 8 mit 10 Mhz getaktet.

Ich würde nun gerne eine (Software)-PWM mit 10 Hz (sodass eine LED 
blinkt) realisieren.
Ich weiß nun nicht richtig, wie ich die Subroutine mit dem Runterzählen 
von 1.000.000 anstellen soll ( sollte am ende 10Hz entsprechen, oder?). 
Ich komme mit den Befehlen nicht klar.
Aktueller Stand, der so nicht funktioniert, aus der Subroutine "erste" 
kommt er nicht raus...

****************************************************************


  .include "m8def.inc"


    LDI r16, HIGH(RAMEND) ; Oberes Byte
    OUT SPH,r16 ; an Stapelzeiger
    LDI r16, LOW(RAMEND) ; Unteres Byte
    OUT SPL,r16 ; an Stapelzeiger



  ldi r16, 0b00000001
  out ddrb, r16

; Hauptprogramm

Haupt:
  ;definieren der Register für 1.000.000
  .equ ges = 1000000 ;gesamtes register
  ldi r16, low(ges) ;bit 0-8
  ldi r17, byte2(ges) ;bit 8-16
  ldi r18, byte3(ges) ;bit 16-24

  rcall erste
  rjmp haupt

erste:
  ;Subtrahieren mit 1
  ldi r19, 0x01
  sub r16, r19
  sbc r17, r19
  sbc r18, r19

  breq weiter
  rjmp erste

weiter: ; hier wird der Port gesetzt.
  ldi r16, 0x01
  out portb, r16

  rjmp haupt

*************************************************************

Wie funktioniert das mit dem zählen??? Kann mir da bitte jemand 
weiterhelfen???
Und Bitte nicht über Sinn oder Unsinn des Programmes diskutieren, es 
dient lediglich dem lernen von Assembler, das es mit dem integrierten 
Timer einfacher und vorallem Sinnvoller geht weiß ich auch, Danke!!!

MFG

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also, deine 24bit zahl zerlegst du in drei achtBit zahlen.
jedes register in einem.
r18:r17:r16
das ist ok. aber ob das mit dem ...byte(2) geht, glaub ich ne
beim rechnen von minus eins:
dazu gibt es einen speziellen befehl: DEC register. => siehe 
instr.summary

beim subrahieren der drei register, darfst du das erstmal NUR mit dem 
niederwertigstens machen, und nur falls du bei dieser rechnung:
r16=0 ist und du da jetzt eins abzieht: dann kommt (wegen acht bit)
nach der ausführung von dec r16 raus:
r16=255 und NUR in diesem fall darfst du vom nächsten (hier r17) eins 
abziehen!! und geht dieses (r17) von null auf 255, dann im 
nächsthöheren... also r18...

rechne doch mal, wie in der schule gelernt, schriftlich: 104-1. das 
ergebnis wieder minus eins.. unso weiter, und beobachte, wann du von der 
nächsthöheren stelle auch was abziehst...

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Gast,

1. "blinken" ist keine PWM

2. wenn Du blinken willst, musst Du auch den Zustand der LED ändern

3. Du musst mehrere Schleifen schachteln

Gruss Otto

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
achja, der port muss auch zurückgesetzt werden, und zwar immer 
abwechselnd..
am besten du invertierst das portpin immer, mittels XOR

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, vielen Dank erstmal.

Ich denke, das mit dem blinken wäre mir spästens nachdem der Zähler 
funktioniert hätte auch aufgefallen :D.

und wie realisiere ich das mit dem runterzählen, gibt es dafür bestimmte 
Befehle, oder muss ich jedes Bit in einer einzelnen Subroutine bis zum 
Übertrag herunterzählen lassen, steh da gerade etwas auf dem Schlauch, 
sorry.

MFG

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Gast,

Du musst nicht mit "SUB" arbeiten,
"djnz" ist viel schöner.....

Gruss Otto

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LDI   r18, 255               (15)
schleife3:
LDI   r17, 255               (255)

schleife2:
LDI   r16, 255               (255)

schleife1:
DEC   r16
BRNE  schleife1

DEC   r17
BRNE  schleife2

DEC   r18
BRNE  schleife3
...


dieser zähler zählt von (255hoch3=16'581'375) bis null runter, dann 
gehts mit ... weiter.. die drei werte musst du noch anpassen. Die Werte 
in der Klammer ergeben fast 1Million durchläufe (975375mal)

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DJNZ gibt es nur bei motorolas...

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt.... entschuldigung

aber

Marke:

Dec         dekrementieren
brne        und solange zur Marke springen, wie nicht 0

wäre auch gut....

Gruss Otto

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok vielen Dank, dass sollte mir weiter helfen...

wollte gerade schon Fragen, wo ich infos zu "djnz" finde, im Datenblatt 
ist er schließlich nicht drin...

MFG

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
entschuldigung - s.o. - ich war auf einem falschen Dampfer!

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so, hab jetzt ein neues Programm geschrieben, laut Debugger funktioniert 
es, die Realität sieht leider anders aus :(.
das Oszi zeigt leider auch keine Reaktion, kommt ne komplette 
Gleichspannung von 5 V raus...
Ist mein Controller vielleicht defekt??? Datenübertragung hat alles 
wunderbar funktioniert...
Vielleicht findet jemand einen Fehler, ich danke euch schonmal im 
voraus, wie immer eben ;)...

MFG

************************************************************************ 
**

;definitionsdatei

  .include "m8def.inc"

; einrichten des Stacks
    LDI r16, HIGH(RAMEND) ; Oberes Byte
    OUT SPH,r16 ; an Stapelzeiger
    LDI r16, LOW(RAMEND) ; Unteres Byte
    OUT SPL,r16 ; an Stapelzeiger

;Ausgänge konfigurieren

  ldi r16, 0b00000001
  out ddrb, r16

; Hauptprogramm

Haupt:
  ;auschalten des ausgangs
  clr r19
  out portb, r19

  .def byt1 = r20 ;R16
  .def byt2 = r21 ;R17

  ; Hier wird runtergezählt bis 0, und dann der Ausgang gesetzt.
  ; bewerten der Register
  ; *********hier die Zeit einstellen, anhand der werte der 
bits**********
  ; 
**********************************************************************
  ldi byt1, 64 ;bit 0-8 (entspricht R16)
  ldi byt2, 13 ;bit 8-16 (entspricht R17)
  ldi r18, 3 ;bit 16-24

  ;die werte noch in die register schreiben
  mov r16, byt1
  mov r17, byt2

  ;das ergibt 1 mio ( 00001111.01000010.01000000 (24bit))
  rcall schleife1 ; bit 0-8 herunterzählen

schleife1:
  dec r16
  breq schleife2
  rcall schleife1

schleife2:
  mov r16, byt1
  dec r17
  breq schleife3
  rcall schleife1

schleife3:
  mov r16, byt1
  mov r17, byt2
  dec r18
  breq einschalten
  rcall schleife1

  ;port einschalten nach ...mio durchläufen
einschalten:
  ldi r19, 0x01
  out portb, r19
  rcall haupt


************************************************************************ 
**

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oder ist der Einschaltimpuls einfach zu kurz??? Ich meine wenn der 5-10 
Zyklen angeschlatet ist, entspricht das vielleicht 0,5 - 1 µs...

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, ich habe es endlich... der stack ist immer übergelaufen...
so funktioniert es.. sorry für die schlechten kommentare, habe ich 
irgendwie hingepfuscht. werde das demnächst noch verbessern, das man 
tastverhältnis und die zeit einfacher programmieren kann...


****************************************************************

;definitionsdatei

  .include "m8def.inc"

; Hauptprogramm

Haupt:

  ;ausschalten
  ldi r19, 0x00
  out portb, r19

  .def byt1 = r20 ;R16
  .def byt2 = r21 ;R17

  .def byt3 = r25 ;R22
  .def byt4 = r26 ;R23

  ; Hier wird runtergezählt bis 0, und dann der Ausgang gesetzt.
  ; bewerten der Register
  ; *********hier die Zeit einstellen, anhand der werte der 
bits**********
  ; 
**********************************************************************
  ldi byt1, 255 ;bit 0-8 (entspricht R16)
  ldi byt2, 255 ;bit 8-16 (entspricht R17)
  ldi r18, 100 ;bit 16-24

  ;ausschalten
  ldi byt3, 255 ;0-8 bit zum ausschalten
  ldi byt4, 255 ;8-16 bit zum ausschalten
  ldi r24, 100 ;16-24 bit zum ausschalten

  ;die werte noch in die register schreiben
  mov r16, byt1
  mov r17, byt2

  ;das ergibt 1 mio ( 00001111.01000010.01000000 (24bit))
;einschalten
schleife1:
  dec r16
  breq schleife2
  brne schleife1

schleife2:
  mov r16, byt1
  dec r17
  breq schleife3
  brne schleife1

schleife3:
  mov r16, byt1
  mov r17, byt2
  dec r18
  breq einschalten
  brne schleife1

;port einschalten nach ...mio durchläufen
einschalten:

  ;Ausgänge konfigurieren
  ldi r23, 0b00000001
  out ddrb, r23
  nop
  ldi r19, 0x01
  out portb, r19

; ausschalten
schleife4:
  dec r22
  breq schleife5
  brne schleife4

schleife5:
  mov r22, byt3
  dec r23
  breq schleife6
  brne schleife4

schleife6:
  mov r23, byt4
  dec r24
  breq haupt
  brne schleife4

******************************************************************

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erzählt doch keinen Schmarrn, Subtraktion geht natürlich 24-bittig, also 
weg mit den ollen umständlichen 8Bit-Schleifen, mach es so:

...
erste:
  ;Subtrahieren mit 1
  subi r16, byte1(1)
  sbci r17, byte2(1)
  sbci r18, byte3(1)
  brne erste

weiter:
...


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok vielen Dank, wieder mal.

werde das heute Abend einmal ausprobieren. Die Schleiferei und 
Verzweigerei ist doch etwas umständlich ;).


MFG

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, habe das jetzt mit dem zählen auch hinbekommen, ist schoneinmal 
übersichtlicher geworden. Vollständigkeitshalber der Code nochmal...

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;definitionsdatei

.include "m8def.inc"

  ;definieren der Ein/Ausgänge
  ldi r16, 1
  out ddrb, r16

; Hauptprogramm
Haupt:

  ;definieren der Variablen
  ;Variable zum Einschalten der LED
  .equ ein = 200000 ;NOP takte
  ldi r16, low(ein)
  ldi r17, byte2(ein)
  ldi r18, byte3(ein)

  ;Variable zum Ausschalten der LED
  .equ aus = 200000 ;NOP takte
  ldi r19, low(aus)
  ldi r20, byte2(aus)
  ldi r21, byte3(aus)

zaehlen: ;Zählen fürs Einschalten

  ;herunterzählen
  subi r16, byte1(1)
    sbci r17, byte2(1)
    sbci r18, byte3(1)
  sbrs r18, 0
  breq einschalten
  rjmp zaehlen

einschalten:

  ;LED einschalten
  ldi r16, 1
  out portb, r16

zaehlen2:;Zählen fürs Ausschalten

  ;herunterzählen
  subi r19, byte1(1)
    sbci r20, byte2(1)
    sbci r21, byte3(1)
    sbrs r21, 0
  breq ausschalten
  rjmp zaehlen2

ausschalten:

  ;LED ausschalten
  ldi r16,0
  out portb, r16
  rjmp haupt

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.