Forum: Mikrocontroller und Digitale Elektronik assembler progr. für mega16 - wer kann mir helfen?


von Stefan B. (stefan75)


Lesenswert?

hallo
ich möchte ein programm in assembler schreiben für einen mega16.
als eingang drei schaltstellungen eines drehschalters.
als ausgang eine led

in schaltstelung 1 soll die led alle 10sekunden (ca.) blinken
in schaltstelung 2 soll die led alle 20sekunden (ca.) blinken
in schaltstelung 3 soll die led alle 30sekunden (ca.) blinken

vielen dank schon im voraus - alleine krieg ich das nicht auf die reihe 
und wenn ich eure beiträge so durchlese , ist mein problem für euch ja 
ein "klaks"

mfg

von Mark E. (mark_e)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

> alleine krieg ich das nicht auf die reihe

welchen Teil des Problems kriegst du alleine auf die
Reihe?

Kannst du mit einem Timer eine LED in den von dir geforderten
Zeiten blinken lassen? Du möchtest das nach Möglichkeit so
machen, dass die Blinkzeit zb in einem Register steht, so
dass sie von anderen Programmteilen eingestellt werden kann.

Wenn du das hinkriegst, dann hast du schon 70% des Problems
gelöst. Der Rest ist Abfrage der Schalterstellung und davon
abgeleitet dann die Änderung der Blinkparameter in diesem
einen Register.

von Stefan B. (stefan75)


Lesenswert?

hallo
erst mal danke für die schnelle reaktion !
bis jetzt hab ich es leider nur geschafft , dass die 3 schalter 
abgefragt werden, und jeweils die led PINB0 leuchtet

.include "m16def.inc"

.def schalter1 = r16    ;PIND0
.def schalter2 = r17    ;PIND1
.def schalter3 = r18    ;PIND2
.def led = r19    ;PINB0


  ldi schalter1, 0x00  ;Eingang
  out DDRD, r16
  ldi schalter2, 0x00  ;Eingang
  out DDRD, r17
  ldi schalter3, 0x00  ;Eingang
  out DDRD, r18
  ldi led, 0xFF  ;Ausgang
  out DDRB, r19

loop1:  sbis PIND, 0          rjmp loop2
  sbi PORTB, 0

loop2:  sbis PIND, 1          rjmp loop3
  sbi PORTB, 0

loop3:  sbis PIND, 2          rjmp loop1
  sbi PORTB, 0

ende:  rjmp loop1    ;Endlosschleife



mach so ja noch nicht viel sinn - wie bekomme ich jetzt die 
verschiedenen zeiten ins programm
hab schon was gelesen mit Timer Overflow bzw. Vorteiler aber wie setzt 
ich das jetzt um ?
bitte nicht zuviel vorraussetzten bin ein absolut beginner und 
quereinsteiger

danke
mfg

von Karl H. (kbuchegg)


Lesenswert?

Stefan Burger wrote:
> hallo
> erst mal danke für die schnelle reaktion !
> bis jetzt hab ich es leider nur geschafft , dass die 3 schalter
> abgefragt werden, und jeweils die led PINB0 leuchtet

Das ist aber keine gute Lösung, die du da hast.
Du musst die Schalter in der richtigen Reihenfolge
drücken um irgendetwas zu bewirken. Gut bei einem
Drehschalter ist das kein wirkliches Problem aber
bei Tastern ist das keine gute Vorgabe.

Als nächstes würde ich mal die Schalter vergessen und mich
an deiner Stelle nur um die Led kümmern.
Ziel: die Led mit einem Timer zum Blinken bringen.

> mach so ja noch nicht viel sinn - wie bekomme ich jetzt die
> verschiedenen zeiten ins programm
> hab schon was gelesen mit Timer Overflow bzw. Vorteiler aber wie setzt
> ich das jetzt um ?

