Assembler set reset

1avr2

Neues Mitglied
21. Jan. 2010
28
0
0
Sprachen
habe wieder mal eine frage zu tastern bzw i/o ports.
ich wuerde gerne mit taster an pb0 eine led anschalten, und diese soll auch eingeschaltet bleiben bis taster an pb1 gedrueckt wird.
bei meinem programm wird die led sofort nach loslassen des tasters geloescht.
also mit kurzem druecken von taster eins soll die led aktiviert bleiben bis kurz taster zwei gedrueckt wird.

gibt es eine einfache moeglichkeit die szu realisieren. mein programm haenge ich an.

gruss bernhard.



HTML:
; taster an pbo = pin 5 schaltet led an 
; led an pb4 = pin 3 led bleibt an
; taster an pb1 schaltet led aus pin 6

.include "tn13def.inc"

.def ar=r16
.def br=r17
	
; stackpointer setzen

	ldi ar,ramend
	out spl,ar

; taster pb0/pb1 als eingang konfigurieren
; sowie pullup an port/pb0 

	cbi ddrb,0
	cbi ddrb,1
	sbi portb,0
	sbi portb,1

; led pb4 als ausgang fuer led konfigurieren

	sbi ddrb,4

; abfrage taster 'ein' pin5 portb0

loop:

	in br,pinb
	ldi ar,0b00000001	; pinb0 isolieren
	and ar,br
	cpi ar,0b00000001
	breq led_on

; abfrage taster 'aus' pin6 portb1

	in br,pinb
	ldi ar,0b00000010	; pinb1 isolieren
	and ar,br
	cpi ar,0b00000010
	breq led_off

	rjmp loop


led_on:

	sbi portb,4
	rjmp loop

led_off:

	cbi portb,4
	rjmp loop
 
Hallo Bernhard!

Die Signale der beiden Tasten an PB0 und PB1 sind invertiert, da du die Mikrocontrollerpins ja sicherlich mit den Tasten nach GND schaltest und du die internen Pullup-Widerstände aktiviert hast.

Dein Code ist soweit richtig, du musst nur anstelle der bedingten Sprünge BREQ (branch if equal) BRNE (branch if not equal) verwenden. Bei gedrücktem Taster ist das entsprechende Bit im Register PINB 0!

Ein bisschen einfacher und kürzer kannst du das aber auch so realisieren (ich nehme mal an, dass die LED bei low am Pin an ist):

Code:
loop:

  sbis PINB, 0  ; skip bit io set
  cbi PORTB, 4  ; clear bit io, LED an

  sbis PINB, 1 ; skip bit io set
  sbi PORTB, 4  ; set bit io, LED aus

rjmp loop:

Grüße,
Dirk
 
hallo dirk,

vielen dank fuer die schnelle antwort.
ich glaube ich hab mich nicht genau ausgedrueckt. ich moechte eine sebsthaltung programmieren.
taster eins kurz druecken, relais (schuetz) zieht an, haelt sich ueber den eigenen kontakt und wird durch austaster wieder zurueckgesetzt.
ist das fuer einen anfaenger, wie mich, zu kompliziert oder haelt sich der aufwand in grenzen.
zusaetzlich sollte der austaster vorrang haben. d.h. beide taster gedrueckt -> led aus.
zur sicherheit noch eine skizze im anhang.

vielen dank im vorraus

gruss bernhard.



P1000086.JPG
 
Hallo Bernhard,

nun ja, von einem Relais hast du nichts erzählt. Du kannst ja an den Ausgang für die LED zusätzlich einen Treiber für das Relais anschließen. So wie ich das verstehe, soll die LED den Zustand des Relais anzeigen.

Die 5 Zeilen Code von mir machen eigentlich genau das, was du möchtest, ohne den Vorrang von Taster2.

Code:
loop:    
  sbis PINB, 0  ; Taster 1 Zustand abfragen   
  cbi PORTB, 4  ; Taster 1 ist gedrückt, LED an / Relais an    
  sbis PINB, 1  ; Taster 2 Zustand abfragen   
  sbi PORTB, 4  ; Taster 2 ist gedrückt, LED aus / Relais aus  
rjmp loop

