www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Einen einfachen Komparator mit Monoflopfunktion ? (ATTiny15)


Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich baue hier gerade eine Schaltung auf, welche hauptsächlich über einen 
mega64 gesteuert wird, welchen ich über C programmiere und das auch nur 
auf der Anfängerebene.

Nun benötige ich einen einfachen Komparator und einen Monoflop.
Zweck: Der Compeartor wird kurzzeitig eine höhere Spannung am nicht inv. 
Eingang haben (beim Tiny15 ist das PB0, denn PB1 ist der inv. Eingang) 
und somit auch kurzzeitig Bit5 (ACO) des ACSR Registers setzen.
Jetzt würde ich gerne das Signal 500ml halten. Denn wenn in dieser Zeit 
PB0 wieder kurz aktiv wird, dann würde das am Ausgang zu einem 
eindeutigen High-Pegel führen, obwohl der n.i. Eingang des OPs schwankt.

Auf Leiterplatte habe ich das mit einem OP und einem Monoflop genaut, es 
funktioniert.
Da ich meine Platine jedoch total klein halten will (alles in SMD) wäre 
die Lösung wie oben beschrieben, doch eleganter?

Problem: ich habe von Assembler keine Ahnung :o)

Könnte mir bitte jemand helfen und mit somit gleichzeitig den Einstieg 
in die Assemblerwelt ermöglichen ;o)

Ich hoffe, es ist nicht zu unverschämt, aber kann bitte jemand so ein 
Prog. kurz erstellen, ich werde daraus nur lernen.

Und soweit ich abschätzen kann, denke ich , ist das nicht viel Aufwand: 
Wenn AC0 gesetzt, dann PB2 für 500ms halten, und das ganze retirggerbar.

Ansonsten würde ich mich auch über jede andere Hilfe freuen, die mir die 
Realisierung in der nächsten Stunde ermöglich ;o)

Vielen Dank im Voraus und Grüße

fifi

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich verstehe nicht recht was Du vor hast. Also du bekommst einen kurzen 
high pegel. Den möchtest Du 500ms halten. Wie kurz ist der high pegel 
und wie und welche pegel werden erreicht?

Florian

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Florian,

Also, es kommt Rauschen (NF) auf den n.i. Eingang.

Der inv. Eingang liegt auf 2V. Also Geht die LED (Ausgang des OPs) nur 
dann an, wenn das Raschen eine höhere Amplitude hat, als 2V. Und da es 
halt hochfrequent ist, flackert die LED am Ausgang nur.
Ich habe ein retriggerbares Monoplop am Ausgang des OPs angebaut und 
dann konnte ich, falls das Rauschen konstant war, einen eindeutigen 
High-Pegel erhalten.

Und das würde ich gerne mit dem Tiny15 erreichen.

Ich denke, es ist nicht viel Aufwand, aber ich kann leider kein 
Assembler.

Es könnte ja so aussehen:

.include "tn15def.inc"

Anfang:
          wenn AC0 = HIGH, dann Interrupt
          rjmp Anfang

Interrupt:
          PB2 = High
          while(i!=4000) {i++;} //eine Zahl langt, die man beliebig
                                //ändern kann, keine Zeitkritische Sache
          PB2 = low

ende:

Wenn ich das nun richtig verstehe, dann wird jedes mal, wenn ein 
Interrupt ausgelöst wird, die Schelife neu gestartet. Und wenn diese 
noch nicht abgelaufen war, wenn ein neues Interrupt kommt, dann bleibt 
PB2 eben weiter an. (also retriggerbar)

Hoffe, du verstehst jetzt, was ich meine.

Danke und Grüße

popi

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha,
das kannst du alles in C machen.
Wenn Du aber in assembler machen willst musst Du Dir erstmal die 
Interrupt Vektortabelle suchen. Die kommt an den Anfang und sieht etwa 
so aus:
(Atmega8)