Was davon hast du nicht verstanden?
So ein Timer ist doch eine simple Sache:
  Der zählt so vor sich hin. Mit jedem Tick zählt er um 1
  weiter. Solange bis er seinen Maximalwert erreicht hat,
  dann beginnt er wieder bei 0.

  Nicht sonderlich aufregend, oder? Interessant wird die
  Geschichte erst dadurch, dass man sich an dieses Rücksetzen
  hängen kann (den sog. Overflow) und sich einen Interrupt
  auslösen lassen kann. Dadurch hat man eine Möglichkeit,
  wie man in regelmässigen Zeitabständen gewisse Funktionalität
  ausführen lassen kann.

Aber im Grunde steht das alles auch im Tutorial. Hast du da schon
reingeschaut?

Das wichtigste über Timer findet sich hier
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer

Es lohnt sich aber auch die Tutorial Teile davor zu lesen.

von Stefan B. (stefan1975)


Lesenswert?

Hallo Karl Heinz

habs jetzt wenigstens mal geschafft , dass der pinb 3 erst nach einer 
gewissen zeitverzögerung kommt.

schaus dir doch bitte mal an
danke


.include "m8def.inc"

.def temp = r20
.def timer = r21

.org 0x0000
        rjmp    main                  ; Reset Handler
.org OVF0addr
        rjmp    timer0_overflow       ; Timer Overflow Handler

main:
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp

  ldi temp, 0x00      ;Eingang
  out DDRD, temp

  ldi temp, 0xFF      ;Ausgang
  out DDRB, temp


loop1:
  sbis PIND , 0
  rjmp loop2

        ldi     temp, 0b00000001      ; CS00 setzen: Teiler 1
        out     TCCR0, temp

        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer 
Overflow
        out     TIMSK, temp

        sei

  loop:   rjmp    loop


  timer0_overflow:

            ;  ldi timer , 1
            ;  dec timer

  cpi timer , 0

       brne timer0_overflow

  sbi portb , 3

  ende: rjmp ende

loop2:

  sbi portb , 4


mfg
stefan

von Stefan B. (stefan1975)


Lesenswert?

hallo
jetzt blinkt die led , aber sobald der schalter einmal gestartet wurde
und die led mit blinken begonnen hat stoppt das blinken nicht durch 
rückstellen des schalters?
wie kann ich den timer "reseten" sobald an portA 0 kein signal mehr 
anliegt??
mfg

  .include "m16def.inc"

  .def temp1         = r17

  .equ XTAL = 4000000

  rjmp    main1

  main1:

  ldi      temp1, 0b00100000
  out      DDRD, temp1

  ldi r16 , 0x00
  out DDRA ,r16

  sbis PINA , 0
  rjmp main1

  ldi      temp1, LOW(RAMEND)     ; Stackpointer initialisieren
  out      SPL, temp1
  ldi      temp1, HIGH(RAMEND)
  out      SPH, temp1

  ;
  ; Timer 1 einstellen
  ;
  ; Modus 14:
  ;    Fast PWM, Top von ICR1
  ;
  ;     WGM13    WGM12   WGM11    WGM10
  ;      1        1       1        0
  ;
  ;    Timer Vorteiler: 8
  ;     CS12     CS11    CS10
  ;      1        0       0
  ;
  ; Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
  ;     COM1A1   COM1A0
  ;      1        0
  ;

  ldi      temp1, 1<<COM1A1 | 1<<WGM11
  out      TCCR1A, temp1

  ldi      temp1, 1<<WGM13 | 1<<WGM12 | 1<<CS12
  out      TCCR1B, temp1

  ;
  ; den Endwert (TOP) für den Zähler setzen
  ; der Zähler zählt bis zu diesem Wert
  ;
  ldi      temp1, 0b01110000
  out      ICR1H, temp1
  ldi      temp1, 0b01000000
  out      ICR1L, temp1

  ; der Compare Wert
  ; Wenn der Zähler diesen Wert erreicht, wird mit
  ; obiger Konfiguration der OC1A Ausgang abgeschaltet
  ; Sobald der Zähler wieder bei 0 startet, wird der
  ; Ausgang wieder auf 1 gesetzt
  ;
  ldi      temp1, 0b00111111
  out      OCR1AH, temp1
  ldi      temp1, 0b11110000
  out      OCR1AL, temp1

  rjmp     main1

