Forum: Mikrocontroller und Digitale Elektronik Timer mit Tiny2313


von Sven (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich versuche mich gerade, in das Thema "Timer" einzuarbeiten. Dazu nutze 
ich das das AVR Tutorial. Als Controller nutze ich einen Tiny2313 und 
habe das Programm in Assembler geschrieben. Ich habe soweit alles 
versucht, an den Tiny2313 anzupassen. Aber leider ohne Erfolg...

So wie ich es jetzt habe, leuchten bei mir die LEDs dauerhaft. Kleine 
Info zur Hardware: Ich nutze das STK 500. Die Frequenz habe ich wie im 
Programmbeispiel im Tutorial auf 4 MHz eingestellt.

Vielleicht kann mal jemand einen Blick darüber werfer, warum das nicht 
funktioniert. Bin für jede Hilfe dankbar ! :)

Möchte dann gerne mit dem Programm ein bißchen das Thema Timer kennen 
lernen und evtl. mal die Signale eines RC Empfänger auswerten. Daher der 
Name PPM-Test.

Viele Grüße
Sven

von Sven (Gast)


Lesenswert?

So, das "Problem" hat sich gelöst... und ich habe wieder einen Teil 
verstanden. Ich hatte den Vorverteiler auf 1 stehen. Also viel zu 
schnell. Da kommt das Auge nicht mit. Aus diesem Fehler habe ich auf 
jeden Fall was gelernt. ;)

von Rolf H. (flash01)


Lesenswert?

Hallo Sven,
ich kämpfe auch schon lange mit den Timer0 für Tiny2313.
Leider gibt mein Buch nur Hinweise zum Mega8.

Hier mal mein Quelltext:
1
; Datei: kran04.asm
2
3
; PORTB: Ausgabe 
4
; PortD: Eingänge
5
;Datum: 05.12.2011
6
7
;AVR: Tiny 2313
8
9
        .INCLUDE  "tn2313def.inc"  ; Deklarationen für Tiny2313
10
        .EQU    takt = 1000000  ; Systemtakt 1 MHz 
11
        .DEF    akku = r16      ; Arbeitsregister r16 in akku benannt
12
        .CSEG         ;Programm - Flash
13
  rjmp start
14
  .ORG  OVF0addr    ;Timer0 Überlauf-Einsprung
15
   rjmp  timer
16
   .ORG  $13
17
        
18
;Vorbereitung: Stapel anlegen, PortB=Out, PortD=Inp.
19
20
start:  ldi  akku,LOW (RAMEND)
21
  out  SPL,akku
22
  ldi     akku,$ff        ; Bitmuster 1111 1111
23
  out     DDRB,akku       ; Port B ist Output
24
          ldi     akku,$00        ; Bitmuster 0000 0000
25
  out     DDRD,akku        ; Port D ist Input
26
27
;Timer0 und Interrupt voreinstellen
28
  ldi  akku,0b00000101  ;Prescale = 1024
29
  out     TCCR0,akku    ;akku in Steuerreg. TCCR0
30
  in  akku,TIMSK
31
  ori  akku,1 << TOIE0
32
  out  TIMSK,akku
33
  sei
34
35
;Arbeitsbeginn
36
    
37
  ldi     akku,0b00000111 ; Bitmuster 0000 0111
38
          out     PORTB,akku      ; Pb0 - Pb2 = High
39
40
           
41
timer:  ldi  r16,100
42
warte:  dec  r16
43
  brne  warte
44
  ldi  r16,0b00000001
45
  out  PORTB,r16
46
  reti
Irgendwas muß mit den Vorbereitungen zum 2313 nicht stimmen.
3 LED am Port (B0 bis B2) leuchten dauerhaft.
Was mache ich nur verkehrt!
Worin erkennt das Interrupt, daß es nach dem Timerdurchlauf
von 256 nach timer: springen soll.
Bei Bascom gab es
Config Timer0 = Timer,Prescale = 1024
On Timer0 timer
Enable Timer0
Grüße

Rolf

von spess53 (Gast)


Lesenswert?

Hi

>Was mache ich nur verkehrt!

>        .DEF    akku = r16      ; Arbeitsregister r16 in akku benannt
>timer:  ldi  r16,100

Entweder du benennst r16 mit akku, dann hat r16 in deinem Programm 
nichts zu suchen. Oder du bleibst bei r16.

>;Arbeitsbeginn

>  ldi     akku,0b00000111 ; Bitmuster 0000 0111
>          out     PORTB,akku      ; Pb0 - Pb2 = High

>timer:  ldi  r16,100
>....

Rate mal was dein ATTiny nach dem 'out PortB,akku' macht.

Außerdem:

-Kein SREG im Interrupt gesichert
-Warten im Interrupt

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

>>  ldi     akku,0b00000111 ; Bitmuster 0000 0111
>>          out     PORTB,akku      ; Pb0 - Pb2 = High
>
>>timer:  ldi  r16,100
>>....
>
> Rate mal was dein ATTiny nach dem 'out PortB,akku' macht.

@Rolf
Ich denke der Hinweis war etwas zu subtil, vor allen Dingen wenn man ihn 
im Zusammenhang mit dem vorhergehenden Hinweis (Akku/R16) sieht.
Daher etwas konkreter:

Wo ist deine Hauptschleife?
JEDES Programm braucht eine Hauptschleife, in der der Programmfluss 
verbleibt, solange der µC unter Strom steht!
Es ist das, was in BASCOM das

...
do

   ... Programmlogik


loop

war.

von Rolf H. (flash01)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
erst mal meinen Dank für Eure Infos!
Ich habe gelesen und nochmals gelesen über Timer0 vom 2313,
und anschließendes Interrupt.
Das Register TCCR0 hab ich voll im Griff..eingestellt auf
Prescale 1024.
Das Zählregister TCNT0 auch überschaubar..wird inkrementiert bei Hoch-
laufen, das macht es von alleine..also nicht wichtig.
Das Überlaufregister TIFR..Bit0=TOVO wird gesetzt bei Überlauf.
Das Register TIMSK muß Bit0 = TOIE0 gesetzt werden. Dieses hat
außer I=sei höchste Priorität.
Wie aus den Bild zu sehen, habe ich alles korrekt vorgegeben.
(hoffentlich gut erkennbar)
3 Leds habe ich zuvor an PORTB/Pin0 - 2 dunkel gesetzt.
Und es tut sich nichts, sie bleiben dunkel; über die ISR "timer"
müßten sie alle 3 zum leuchten kommen, oder?
An der Hardware kann es nicht liegen, denn sie lassen sich ohne
Timer problemlos steuern.
Jetzt sind die Experten gefragt!