.include" "
$000 rjmp RESET ; Reset Handler
$001 rjmp EXT_INT0 ; IRQ0 Handler
$002 rjmp EXT_INT1 ; IRQ1 Handler
$003 rjmp TIM2_COMP ; Timer2 Compare Handler
$004 rjmp TIM2_OVF ; Timer2 Overflow Handler
$005 rjmp TIM1_CAPT ; Timer1 Capture Handler
$006 rjmp TIM1_COMPA ; Timer1 CompareA Handler
$007 rjmp TIM1_COMPB ; Timer1 CompareB Handler
$008 rjmp TIM1_OVF ; Timer1 Overflow Handler
$009 rjmp TIM0_OVF ; Timer0 Overflow Handler
$00a rjmp SPI_STC ; SPI Transfer Complete Handler
$00b rjmp USART_RXC ; USART RX Complete Handler
$00c rjmp USART_UDRE ; UDR Empty Handler
$00d rjmp USART_TXC ; USART TX Complete Handler
$00e rjmp ADC ; ADC Conversion Complete Handler
$00f rjmp EE_RDY ; EEPROM Ready Handler
$010 rjmp ANA_COMP ; Analog Comparator Handler
$011 rjmp TWSI ; Two-wire Serial Interface

ldi r16,(1<<ACIS0)+(1<<ACIS1)+ACISR
out ACSR,r16      ;interrupt bei steigender Flanke am cmp Ausgang

ich weiss jetzt nicht was man bei dem ACISR noch beachten muss und 
einstellen sollte, aber darüber geben die Datenblätter auskunft

wenn ein interrupt vom cmp ausgelöst wird springt er an die stelle $010
(die hex adresse in der asm datei weglassen) rjmp ist ein relativer 
sprung and die sprungmarke ana_comp:

nach ";"  darf man komentare einfügen

auf einen Port schreibst man:
ldi r16,0xFF         ; lade 0xFF in r16
out DDRB,r16         ;PortB als ausgang
ldi r16, 0b000000001 ; 0b000xx in bin darstellung; 0x0f ist hex
out PORTB,r16        ;PB0 high

die vektortabelle findest Du im Datenblatt und es gibt ein paar gute 
tuts fürn assembler. Ich hoffe ich konnte Dir helfen.
viel Spass
Florian

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ja die appnotes unter
http://www.atmel.com/dyn/products/app_notes.asp?fa...
sind echt klasse! da wird immer gezeigt wie man z.b. den adc in 
assembler und c configuriert. da gibts bestimmt auch was fürn cmp. :)

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Florian,

so weit konnte ich mich durchkämpfen:

.include "tn15def.inc"       ; Definitionsdatei einbinden

rjmp ANA_COMP ; Analog Comparator Handler

ldi r16,(1<<ACIS0)+(1<<ACIS1)+(1<<ACD)+(1<<ACIE)+ACSR
out ACSR,r16      ;interrupt bei steigender Flanke am cmp Ausgang


ANA_COMP:
         ldi r16, 0xFF       ; 0xFF ins Arbeitsregister r16 laden
         out DDRB, r16       ; Inhalt von r16 ins IO-Register DDRB 
ausgeben
         ldi r16, 0b00100    ; 0b11111100 in r16 laden
         out PORTB, r16      ; r16 ins IO-Register PORTB ausgeben

ende:    rjmp ende           ; Sprung zur Marke "ende" -> Endlosschleife


Aber es funktioniert noch nicht ;o)
Die Interruptadresse beim Tiny15 ist die 007. Womoglich liegt da der 
Fehler, oder? Denn die habe ich nicht definiert.

Nur wie man das macht, habe ich noch nicht verstanden.

vielen Dank für Deine Erklärung bisher, hat mir sehr geholfen.
Tatsächlich musste ich das ACRS register anpassen.

Und mal nebenbei: Wie realisiert man denn in Ass. eine einfach Schleife, 
also sowas: while(i!=4000){i++:}

danke nochmal und liebe Grüße

fifi

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tu folgendes:

(1) Konfigurier den Analog-Komparator so, dass bei einer steigenden 
Flanke ein Interrupt ausgelöst wird.

(2) Konfigurier einen Timer so, dass er z. B. alle 10 ms einen Interrupt 
auslöst (z. B. Overlow- oder Output-Compare-Interrupt).

(3) Definier eine Variable "k".

(4) Schreib diesen Code:



[Interrupt-Vektor-Tabelle]

--------------------------------

Analog-Komparator-Interrupt:

k = 50     // "50" weil 50 * 10 ms = 500 ms

reti

--------------------------------

Timer-Overflow-Interrupt:

IF (k==0)
  {
  [LED-Pin auf "0" setzen]
  }
ELSE
  {
  [LED-Pin auf "1" setzen]
  k = k - 1
  }

reti

--------------------------------

Main:
  rjmp Main

Autor: Barti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kleine Anmerkung an Florian: C dürfte auf dem Tiny15 nicht 
funktionieren, da er kein SRAM hat. Sollte jemand einen Trick kennen, 
bitte ich ihn, den hier zu posten.

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Mega64 hat doch selber einen Analog-Komparator, wieso nicht einfach 
den benutzen? (hab mir nicht alle Posts durchgelesen...=

>Jetzt würde ich gerne das Signal 500ml halten
Interessant, dass Controller inzwischen auch Volumina messen können... 
;)

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

das und mehr habe ich hinbekommen.

Aber ich verstehe nicht so ganz (auch am Beispiel oben) wie man den 
Timer jetzt dazu einsetzen muss, um eine Sekunde (oder halbe, egel) zu 
vergögern.

Wenn es auch ohne Timer geht, würde ich auch diese Variante nehmen.
Das ist ja die einzige Tätigkeit, die der tiny15 machen soll:

Interrupt von Comparator empfangen und Signal 1 Sek. halten.

Der ersdte Teil klappt ja schon, dank Eurer Hife.
Jetzt bitte nochmal den 2 Teil, also die Monoflopfunktion.

Hier der Code:
.include "tn15def.inc"       ; Definitionsdatei einbinden

.def k = r20

rjmp Init
.org $007           ;ana_comp vector adres
rjmp ANA_COMP         ;interrupt handler


Init:
    ldi r16,0b00001011
    nop
    nop
    out ACSR,r16    ;analogue comp interrupt enable
    sei         ;global interrupt enable

Main:  ldi r16, 0x00      ; 0b11111100 in r16 laden
    out PORTB, r16      ; r16 ins IO-Register PORTB ausgeben
     ;reti
    rjmp Main      ; Sprung zur Marke "ende" -> Endlosschleife

ANA_COMP:
    ldi r16, 0x04       ; 0xFF ins Arbeitsregister r16 laden
    out DDRB, r16       ; Inhalt von r16 ins IO-Register DDRB ausgeben
    ldi r16, 0x04      ; 0x04 in r16 laden
    out PORTB, r16     ; r16 ins IO-Register PORTB ausgeben
    ldi r17, 0xff    ; r17 auf 255 für Delay setzen
    rcall Delay
    ldi r16, 0x00      ; 0b11111100 in r16 laden
    out PORTB, r16      ; r16 ins IO-Register PORTB ausgeben
     reti

Delay:
    dec r17        ; Vermindert Inhalt in r17 um 1
    brne Delay      ; Sprung nur, wenn r17 nun nicht 0 ist.
    ret


Vielen Dank uund Grüße
fifi

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Aber ich verstehe nicht so ganz (auch am Beispiel oben) wie man den
>Timer jetzt dazu einsetzen muss, um eine Sekunde (oder halbe, egel) zu
>vergögern.

Die halbe Sekunde entsteht in Gemeinschaftsarbeit zwischen dem im AVR 
eingebauten, aus 300 [*] Transistoren bestehenden "Hardware-Timer" und 
dem durch die Variable "k" implementierten "Software-Timer", der vom 
Hardware-Timer "getrieben" wird. Was der Hardware-Timer macht, hab ich 
doch gesagt: Er löst alle 10 ms (Beispielwert) einen Interrupt aus.  Wie 
der k-Timer funzt, geht eindeutig aus dem Code hervor.