von Karl H. (kbuchegg)


Lesenswert?

Stefan Burger wrote:
> hallo
> jetzt blinkt die led , aber sobald der schalter einmal gestartet wurde
> und die led mit blinken begonnen hat stoppt das blinken nicht durch
> rückstellen des schalters?
> wie kann ich den timer "reseten" sobald an portA 0 kein signal mehr
> anliegt??

Ein Timer hört dann zu zählen auf, wenn du den Vorteiler wieder
rausnimmst.


>   rjmp     main1

Warum springst du hier wieder zurück nach main1?
Bei main1 beginnt das ganze Programm. Dort finden alle
Initialisierungen statt. Wenn das Programm an dieser
Stelle angelangt ist, dann wurde bereits alles richtig
initialisiert. Es gibt keinen Grund das alles noch mal
durchzulaufen. Lass doch die Hardware arbeiten und
hör auf das alles immer wieder neu zu initialisieren.

Deine komplette Schalterabfrage muss also in die Hauptschleife,
die du noch nicht hast:

   ; Programmanfang

   ...  nimm alle Initialisierungen vor:
   ...  Stackpointer aufsetzen
   ...  Timer in seinen Grundwerten einstellen (aber noch nicht starten)
   ...  sonstiges

loop:    ; hier beginnt dann die Hauptschleife

    .... Wenn am PortA das Bit 0 gesetzt ist, dann schalte
    .... denn Timer ein, indem ihm ein Vorteiler gesetzt wird

    .... Ist besagtes Bit nicht gesetzt, dann schalte den Timer
    .... aus, indem der Vorteiler wieder auf 0 gesetzt wird

    rjmp loop

von Stefan B. (stefan1975)


Lesenswert?

hallo

danke - jetzt kann ích das blinken auch wieder ausschalten!!
wie bringe ich es jetzt noch fertig eine zweite schaltstellung mit einem 
anderen blink interval zu programmieren ?
aber hier erst mal der jetzige stand:

.include "m16def.inc"
.def temp1         = r17
.equ XTAL = 4000000

    rjmp init1

init1:

ldi     temp1, 0b00100000
out     DDRD, temp1

ldi   r16 , 0x00
out   DDRA ,r16


    ldi      temp1, LOW(RAMEND)     ; Stackpointer initialisieren
    out      SPL, temp1
    ldi      temp1, HIGH(RAMEND)
    out      SPH, temp1


   ;ldi      temp1, 0b01110000
   ;out      ICR1H, temp1
   ;ldi      temp1, 0b01000000
   ;out      ICR1L, temp1

    ldi      temp1, 0x01ff
    out      OCR1AH, temp1
    ldi      temp1, 0xffff
    out      OCR1AL, temp1


main1:

sbis PINA , 0      ; überspringe nächste wenn 1
rjmp main2

    ldi      temp1, 1<<COM1A1 | 1<<WGM11
    out      TCCR1A, temp1

    ldi      temp1, 1<<WGM13 | 1<<WGM12 | 1<<CS10
    out      TCCR1B, temp1

main2:

sbic PINA , 0      ; überspringe nächste wenn 0
rjmp main1

    ldi      temp1, 0b00000000
    out      TCCR1A, temp1

    ldi      temp1, 0b00000000
    out      TCCR1B, temp1

rjmp  main1


viele Dank
mfg
stefan

von Karl H. (kbuchegg)


Lesenswert?

Stefan Burger wrote:
> hallo
>
> danke - jetzt kann ích das blinken auch wieder ausschalten!!

Aber du kannst es nicht wieder einschalten :-)

> wie bringe ich es jetzt noch fertig eine zweite schaltstellung mit einem
> anderen blink interval zu programmieren ?