Grüße

Rolf
Im Buch steht:
TOVO=1 (Überlauf)und TOIE0=1 und I=1 (sei)wird der Timer0 Interrupt
ausgelöst.

von Karl H. (kbuchegg)


Lesenswert?

Bitte Programmtext immer als Text und nicht als Bild.
Unterschied: Aus einem Text kann ich mir mit Cut&Paste Teile 
ausschneiden, auf die ich Antworten möchte. Bei einem Bild kann ich das 
nicht.
Weiterer Unterschied: Bei einem Text hängst DU einfach dein Programmfile 
als Attachment an, bei einem Bild hast du mehr Arbeit.

Du hast 8 LED am Port B hängen?

Dann ist es immer eine gute Idee, wenn du nicht alle 8 entweder auf 0 
oder auf 1 stellst, sondern erst mal zb abwechselnd auf 0 und 1

  ldi  led,0b10101010

auf die Art brennen unabhängig davon, ob deine LED jetzt alle nach Masse 
oder alle nach Vcc verschaltet sind, immer auf jeden Fall 4 LED

von spess53 (Gast)


Lesenswert?

Hi

Nimm bitte deine ASM-Datei als Anhang.

>Und es tut sich nichts, sie bleiben dunkel; über die ISR "timer"
>müßten sie alle 3 zum leuchten kommen, oder?

Kommt darauf an, wie die Leds angeschlossen sind. Der erste Overflow 
kommt nach etwa einer viertel Sekunde. Danach passiert nichts mehr.

>Das Register TIMSK muß Bit0 = TOIE0 gesetzt werden.

In meinem Datenblatt ist TOIE0 Bit1. Deshalb ist

ldi akku,0b00000001 auch Unsinn. Mit

ldi akku,1<<TOIE0 passiert das nicht.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

> Jetzt sind die Experten gefragt!

Solche Dinge lassen sich aber auch noch im Simulator wunderbar testen. 
Dort kann man dann auch in der Registerübersicht wunderbar sehen, welche 
Bits man wirklich gesetzt hat und wie der Timer hochzählt.

Hinweis: Für den Simulator den Prescaler auf 1 setzen, sonst tippt man 
sich die Fingerkuppen wund.

von Uwe (Gast)


Lesenswert?

>          ldi     akku,0b00000111 ; Bitmuster 0000 0111
>          out     PORTB,akku      ; Pb0 - Pb2 = High
Das macht er und dann macht er hier weiter (ldi r16,100) und schaltet 
Sie wieder ein paar 100µS später wieder aus
>
>timer:  ldi  r16,100
>warte:  dec  r16
>  brne  warte
>  ldi  r16,0b00000001
>  out  PORTB,r16
>  reti

mach mal ne Endlosschleife dazwischen damit er nicht in den Handler 
reinläuft (loop:     rjmp loop):

          ldi     akku,0b00000111 ; Bitmuster 0000 0111
          out     PORTB,akku      ; Pb0 - Pb2 = High
loop:     rjmp loop

timer:    ldi  r16,100
warte:    dec  r16
          brne  warte
          ldi  r16,0b00000001
          out  PORTB,r16
          reti

von spess53 (Gast)


Lesenswert?

Hi

@Uwe

Wir sind schon hier:

Beitrag "Re: Timer mit Tiny2313"

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo Spess,
Erfolg....jetzt leuchten die 3 Leds an Pb0 bis PB2 nach Änderung
wie in Deinem Vorschlag.

;Timer0 und Interrupt voreinstellen
ldi    akku, 0b00000101  ;Prescale = 1024
out    TCCR0, akku    ;akku in Steuerreg. TCCR0
ldi    akku,(1<<TOIE0)  ; Register TIMSK (Bit0=1)
out    TIMSK, akku    ; Interrupt frei gegeben
sei        ; I=sei (Inter. frei)

evtl. muß ich bei Prescale auch eine Änderung durchführen,
denn das macht mich dann mit akku, xxxxxx auch stutzig!
Wie soll ich das mit 0101 vorgeben =1024
Die Leds hängen an Plus über NPN gesteuert, d.h. High=LED Pin=1

Allen Anderen antworte ich morgen!

grüße Rolf
noch was: muß die Anweisung 1<<TOIE0 in Klammern?

von spess53 (Gast)


Lesenswert?

Hi

>evtl. muß ich bei Prescale auch eine Änderung durchführen,
>denn das macht mich dann mit akku, xxxxxx auch stutzig!
>Wie soll ich das mit 0101 vorgeben =1024

Das Bitmuster stimmt dort schon. Allerdings ist auch hier ein

ldi r16, 1<<CS2|1<<CS0

informativer.

>noch was: muß die Anweisung 1<<TOIE0 in Klammern?

Nicht unbedingt. Aber stören tut es auch auch nicht.

MfG Spess

von Steffen H. (avrsteffen)


Lesenswert?

Nur mal so als Anmerkung:

spess53 schrieb:
> ldi r16, 1<<CS2|1<<CS0
Das was Spess hier schreibt (Bitmanipulation) steht hier
http://www.mikrocontroller.net/articles/Bitmanipulation
sehr gut beschrieben.

Welche Bits sich genau hinter CS2, CS0 oder auch TOIE0 verbergen findest 
du in der "tn2313def.inc" beschrieben.

Gruß Steffen

von spess53 (Gast)


Lesenswert?

Hi

>Nur mal so als Anmerkung:
>....