Der Sinn der Geschichte besteht darin, eine 500 ms-Delay-Schleife zu 
vermeiden, denn damit kriegst Du kein retriggerbares Monoflop (gut) hin. 
Mit Delay-Schleifen innerhalb von Interrupts dürftest Du nur schwer froh 
werden (zum Beispiel weil der Interrupt dann während dieser Zeit nicht 
nochmal auftreten kann, d. h. er kann dann auch nicht das Monoflop 
nachtriggern).

[*] keine Ahnung, wieviele es wirklich sind... ;-)

>Wenn es auch ohne Timer geht, würde ich auch diese Variante nehmen.

Hast Du eine Timer-Antipathie?  Timer sind der Schlüssel dazu, Programme 
zu schreiben, die a) zuverlässig funktionieren, b) sich durch einen 
sauberen, leicht verständlichen und wartbaren Code auszeichnen, c) 
mehrere Sachen (quasi-) parallel ablaufen lassen können (Multitasking). 
Deshalb sind Timer ungefähr so genial, wie Delay-Schleifen doof sind 
lach.

>Das ist ja die einzige Tätigkeit, die der tiny15 machen soll:

Spar Dir den Tiny und lass es den Controller nebenbei erledigen, den Du 
schon hast.  Das Monoflop wird ihn nur 0.001% zusätzlich belasten.

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo AVRfan,

auch wenn Du mich jetzt für bekloppt hältst, aber ich habe k = 50 
eingegeben und der Assembler versteht die Aussage nicht.
Und if schleifen kann man doch auch nicht unter Ass. erstellen, oder?
Zumindenst streikt mein Assembler bei der Eingabe des Beispiels.

Nun, mein Problem besteht ja nicht darin, es in C auszudrücken ;o) 
sondern es in Assembler umzusetzen.

Und du hast recht, der mega64 macht das mit links. Aber das soll ein 
selbstständiges Modul werden, was vergossen später am Mega64 
angeschlossen werden kann und das an verschiedenen beliebigen Ports.

Also ich werde jetzt mal den Timer konfigurieren (Datenblatt lesen).
Mit der Schleife aber würde ich mich freuen, wenn Du mir da noch mal 
helfen kannst.

Danke und Grüße

fifi

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau bitte ins Assembler Tutorial auf dieser Site
hinein. Da kannst du zumindest die Grundlagen der
Assembler Syntax sehen.

> aber ich habe k = 50

In dem Beispiel oben?
Da heist es

.def k = r20

und das ist das was du von C als #define kennst, also
ein einfaches Textsubstitutionsmakro. Der Sinn der Sache
ist es, dem Register r20 einen anderen Namen, nämlich k
zu geben.

> Und if schleifen kann

Das Wesen einer Schleife besteht darin, dass Code wiederholt
wird. Darum heist es Schleife. Ein 'if' wiederholt aber nichts.
Ein 'if' testet eine Bedingung und wählt abhängig vom Ausgang
der Bedingung den einen oder den anderen Zweig. Da das was
völlig anderes ist, kann das daher auch nicht 'if-Schleife'
heissen.

> Aber ich verstehe nicht so ganz (auch am Beispiel oben) wie man
> den Timer jetzt dazu einsetzen muss, um eine Sekunde (oder halbe,
> egel) zu vergögern.

Das Prinzip ist einfach:

Der Timer gibt dir eine Zeitbasis. Sagen wir mal 10ms. Bei jedem
Auftreten dieser Zeitbasis erzeugt er einen Interrupt. Sagen wir
mal einen Overflow Interrupt. Das tut er, weil der Timer hardware-
mässig, wenn er eingeschaltet ist, ständig durchzählt und (bei
einem 8 Bit Timer) wenn er 255 erreicht hat, besagten Overflow
Interrupt auslösen kann und wieder bei 0 weitermacht.
Wenn du das jetzt richtig getimed hast, dann löst also der Timer
alle 10ms einen Interrupt aus. Wenn du jetzt mitzählst wieoft
dieser Overflow aufgetreten ist, dann ist nach 50 Overflow
Interrupt Aufrufen genau eine halbe Sekunde vergangen. (Deine
tatsächlichen Zahlen werden variieren, da du es wahrscheinlich
nicht schaffst die 10ms zu erreichen. Ist aber egal, es geht
ums Prinzip).

Damit ergibt sich dein Monoflop zu.

0    Timer auf Overflow Interrupt einstellen und
     Interrupts zulassen

1    Warte auf den Auslöser (Pin geht auf high)
2    Setze den Zähler auf 0 und
3    aktiviere den Timer (durch setzen eines Prescalers)
4    Schalte den Ausgang auf high
5    gehe zu 1

Und im Overflow-Interrupt machst du ganz einfach

10    Erhöhe den Zähler
11    Ist der Zähler gleich 50   (hier die korrekte Zahl einsetzen)
12    wenn nein -> reti
13    Schalte den Ausgang wieder auf low
14    deaktiviere den Timer wieder durch setzen des Prescalers auf 0
15    reti

Was passiert, wenn während der Overflow schön genüsslich den
Zähler bis auf 50 hochzählt ein neuer Impuls am Eingang
eintritt. Nun dann kommt das Hauptprogramm aus der Schleife
bei Punkt 1 heraus und setzt den Zähler wieder auf 0, d.h
der Overflow Interrupt beginnt wieder von vorne zu zählen
und es vergehen ab Eintreffen des Signals erneut 500 ms
bis der Interrupt den Zählerwert 50 erreicht hat und den
Ausgang wieder abschaltet.
Das Monoflop wurde als ge-rettriggert.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> aber ich habe k = 50 eingegeben und der Assembler versteht
> die Aussage nicht

Jetzt weis ich welches Bsp. du meinst. Hab nicht weit
genug hochgescrollt.

Das war auch kein Assembler, sondern Pseudocode. Sieht
doch völlig anders aus.

Ob du jetzt k von 50 auf 0 runter, oder von 0 auf 50
hochzählst, ist Jacke wie Hose.

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich habe mal den Timer konfiguriert, aber er läuft nicht!!!

Ich habe das Datenblatt (berreich Zähler) nun 2x durch, aber finde nix 
mehr, zumindenst nicht, was ich als wichtig deute.
Alle anderen Register beziehen sich auf Timer1, aber ich nutze Tomer= 
(warum auch nicht).

Könnt ihr einen Fehler entdecken, warum der Timer nicht anläuft?

Code:

.include "tn15def.inc"       ; Definitionsdatei einbinden

.def k = r20

rjmp Init
.org $005
rjmp Timer0_Overflow
.org $007
rjmp ANA_COMP


Init:
    ldi r16,0b00001011
    out ACSR,r16    ;analogue comp interrupt enable
    ldi r16, (1<<CS00)+(1<<CS02)+TCCR0    ; Frequenz teilen durch 1024
    out TCCR0, r16
    ldi r16, (1<<TOIE0)+TIMSK  ; Timer0 OVL Interrupt Enable
    out TIMSK, r16
    ldi r16, 0x0f        ; Timer soll bis 16 Zählen
    out TCNT0, r16


    sei         ;global interrupt enable

Main:  ;ldi r16, 0x00      ; 0b11111100 in r16 laden
    ;out PORTB, r16     ; r16 ins IO-Register PORTB ausgeben
    rjmp Main      ; Sprung zur Marke "ende" -> Endlosschleife