Mit Taster 2 Vorrang:
(ist nur ein Beispiel, kann man auch anders lösen)
Code:
loop:    

  sbic PINB, 0  ; Taster 1 Zustand abfragen
  rjmp loop_taster2 ; Taster 1 nicht gedrückt, nun Taster2 abfragen
  sbis PINB, 1  ; Taster 1 gedrückt, aber erst mal Taster 2 Zustand abfragen   
  rjmp loop_taster2 ; Achtung: Taster 2 gedrückt   
  cbi PORTB, 4  ; Taster 1 ist gedrückt, LED an / Relais an 

loop_taster2:   
  sbis PINB, 1  ; Taster 2 Zustand abfragen   
  sbi PORTB, 4  ; Taster 2 ist gedrückt, LED aus / Relais aus  

rjmp loop

Vielleicht passt das ja jetzt.

Dirk
 
Hi
Hier mal eine kleine Hilfe von mir: Versuche immer nach folgendem Schema vorzugehen
Einlesen von Eingängen
Verarbeiten
Ausgeben der Ergebnisse
Es ist völlig unabhängig, welche Sprache du benutzt. Wenn du für das Einlesen der Eingänge eine eigene Sub-Routine schreibst und diese mit RCALL aufrufst, hast du nur eine Stelle im Programm, wo du deine Information in den Controller holst. Das erleichtert dir spätere Anpassung und Korrekturen.
Ist die Priorität eines Ausganges "löschen", dann wird zuerst die "Setz-Funktion" und danach die "Lösch-Funktion" aufgerufen.
Anschließend gibst du in einer eigenen Sub-Routine die bearbeitete Info aus
Hier mal ein schematisches Beispiel von einer Programmstruktur:
Code:
Start: ...      ; initialisieren Stack und Variablen
         ...      ; Initialisieren Timer, Uart etc.
Loop:           ; Programmschleife
   RCALL Read_IO    
                 ; Einlesen der Eingänge und anpassen auf Signallage
                 ; Ergebnis in eine Variable eintragen z.B. "New_In"
   RCALL Do_Set_Order     
                 ; Setzbedingungen der Ausgänge bearbeiten (Priorität "Aus")
                 ; Ergebnis in eine Variable eintragen z.B. "New_Out"
       RCALL Do_Reset_Order   
                 ; Löschbedingungen der Ausgänge bearbeiten (Priorität "Aus")
                 ; Quelle ist Variable, Ergebnis wieder in Variable eintragen  
       RCALL Write_IO           
                 ; Ausgabeport mit Bits aus Variable setzen
RJMP Loop   ; Schleife erneut durchlaufen
Soll die Priorität "Setzen" sein, tauscht du einfach die Aufrufe der Sub-Routinen. Soll es sowohl als auch Proitäten geben, dann schreibst du halt für 2 Gruppen z."A" und "B" jeweils die Subroutinen. Wenn du dir diese Struktur angewöhnst und nicht immer alles in die Programmschleife schreibst, dann ist Assembler relativ einfach zu beherrschen. Sieh dazu mal in die FAQ in den Beitrag "keine Angst vor Assembler". Ich glaube, da findest du noch viel hilfreiche Infos.
Dann noch viel Spaß mit Assembler.
Gruß oldmax
 
vielen dank fuer die anregung an old max.

Start: ... ; initialisieren Stack und Variablen
... ; Initialisieren Timer, Uart etc.
Loop: ; Programmschleife
RCALL Read_IO
; Einlesen der Eingänge und anpassen auf Signallage
; Ergebnis in eine Variable eintragen z.B. "New_In"
RCALL Do_Set_Order
; Setzbedingungen der Ausgänge bearbeiten (Priorität "Aus")
; Ergebnis in eine Variable eintragen z.B. "New_Out"
RCALL Do_Reset_Order
; Löschbedingungen der Ausgänge bearbeiten (Priorität "Aus")
; Quelle ist Variable, Ergebnis wieder in Variable eintragen
RCALL Write_IO
; Ausgabeport mit Bits aus Variable setzen
RJMP Loop ; Schleife erneut durchlaufen

koenntest du das ganze bitte noch mit einem beispiel versehen, evtl ein paar zeilen aus einem programm kopieren,
damit ich mir das besser vorstellen kann.
die tipps in faq hab ich mir durchgelesen. mein problem ist jedoch erstens, keine grosse programmiererfahrung,
ueber 50 und asserdem ziemlich chaotisch.
trotzdem machts riesigen spass wenn ab und zu ein paar led's zu richtigen zeitpunkt leuchten bzw ein piezo piepst.

gruss bernhard.
 