Das Problem ist das die meisten ,die hier mit Assemblerproblemen 
auftauchen, blutige Anfänger sind. Da liegt das Interesse erst mal 
darin, ein meist recht begrenztes, Ziel irgendwie zu erreichen. Die Form 
ist recht egal. An Lesbarkeit, Wartbarkeit oder gar Wiederverwendbarkeit 
des Codes wird kein Gedanke verschwendet, zumal die Mittel dazu 
(AVR-Assembler->Directives/Expressions oder AVR-Assembler->Preprocessor 
und anderes) weitestgehend unbekannt sind.

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo Spess und Seffen,

danke für Eure Antwort noch zu später Stunde.
Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0,
kann sowas auf dem Laptop nicht finden..einen / ja!

Zu Karl Heinz:
ok, Quelldatei als Text und nicht Bild.
3 Leds liegen gegen Plus über 3 NPN Trans. an PB0-PB2

Der erste Durchbruch ist geschafft, nun geht es ins Eingemachte.

Grüße

Rolf

von spess53 (Gast)


Lesenswert?

Hi

>Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0,
>kann sowas auf dem Laptop nicht finden..einen / ja!

Sollte auch auf deinem Laptop mit AltGR + <>-Taste (links neben Y) 
erreichbar sein.

MfG Spess

von Volkmar D. (volkmar)


Lesenswert?

Rolf Hegewald schrieb:
> Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0,

Der befindet sich normalerweise (deutsche Tastatur) auf der Taste mit < 
und >. Erreichbar über "Alt Gr" zusammen mit <. Wird in der Regel durch 
einen unterbrochenen senkrechten Strich dargestellt.

Volkmar

von Rolf H. (flash01)


Lesenswert?

|| ok, hat geklappt!
Nun steh ich vor einem Wahnsinns-Projekt, das ich in Hamburg
im Miniatur-Wunderland (Modelleisenbahn) gesehen habe und im Jahr
2011 umgesetzt. Es handelt sich um einen Contenerkran der Fa.
Brawa mit 2 Motoren.
1. Motor AUF/AB
2. Motor LINKS/RECHTS
Das alles läuft mit einem PIC in Pic-Assembler. Mein Wunsch war es,
mit Atmel, aber nicht mit Bascom umzusetzen, sondern wieder Assembler.
Die Motoren zu steuern, ist nicht das Problem, dagegen Pausenzeiten
in verschiedenen Zeitabständen schon.
Mit den Pic habe ich 3 Register geladen und inkrementiert, sehr auf-
wendig. Also habe ich mich mit den Timer0 angetan.
Das Blockschema sieht so aus:
1. Motor AUF=EIN
2. Pause1 ;ca. 5 Sec.
3. Motor AUF=AUS
4. Pause1
5. Motor LINKS=EIN
6. Pause2 ;ca. 20 Sec.
7. Motor LINKS=AUS
8. Pause1
9. Motor AB=EIN
10. Abfrage über Lichtschranke
usw. dann geht es wieder aufwärts, rechts und ab.
Es kommen also zwei Zeiten in Betracht. Eine mit 5 Sec.
die andere mit 20 Sec.
Nun habe ich schon in der ISR herumgefummelt...aber!

;Timer0 und Interrupt voreinstellen
    ldi  akku, 0b00000101  ;Prescale = 1024
    out  TCCR0, akku  ;akku in Steuerreg. TCCR0
    ldi  akku,(1<<TOIE0)  ; Register TIMSK (Bit0=1)
    out  TIMSK, akku  ; Interrupt frei gegeben
    sei      ; I=sei (Inter. frei)

;Arbeitsbeginn

loop:    rjmp  loop


timer:    ldi    leds,0b00000001
    out    PORTB,leds  ;Register r17
    ldi    akku,0b00000111
    dec    akku
    brne  gehe    ;Sprung, wenn akku nicht Null
    ldi    leds,0b00000100
    out    PORTB,leds
    ldi    akku,0b00000111
    dec    akku
    brne  gehe
gehe:    reti

Was meint Ihr, soll ich bei der alten Register-Methode bleiben,
oder mich durchkämpfen.

Grüße

Rolf

von Karl H. (kbuchegg)


Lesenswert?

Rolf Hegewald schrieb:
> Was meint Ihr, soll ich bei der alten Register-Methode bleiben,
> oder mich durchkämpfen.
>

Auf jeden Fall: Timer

Timer sind deine Arbeitspferde. Ohne sie sind komplexere Programme nicht 
sinnvoll machbar.


> Nun habe ich schon in der ISR herumgefummelt...aber!

Aber was?

>
> ;Timer0 und Interrupt voreinstellen
>     ldi  akku, 0b00000101  ;Prescale = 1024
>     out  TCCR0, akku  ;akku in Steuerreg. TCCR0
>     ldi  akku,(1<<TOIE0)  ; Register TIMSK (Bit0=1)
>     out  TIMSK, akku  ; Interrupt frei gegeben
>     sei      ; I=sei (Inter. frei)
>
> ;Arbeitsbeginn
>
> loop:    rjmp  loop
>
>
> timer:    ldi    leds,0b00000001
>     out    PORTB,leds  ;Register r17
>     ldi    akku,0b00000111
>     dec    akku

was machst du da?
Wenn du vorher 7 in den Akku lädst
(warum schreibst du dann nicht auch einfach
      ldi    akku, 7
 ist doch viel einfacher zu lesen. Ob dezimal oder hexadezimal oder 
binäre Schreibweise benutzt wird, hängt davon ab, wofür die Zahl steht. 
Man wählt immer die Schreibweise, die in der gegebenen Situation die 
natürlichste ist. Du willst etwas zählen, also wird dezimal die 
natürliche Schreibweise sein, denn du denkst dezimal)

und diese 7 dann um 1 runterzählst, dann steht 6 im akku. Immer. Denn 
bei jedem Aufruf der Timer-ISR lädst du ja wieder 7 in den Akku.


>     brne  gehe    ;Sprung, wenn akku nicht Null

das kann daher nie 0 sein

>     ldi    leds,0b00000100
>     out    PORTB,leds
>     ldi    akku,0b00000111
>     dec    akku
>     brne  gehe
> gehe:    reti