ANA_COMP:
    ldi r16, 0x04       ; 0xFF ins Arbeitsregister r16 laden
    out DDRB, r16       ; Inhalt von r16 ins IO-Register DDRB ausgeben
    ldi r16, 0x04      ; 0x04 in r16 laden
    out PORTB, r16     ; r16 ins IO-Register PORTB ausgeben
    ldi r17, 0xff    ; r17 auf 255 für Delay setzen
    rcall Delay
    ldi r16, 0x00      ; 0b11111100 in r16 laden
    out PORTB, r16      ; r16 ins IO-Register PORTB ausgeben
     reti


Timer0_Overflow:
    ldi r16, 0x04       ; 0xFF ins Arbeitsregister r16 laden
    out DDRB, r16       ; Inhalt von r16 ins IO-Register DDRB ausgeben
    ldi r16, 0x04      ; 0x04 in r16 laden
    out PORTB, r16     ; r16 ins IO-Register PORTB ausgeben
    reti

Delay:
    dec r17        ; Vermindert Inhalt in r17 um 1
    brne Delay      ; Sprung nur, wenn r17 nun nicht 0 ist.
    ret


Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nimmst Du keinen MAX951??
Du wärst längst fertig ;-))
http://datasheets.maxim-ic.com/en/ds/MAX951-MAX954.pdf

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>    ldi r16, (1<<CS00)+(1<<CS02)+TCCR0    ; Frequenz teilen durch 1024

Warum addierst du da den Zahlenwert TCCR0 noch mit dazu?
Wenn die Absicht war, den Inhalt von TCCR0 noch mit
dazuzunehmen: Das hier ist Assembler! Wenn du den
Inhalt von TCCR0 haben möchtest, musst du den schon mit 'in'
einlesen.

Lass das doch weg. TCCR0 hat beim Einschalten den Wert 0.

   ldi r16, ( 1<<CS00 ) | ( 1<<CS02)   ; Frequenz teilen

>    ldi r16, (1<<TOIE0)+TIMSK  ; Timer0 OVL Interrupt Enable

Hier nochmal

     ldi r1, (1<<TOIE0)    ; Timer 0 OVL Interrupt Enable


Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl heinz Buchegger ,

nun habe ich alles so umgesetzt, wie Du das vorschlägst (zumindenst 
ähnlich).

Es sollte so auch wirklich funktionieren, tut es aber leider nicht.

Wie kann man denn in Assembler ausdrücken, das man bei "nicht 
gleichheit" wieder uas der Routine springt (in meinem Code ist das der 
Abschnitt Timer0_Overflow und da die 3 Zeile).
Denn nur da kann der Fehler liegen.

Wäre nett, wenn Du mal drüberschaust.

Danke im Voraus und Grüße

fifi

.include "tn15def.inc"       ; Definitionsdatei einbinden

.def anzahl = r20

rjmp Init
.org $005
rjmp Timer0_Overflow
.org $007
rjmp ANA_COMP


Init:
    ldi r16,0b00001011
    out ACSR,r16    ;analogue comp interrupt enable
    ldi r16, (1<<CS00)|(1<<CS02) ; Frequenz teilen durch 1024 
(1<<CS00)+
    out TCCR0, r16
    ldi r16, (1<<TOIE0);  ; Timer0 OVL Interrupt Enable
    out TIMSK, r16
    ldi anzahl, 0x32    ; setzet Variable "anzahl" auf 50
    sei           ;global interrupt enable

Main:
    rjmp Main      ; Sprung zur Marke "ende" -> Endlosschleife

ANA_COMP:
    ; Setze PB2 auf high
    ldi r16, 0x04
    out DDRB, r16
    ldi r16, 0x04
    out PORTB, r16
    ; setze Zähler zurück und starte Prescaler
    ldi r16, 0x00
    out TCNT0, r16
    ldi r16, (1<<CS00)|(1<<CS02)
    out TCCR0, r16
    reti


Timer0_Overflow:
    inc anzahl
    cpi anzahl, 0x32
    brne reti
    ; Zähler stoppen
    ldi r16, 0x00
    out TCCR0, r16
    ; Variable zurücksetzen
    ldi anzahl, 0x00
    ; Port B2 löschen
    ldi r16, 0x04
    out DDRB, r16
    ldi r16, 0x00
    out PORTB, r16
    reti


Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>    inc anzahl
>    cpi anzahl, 0x32
>    brne reti

