Forum: Mikrocontroller und Digitale Elektronik anfänger bei assembler


von Richard X. (synq1e)


Lesenswert?

Ich bin gerade dabei das "AVR-Tutorial: IO-Grundlagen" durchzuarbeiten. 
mit dem unterschied dass ich einen "ATTINY13" verwende und nicht wie in 
dem Tutorial angegebenen "ATmega8"
der attiny hat ja nur einen PORTB pin0-pin5
meine peripherie zu dem tutorial sind 2 leds und 2 taster
und ich möchte einen assembler code schreiben dass bei gedrückter 
taste-A led-A leuchtet und bei gedrückter taste-B led-B leuchtet

habs ja zunächst mit nur einem taster probiert aber ich bekomm es nicht 
hin dass er mir die anliegenden werte in das arbeitsregister einließt

hier ein mal ein code das ihr wisst was ich versuche ist aber nicht der 
richtige weg
Am chip liegt ein taster mit externem pull up widerstand 10kohm an PB0
und 2 LEDS an PB3 und PB4
1
.include "tn13def.inc"    
2
3
  ldi r16, 0b00011000 
4
  out DDRB, r16    
5
6
  ldi r16, 0xFF
7
  out PORTB, r16
8
loop:
9
         in r16, PINB0      
10
         out PORTB3, r16   
11
         rjmp loop
ich wüsste nicht wie das sonst gehen sollte mit eingang und ausgang an 
einem port gemeinsam setzen außer mit der bitmaske

ich bin für jede antwort dankbar

von Steffen H. (avrsteffen)


Lesenswert?

Für den einfachen Anfang reicht der sbic/sbis Befehl zum Einlesen des 
Port-Pins und der sbi/cbi Befehl zur Ausgabe eines Bits auf dem 
Port-Pin.

sbic - überspringe nächsten Befehl, wenn PinX im PortPinX '0' ist
sbis - überspringe nächsten Befehl, wenn PinX im PortPinX '1' ist

Beispiel:   sbic   PINB,PB0
            rjmp   xyz
            rjmp   Beispiel


cbi  - lösche BitX im I/O PortX zu '0'
sbi  - setze BitX im I/O PortX zu '1'

Beispiel:   sbi   PORTB,PB4

Übrigens:
1
    out PORTB3, r16  // <<---- müsste Error-Meldung bringen
sollte nicht gehen.

Gruß Steffen

von Kai S. (kai1986)


Lesenswert?

Hallo,

der Befehl "in" lädt ein ganzes Byte auf einmal, es ist also nicht 
möglich nur ein einzelnes Bit zu laden.
Die Idee mit der Bitmaske ist hier schon richtig.

Zusätzliche Informationen zu den einzelnen ASM Befehlen von Atmel 
findest du im Instruction Set
http://www.atmel.com/images/doc0856.pdf

Darin stehen auch die Informationen, auf welche Register die Befehle 
anwendbar sind. Auch enthält es meist kurze Beispiele für die einzelnen 
Befehle.

Gruß Kai

von Jano (Gast)


Lesenswert?

Schau dir auch mal die Instruktionen SBIC, SBIS, SBI, CBI an.

von Richard X. (synq1e)


Lesenswert?

funktioniert noch immer nicht :-/
setting : an PB0 hängt ein taster mit externem pullup widerstand
und an PB3 eine LED mit der anode auf VCC
1
.include "tn13def.inc"    ;definitionsdatei für den spezifischen chip
2
3
  ldi r16, 0b00011000 
4
  out DDRB, r16    
5
6
  ldi r16, 0b00011000
7
  out PORTB, r16
8
9
loop: sbic PINB,PB0
10
rjmp loop
11
  sbi  PORTB, PB3
12
13
14
ende: rjmp ende

wenn ich dann einmal den taster drücke leuchtet die led nicht , warum ?

von Spess53 (Gast)


Lesenswert?

Hi

> an PB0 hängt ein taster mit externem pullup widerstand
>und an PB3 eine LED mit der anode auf VCC

Dann solltest du statt 'sbi  PORTB, PB3' besser 'cbi  PORTB, PB3' 
nehmen.

MfG Spess

von Richard X. (synq1e)


Lesenswert?

dann leuchtet sie ohne den taster gedrückt zu haben. ich nehme an das 
somit rjmp loop übersprungen wurde ohne dass der taster gedrückt wurde , 
kein plan warum

von Stefan (Gast)


Lesenswert?

1
loop: cbi PINB,PB0
2
rjmp loop
3
sbi  PORTB, PB3

Das ist doch auch falsch! cbi soll ein Bit clearen, aber dann doch 
sicher nicht im Eingabe-Register. Und der rjmp Befehl springt immer 
wieder an die Sprungmarke, der Befehl darunter, der PB3 auf High setzt 
wird so niemals ausgeführt.

Mein Vorschlag:
1
; PB0 = Taster, Low wenn gedrückt
2
; PB3 = LED, leuchtet wenn Low  
3
4
; Schalte PB3 auf Ausgang
5
  ldi r16, 0b00001000 