Du hast das Prinzip noch nicht verstanden.
In der ISR realisierst du die Dinge, die nach einer gewissen 
Zeiteinheit(!) getan werden müssen. Das AUfsetzen bzw. Einstellen der 
Umgebung machst du ausserhalb. Die ISR ist wie das Ticken einer Uhr und 
bei jedem Tick siehst du nach bzw. bestimmst du, was genau jetzt, zu 
diesem Zeitpunkt, bei diesem Tick der Uhr, getan werden muss.

Du denkst noch in Warteschleifen! Und genau das ist der falsche Ansatz. 
Du musst in zeitlichen Ereignissen denken.
Tick     ... 1 Sekunde vergangen, was gibt es jetzt zu tun?
Tick     ... wieder 1 Sekunde vergangen, ist jetzt etwas zu tun?
Tick     ... die nächste Sekunde ist abgelaufen, ich könnte mal den
             Motor einschalten
Tick     ... 1 Sekunde aufs Konto gutschreiben, ansonsten gibt es nichts
Tick     ... noch eine Sekunde. Heissa, ich wollte doch nach 2 Sekunden
             den Motor wieder ausschalten! Vor 2 Ticks hab ich ihn ein-
             geschaltet, also ist jetzt der Zeitpunkt, ihn auszuschalten
Tick     ...
....


Grundsätzlich wirst du Ticks zählen müssen, weil du ja längere Zeiten 
als 1 Sekunde brauchst. Nehmen wir mal an, dass der Tick jede Sekunde 
kommt (du also genau alle 1 Sekunde einen Aufruf der ISR hast).

Was musst du tun?

   du zählst 1 zu deiner Anzahl an Ticks dazu, weil du ja längere
   Zeiteinheiten als 1 Sekunde haben willst. Wenn du 20 derartige
   Ticks abzählst, dann sind 20 Sekunden vergangen, wenn du bei
   20 angelangt bist (du kannst natürlich auch von 20 runterzählen
   und wenn du bei 0 bist, sind 20 Sekunden vergangen. Kommt aufs
   gleiche raus. Runterzählen ist meist einfacher)

   Solange du deine Sekunden nicht erreicht hast, gibt es nichts
   zu tun -> verlassen der ISR

   Sind die Sekunden erreicht, dann musst du zb etwas schalten
   zb LED ein oder LED aus. Dazu wirst du irgendeinen Mechanismus
   brauchen, der dir sagt ob jetzt ein oder ausgeschaltet werden
   soll. Du kannst zb das Portregister befragen ob zur Zeit
   eingeschaltet ist und dann daraus deine Schlüsse ziehen.

   Wie auch immer, auf jeden Fall muss dann deine Tickzählerei
   wieder von vorne beginnen. D.h. du setzt den Tickzähler wieder
   zurück (auf 0 wenn du ihn erhöhst, auf zb 20 wenn du mit der
   Methode runterzählen arbeitest)


Und eines solltest du auf jeden Fall machen:
In der ISR wird auf jeden Fall das Status-Register SREG gesichert! Das 
ist lebenswichtig, weil du nie vorhersehen kannst, welche andere 
Anweisungssequenz in der Hauptschleife durch die ISR unterbrochen wird.

Zur Zeit ist deine Hauptschleife noch leer

loop:   rjmp loop


aber das wird nicht immer so bleiben!

von Hannes L. (hannes)


Lesenswert?

Rolf Hegewald schrieb:
> Was meint Ihr, soll ich bei der alten Register-Methode bleiben,
> oder mich durchkämpfen.

Es ist einfacher als Du jetzt denkst...

Lies Dich mal hier durch:
http://www.hanneslux.de/avr/index.html

Ist zwar alles schon etwas älter, hilft Dir aber sicherlich beim 
Verstehen.
Ohne Timer komme ich eigentlich gar nicht zurecht...

...

von Rolf H. (flash01)


Angehängte Dateien:

Lesenswert?

Hallo,
meinen Dank besonders an Karl Heinz für seine vielen
aufklärenden Worte. Wenn ich das mit dem Tick richtig verstanden habe,
würde bei mir eine Zeit von: (ich gehe mal von 1MHz Systemtakt aus)
1 ys x 1024 = 1,024 ms x 256 = 262,144 ms etwa 0,26 Sec.
Auf die Genauigkeit kommt es jetzt nicht drauf an, nur vom Prinziep.
Würde ich ein Register in der ISR auf $0F setzen und zu Null runter
zählen, hätte ich ein Ergebnis von 0,26 x 15 = 3,9 Sec.
Was habe ich nun in der Zwischenzeit gemacht..also wieder gelesen!
Und dazu ist mir das von Hannes eine große Hilfe gewesen.
D.h. ich muß den Tick EIN und Ausschalten können, bzw. eine loop
Arbeitsschleife aufbauen.
Das Ganze sieht jetzt so aus:
.INCLUDE  "tn2313def.inc"  ; Deklarationen für Tiny2313
        .EQU    takt = 1000000  ; Systemtakt 1 MHz
                  .EQU     laufein = 1<<CS02|1<<CS00
    .EQU  laufaus = 0<<CS02|0<<CS00
    .DEF  flashein = r7
    .DEF  flashaus = r8
    .DEF    akku = r16 ; Arbeitsregister r16 in akku benannt
                 .DEF  warte4 = r17  ; für Pausenzeit ca. 4 Sec.
    .DEF  warte15 = r18  ;für Pausenzeit ca. 15 Sec.
    .ORG  0x0000
    rjmp  start    ;Sprung zu Vorbereitung
    .ORG  OVF0addr    ;Timer0 Überlauf-Einsprung
    rjmp  timer    ;Sprung zur ISR

start: hier werden nur PortB als Ausg. gesetzt.

Timer 0 voreinstellen
;Timer0 und Interrupt voreinstellen

      ldi akku,(1<<TOIE0)  ; Register TIMSK (Bit0=1)
      out timsk,akku  ; Interrupt frei gegeben
      sei            ; I=sei (Inter. frei)