Wer oder was ist für das Blinkintervall zuständig? (Frage an Dich)
Wenn du das identifiziert hast, dann musst du einen zweiten
Schalter abfragen und je nach Schalterstellung einmal den
einen Parametersatz in die entsprechenden Timer Register
laden bzw. den anderen Parametersatz laden.

Aber programmier erst mal dein jetztiges Beispiel fertig,
so das du das Blinken nach belieben ein und ausschalten
kannst.

von Stefan B. (stefan1975)


Lesenswert?

hallo
1.
also zumindest in der avr studio simulation kann ich den schalter schon 
wieder einschalten (falls ich das richtig mache? auto start mit 
gesetztem pin A - dann stoppe ich den Ablauf in dem ich auf pause drücke 
- jetzt nehm ich den pin A raus und geh wieder auf auto start - daselbe 
nochmal beim wiedereinschalten)

2.
für die Dauer des Blinkintervalls ist folgender Absatz verantwortlich

    ldi      temp1, 0b01110000
    out      ICR1H, temp1
    ldi      temp1, 0b01000000
    out      ICR1L, temp1

    ldi      temp1, 0x01ff
    out      OCR1AH, temp1
    ldi      temp1, 0xffff
    out      OCR1AL, temp1

richtig??

danke
mfg
stefan

von Stefan B. (stefan1975)


Lesenswert?

hallo nochmal

ich meine zwar immer noch, wie oben beschrieben , dass der icr1 bzw. der 
ocr1a wert für die dauer des intervalls verantwortlich ist , aber egal 
wie ich die werte änderte - es ändert sich nicht viel beim simulieren !?

hat das etwas mit den einstellungen bei TCCR1A und TCCR1B zu tun ?- 
soweit ich das aus dem Datenblatt des atmega16 erkenne wird hier 
eingestellt, welche Werte miteinander verglichen werden und was dann 
passieren soll.
z.b. clear OS1A , set output to low lever usw.


danke
stefan

von Karl H. (kbuchegg)


Lesenswert?

Stefan Burger wrote:
> hallo
> 1.
> also zumindest in der avr studio simulation kann ich den schalter schon
> wieder einschalten (falls ich das richtig mache? auto start mit
> gesetztem pin A - dann stoppe ich den Ablauf in dem ich auf pause drücke
> - jetzt nehm ich den pin A raus und geh wieder auf auto start - daselbe
> nochmal beim wiedereinschalten)

Mein Fehler.
Ich hab mich bei den ganzen rjmp verlesen.
So wie du das gemacht hast ist das schon in Ordnung.
Das ist schon fast die Programmstruktur zu der ich
dich bringen wollte, bevor ich meinen Fehler bemerkt habe.

Anzumerken bleibt noch:

Es ist innerhalb der Hauptschleife nicht notwendig,
so wie hier

>    ldi      temp1, 1<<COM1A1 | 1<<WGM11
>    out      TCCR1A, temp1
>
>    ldi      temp1, 1<<WGM13 | 1<<WGM12 | 1<<CS10
>    out      TCCR1B, temp1

jedesmal TCCR1A bzw. TCCR1B komplett zu setzen, bzw. zu
löchen. (Einmal, ganz am Anfang musst du das natürlich machen,
aber das machst du ohnehin).

Wenn du willst, dass der Timer stehen bleibt, dann genügt
es vollauf, wenn du das CS10 Bit im Register TCCR1B auf
0 setzt. Um den Timer wieder einzuschalten, wird dieses
Bit (und nur dieses Bit) wieder gesetzt.

Warum wäre es besser sich nur auf dieses Bit zu kontentrieren.
Ganz einfach: Weil an dieser Stelle es dann völlig egal ist,
welche anderen Bits in diesen Registern gesetzt wurden. Damit
wird diese ein/ausschalt - Sequenz aber völlig unabhängig davon
in welchem Modus der Timer gerade läuft. Den Modus (Zähler, CTC
Modus, PWM Modus, etc) stellst du an anderer Stelle ein, der muss
und soll hier nicht interessieren. Hier geht es einzig und alleine
den Timer an sich über den Vorteiler ein und auszuschalten. Mehr
nicht. Also sollte der Code an dieser Stelle auch nicht mehr machen!