Hi
Ein paar Bemerkungen zu deinen Problemen....
Ü 50 .... das ist kein Grund, bin selbst über 60 :cool: und hab mit AVR's erst vor ca. 3 Jahren begonnen...
keine Programmiererfahrung... na dafür war mein Beitrag gedacht und da sollte alles drin stehen. Es hier noch einmal zu wiederholen, sorry, aber hast du mal die Seiten gezählt, die dieser Beitrag beinhaltet ?
Trotzdem, kurze Info
"RCALL Read_IO"
ist der Aufruf eines Unterprogrammes. Das mußt du natürlich schreiben und dort die Infos aus den Eingangsports holen. Auch hier kann ich nur ein Schema liefern, da dieses Unterprogramm von deiner verwendeten Hardware abhängig ist.
Code:
Read_IO:                            ;Adressmarke des Unterprogrammes 
    In      Reg_A, PortB          ; lesen gesamtes Port- Byte in Register
    COM  Reg_A                   ; Wenn die Taster gegen "0" schalten, dann 
                                         ; Signallage  drehen...
                                         ; Taster/ Schalter betätigt ="1"
    ANDI  Reg_A, 0b00110011 ; nur Eingänge bewerten
    MOV  Reg_B, Reg_A        ; Kopie in 2. Register
    ANDI Reg_B, 0b00000011 ; nur Bit 0 und Bit 1 bewerten
    ROR  REG_A                   ; Bits in Register A nach rechts verschieben 
    ROR  REG_A                   ; Bits in Register A nach rechts verschieben 
    ANDI Reg_A,0b00001100 ; nur Bits 2 und 3 bewerten
    Or     Reg_A, Reg_B        ; Register zusammenführen
    STS  New_In, Reg_A      ; Ergebnis in Variable schreiben
RET
Das kleine Programm erfüllt nun die Aufgabe, die Bits 0 und 1 sowie 4 und 5 zusammen zu führen auf die Bitfolge 0-3 und in eine Variable zu schreiben.
Angenommen, alle 4 Signale liegen an Port B an, läuft es folgendermaßen ab:
Reg_A erhält xx00xx00 ; geschlossene Schalter sind Signallage "0"
"Com" dreht xx00xx00 zu xx11xx11
AND maskiert xx11xx11 zu 00110011
Register B wird auf 00000011 maskiert
Register A auf 00001100 geschoben
nochmal maskiert zu 00001100
Register B und Register A zusammengeführt zu 00001111
und in Variable abgelegt.
Willst du nun dein Programm auf andere Eingabepins ändern, so brauchst du nicht im Programmrumpf mühsam die Stellen suchen, wo du die Eingänge einliest, sondern hast in dieser kleinen Routine einen übersichtlichen Block. Genauso gehst du mit den Ausgaben vor. Auch Initialisierungen können in kleine Sub-Routinen gepackt werden.
Dein Programm besteht dann (fast) nur noch aus "RCall's"
Code:
Start:
   ! Wichtig ! Stack setzen, und dann erst Unterprogramme aufrufen !
  RCALL Init_IO            ; Initialisieren der Ports
  RCALL Init_Uart         ; serielle Schnittstelle
  RCALL Init_Timer       ; Timer
  RCALL Init_Register    ; Vorbesetzen der Register
  RCALL Init_Variablen  ; vorbesetzen von Variablen
  RCALL Set_Params    ; Parameter au EEProm holen 
                                 ; ( falls welche abgelegt sind)
Loop:                         ; Begin der Programmschleife
   RCall Read_IO          ; lesen der Eingänge
   RCALL Chk_Comm_Event    ; seriellen  Empfang prüfen
                                  ; Empfang ist Interrupt
   RCALL Chk_TimerEvent ; Zeitereignis prüfen
                                  ; Zeitereignis ist Interrupt
   RCALL Do_Something ; mach irgendwas mit den Infos
   RCALL Send_Comm     ; versende Daten
   RCALL Set_IO             ; setze Ausgänge
   RJMP Loop                 ; und das ganze wiederhole....
Zu den Ereignissen.
Beim seriellen Empfang schreibst du in der Interruptroutine die Daten in einen Ringpuffer. Das ist in dem angesprochenen Beitrag beschrieben, ebenfalls die Bearbeitung von Timer-Events mittels Flags. Das wiederhole ich jetzt mal nicht. Scheint auch im Moment noch nicht aktuell zu sein.....
Gruß oldmax
 

Ü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)