;Timer0 EIN-AUSschalten:

      ldi  akku,laufein  ;Bitm. 0101=1024
      out  flashein,akku  ;in r7 Inhalt von akku
      ldi  akku,laufaus  ;Bitm. 0000=Timer Stopp
      out  flashaus,akku  ;in r8 Inhalt von akku

; out TCCR0,flashein = Timer EIN / out TCCR0,flashaus = Timer AUS

Jetzt beginnt der eigentliche Arbeitsbeginn:
loop:             rcall  pause4  ;Pause 4 Sec.
      rcall  ein  ;Motor linksauf-EIN
      rcall  pause4  ;Pause 4 Sec.
      rcall  halt  ;Motor linksauf-HALT
                           rjmp     loop
hier die Unterpr.
pause4:
      warte4  $0F  ;Bitmuster 0b00001111 in r17
      out  TCCR0,flashein  ;Timer = EIN
ende4:             out  TCCR0,flashaus  ;Timer = HALT
      ret

ein:
      ldi    akku,$02  ; r16 =  02
      out    PORTB,akku
      ret
halt:
      ldi    akku,$00
      out    PORTB,akku
      ret
und zum Schluß die ISR (und hier bin ich mir mit den brne noch
etwas unsicher)
timer:
      dec  warte4
      brne  laufe
laufe:    rjmp  ende4
      reti

      .EXIT
mit der Sreg muß ich mich noch antun.
Ganz schön komplex..das Ganze, aber da blickt Ihr doch durch, oder?
Aber ich komme aus einem Fehler nicht raus, der so aussieht.
D:\Tiny2313\krantest2.asm(64): error: syntax error, unexpected INTEGER, 
expecting ':'
Also wie gesagt, es läuft noch nicht!

Grüße erst mal

Rolf

von spess53 (Gast)


Lesenswert?

Hi

>Ganz schön komplex..das Ganze

Ich habe Assemblerprogramme, die sind 200x größer. Da fängt es langsam 
an komplex zu werden.

>aber da blickt Ihr doch durch, oder?

Du must durchblicken.

Fangen wir mal an:

-Kein Stack initialisiert
-Kein SREG gesichert
-Sprung aus der Interruptroutine

>      dec  warte4
>      brne  laufe
>laufe:    rjmp  ende4

Unsinn. Egal ob Null oder nicht kommt das Programm zu 'laufe'.

>      warte4  $0F  ;Bitmuster 0b00001111 in r17

Was soll das sein?

>out  flashein,akku  ;in r7 Inhalt von akku

heißt: out r7,r16 und das ist falsch.  Richtig mov r7,r16

Das ist das, was ich auf die Schnelle gefunden habe. Aber da sind mit 
Sicherheit noch andere Eier vesteckt.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

Rolf Hegewald schrieb:
> D.h. ich muß den Tick EIN und Ausschalten können, bzw. eine loop
> Arbeitsschleife aufbauen.

Damit wirst Du nicht viel weiter kommen. Schau Dir mal meine 
Feuerwerks-Zünduhr an, da werden zu bestimmten Terminen bestimmte 
Aktionen ausgeführt:
http://www.hanneslux.de/avr/zuenduhr/index.html
http://www.hanneslux.de/avr/zuenduhr/ZndUhr01.asm

Nur mit Zeit gesteuert wird Dein Kran sich aber verhedern, da würde ich 
auch noch mit Endschaltern (Lichtschranken) arbeiten, die signalisieren, 
dass eine bestimmte Position erreicht ist.

Dann würde ich mir ein "Datensatzformat" ausdenken, z.B. 2 Bytes für die 
Verzögerung bis zum nächsten Schritt, 1 Byte für das Bitmuster, was zu 
tun ist, 1 Byte für das Bitmuster, welcher Endschalter die Sache 
vorzeitig beendet. Diese Datensätze kommen dann ins EEPROM des AVRs und 
können jederzeit nach Bedarf berändert werden, ohne das Programm (im 
Flash) verändern zu müssen.

Mit einem (frei durchlaufenden ) Timer generiert man nun einen Basistakt 
von z.B. 10ms. In diesem findet erstmal die Entprellung der 
Endschaltereingänge statt, sowie auch das Herunterzählen der gerade 
laufenden Zeitverzögerung. Wird die laufende Verzögerung 0, dann wird 
ein Merker (Flag, Semaphore, Bitvariable,...) gesetzt, der dem 
Hauptprogramm mitteilt, dass der laufende Arbeitsgang zu Ende ist.

Das Hauptprogramm prüft nun dieses "FertigMaisTeer-Flag" und macht 
Folgendes, falls es gesetzt war:
FertigMaisTeer-Flag löschen (Jobauftrag entwerten, Job ist ja in Arbeit)
Nächsten Datensatz aus EEP holen,
Wartezeit-Zähler auf neuen Startwert setzen
Ausgangs-Bitmuster ausgeben (also Schalthandlung ausführen)
Eingangs-Bitmaske aktualisieren (welcher Eingang darf Abbruch auslösen)
Endschalter-Flags löschen (alte Auslösungen entwerten)

Weiterhin prüft die Hauptschleife die Endschalter-Flags und setzt bei 
Betätigung einfach mal den FertigMaisTeer-Merker, um den Arbeitstakt 
vorzeitig zu beenden.

Vereinbart man, dass 0xFFFF (leeres EEPROM) als Verzögerungszeit 
ungültig ist und stattdessen als Rücksetzen des Arbeitstaktzählers auf 
den Anfang interpretiert wird, so kann man das Bewegungsprogramm als 
endlosen Ring ausführen.

Baut man noch Routinen zum Update des Bewegungsprogramms per RS232 ein, 
dann kan das Bewegungsprogramm jederzeit von einem PC (auch über 
USB-RS232-Wandler) ersetzt werden, mindestens hunderttausend mal.

Schreibt man sich für den PC noch ein Programm (GUI?) zum Editieren des 
Bewegungsprogramms und Verwalten eines Archives mit Bewegungsprogrammen 
sowie den Routinen zum Senden eines Bewegungsprogramms an den AVR der 
Kransteuerung, dann kann man den Kran recht flexibel zappeln lassen. 
Baut man in die Kommunikation zwischen PC und AVR neben den Kommandos 
zum EEP-Update noch ein paar Kommandos zur Direktsteuerung ein, dann 
kann man das Ding auch mal per Mausklick steuern. Ist mE kreativer, als 
nur ein Detail vom MiWuLa kopieren zu wollen.