Wie kannst du ein Bit setzen.
Ganz einfach du holst dir den Inhalt des TCCR1B Registers in
eines der Univeralregister, so dass du es manipulieren kannst.
Mit einem ODER (einer logischen Operation) wird dann das Bit
gesetzt und der neue Wert wieder nach TCCR1B ausgegeben.

Um ein Bit zu löschen, benutzt man eine Maske und die UND Operation.
Die Maske enthält an allen Bitpositionen eine 1 die unverändert
bleiben soll und nur dort eine 0, wo auch im Ergebnis eine 0
auftauchen soll.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Logik
1
main1:
2
    sbis PINA , 0      ; überspringe nächste wenn 1
3
    rjmp main2
4
5
    in       temp1, TCCR1B      ; setzte CS10 in TCCR1B
6
    ori      temp1, 1<<CS10
7
    out      TCCR1B, temp1
8
9
main2:
10
11
    sbic PINA , 0      ; überspringe nächste wenn 0 
12
    rjmp main1
13
14
    in       temp1, TCCR1B
15
    andi     temp1, ~(1<<CS10)
16
    out      TCCR1B, temp1
17
18
rjmp  main1


anstelle der ganzen  in  ori/andi  out  Sequenz müsste, glaub
ich, auch ein sbi/cbi  funktionieren.

> 2.
> für die Dauer des Blinkintervalls ist folgender Absatz verantwortlich
>
>     ldi      temp1, 0b01110000
>     out      ICR1H, temp1
>     ldi      temp1, 0b01000000
>     out      ICR1L, temp1
>
>     ldi      temp1, 0x01ff
>     out      OCR1AH, temp1
>     ldi      temp1, 0xffff
>     out      OCR1AL, temp1
>
> richtig??

Im Prinzip ja. Wenn wir hier in der Schule wären, würde ich die
Antwort trotzdem nicht gelten lassen, weil sie mir nicht zeigt,
dass du verstanden hast, was du tust. Das ist so, wie wenn ich
dich frage wodurch eigentlich in einem Auto die Kraftentwicklung
passiert und du deutest auf den Motorblock und sagst: irgendwo
da drinnen. Klar hast du schon recht, aber ich wollte eigentlich
auf die Zündkerzen, Benzin, Brennraum, Kolben, etc hinaus.

Im gegenständlichen Fall, arbeitet ja der Timer in einem bestimmten
Modus. Diesen Modus hast du mit den WGM Bits eingestellt. Dieser
Modus bestimmt, wie und woher der Timer seinen Endwert nimmt.
Um also die Frequenz zu verändern, muss dieser Endwert verändert
werden. In welchem Register dieser Endwert steht, hängt vom
Modus ab. Weiters benutzt du den Timer in einem Modus, in dem
du das Blinken völlig eigenständig entsteht.

Und genau das kannst du ja bereits: Je nach Schalterstellung
Register zu verändern. Mit dem Datenblatt musst du jetzt
nur noch das Zusammenspiel von ICR1 und OCR1A herausfinden.

von Stefan B. (stefan1975)


Lesenswert?

hallo

bin jezt mal vom timer1 auf timer0 umgestiegen , hier kann man das 
intervall viel einfacher progammieren !

so funktionierts jetzt auch mal

    ldi      temp1, 0b00111111      ;bei 00001111 ist das intervall 
kürzer
    out      OCR0, temp1

main:

    ldi      temp1, 0<<COM01 | 1<<COM00 | 1<<WGM01 | 1<<CS01
    out      TCCR0, temp1

rjmp main

hier kann man die led jedoch nur kurz blinken lassen .
um die led z.b. 10sek aus - 3sek. ein - 10sek. aus usw. blinken zu 
lassen muss ich wohl wieder den timer1 benutzen -richtig ??

mfg
stefan

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.