6
  out DDRB, r16    
7
8
; Ausgänge auf High, Eingänge mit Pull-Ups
9
  ldi r16, 0xFF
10
  out PORTB, r16
11
12
loop:
13
; Eingänge einlesen
14
    in r16, PINB
15
; Testen, ob Taster gedrückt ist
16
    andi r16, 0b00000001
17
; Branch if equal (= zero)
18
    breq gedrueckt
19
20
losgelassen:
21
    sbi PORTB, PB3
22
  rjmp loop
23
24
gedrueckt:
25
    cbi PORTB, PB3
26
  rjmp loop
Unter Zuhilfenahme des T Flags kann man es auch so machen:
1
loop:
2
; Eingänge einlesen
3
    in r16, PINB
4
; Zustand des Taster (Bit 0 in r16) ins T-Flag kopieren
5
  bst r16, 0
6
; Aktuellen Zustand der Ausgänge holen
7
    in r16, PORTB
8
; T-Flag auf Bit 3 (LED) kopieren
9
    bld r16, 3
10
; Ausgänge beschreiben
11
    out PORTB, r16
12
    rjmp loop

von Kai S. (kai1986)


Lesenswert?

Hallo,

dein Programm reagiert nur einmal überhaupt, danach hängt es in einer 
Endlosschleife und macht nichts mehr. Falls das nicht dein Ziel ist 
tausch mal die Befehle "rjmp loop" und "rjmp ende".

Wenn du zum Programmieren AVR Studio verwendest kannst du deine 
Programme simulieren und dir dabei ansehen, was jeder Schritt macht.

Gruß Kai

von Stefan (Gast)


Lesenswert?

Noch eine Erklärung zu diesen Zeilen:

andi r16, 0b00000001
breq gedrueckt

Andi ist eine bitweise UND Verknüpfung, um r16 auf das eine Bit zu 
reduzieren, wo der Taster dran hängt. Danach ist r16=0 (Low) wenn der 
Taster gedrückt ist. Wenn der Taster nicht gedrückt ist, ist r16 danach 
größer als 0.

Breq springt, wenn das Zero-Flag gesetzt ist. Das Zero Flag ist gesetzt, 
wenn die vorherige Operation eine 0 ergeben hat, also wenn der Taster 
gedrückt ist.

Hier muss man ein bisschen aufpassen, die Buchstaben "eq" (equal) nicht 
wörtlich zu nehmen. Eigentlich müsste der Befehl brz (branch if zero) 
heissen, um präziser auszudrücken, was der Befehl macht - das ist 
zumindest meine Meinung dazu.

Der Name breq (branch if equal) geht davon aus, daß man vorher eine 
compare Operation (oder eine subtraktion) durchgeführt hat. Aber das 
haben wir ja nicht gemacht, wir haben eine andi (UND Verknüpfung) 
vorgenommen.

Ein Blick in den Befehlssatz hilft hier, Unklarheiten zu beheben. andi 
setzt das Z Flag, wenn das Ergebnis 0 ist. Und breq springt, wenn das 
Z-Flag gesetzt ist.

von Richard X. (synq1e)


Lesenswert?

vielen dank an Stefan das du dir so viel mühe gegeben hast die befehle 
zu erklären.
habs ausprobiert und funktioniert alles prächtig :-).
nun möchte ich gern wissen wie es bei assembler aussieht wenn ich 2 oder 
mehr taster zum steuern für 2 oder mehrere leds haben möchte.
wie gesagt taste-A led-A leuchtet und bei gedrückter taste-B led-B 
leuchtet

ich hab mir auch schon einiges angeschaut über die Instructions die z.B 
bei atmel studio dabei sind (AVR Assembler User Guide) verstehe aber 
irgendwie nicht viel wenn ich mir das so durchlese ,nicht weil es mir an 
englisch mangelt.
aber wenn ich sowas lese:
(i)ANDI Rd,K 16 ≤ d ≤ 31, 0 ≤ K ≤ 255 PC ← PC + 1

16-bit Opcode:
0111KKKKddddKKKK
dann sind das für mich nur irgendwelche Aneinanderreihung von Zeichen

und was hat es mit dem "Status Register (SREG) and Boolean Formulae:" 
auf sich ??

von Hannes L. (hannes)


Lesenswert?

chris __ schrieb:
> aber wenn ich sowas lese:
> (i)ANDI Rd,K 16 ≤ d ≤ 31, 0 ≤ K ≤ 255 PC ← PC + 1

Andi: And immidiate, AND-Verknüpfung direkt, also mit Konstante

RD: Destinationsregister (Ziel), erlaubt ist R16 bis R31

K: Konstante, erlaubt ist 0 bis 255

>
> 16-bit Opcode:
> 0111KKKKddddKKKK

0 und 1 steht für den Opcode ANDI, d steht für das Destinationsregister, 
K steht für die Konstante. Alles zusammen ergibt den 16-Bit-Code des 
Befehls, also 4 Befehlsbits, 4 Bits für des verwendete Register und 8 
Bits für die Konstante.