So, nun mach' was Du willst, aber mach' was (oder auch nicht...)

...

von spess53 (Gast)


Lesenswert?

Hi

Noch etwas:

Der Timer0 besitzt TCCR0A und TCCR0B, aber kein TCCR0. Der Assembler 
akzeptiert TCCR0 nur weil er diese Bezeichnung nach TCC0B umleitet. Nimm 
bitte die richtigen Registerbezeichnungen.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

spess53 schrieb:
> was ich auf die Schnelle gefunden habe.

Ich habe garnicht erst gesucht, da ich das Konzept für suboptimal halte.

...

von spess53 (Gast)


Lesenswert?

Hi

>Ich habe garnicht erst gesucht, da ich das Konzept für suboptimal halte.

Nicht nur du.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Ich seh das wie ihr.
Und ich bin mir ziemlich sicher, dass die Jungs im MiWuLa da Endschalter 
(zb in Form von Gabellichtschranken) zur Fahrkontrolle eingebaut haben. 
Die können es sich doch gar nicht leisten, dass sich der Kran jeden 
2.ten Tag verheddert. Das Zeug muss laufen!

Ich bin eigentlich nur deswegen auf den Timer aufgesprungen, weil Timer 
nun mal ein wichtiges Arbeitsmittel sind. So wie der 2.te Gang beim Auto 
:-)

von *kopfkratz* (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> So wie der 2.te Gang beim Auto
> :-)

Ich würde den 1. bevorzugen...

von Hannes L. (hannes)


Lesenswert?

*kopfkratz* schrieb:
> Ich würde den 1. bevorzugen...

Ich auch, aber Kalle fährt sicherlich keinen Kleinwagen... ;-)))

...

von Rolf H. (flash01)


Lesenswert?

mh...nun steh ich da!
erst mal zu spess:
sicher habe ich den Stack initial.
Hab es hier weggelassen.
Das mit TCCR0B und mov r7,r16 zieh ich mir nochmal rein.
Ich denke, wenn ich zu Beginn r16 in akku benenne, soll ich dann
nicht später mit r16 weiter machen.
Am Anfang stehen die .DEFxxx Bezeichnungen.
Nochmals zu diesen Kran:
In AUF  Rechts  Linksbetrieb sind Endlagenschalter eingebaut, aber um
die brauch ich mich garnicht zu kümmern. Der Motor wird autom. ab-
geschaltet. Egal ob 4 oder 5 Sec. die Zeit muß nur so lang sein,
daß die Endlage auch erreicht wird.
Die Abwärtsfahrt zum Contener habe ich mit einem Readkontakt gelöst.
Aber soweit bin ich noch lange nicht.
Vergessen wir doch mal das Thema "Kran" und nehmen eine einzige
LED an PortB,1 gegen Plus über NPN
kleines Quellprogramm:
loop:
pause4 (ca. 4 Sec.)
PB1 = EIN
pause4
PB1 = AUS
rjmp loop
Ich muß doch den Timer0 EIN bzw. AUSschalten, oder sollte ich das mit
sei machen?
Nun lasst mich doch nicht so zappeln, es fehlt nur noch ein Tick
bei mir, dann kommt der Durchbruch.
Meine ISR
timer:
     dec    warte4
     brne
     rjmp   ende4
     reti
Darf ich den rjmp  ende4 innerhalb der ISR machen oder nicht
Bin gespannt, ob ich es schaffe, die eine LED zum blinken zu bringen.

Grüße

Rolf

von Hannes L. (hannes)


Lesenswert?

Rolf Hegewald schrieb:
> Vergessen wir doch mal das Thema "Kran"

Gut, vergessen wir's...

...

von MWS (Gast)


Lesenswert?

Rolf Hegewald schrieb:
> Darf ich den rjmp  ende4 innerhalb der ISR machen oder nicht

Nein, darfst Du nicht.
> ende4: out  TCCR0,flashaus
> ret

Das ret würde zwar auch aus der ISR zurückkehren, aber nur reti setzt 
das I-Flag in SREG wieder und erlaubt wieder Interrupts.

Besorg' Dir erst mal das Instruction Set Pdf von Atmel.

Rolf Hegewald schrieb:
> Nun lasst mich doch nicht so zappeln, es fehlt nur noch ein Tick
> bei mir, dann kommt der Durchbruch.

Sagte der Blinddarm :D

von Karl H. (kbuchegg)


Lesenswert?

Rolf Hegewald schrieb:

> In AUF  Rechts  Linksbetrieb sind Endlagenschalter eingebaut, aber um
> die brauch ich mich garnicht zu kümmern. Der Motor wird autom. ab-
> geschaltet. Egal ob 4 oder 5 Sec. die Zeit muß nur so lang sein,
> daß die Endlage auch erreicht wird.

Ist zwar jetzt egal, aber für die Zukunft: Für sowas nimmt man der 
Einfachheit halber gleich die Endlagenschalter her. Ist doch viel 
einfacher.

> Ich muß doch den Timer0 EIN bzw. AUSschalten, oder sollte ich das mit
> sei machen?

Der Timer läuft STÄNDIG

Den stellst du am ANfang ein, dann kommt irgendwann der sei (wodurch die 
Timer ISR ab sofort dann regelmässig aufgerufen wird) und dann gehts im 
Hauptprogramm in die Hauptschleife hinein.

> Meine ISR
> timer:
>      dec    warte4

Lies es mir von den Lippen ab:
In einer ISR wird nicht gewartet!


Der Programmaufbau ist so
1
      rjmp start
2
3
     Interrupt Vektoren
4
5
start:
6
      Stack Initialisieren
7
 
8
      Timer initialisieren
9
10
      Zustand des Krans sei gleich "fahre nach links"
11
      Wartezeit für diesen Zustand sei 4 Sekunden
12
13
      sei