Die Grundidee die du hast ist schon ganz gut.
Nur: Springen kann man nur zu einem Label.
reti ist aber kein Label. reti ist eine Anweisung.
Aber wo steht denn der reti, den du anspringen könntest:

    ...
    out PORTB, r16
    reti

Also fügst du dort vor dem reti ein Label ein:

    ...
    out PORTB, r16
ExitInterrupt:
    reti

Und springst ihn an.

    ...
    inc anzahl
    cpi anzahl, 0x32
    brne ExitInterrupt
    ...

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timer starten und wieder stoppen... ist doch viel zu umständlich.  Bei 
genügend kleinem Timer-Interrupt-Intervall (10 ms reichen völlig) gibt 
es  keinen Grund, den Timer nicht einfach im Dauerbetrieb laufen zu 
lassen.  Also das Dingens am Programmstart konfigurieren, starten und 
niemals mehr stoppen.  Dadurch kannst Du Dein Programm noch viel 
einfacher gestalten.

Hier was für Deine kleinen grauen Zellen *g*:
ANA_COMP:
    ldi k, 50
    
    reti

-------------------------------

Timer0_Overflow:
    clt
    tst  k
    brne Timer0_Overflow_00

    set
    dec  k

Timer0_Overflow_00:
    in   r16, PORTB
    bld  r16, LEDPIN   // LEDPIN = 0...7
    out  PORTB, r16

    reti

So oder so ähnlich würde ich es realisieren.

Autor: fifi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ES GEHT !!!!!

Ersmal vielen Dank an alle und allen Tips.

Hier ist mein Code. Ich will nix wissen über bessere Schreibweise ;o), 
bin froh, das es jetzt geht.
@AVRFan: Das probiere ich noch aus ;o)

Also, nochmal Danke und viele Grüße

fifi

Code:

.include "tn15def.inc"       ; Definitionsdatei einbinden

.def temp = r16
.def anzahl = r20

rjmp Init
.org $005
rjmp Timer0_Overflow
.org $007
rjmp ANA_COMP




Init:
    ldi temp,(1<<ACIE)|(1<<ACIS1)|(1<<ACIS0) ;0b00001011
    out ACSR,temp          ; analogue comp interrupt enable
    ldi temp, (1<<CS00)|(1<<CS02)   ; Frequenz teilen durch 1024 
(1<<CS00)+
    out TCCR0, temp
    ldi temp, (1<<TOIE0)        ; Timer0 OVL Interrupt Enable
    out TIMSK, temp
    ldi anzahl, 0x00        ; setzet Variable "anzahl" auf 0
    sei               ;global interrupt enable

Main:
    rjmp main            ; Sprung zur Marke "ende" -> Endlosschleife

ANA_COMP:
    ; Setze PB2 auf high
    ldi temp, 0x04
    out DDRB, temp
    ldi temp, 0x04
    out PORTB, temp
    ; setze Zähler zurück und starte Prescaler
    ldi temp, 0x00
    out TCNT0, temp
    ldi temp, (1<<CS00)|(1<<CS02)
    out TCCR0, temp
    reti


Timer0_Overflow:
    ; erhöht "anzahl" und prüft ob es gleich 50 ist
    inc anzahl
    cpi anzahl, 0x02  ; hier Haltedauer des Monoflops einstellbar
    brne ExitInterrupt
    ; Zähler stoppen
    ldi temp, 0x00
    out TCCR0, temp
    ; Variable zurücksetzen
    ldi anzahl, 0x00
    ; Port B2 löschen
    ldi temp, 0x04
    out DDRB, temp
    ldi temp, 0x00
    out PORTB, temp

ExitInterrupt:
    reti


Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

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

Formatierung (mehr Informationen...)

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




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

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