> dann sind das für mich nur irgendwelche Aneinanderreihung von Zeichen

Ich hoffe, jetzt nicht mehr.

chris __ schrieb:
> und was hat es mit dem "Status Register (SREG) and Boolean Formulae:"
> auf sich ??

Die Befehle können Bits im SREG verändern. Mit den bedingten Sprüngen 
(Branch-Befehle) kann man auf bestimmte Bits des SREG reagieren. Das 
macht dann das, was in Hochsprachen mit IF erreicht wird.

...

von Stefan (Gast)


Lesenswert?

Diese Formeln sind auch nicht so leicht zu verstehen. Aber zusammen mit 
dem Text sollte es dann klar sein. Ich habe mir das im AVR Studio noch 
nie angesehen, ich arbeite immer mit dem "AVR 8-bit Instruction Set" 
Handbuch im PDF Format. Das steht bei ANDI:

>Performs the logical AND between the contents of register Rd
>and a constant and places the result in the destination register Rd.

>Rd ← Rd • K

Rd wird mit dem Ergebnis von "Rd UND K" beschrieben. Der Punkt steht für 
die Bitweise UND Verknüpfung. d ist eine Registernummer und K eine 
Konstante. Siehe auch die erste Seite in dem PDF mit Titel "Instruction 
Set Nomenclature"

>16 ≤ d ≤ 31, 0 ≤ K ≤ 255

Das sagt und, dass der Befehl nur mit den Registern R16 bis R31 
funktioniert und dass die Konstante im Bereich 0-255 sein muss (logisch, 
ist ja ein 8-Bit Prozessor).

Ich interessiere mich auch immer wieder dafür, welche Flags durch den 
Befehl wie beeinflusst werden. Da steht dann beispielsweise für das 
Z-Flag:

Z: Set if the result is $00; cleared otherwise.

Mein Code-Beispiel kannst Du auf beleibig viele Taster erweitern. Du 
machst dann halt für jede Taste eine UND Verknüpfung und einen bedingten 
Sprung:
1
loop:
2
; Eingänge einlesen
3
    in r16, PINB
4
5
; Testen, ob Taster A gedrückt ist
6
    andi r16, 0b00000001
7
; Branch if equal (= zero)
8
    breq gedruecktA
9
; LED aus schalten
10
    sbi PORTB, PB3
11
    rjmp endeA
12
gedruecktA:
13
; LED einschalten
14
    cbi PORTB, PB3
15
endeA:
16
17
; Testen, ob Taster A gedrückt ist
18
    andi r16, 0b00000010
19
; Branch if equal (= zero)
20
    breq gedruecktB
21
; LED aus schalten
22
    sbi PORTB, PB4
23
    rjmp endeB
24
gedruecktB:
25
; LED einschalten
26
    cbi PORTB, PB4
27
endeB:
28
29
    rjmp loop

von Stefan (Gast)


Lesenswert?

Wo DU gerade mit LED's und Tastern am ATTiny13 bastelst, schu Dir doch 
mal mein Assembler Tutorial an. Ich glaube, das passt gerade ganz gut:

http://stefanfrings.de/avr_workshop/index.html

von Rolf H. (flash01)


Lesenswert?

Hallo Chris,
mit Interesse habe ich Deine Aufgabenstellung gelesen,
und habe mich hingesetzt, um es in die Tat umzusetzen.

Die Hardware mit zwei Taster und zwei LEDs sieht wie folgt aus:

Taste "sw1" an PB0
Taste "sw2" an PB1 (beide Tasten gegen GND)