14
15
loop:  rjmp loop
16
17
18
Timer ISR:
19
   SREG sichern
20
21
   Wartezeit um 1 runtzählen
22
   ist die Wartezeit 0?
23
   Nein -> zum Ende der ISR
24
25
   ; die Zeit für die Bewegung ist abgelaufen, wie gehts weiter
26
   erst mal Motor aus
27
28
   welches ist der 'Zustand' des Kranes?
29
30
   "fahre nach links"
31
       Neuer Zustand ist "fahre nach unten links"
32
       Wartezeit sei 10 Sekunden
33
       entsprechenden Motor ein
34
       -> zum Ende der ISR
35
36
   "fahre nach unten links"
37
       Neuer Zustand ist "fahre nach oben links"
38
       Wartezeit sei 10 Sekunden
39
       entsprechender Motor ein
40
       -> zum Ende der ISR
41
42
  "fahre nach oben links"
43
       Neuer Zustand ist "fahre nach rechts"
44
       Wartezeit sei 4 Sekunden
45
       entsprechender Motor ein
46
       -> zum Ende der ISR
47
48
  "fahre nach rechts"
49
       Neuer Zustand ist "fahre nach rechts unten"
50
       Wartezeit sei 10 Sekunden
51
       entsprechender Motor ein
52
       -> zum Ende der ISR
53
54
  "fahre nach rechts unten"
55
       Neuer Zustand ist "fahre nach rechts oben"
56
       Wartezeit sei 10 Sekunden
57
       entsprechender Motor ein
58
       -> zum Ende der ISR
59
60
  "fahre nach rechts oben"
61
       Neuer Zustand ist "fahre nach links"
62
       Wartezeit sei 4 Sekunden
63
       entsprechender Motor ein
64
       -> zum Ende der ISR
65
66
Ende der ISR:
67
   SREG wieder herstellen
68
   reti

> Bin gespannt, ob ich es schaffe, die eine LED zum blinken zu bringen.

Einfach ein Register in der ISR um 1 runterzählen.
Wenn es danach nicht 0 ist, wird die ISR wieder verlassen.
Ist es 0, dann schaltest du die LED um und belegst das Register wieder 
mit einem Zählwert vor, von dem aus runtergezählt wird.
Wie gross dieser Zählwert ist, hängt davon ab wie schnell die LED 
blinken soll und wie oft die ISR aufgerufen wird. Das wiederrum hängt 
davon ab, wie schnell der Timer zählt und das wiederrum hängt von der 
Taktfrequenz und dem Vorteiler ab.

von spess53 (Gast)


Lesenswert?

Hi

>Ich denke, wenn ich zu Beginn r16 in akku benenne, soll ich dann
>nicht später mit r16 weiter machen.
>Am Anfang stehen die .DEFxxx Bezeichnungen.

Richtig. Das sollte dir auch nur zeigen, was du machst. Wenn man einen 
Port den Namen 'flashaus' verpasst ist 'out flashaus,akku' richtig. Bei 
einem Register aber nicht.
Persönlich bin ich Gegner von diesem .def-Gedödel. Das mag bei solchen 
Spielzeugprogrammen ganz nett sein. Bei größeren Programmen kann man 
einem Register nicht nur eine Funktion zuweisen. Und wenn man Librarys 
für Displays, Sensoren, Schnittstellen usw. schreibt müssen die mit 
verschiedenen Programmen konfliktlos zusammenarbeiten. Und da ist nun 
mal der Registername der kleinste gemeinsame Nenner.

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo an Alle,
ich habe sofort alles von Karl Heinz ausgedruckt und das Pferd ganz
Neu aufgesattelt.
Ihr habt Recht, das Ding war suboptimal.
Habe also von Anfang Neu aufgebaut und viele Anregungen von
Euch zu Herzen genommen.
Z.B. den .defxxx Düttelkram weggelassen und stur mit r16 losgearbeitet.
Mich um das SREG Register gekümmert und die Sache läuft schon mal.
 Das Thema "Kran" wird ersetzt durch 3 LEDs an PB0-PB2.
Hier also das Neue:

; PORTB: Ausgabe
; PortD: Eingänge
;Datum: 10.12.2011

;AVR: Tiny 2313

        .INCLUDE  "tn2313def.inc"  ; Deklarationen für Tiny2313
        .EQU    takt = 1000000  ; Systemtakt 1 MHz

; r16=Arbeitsregister
    rjmp  start
    .ORG  OVF0addr      ;Interrupt Vektoren
    rjmp  timer         ;Sprung zur ISR



;Stack initialisieren, PortB=Outp., PortD=Inp.

start:    ldi    r16,LOW (RAMEND)
    out    SPL,r16
    ldi     r16,$ff      ; Bitmuster 1111 1111
    out     DDRB,r16      ; Port B ist Output
                   ldi   r16,$00      ; Bitmuster 0000 0000
    out    DDRD,r16    ; Port D ist Input


;Timer0 initialisieren
           ldi  r16,1<<CS02|1<<CS00  ;Prescale = 1024
           out  TCCR0B,r16  ;r16 in Steuerreg. TCCR0
      ldi   r16,1<<TOIE0  ;r16< 1 = Interrupt-Freigabe
      out  TIMSK,r16  ;TIMSK = Timer Interrupt
                            sei  ; I-Bit im Statusregister SREG
                                              ; 0 = Interrupt gesperrt
        ; 1 = "      "  freigegeben
;Arbeitsbeginn

loop:             ldi  r16,2
      out  PORTB,r16
      rjmp  timer  ;Sprung zur ISR
      rjmp  loop

;Interrupt - ISR
timer:    push  r16    ;Register retten
    in  r16,SREG           ;Statusregister
    ldi  r16,1
    out  PORTB,r16
      reti
Wie schon gesagt,das läuft.

Diese Versuche stecken nicht in den Quelltext wie oben!
Nun wollte ich die ersten Gehversuche mit einem Register z.B. r17
in der ISR machen und dieses runter zählen, und da komme ich mit brne
immer noch ins schleudern.
1.Schritt...im Arbeitsbereich loop: habe ich r17 mit 0F geladen.
2. "     ....springe mit rjmp  timer zur ISR
gehe         dec,r17
             brne gehe
             reti
aber so ist das doch nicht ok, ich möchte doch nur nach jedem
Timer-Überlauf r17 = -1 zählen.
Ich weiß noch nicht, wie ich exakt rauskomme, na ja..Ihr
werdet darüber lächeln, aber ich nehms hin!

Grüße

Rolf

von spess53 (Gast)


Lesenswert?

Hi

>;Interrupt - ISR
>timer:    push  r16    ;Register retten
>    in  r16,SREG           ;Statusregister
>    ldi  r16,1
>    out  PORTB,r16
>      reti

Das Sichern von SREG macht nur Sinn wenn man es auch wieder 
rekonstruiert. Push und Pop funktionieren nur wenn es genau so viele 
Pushs wie Pops gibt.
Und warum erfindest du einen eigenen Namen für den Interrupt. Nimm den 
aus dem Datenblatt. Da weiß jeder, was gemeint ist.
1
TIMER0_OVF:   push r16       ; Timer0 Overflow
2
              in r16,SREG
3
              push r16
4
              ....        
5
              pop r16
6
              out SREG,r16
7
              pop r16
8
              reti

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

>Wie schon gesagt,das läuft.

Nicht wirklich.

>;Arbeitsbeginn

>loop:             ldi  r16,2
>      out  PORTB,r16
>      rjmp  timer  ;Sprung zur ISR
>      rjmp  loop

Wenn du einen Motor eine bestimmte Zeit in eine Richtung fahren lassen 
willst geht das einfach so:
1
      ldi  r16,2
2
      out  PORTB,r16  ; Motor einschalten
3
      ldi r17,10      ; Zeit laden
4
loop: test r17        ; Zeit abgelaufen?
5
      brne loop
6
      ldi r16,0
7
      out  PORTB,r16 ; Motor ausschalten
8
      ....
9
10
TIMER0_OVF:
11
      push r16       ; Timer0 Overflow
12
      in r16,SREG
13
      push r16
14
15
      dec r17
16
17
      pop r16
18
      out SREG,r16
19
      pop r16
20
      reti

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo spess,
aufatmen, Dein Vorschlag läuft!
Muß alles erst mal verarbeiten.
Z.B. test war der Befehl "tst"
nach ca. 2 Sec. schaltet ein PORT,x nach PORT,y
Ich komme der Sache immer näher, meinen Dank nochmals.
Übrigens: Studio gab mir eine Warnung mit "1<<CS2|1<<CS0

Habe ich abgeändert in "1<<CS02|1<<CS00" alles war ok!

Nochmals mein Dankeschön


Rolf

von spess53 (Gast)


Lesenswert?

Hi

>Z.B. test war der Befehl "tst"

Ja, das war ein Tippfehler.

Noch was: Quelltext sollte keine Tabs enthalten. Sonst sieht es in jedem 
Editor anders aus. Am besten du stellst in den Editor-Options vom 
AVR-Studio Tabwith auf 1 und aktivierst 'Replace Tabs with Space'.

MfG Spess

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Du willst bestimmt nicht für jede Motorfahrt einen eigenen Code 
schreiben. Im Anhang mal eine Minimalvariante wie so etwas mit wenig 
Code flexibel geht. Die Motoransteuerungen (pause, M1_right, M1_left 
...) und die Zeiten sind meiner Phantasie entsprungen. Musst du also 
anpassen. In der Tabelle 'ablauf' muss einfach nur eingetragen werden, 
was wie lange gemacht werden soll.

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

War die Debugversion:

ldi r16,1<<CS00  ;    1<<CS02|1<<CS00 
;FOC0A,FOC0B,WGM02,CS02,CS01,CS00

in

ldi r16,1<<CS02|1<<CS00    ;FOC0A,FOC0B,WGM02,CS02,CS01,CS00

ändern.

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo Spess und Karl Heinz,
alles super geworden mit dem Quelltext für den Contener.
2 Eingänge an PortD liegen über Readkontakte gegen GND.
Habe ich so gelöst:

loop:   nop
read1:  spic   PIND,PD0
        rjmp   read1
Motor aufwärts EIN

Dann auf 2 Unterprogramme (5 bzw. 20 Secunden)

         rcall  zeit5
         rcall  zeit20

zeit5:
pause5:   tst   r17,17  ;gemessen ca. 5 Sec.
          brne  pause5
          ret
zeit20:
pause20:  tst   r17,5C  ;gemessen ca. 24 Sec.
          brne  pause20
          ret
Nun muß ich noch die Hardware zusammen stricken und dann kommt der große
Momment.
Leider zeigt mein Buch nur den Timer1 für einen Mega8.
So wie ich lese, ist das Gebiet umfangreicher als der Timer0.
Für die übernächste Zeit werde ich sowas für einen
Tiny13 brauchen, und zwar als Ortungspieper für einen 3m Segler.
Aber ich glaube, der kleine Tiny hat nur Timer0.

Also meinen Dank nochmals für Eure Hilfe und geduldige
Ausdauer mit mir.

Grüße

Rolf

von spess53 (Gast)


Lesenswert?

Hi

>Leider zeigt mein Buch nur den Timer1 für einen Mega8.

Vergiss das Buch und nimm das Datenblatt.

MfG Spess

von Rolf H. (flash01)


Lesenswert?

mh...was wäre das schön, wenn ich Eure Englischkenntnisse hätte!
Und mit über 70 Jahren fange ich nicht mehr damit an, zumal
mir das Volkshochschul-Englisch nicht viel nützen wird.

von Rolf H. (flash01)


Lesenswert?

Sorry, eigentlich wollte ich das in diesen Thread reinsetzen!

Grüße

Rolf

von Rolf H. (flash01)


Lesenswert?

Hallo an ALLE,
habe heute nochmal den ganzen Thread durchgekaut, um viele
Sachlagen zur Erinnerung zu rufen.
Der Containerkran (jetzt will ich es aber mal richtig schreiben)
läuft und läuft.

Danke nochmals und Grüße

Rolf

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.