rote LED an PB3
grüne LED (gn) an PB4 (beide LEDs werden über Transistoren nach Vcc
gesteuert. D.h. HIGH an Ports LEDs = EIN.

Hier den Quellcode mit Studio4 erstellt.
Nach dem flashen leuchtet die rote LED, deshalb habe ich diese
zu Beginn mit cbi auf dunkel gesetzt.
1
; Projekt-Name: Projekttiny13           Datum: 21.02.2013                  
2
3
; Datei: Taste-LED.asm              
4
5
; PORTB,xx  (Output)
6
; PINB,xx   (Input)
7
; DDRB,akku (Datenrichtung)
8
9
; AVR: Tiny13-20PU
10
11
  .INCLUDE   "tn13def.inc"  ; Include-Datei für Tiny13
12
    
13
  rjmp    reset             ; Reseteinsprung
14
  .ORG    OVF0addr          ; Interrupt-Vektor
15
  
16
 .def     akku=r16
17
 .def     temp1=r17
18
19
reset:       
20
21
  ldi     akku,0x18         ; 0b0001.1000 
22
  out     DDRB,akku         ; Datenricht. PB3-PB4=Outp.
23
                            ;   "     " . PB0-PB1=Inp.
24
25
  ldi     akku,0x03         ; 0b0000.0011
26
  out     PORTB,akku        ; PB0-PB1=PullUp 
27
  
28
  cbi     PORTB,PB3
29
  cbi     PORTB,PB4         ;  LED rot+gn zu Beginn dunkel
30
31
loop:      
32
sw1:
33
  sbic   PINB,PB0           ; überspringe,wenn Taste sw1=LOW
34
  rjmp   sw2                ; springe nach sw2, wenn sw1=HIGH
35
  rcall  LEDrot
36
37
sw2:
38
  sbic   PINB,PB1           ; überspringe,wenn Taste sw2=LOW
39
  rjmp   sw1                ; springe nach sw1, wenn sw2=HIGH
40
  rcall  LEDgn  
41
42
  rjmp    loop
43
44
LEDrot:
45
  sbi    PORTB,PB3          ; rote LED an PB3 = EIN
46
  cbi    PORTB,PB4          ; grüne LED an PB4 = AUS
47
  ret
48
49
LEDgn:
50
  sbi    PORTB,PB4          ; grüne LED an PB4 = EIN
51
  cbi    PORTB,PB3          ; rote LED an PB3 = AUS
52
  ret 
53
54
  .EXIT
Die Tab-Übersicht habe ich aus dem Forum gelernt.

Sicher mögen manche sagen "wofür Unterprogramme" aber ich arbeite
gern mit diesen...man behält eine gute Übersicht.
Gewöhne Dir evtl. auch an Kommentare zu setzen sie können
sehr hilfreich sein. Toll, daß Du in Assembler arbeitest, man blickt
einfach mehr in die Tiefe dieser AVRs.
Heute will ich mich nochmal mit Hannes Lux beschäftigen,
denn diese 1001 1010 AAAA Abbb sind für mich auch noch ein rotes Tuch.
Danke für seine Erklärung.
Also weiter üben, sonst ist manches schnell wieder weg.

Dieses Forum mit seinen Spitzenleuten wie Spess, Hannes und Oldmax
wie ich sie kennen gelernt habe...ist einfach SPITZE!

Grüße

Rolf

von Hannes L. (hannes)


Lesenswert?

Rolf H. schrieb:
> diese 1001 1010 AAAA Abbb sind für mich auch noch ein rotes Tuch.

Das muss man auch nicht wissen, denn man gibt die Befehle ja nicht binär 
ein. Es reicht zu, wenn der Assembler das weiß und natürlich der AVR. 
Wenn Du weißt, dass die Parameter des Befehls mit im Bitmuster codiert 
werden, dann weißt Du eigentlich genug, die genaue Bitposition muss man 
als Benutzer nicht wissen.

Wichtig für den Benutzer ist, dass man weiß, welche Flags die einzelnen 
Befehle beeinflussen und auf welche Flags die Branch-Befehle reagieren. 
Dazu ist es für den Anfänger sinnvoll, aus dem Datenblatt des 
verwendeten AVRs die Liste "Instruction Set Summary" auszudrucken und 
als Arbeitsblatt liegen zu haben.

Gleiches gilt für die Liste "Register Summary", die eine komprimierte 
Zusammenstellung der Namen der I/O-Register und deren Bits darstellt.

...

von Rolf H. (flash01)


Lesenswert?

haste Recht   Hannes Lux,
diese beiden Listen hab ich mir vom Tiny13 und 2313 ausgedruckt.


Gehört hier zwar nicht in diesen Thread aber nur so nebenbei:
Als Test habe ich beim Tiny2313 vom PORTB mit seinen 8 Pins
sage 24 Pins als Ausgang realisiert.
Benötige ich für die Modelleisenbahn-Anlage zum schalten von
Weichen, Signale, Entkuppl. Gleise, Drehscheibe usw.
D.h. an den 8 Pins hängen parallel geschaltet 3x 74LS374
(8x D-Flips). Und vom PORTD nehme ich PD0, PD1 und PD2 die ich zu den
3 Chips an Pin 11 (Enable) führe.
Haut alles wunderbar hin..nicht nur auf dem Papier.

Werde mir bei Reichelt nen Mega 16 kommen lassen, da ich auch
Eingänge für Readkontakte brauche.

Grüße

Rolf

von Karl H. (kbuchegg)


Lesenswert?

> D.h. an den 8 Pins hängen parallel geschaltet 3x 74LS374
> (8x D-Flips). Und vom PORTD nehme ich PD0, PD1 und PD2 die
> ich zu den 3 Chips an Pin 11 (Enable) führe.

Nimm das nächste mal 3 kaskadierte 74595
* du kommst mit lediglich 3 Pins am AVR durch
* wenn du dann irgendwann noch mehr Ausgänge brauchst, hängst du
  hinten in der Kette einfach noch einen 595 dazu und kriegst
  8 Ausgänge mehr
* die programmtechnische Ansteuerung ist auch nicht komplizierter

AVR-Tutorial: Schieberegister

von Rolf H. (flash01)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
> Nimm das nächste mal 3 kaskadierte 74595
> * du kommst mit lediglich 3 Pins am AVR durch
> * wenn du dann irgendwann noch mehr Ausgänge brauchst, hängst du
>   hinten in der Kette einfach noch einen 595 dazu und kriegst
>   8 Ausgänge mehr
> * die programmtechnische Ansteuerung ist auch nicht komplizierter
>
> AVR-Tutorial: Schieberegister

oh...weia! Den Quelltext zu erstellen könnte ich mir mit
Schieberegistern komplizierter vorstellen.

Wie einfach sieht es jetzt aus?

1. mit sbi oder cbi den Pinx aktivieren. (PORTB)
2. PORTB hängt parallel an die 3x 74LS374 (N1 bis N3)
3. Freigabe-Impuls an ausgewählten Nx....Fertig!
Hinzu kommt hier noch eine Sicherheitsstufe, die für ca. 3 Sek.
die Spannung an den Signalen bzw. Weichen freigiebt.
Die Versorgung zu den Spulen sollte nicht dauerhaft anliegen.
Wem das mehr interessieren würde, kann ich einen neuen Thread eröffnen.
Der Quelltext steht bereits und erste Gehversuche mit LEDs sind gemacht.

Grüße

Rolf

von Hannes L. (hannes)


Lesenswert?

Rolf H. schrieb:
> oh...weia! Den Quelltext zu erstellen könnte ich mir mit
> Schieberegistern komplizierter vorstellen.

Nicht wirklich. Das ist aber eine Frage des Konzeptes.

Wenn man nur dann schiebt, wenn man denkt, dass man es braucht, dann 
hast Du natürlich recht. Dann blockieren sich die Programmteile 
gegenseitig, so wie es in vielen Beispielcodes von Tutorials (zum 
Verstehen der ersten Schritte!) vorgebetet wird.

Legt man die Schieberei aber als Zustandsautomat (Statemachine) in den 
Hintergrund (Timer-Interrupt), so braucht man sich nur noch um die 
RAM-Zellen zu kümmern, deren Inhalt rausgeschoben werden sollen und 
erhält ganz nebenbei noch einen Systemtakt, den man für Entprellung, 
Verzögerungszeiten, Ringelpitz und Trallalla nutzen kann. Die 
Vorgehensweise ist im Artikel Multitasking ganz gut beschrieben und 
auch mit den knappen Ressourcen des Tiny2313 sehr gut umsetzbar.

Und mit einer vierten Leitung liest man gleichzeitig noch die Rückmelder 
ein...

Spendiert man dem Tiny2313 noch einen Baudratenquarz, dann kann man über 
UART auch noch den PC einbinden, was dann dank echtem RS232 auch über 
USB-Seriell-Wandler funktioniert.

...

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Nimm das nächste mal 3 kaskadierte 74595
> * du kommst mit lediglich 3 Pins am AVR durch
> * wenn du dann irgendwann noch mehr Ausgänge brauchst, hängst du
>   hinten in der Kette einfach noch einen 595 dazu und kriegst
>   8 Ausgänge mehr
> * die programmtechnische Ansteuerung ist auch nicht komplizierter

Hab dazu auchmal eine Schaltung incl. Layout gemacht. Siehe oben und 
hier:
Beitrag "Re: Schieberegister 74HC595 und 74HC165"


Gruß Steffen

von Rolf H. (flash01)


Lesenswert?

mh...und so sehen bei mir die einzelnen Proceduren aus:

zu Beginn erst mal alle Outputs auf LOW setzen
1
 RUN:                      ;Programm-Start
2
  clr     akku        
3
  out     PORTB,akku      ;PORTB = LOW
4
  rcall   Takt01          ;Takt von PD0  
5
  rcall   Takt02          ;Takt von PD1
6
  rcall   Takt03          ;Takt von PD2
7
  ret
die Soubroutienen Takt01 bis Takt03
1
Takt01:                   ;Takt an 74LS374 / N1
2
  clr     akku
3
  out     PORTD,akku
4
  sbi     PORTD,PD0
5
  cbi     PORTD,PD0
6
  ret
7
8
9
Takt02:                   ;Takt an 74LS374 / N2
10
  clr     akku
11
  out     PORTD,akku
12
  sbi     PORTD,PD1
13
  cbi     PORTD,PD1
14
  ret
15
16
Takt03:                   ;Takt an 74LS374 / N3
17
  clr     akku
18
  out     PORTD,akku
19
  sbi     PORTD,PD2
20
  cbi     PORTD,PD0
21
  ret
das Schaltrelais was für 2 Sek.die Versorgung frei giebt
1
out1h:                    ;N1 / Q0
2
  sbi     PORTB,0         ;an Pin 2c
3
  rcall   Takt01
4
  rcall   zeit2
5
  cbi     PORTB,0
6
  rcall   Takt01
7
  rcall   zeit2
8
  ret
und hier als Beispiel 7x Proceduren
1
; out2h bis out8h (PORTB,1 - PORTB,7) = High
2
; aktivieren über Takt01 (PORTD,PD0)
3
4
out2h:                    ;N1 / Q1 = High
5
  sbi    PORTB,1          ;Signal S1=Fahrt an Pin 3c
6
  rcall  Takt01
7
  rcall  out1h
8
  ret
9
10
out3h:                    ;N1 / Q2 = High
11
  sbi    PORTB,2          ;Signal S2=Fahrt an Pin 4c
12
  rcall  Takt01
13
  rcall  out1h
14
  ret
15
16
out4h:                    ;N1 / Q3 = High
17
  sbi    PORTB,3          ;Signal S3+S5=Fahrt an Pin 5c
18
  rcall  Takt01
19
  rcall  out1h 
20
  ret
21
22
out5h:                    ;N1 / Q4 = High
23
  sbi    PORTB,4          ;Textmodul=EIN an Pin 6c
24
  rcall  Takt01           ;ohne Verzögerung
25
  ret
26
27
out6h:                    ;N1 / Q5 = High
28
  sbi    PORTB,5          ;Entk. EKA2=EIN an Pin 7c
29
  rcall  Takt01           ;ohne Verzögerung         
30
  ret
31
32
out7h:                    ;N1 / Q6 = High
33
  sbi    PORTB,6          ;Entk. EKA1=EIN an Pin 8c
34
  rcall  Takt01           ;ohne Verzögerung
35
  ret
36
37
out8h:                    ;N1 / Q7 = High
38
  sbi    PORTB,7          ;Entk. EKI=EIN an Pin 9c
39
  rcall  Takt01           ;ohne Verzögerung
40
  ret
41
;############################################

von Karl H. (kbuchegg)


Lesenswert?

Rolf H. schrieb:
> mh...und so sehen bei mir die einzelnen Proceduren aus:

Schau.
Das bezweifelt ja auch keiner, dass es so AUCH geht.
Aber du brauchst am µC dafür 11 Pins.
Mit Schieberegistern brauchst du nur 3 Pins. Und der Softwareaufwand 
dafür hält sich in Grenzen.

Du brauchst:
* ein Register (oder ein Byte im SRAM), welches 8 Ausgangsleitungen 
darstellt. Wann immer sich ein Ausgangspin ändern soll, dann wird die 
Operation auf diesem Byte gemacht.
* eine Routine, die dieses Byte an das Schieberegister raustaktet.

Die Raustaktroutine ist auch nicht aufwändig. Das sind über den Daumen 7 
bis 10 Befehle. Und man muss sie noch nicht mal selber ausfrufen, man 
kann sich auch einen Timer aufsetzen, der alle 1 Millisekunde 
(Hausnummer), dieses Byte ans Schieberegister raustaktet. Dann sieht für 
den Rest des Programms die Sache so aus, dass dieses 'Spezialregister' 
'magisch' auf die Ausgabepins gespiegelt wird. Um einen Ausgang zu 
setzen/löschen genügt es, in diesem Register ganz einfach das 
betreffende Bit zu setzen.
Und: Wenn ich will kann ich mir da auch 80 Ausgangsleitungen machen, 
OHNE dass sich am zugrundeliegenden Mechanismus etwas ändert.

Ich sag ja auch nicht, dass du dein Programm oder den Aufbau jetzt 
ändern sollst. Überhaupt nicht. Aber beim nächsten Entwurf sieh dir auch 
mal Alternativen an. Du wirst sehen, so schwer ist das nicht. Und wenn 
du das ganze in Aktion siehst wirst du auch feststellen: Am Anfang sieht 
es komplizierter aus - das ist es aber eigentlich nicht. Übers ganze 
Programm gesehen, ist es sogar einfacher.


Ein Signal zu schalten kann mit dem entsprechenden Unterbau dann so 
einfach sein, wie
1
....
2
;   Fahrstrasse freigben
3
     sbi   SIGNAL, S1                    ; S1 auf Fahrt
4
     cbi   SIGNAL, S2                    ; S2 auf Stop
5
     cbi   SIGNAL, S3                    ; S3 auch auf Stop
6
     sbi   SIGNAL, S4                    ; und S4 auf Fahrt
7
8
....
9
;   Fahrstrasse wieder sperren
10
     cbi   SIGNAL, S2                    ; S1 auf Stop
11
     cbi   SIGNAL, S2                    ; S2 auf Stop
12
     cbi   SIGNAL, S3                    ; S3 auch auf Stop
13
     cbi   SIGNAL, S4                    ; und zum Schluss S4 auf Stop
14
...

und zwar im laufenden Programm, ganz ohne dass man eine Routine aufrufen 
muss oder sonst irgendetwas tun muss. Am Anfang muss man ein wenig 
investieren und sich den Mechanismus bauen. Hat man den aber erst mal, 
dann vereinfacht sich der Rest. Und irgendwo gibt es einen 
Breakeven-Point, an dem die Vereinfachung die 'Vorleistung' aufwiegt.



PS: Eigentlich sind deine Routinen nicht ganz sauber.
Deine Taktxx Routinen verändern den kompletten PORTD, was sie eigentlich 
nicht tun sollten.


> das Schaltrelais was für 2 Sek.die Versorgung frei giebt
>
1
> out1h:                    ;N1 / Q0
2
>   sbi     PORTB,0         ;an Pin 2c
3
>   rcall   Takt01
4
>   rcall   zeit2
5
>   cbi     PORTB,0
6
>   rcall   Takt01
7
>   rcall   zeit2
8
>   ret
9
>

Auch so ein Thema. Verzögerungen macht man nicht durch Warten, sondern 
indem man die Aufgabe einem Timer überträgt. Aber das ist eine andere 
Geschichte.


Aber das wird schon. Auch Rom ist nicht an einem Tag erbaut worden. Mach 
nur nicht den Fehler, dich auf dem was du erreicht hast auszuruhen. Zu 
lernen, wie man Programme schreibt ist ein lebenslanger Prozess. Es gibt 
immer Dinge die man besser machen kann, auch wenn sich einem nicht 
sofort auf den ersten Blick erschliesst, warum sie besser sind. Man kann 
sich viel von anderen Programmen abschauen, auch wenn die erst mal 
scheinbar nichts mit dem eigenen Thema zu tun haben. Es geht um 
Programmstrategien, die man lernt und die man dann in der jeweiligen 
Situation anwendet.

von Richard X. (synq1e)


Lesenswert?

also da mein Thread so beliebt ist kommt meine nächste Anfängerfrage ^^

ich möchte versuchen das ein zähler entsteht der mir den stand am port 
mit leds binär ausgibt

durch anzahl der tastenklicks soll der zähler weiterzählen

ich verwende dazu den code AVR-Tutorial: Tasten \\ 4.1 Einfache 
Tastenentprellung und Abfrage \\
mit timer , um die tastenanschläge zu zählen ohne prellung

nur wenn ich dann in der hauptschleife

das gemacht wird:
1
loop:
2
    cli                            ; 
3
    mov     temp1, key_press       ; Einen ev. Tastendruck merken und ...
4
    clr     key_press              ; Tastendruck zurücksetzen
5
    sei  
6
  
7
  out    led_port, leds
8
  out    led_port2, leds2
9
  
10
11
  andi  temp1 , 0b00000100  ;testen ob PB2 gedrückt wurde
12
  breq  weiter
13
  inc  leds
14
  
15
16
weiter:
17
18
  andi  temp1 , 0b00000010  ;testen ob PB1 gedrückt wurde
19
  breq  weiter2
20
  inc  leds2
21
  
22
weiter2:
23
  
24
  rjmp  loop

also an PB1 und PB2 is jeweils ein taster

und soll die register r16(PB1) und r17(PB2) jeweils hochzählen
nur funktioniert das auch , aber nur bei PB2.
stand bei leds2 bleibt gleich.
warum?

wenn wer verbesserungsvorschläge hat für den ganzen vorgang kann er sie 
gerne schreiben
ich hab noch nicht so den durchblick bei assembler :-\

von spess53 (Gast)


Lesenswert?

Hi

>aber nur bei PB2. stand bei leds2 bleibt gleich. warum?

>  andi  temp1 , 0b00000100  ;testen ob PB2 gedrückt wurde
>  breq  weiter
>  ...

>weiter:
>andi  temp1 , 0b00000010  ;testen ob PB1 gedrückt wurde


Mit dem ersten 'andi' löschst du Bit 1. Also kann es bei der zweiten 
Abfrage nie 1 sein.

MfG Spess

von Rolf H. (flash01)


Lesenswert?

Hallo Chris,
schön wäre es, man könnte den gesamten Quelltext von
Anfang bis Ende sehen....aber so fehlt der richtige Durchblick!

Grüße

Rolf

von Hannes L. (hannes)


Lesenswert?

chris __ schrieb:
> und soll die register r16(PB1) und r17(PB2) jeweils hochzählen
> nur funktioniert das auch , aber nur bei PB2.

Wie Spess bereits schrieb, löscht das ANDI alle unbeteiligten Bits.

Wenn Du Bits prüfen willst, ohne sie zu verändern, dann schau Dir mal 
die Skip-Befehle an (sbrs, sbrc). Sie überspringen den nächsten Befehl 
(in dem dann der "Wegsprung" steht), wenn das entsprechende Bit den 
entsprechenden Zustand hat.

...

Rolf H. schrieb:
> aber so fehlt der richtige Durchblick!

Nööö, der Fehler ist auch so offensichtlich.

...

von Richard X. (synq1e)


Angehängte Dateien:

Lesenswert?

hier der code als anhang

von Richard X. (synq1e)


Angehängte Dateien:

Lesenswert?

ich habe beschlossen, dass mein erstes vernünftiges projekt eine 
binäruhr sein soll

und bin mit hilfe der tutorials auf dieser seite, und anderer quellen 
auf die ich im laufe der zeit
gestoßen bin soweit gekommen.

nun würde ich gerne eine "funktion" einbauen die es mir ermöglicht die 
zeit zu setzen, da die uhr
momentan ja nur von 0 wegläuft, oder mithilfe einer konstante die ich 
vorgebe.
es sollte mit ganz einfachen tastern möglich sein.

ich habe schon einiges ausprobiert und mein zusammenführen von anderen 
codebeispielen die ich
gefunden habe, hat leider nicht geklappt.

ich denke dass die prellung berücksichtigt werden muss oder doch nicht ?


ich bin für alle verbesserungsvorschläge offen

von Rolf H. (flash01)


Lesenswert?

he chris,
Du legst ja richtig los...mit Timer1 usw.
Und Dein Thread nennt sich "anfänger bei assembler"
Das ist ja schon fortgeschritten bei assembler.

Jetzt sind hier die Provies gefragt.
Interessant für mich .equ  xxxx (und dann einem Port einen Namen geben)

Grüße

Rolf

von Karl H. (kbuchegg)


Lesenswert?

Studier im AVR-Tutorial den Abschnitt "Tasten"

AVR-Tutorial:_Tasten

Aber studier es vollständig. Probier die Programme aus. Verändere sie.
Dann wirst du auch wissen, wie du das ganze in deine Uhr einbauen 
kannst.

von oldmax (Gast)


Angehängte Dateien:

Lesenswert?

Hi
Vielleicht ergänzend dazu eine kleine Skizze
Wenn du etwas einmal nicht verstehst, dann versuch dir davon ein Bild zu 
machen.
Zuerst: du liest einen Port ein. Sind die Tasten an GND gebunden, macht 
es Sinn, mit einem "COM"-Befehl die Bits zu drehen. Somit entspricht 
dann eine logische "1" auch einem geschlossenen Kontakt. Anschließend 
der Übersicht halber den eingelesenen Wert in eine Variable.
Wenn du das in einer eigenen Routine erledigst, kannst du nun den 
Portzugriff "vergessen".
Nun besteht noch die Geschichte mit dem Prellen der Kontakte, das heißt, 
bis ein Kontakt ein stabiles Signal liefert, welches auch seiner Lage 
entspricht. Dazu brauchst du eine Variable, die du auf einen Wert setzt. 
In meiner Skizze würden 5 Programmzyklen bis zur stabilen Kontaktlage zu 
grunde gelegt. Das ist ziemlich ungenau und deshalb läßt man eigentlich 
den Timer diesen Part erledigen. Aber belassen wir es erst einmal mit 
Programmzyklen.
Wenn du den frisch eingelesenen Wert mit einem "alten" Wert Exclusiv - 
Oder verknüpst, dann bekommst du nur bei einem unterschiedlichen 
Bitzustand eine "1" als Ergebnis. Da hier Byteweise gearbeitet wird, ein 
Beispiel:
      11001110
EOR   01110011
---------------
   =  10111101

Du mußt also die Bitverknüpfung senkrecht durchführen. Da alt und neu 
unterschiedlich sind, hat sich was am Port getan, sonst wäre das 
Ergebnis 0
Daher starten wir nun den Entprellvorgang, d.H. wir warten etwas, bis 
die "alten" und neuen Signalmuster wieder gleich sind und das sieht dann 
so aus:
      01110011
EOR   01110011
-----------------
    = 00000000

Nun wird noch der Zeitzähler bis 0 herab gezählt und dann ist das 
Ergebnis des Ports gültig. Jetzt folgt die Flankenerkennung. Auch hier 
gibt es einen letzten gültigen Wert und den nun ermittelten neuen 
gültigen Wert.
Diese beiden Werte werden ebenfalls mit EOR verknüpft, um die Bits zu 
erfassen, welche sich geändert haben. Also, das Ergebnis Alt EOR neu 
ergibt eine "1", wo sich ein Bit entweder von "0"nach "1" oder umgekehrt 
geändert hat. Etwa wie ein "KeyPressed" oder "KeyUp"-Signal.

alter Wert    11001110
neuer Wert    01110011
-----------------------
            = 10111101
Nehmen wir nun das Ergebnis aus EOR und Verunden es mit dem alten Wert, 
der noch in der Ablage liegt ist klar, nur Änderungen von "1" nach "0" 
bleiben übrig.

Dazu:
                  alter Wert             neuer Wert
                   11001110                01110011
Ergebnis aus EOR   10111101                10111101
                   ---------               --------
Ergebnis aus UND   10001100                00110001
                   Bits von "1"            Bits von "0"
                   nach "0"                nach "1"
                   (KeyUp)                 (KeyPressed)

Mit diesen Bits lassen sich nun Event-Steuerungen bauen, z. B. einen 
Tasten betätigt Zähler.
Dazu wird geprüft, ob ein KeyPressed vorliegt, entsprechend dem Ergebnis 
der Counter hochgezählt und Keypressed auf "0" gesetzt.
Viel Stoff, aber hier wird klar, wie man mit Bitmanipulation eine 
Ereignissteuerung aufbaut. Man muß die Bits im Kopf schon ganz schön hin 
und her werfen, bis ein gewünschtes Ergebnis erwartet werden kann. Aber 
einfach langsam Schritt für Schritt nacharbeiten. Einmal verstanden, 
dann ist der Knoten gelöst.
Gruß oldmax

Beitrag #6978258 wurde von einem Moderator gelöscht.
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.