Hallo zusammen,
ich brauche einen Befehl für mein Assemblerprogramm, der das Programm
für eine definierte Zeit (z.B. 500ms) anhält. (Ein Relais soll für eine
kurze Zeit anziehen und wieder loslassen.)
Oder mache ich das über einen Timer? Gibt es eine Art Delay-Befehl
(nicht den nop)?
Danke im voraus! :-)
Sebastian
Also mir ist kein solcher Befehl bekannt. Du kannst entweder den Delay
Schleifen generator(irgendwo zu downloaden, such in den
Beiträgen)verwenden oder den Timer. Beides ist ziemlich einfach. Um nur
schnell etwas mit dem Relais zu machen ist der Schleifengenerator ideal.
Man kan genau eingeben wie lange gewartet werden soll und der Code wird
generiert.
Fritz 7
Wenn du während des Wartens was anderes zu tun hast bzw ein Interrput
oder so ausgelöst werden könnte und die Zeit eher kritisch ist, ist die
Lösung über den Timer weitaus eleganter als den Prozessor nop'en zu
lassen, bis die 500ms vorbei sind (denn was anderes zum warten gibts
eigentlich nicht).
Hi,
danke für den Link. Allerdings geht es da ja meistens um einen
Generator, der den Code erzeugt (die meistens Links sind defekt). Ist es
denn wirklich so schwer? Gibt es nicht ein paar gut kommentierte Zeilen,
daß ich auch weiß, was ich mache?
Kennt noch jemand einen funktionierenden Link zu einem Generator?
Danke!
Sebastian
Der Generator baut dir einfach aus ein paar Befehlen (rjmp, cmp, inc...)
eine Schleife mit der gewünschten Länge zusammen. Natürlich kann man das
auch von Hand machen, nur wozu?
http://www.home.unix-ag.org/tjabo/avr/AVRdelayloop.html
so als perfektionist: was mache ich denn wenn ich es ganz genau haben
will? soweit ich das ueberblickt habe, ist in dem generierten code die
zeit, die die schleifenverwaltung benötigt nicht mit einbezogen. da
stellt sich natürlich die frage: war ich nur unfähig die anleitung zu
lesen oder fehlt da eine liste mit der zyklenanzahl, die pro befehl
benötigt werden?
antworten werden dankbar entgegengenommen...
Holger
Ich denke schon das die Takte für die Sprungbefehle usw mit eingerechnet
werden. Ansonsten bekommt man ja völlig falsche Werte.
Die Genauigkeit der Zeitmessung hängt auch mit der Taktfrequenz
zusammen.
> Ich denke schon das die Takte..
Und ich weiß es. (Hab nachgesehen).
> Die Genauigkeit der Zeitmessung hängt auch mit der Taktfrequenz zusammen.
Nein. Vielleicht meinst du die Auflösung - die Genauigkeit jedenfalls
hängt nicht mit der Taktfrequenz zusammen.
Schmittchen.
Hi
Also mit den Schleifen beim AVR ist das so eine Sache. Als Beispiel sei
die RC5 Fernbedienung genannt. Wenn man den Anhang anschaut, so ist das
eine simpelst Geschichte bei der C-Control von Conrad. Programmiert man
das Gleiche beim AVR, so erhält man alles, nur keine RC5 Befehle. Wenn
man sich dann den generierten Code von Compilern (Bascom etc.) oder was
zu RC5 an Codebeispielen zum AVR anschaut, so stellt man schnell fest,
dass hier mit ober und unter-limits gearbeitet wird. Warum, wenn die
Befehle immer die gleiche Zeit benötigen?
Also ich habe meine absoluten Zweifel an Schleifen oder auch Timer
Routinen beim AVR
Peter
Hi Markus
Ich habe jetzt mal das umgeschriebene Prog für AVR angehängt. Ich weis
zwar nicht mehr, auf welchem Versuchsstand das Prog ist, aber wenn du
die beiden Progs vergleichst, siehst du, dass sie das gleiche machen.
Der Unterschied, mal von Kleinigkeiten abgesehen, besteht darin, das
Prog für C-Control funzt, das Prog für AVR funzt nicht. Ich habe dann
das Prog für den AVR in alle möglichen Richtungen geändert, um zu
erfahren, wie lange ein Biphasenslot dauert (mit Schleifen). Es kam nur
selten der gleiche Schleifenzähler dabei raus. Wenn du dir dann mal die
funktionierenden Progs für den AVR anschaust, siehst du, dass diese mit
Zeitunter- und Zeitobergrenzen für einen Biphasenslot arbeiten. Ich habe
jedenfalls kein funktionierendes RC5 Prog für den AVR gefunden, dass wie
bei der C-Control mit festen Schleifenzählern läuft.
lg
Peter
Hi Peter,
kenn mich mit RC5 nicht aus. Weiß auch nicht was mit Bipahsenlot gemeint
ist.
Aber ich sehe trotzdem keinen Grund warum man mit dem AVR keine
Schleifen oder sowas machen können soll. Vielleicht liegt es einfach
daran das der AVR um einiges schneller ist als die C-Control und daher
bestimmte Programmiertechniken, die mit der C-Control noch
funktionieren, mit dem AVR nicht mehr möglich sind. Deshalb evt die von
Dir angesprochene Lösung mit den Ober- und Untergrenzen. Vielleicht um
Signalungenauigkeiten, die die C-Control noch nicht registrieren würde,
auszugleichen.
Gruß
Markus
> Der Unterschied [...] besteht darin, das Prog für C-Control funzt, das Prog für AVR funzt nicht
Aha, und den Grund dafür suchst du dann am AVR? Seltsame Logik.
Im Netz gibts genug RC5-Beispiele für AVRs. Die meisten bauen auf Peter
Fleurys Implementation auf.
<http://www.mysunrise.ch/users/pfleury/avr-software.html>
Das Problem bei der Fernbedienungssoftware ist nicht AVR oder RC5,
sondern daß nicht alle Hersteller sich streng an RC5-Specs halten.
(Viele Fernbedienungen benutzen auch andere, RC5-inkompatible Protokolle
- das nur nebenbei). Oftmals wird auch der EmpfägerIC (TSOP17xx) mit der
falschen Frequenz eingesetzt.
Das gleiche Problem sehe ich übrigens beim Empfang/Auswertung der
DCF77-Signale. Wirklich idiotensichere AVR-Software dazu gibt es
nicht... aber auch den AVR als solchen würde ich das nicht schieben.
Schmittchen.
Hi
erklärt mir doch einmal, was an meiner Logik falsch ist. Ein Bit dauert
Biphasencodiert 1778 us. Bei 8MHz dauert ein Takt 0,000000125 s. 1778us
= 0,001778 s. 0,001778 / 0,000000125 = 14224. Wenn nun das
Biphasensignal in 4 Teile zerlegt wird, dann 14224 / 4 = 3556 Takte bis
zur Abfrage des Pegels. Bei dem AVR vergehen bei mir zwischen 11000 und
17000 Takten pro Bit. Bei der C-Control ist die Anzahl der Takte immer
gleich.
Wie gesagt, ich möchte den AVR nicht madig machen. Wenn ich den nicht
gut finden würde, dann würde ich ihn nicht nutzen. Tue ich aber. Ich
warne nur vor Schleifenzählern. Möglicherweise treibt der AVR durch INTs
etc. andere Dinge die Zeit brauchen. Dann ist mein Schleifenzähler
makulatur.
Was lernt man aus der von Schmittchen angegebenen Referenz?
if ( (timer > RC5BITREF1) && (timer < RC5BITREF2) ) {
// startbit ok, decode
Nun, es wird ein Zeitslot für die Codierung verwendet, also kein fester
Zeitwert wie bei der C-Control. Allein die Ermittlung des Zeitslots ist
fast so aufwendig, wie der gesamte RC5-Code der C-Control. Das heist
meiner Meinung nach aber nicht, dass die C-Control dem AVR überlegen
ist.
lg
Peter
Vorweg: Mein "Peter-Fleury-Link" war leider nicht der, den ich zu diesem
Thema bringen wollte (hab mich in meinen Bookmarks verirrt). Eigentlich
wollte ich auf Bray verweisen:
http://bray.velenje.cx/avr/
Und der verwendet einen Interrupteingang und den Timerinterrupt zur
Dekodierung.
> Bei dem AVR vergehen bei mir zwischen 11000 und 17000 Takten pro Bit.
Nein, sondern genau 14224, wie du auch oben ausgerechnet hast (@8MHz).
Nochmal: 1Bit ist 1778us lang. Bei 8MHz (=125ns) werden genau 14424
Takte ausgeführt. Das was du beobachtet hast, war wahrscheinlich bei
einer AVR-RC5-Version, die nicht auf die fallende Flanke des
IR-Empfängerausgangssignal reagiert. So können in deinem Falle noch alle
möglichen Interrupts dazwischenkommen bis das Hauptprogramm per Polling
merkt, daß da was ansteht. Oder je nach Zustand des AVRs/ext.Hardware
kann die Ausführung einzelner Hauptprogrammteile unterschiedlich viel
Zeit in Anspruch nehmen. Das kann dann zu den 11000-17000 Takten führen.
Aber das hast du ja schon selbst bemerkt:
> Möglicherweise treibt der AVR durch INTs etc. andere Dinge die Zeit brauchen...
Wie RC5 am besten dekodiert wird, beschreibt Ralf Spettel auf seiner
Seite sehr anschaulich:
http://www.spettel.de/ralf/index_reload.html?http://www.spettel.de/ralf/projekte/avr_rc5/index.shtml
Zieh dir die Seite mal rein, dann dürften auch deine Bedenken/Probleme
bzgl. unterschiedlicher Taktzahlen im Prinzip geklärt sein.
> Was lernt man aus der von Schmittchen angegebenen Referenz?
Wie mans besser nicht machen sollte. ;-) oder besser :-(
Können bei der C-Control keine "unvorgesehenen" Dinge (wie z.B. INTs
oder je nach Situation zeitlich unterschiedlich lange Programmteile)
auftreten? Das hieße dann ja, daß während RC5 dekodiert wird, nichts
anderes ausgeführt werden kann?
(Anm.: Ich kenne die C-Control nicht).
Schmittchen.
Hallo Schmittchen
Erst mal danke für die links. ich denke, die sind für alle interessant.
weiter denke ich, dass wir den disput hier beenden können, denn mit
deinem satz
>Oder je nach Zustand des AVRs/ext.Hardware kann die Ausführung einzelner
Hauptprogrammteile unterschiedlich viel Zeit in Anspruch nehmen. Das kann dann zu
den 11000-17000 Takten führen.
Aber das hast du ja schon selbst bemerkt:<
haben wir ja doch noch einigkeit erzielt. ursprünglich wollte ich ja
lediglich zur vorsicht bei der verwendung von schleifen mit
schleifenzählern warnen. die rc5 problematik war nur ein beispiel zur
verdeutlichung. viele standartroutinen zur zeitvertrödelung benutzen
aber genau diesen schleifentyp. auch delay.zip auf der homepage von bray
(http://bray.velenje.cx/avr/) verwendet diesen typ. dein zweiter link
ist ebenfalls sehr hilfreich in der angelegenheit. er besagt, grob
vereinfacht, vertraue nicht auf einen zähler, sondern synchronisiere
dich mit hilfe von steigenden oder fallenden flanken. er weist auch
darauf hin, dass die methode von bray problematisch sein kann. kann,
nicht muss.
lg
peter
Hi
Einen kleinen Einwurf habe ich noch. Wiso gibt es keine Idiotensichere
SW für DCF77, wie meinst du das Schmittchen? Erst solltest du testen und
dann drüber herfallen.
Schleifen benutze ich übrigens nur um eine min. benötigte Zeit zu
überbrücken, niemals aber um Zeiten zu messen,(naja fast nie) wozu sind
denn sonst Timer da.
Gruss Uwe
Hallo Uwe
als ich die implementation der rc5 routine gestartet habe, war ich noch
neu beim avr. was lag da näher, als mit schleifen zu arbeiten. der timer
kam erst später. wenn man neu an einem prozessor rangeht, fängt man halt
mit dem leichten (schleifen) an. wenn das dann schon nicht klappt, naja
dann kann es sein, dass einem das selbstvertrauen zur
timerprogrammierung fehlt. ging mir jedenfalls so.
lg
peter
> Wiso gibt es keine Idiotensichere SW für DCF77
Ich schrieb: "Probleme beim Empfang/Auswertung [...]. Idiotensichere
Software gibts nicht..."
Naturbedingt ist das DCF77-Signal nicht immer frei von Störungen und der
Empfang ist auch nicht immer perfekt. Wenn man den TTL-Ausgang der
gängigen DCF-Empfänger betrachtet, so erscheint das eigentlich immer
sauber. Timingkritisch sollte die DCF-Kodierung im Gegensatz zu RC5 auch
nicht sein. Dennoch schaffen es die meisten Softwareimplementationen
nicht daraus die richtige Zeit zu erzeugen. Die meisten im Netz
verfügbaren Sourcen bauen auf Volker Oths Code auf. Er verzichtet auf
Plausibilitätsprüfungen, die meiner Meinung nach bei schlechtem Empfang
wichtig sind. Z.B. wenn eben noch der 25.Aug war, dann kann in 5min
nicht der 23.Aug sein usw.. Aber dann besteht ja auch das Problem, daß
man anfangs eine verläßliche Zeit/Datumsangabe braucht, um solche
Prüfungen durchzuführen.
Zusammenfassend: Das Problem liegt im (teilweise) schlechten Empfang mit
fehlender Plausibilitätskontrolle. Eine Software, die man irgendwo
hernimmt, wie sie z.B. auf jeder AVR-Seite für LCDs bereitsteht, gibts
für DCF77 ((noch)) nicht.
Vom Gegenteil lasse ich mich natürlich gern überzeugen. Ich muß
allerdings auch dazusagen, daß seit meinen Erfahrungen inzwischen über
ein Jahr vergangen ist.
Schmittchen.
@Uwe: So wie ich deinen Assemblercode lese hast du auch keine
Plausibilitätsprüfungen integriert (habe den für mich schwer lesbaren
Ass.Code nur überflogen, falls doch implementiert, bitte nicht schlagen
:-)). Und das Problem mit der Anfangsuhrzeit bleibt auch bestehen -
irgendwann braucht man eine Uhrzeit, für die man sicher sein kann, daß
sie stimmt, sonst sind alle Plausibilitätskontrollen unnütz. Dreimalige
"gültige", aufeinanderfolgende Uhrzeit könnte dafür reichen. (Bei mir
dauert das dann ca. 30min - 3h, bis 3x gültige Uhrzeit kommt; mit Volker
Oths C-Code).
Allgemein: Die Uhrzeit der Uhr per Taster (oder sonstwie) vorsagen,
finde ich am Ziel einer Funkuhr vorbei.
Ich habe hier auch eine gekaufte fertige Funkuhr (mit Funkthermometer),
die auch manchmal die falsche Zeit anzeigt. Meist werden die Stunden als
0 erkannt. Dann ist um 16:54 -> 0:54.
Ich bin hier ca. 150km südwestlich von Frankfurt. Zwischen Frankfurt und
der Funkuhr (auch dem Modul) stehen noch ein paar Bildschirme und die
Gebäudeaußenwand - evtl. wirkt sich das auf meinen schlechten Empfang
aus?
Schmittchen.
Hi
Habe leider momentan etwas wenig Zeit.
Ich mache einen Quersummentest zwischen alter und neuer Zeit. Da sich
pro Übertragung meistens nur die Minute ändert ist das sehr
wirkungsvoll.
Will sagen: alte Zeit + 1 mit neue Zeit muss gleich sein, sonst war es
fehlerhaft. Damit konnte ich bis jetzt alle fehlerhaften Zeichen
verhindern. Das Ding läuft bei mir als Schaltuhr und da wären falsche
Zeiten fatal.
Ich mache es noch mal optisch:
12:20 30.8.02 Quersumme = 18+1 = 19
12:21 30.8.02 Quersumme = 19
Wenn das OK ist kann die Zeit synchronisiert werden.
Es wird automatisch ein Fehler bei jedem Übergang der Minutenzehner
erzeugt (19->20 Q1=3 Q2=2)
Für 1.Synchr.braucht man, wenn Sign.OK 2 Minuten, wenn Sign. Müll halt
länger. Ich habe schon mal ne 1/2h gewartet.
Wie gesagt die Sache ist sehr sicher.
Gruss Uwe
Ist zwar schon etwas her dieser Beitrag, aber vielleicht schaut einer
von Euch doch nochmal vorbei.
Hallo Sebastian,
wie schon gesagt wurde, kann man Wartezeiten sehr gut und sehr genau
über Zählschleifen realisieren, jedoch mit 2 Nachteilen:
1. man kann dabei nichts anderes machen.
2. wenn die maximale Zeit auch eingehalten werden soll, müssen alle
Interrupts gesperrt sein.
Deshalb macht man das üblicher Weise nur bei sehr kurzen Zeiten. Z.B.
benötigt meine 1-Wire-Routine (z.B. für die Maxim DS18B20
Temperatursensoren) Zeiten von 15µs und 60µs.
Bei Deiner Anwendung kommt es warscheinlich nicht darauf an, ob es 500
oder 600ms sind. Da würde ich dann einen Timerinterrupt nehmen, der
einen Takt von etwa 100ms erzeugt. Und wenn das Relais eingeschaltet
wurde, wird ein Register auf 6 gesetzt und der Timerinterrupt zählt es
runter und schaltet das Relais ab, wenn der Wert 0 erreicht wurde.
Hallo Peter,
daß das AVR-Programm nicht funktioniert liegt bestimmt nicht an der
Delay-Routine sondern daß es eben doch nicht gleich ist.
Z.B. ist mir sofort ins Auge gesprungen, daß das SREG nicht gesichert
wird, es ist doch aber ein Interrupt (endet mit RETI).
D.h. Dein Hauptprogramm hat eigentlich gar keine andere Chance, als
gegen den Baum zu laufen.
Außerdem springst Du immer zum Ende (rjmp zurueck), das C-control aber
zum Anfang (brset 0,PC,rc5).
RC5-Dekodierung:
Der RC5-Kode synchronisiert sich ja bei jedem Bit neu. Damit sind exakte
Zeiten völlig unnötig. Abweichungen von 20% sind kein Problem. Man kann
deshalb sogar ohne Quarz arbeiten und z.B. den Tiny15 nehmen.
Der Trick ist natürlich, man synchronisiert bei jedem Bit und nicht nur
beim Startbit.
Mein Beispiel könnt Ihr im Anhang finden.
Kurz zum Prinzip:
Es wird mit dem Timerinterrupt die Zeit bis zum nächsten Pegelwechsel
gemessen. Der Bittakt ist ja etwa 1,8ms.
Alles kleiner als 0,75 * Bittakt ist nur der zusätzliche Puls, wenn das
gleiche Bit nochmal kommt.
Alles größer 1,25 * Bittakt ist ne Störung.
Alles dazwischen ist dann das Bit. Der Pegel nach dem Wechsel entspricht
dem Bitwert und wird in das Ergebnis reingeschoben.
Das ganze 13 mal und fertig.
Falls noch weitere Fragen sind, fragt ruhig.
DCF77-Dekodierung:
also meine Routine ist 100%-ig störsicher (das war doch wohl gemeint mit
"idiotensicher").
Mir ist jedenfalls noch nie eine falsche Zeit untergekommen.
Mann muß natürlich trotzdem noch eine normale Digitaluhr programmieren.
Z.B. solange der Fernseher oder der PC-Monitor an sind, empfängt meine
Routine absolut nichts.
Ich benutze den Conrad-Empfangsmodul.
Die Routine ist auf meiner Webseite:
http://www.specs.de/~danni/appl/soft/c51/thclock/index.htm
Die einzelnen Zeiten messe ich mit einem Timerinterrupt von 64Hz.
Dann ergeben sich folgende Zählerwerte:
0-Bit: 6 (6,4)
1-Bit: 12 (12,8)
Pulsabstand: 64
Synchronimpulsabstand: 128
Das ganze wird also in ein Byte gezählt und dann getestet:
Puls < 5: Fehler
4 < Puls < 10: 0-Bit
10: Fehler
10 < Puls < 20: 1-Bit
Puls > 20: Fehler
Pulsabstand < 60: Fehler
60 < Pulsabstand < 70: O.K.
70 < Pulsabstand < 120: Fehler
120 < Pulsabstand < 140: Synchronimpuls
Pulsabstand > 140: Fehler
Zusätzlich werden noch die 3 Paritätsbits geprüft und ob es auch genau
59 Impulse waren.
Alle diese Tests sind nur Byte-Vergleiche, d.h. der Rechenaufwand ist
absolut minimal.
Dafür spare ich ne Menge Code bei der Auswertung:
Üblicher Weise sieht man oft riesige Programme, die jeden Impuls extra
behandeln.
Aber es wird eigentlich immer nur das gleiche gemacht: Es wird ein Wert
(1,2,4,8,10,20,40,80) zu einer Speicherstelle addiert. Es gibt also nur
eine kleine Tabelle, in der steht, welcher Wert auf welcher Adresse
addiert werden muß.
Und immer, wenn eine 1 addiert wird, wird vorher gelöscht.
Und der Tabellenwert FF bedeutet, daß die Parität geprüft wird.
Das ganze sind dann gerade mal lächerliche 250Byte an Code.
Ich würde mich über Rückmeldungen freuen, d.h. ob Ihr mit Routinen nach
diesem Prinzip immer noch diese Probleme habt.
Peter
Hallo Peter
>>daß das AVR-Programm nicht funktioniert liegt bestimmt nicht an >>der
Delay-Routine sondern daß es eben doch nicht gleich ist.
>>Z.B. ist mir sofort ins Auge gesprungen, daß das SREG nicht >>gesichert wird, es
ist doch aber ein Interrupt (endet mit RETI).
>>D.h. Dein Hauptprogramm hat eigentlich gar keine andere Chance, >>als gegen den
Baum zu laufen.
Wie ich schon schrieb, handelt es sich um einen Auszug des Programmes.
Weiter schrieb ich, dass ich nicht mehr weis, welcher Stand der vielen
Testversuche es ist. Aber egal. Tatsache ist, dass man mit Zeitschleifen
über vertrödeln mit "nop" oder ähnliches keine genauen Zeiten hinkriegt.
Versuche doch mal bitte die Routine von der C-Control in AVR (AT90S*)
Assembler zu programmieren. Ich wünsche viel Freude.
Weiter mußte ich feststellen, dass auch der Timer nicht besonders genau
ist. Beispiel:
Die Routine von Volker Oth zum DCF77 Signal prüft bei einem AVR mit 8
MHz und eingestelltem Teiler von 1024 mit dem Timer 1 und INT1 bei der 0
auf Timercounter 1 kleiner 1171, bei einer 1 auf kleiner 1953 und beim
Startbit auf größer 11718. Bei mir wurde gemessen:
Für eine 0 zwischen 600 und 960
Für eine 1 zwischen 1300 und 1600
Für das Startbit 14000 und 15500
also bei zwei Sekunden ungenau auf etwa 200 ms. Bei Zeitkritischen
Sachen wohl etwas zu ungenau.
Frage mich bitte nicht, woran das liegt. Die Funkuhr von Volker Oth
funktioniert einwandfrei. Auch bei laufendem PC und laufendem Fernseher.
Es sollte aber klar sein, dass Zeitschleifen ohne Sync über ein externes
Signal problematisch sind.
Welchen Grund das hat, ob z.B. die Taktfrequenz des Quarzes schwankt,
oder bei Schaltvorgängen die Spannung kurz zusammenbricht, oder, oder,
oder, muß man wohl von Fall zu Fall untersuchen.
lg
Peter
Hallo Peter,
es gibt überhaupt keinen Grund, warum Verzögerungsschleifen oder Timer
nicht genau sein sollen. Bei einem 2313 mit 10MHZ sind sie auf 100ns
genau. Und die Quarze schwingen auch auf mindestens 6 Stellen genau.
Wenn Du aber analoge Signale messen willst, können diese natürlich
erheblich schwanken.
Z.B. durch wechselnde Empfangssignalstärke und auch durch die Tiefpässe
zum Ausfiltern der Trägerfrequenz kriegst Du automatisch erhebliche
Schwankungen draufaddiert.
Deshalb muß man bei Signalen aus der analogen Welt immer mit unteren und
oberen Schwellen arbeiten.
Wenn Du dagegen mit einem 2. AVR die Impulse erzeugen würdest, kriegst
Du auch immer ein konstantes Meßergebnis geliefert.
Die Programme habe ich mir nur auf Unterschiede und Fehler hin
angesehen.
Es macht ja auch keinen Sinn, ein Assemblerprogramm zu schreiben, wenn
ich schon ein super funktionierendes C-Programm fix und fertig habe.
Peter
Welche Probleme? Bitte ein konkretes _Minimal_-Beispiel.
Die Ausführungszeiten der Befehle sind im Instruction Set genau
angegeben, z.B. bei sbrc:
| Cycles:
| 1 if condition is false (no skip)
| 2 if condition is true (skip is executed) and the instruction skipped is 1 word
| 3 if condition is true (skip is executed) and the instruction skipped is 2 words
Bei welchem Befehl ist diese Angabe falsch?
Hallo Andreas
Ich weis nicht, ob Du mich meinst. Ich habe nicht behauptet, dass die
Angabe der Anzahl der Takte pro Befehl falsch ist. Ich habe behauptet,
dass die Ausführung von Schleifen unterschiedlich lange dauern kann.
Auch der Timer 1 liefert unterschiedlich Timercounts bei der DCF77 Uhr
von Volker Oth. Ich denke weiter, dass das Thema nun ausgereizt und
ausdiskutiert ist. Wer glaubt, man könne den Werten trauen, der soll sie
halt nutzen. Ich jedenfalls traue ihnen nicht mehr von 12:00 bis Mittag.
Wer meint ich wäre im Unrecht, naja der soll mir eine funktionierende
Umsetzung der C-Control Routine zeigen. Die ist wie gesagt winzig und
funktioniert. Alle RC5 Programme des AVR sind wahre Monster im Vergleich
dazu. Wenn ich so im unrecht bin, warum sind die Programme für den AVR
so riesig? Warum arbeiten sie mit Bereichswerten und nicht mit starrem
Schleifenzähler, meinetwegen auch festen Timercounts? Ich habe technisch
nicht die Möglichkeit zu prüfen, was denn nun zu den Unterschieden
führt. Ich denke aber mal, wenn ein und derselbe RC5 Empfänger an der
C-Control feste Zeiten pro Bit hat und beim AVR nicht, wenn die Zeiten
bei der DCF77 Uhr dermaßen schwanken, dann liegt für mich die Ursache
eindeutig beim AVR. Wenn man dies berücksichtigt, dann kann man denke
ich mit dem AVR alles machen. Die C-Control hat bei weitem nicht die
Leistungsfähigkeit des AVR. In Assembler geschriebene Programme dürfen
nur einige wenige Byte groß werden. Der Basic Interpreter ist extrem
fehlerhaft, und, und, und.
lg
Peter
Die unterschiedlich lange Schleifendauer ist nur durch
dazwischenkommende Interrupts erklärbar.
Die Timer liefern auch genaue Werte, allerdings kann bei manuellem
Reload Jitter auftreten, weswegen man bei hohen Frequenzen den
Compare-Interrupt von Timer 1 verwenden sollte. Jitter gibt es zwar auch
beim Aufruf dieses Interrupts, aber da der Timerwert hier nicht von Hand
geändert werden muss, sondern automatisch zurückgesetzt wird, addiert
sich dieser Fehler nicht.
Ich kann deine Probleme nicht nachvollziehen. Das DCF77-Programm kann
ich leider nicht ausprobieren, da ich kein DCF77-Modul habe (bzw. meinen
Wecker nicht zerlegen will).
Gruß
Andreas
Hallo Andreas
Leider war nur der Int0 für die RC5 aktiv. Somit schwer erklärbar. Bei
der DCF77 war nur INT 1 aktiv und an dem hing die DCF77. Wie gesagt, mir
fehlen die technischen Möglichkeiten, um abzuklären, was die
unterschiedlichen Timercounts/Zeitschleifen erklärt. Ich denke, ich habe
sogar Ints abgeklemmt, gepollt und trotzdem keine korrekte Erkennung der
RC5 mit Zeitschleifen hinbekommen. Aber egal, die AVR's sind super und
ich bleibe dabei. Probleme sind keine mehr, wenn man sie als Problem
erkannt hat und einen Ausweg dafür gefunden hat. Dies ist sowohl bei RC5
als auch mit DCF77 gelungen. Man verwendet eben Zeitbereiche. Auch wenn
das vielleicht für einen Perfektionisten nicht optimal erscheint, mir
reicht es, wenn es funktioniert. Ich muß nicht für alles eine hieb und
stichfeste Erklärung haben. Wenn mir einer eine gibt, super, wenn nicht,
na dann eben klapt oder klapt nicht. Wenns klapt, bin ich zufrieden.
lg
Peter
Ich hab jetzt mal mein C-Programm in AVR Assembler umgesetzt.
Ich kann nicht behaupten, daß es mit 30 Zeilen (=60 Bytes) sehr lang
ist.
Wie gesagt, alle Werte aus der Analogwelt können schwanken. Deshalb wird
für ein Bit ein Zeitfenster von 0,75 ... 1,5 Bitzeiten getestet.
Ich habs ausprobiert, es läuft sowohl mit einem 8MHz als auch mit einem
12MHz Quarz einwandfrei. Aber man sollte trotzdem die richtige
Quarzfrequenz (z.B. 10MHz) eintragen.
Dein Assemblerprogramm habe ich nicht verwendet, da Du ja die gesamte
Zeit im Interrupt verwartest. Und das sollte man besser vermeiden,
schließlich soll die CPU ja noch anderes zu tun.
Peter
Hallo Peter
damit wären wir ja mal wieder einig. Ein Zeitfenster muß her. Feste
Werte klappen nicht. Mit Routinen, die beim AVR Zeitfenster verwenden,
kannst Du die Strasse pflastern. Es ist mir aber kein Programm bekannt,
welches mit festen Werten (ob über Schleifen oder über Timercounter)
realisiert wurde.
lg
Peter
Das liegt aber, wie gesagt, am analogen Charakter der
Übertragungsstrecke und daran, daß in den Fernbedienungen billige
unpräzise Schwinger verwendet werden.
Wenn Du Dir das C-Control-Programm genauer ansiehst, wartet die Funktion
getbit auch innerhalb eines Zeitfensters auf einen Pegelwechsel und
synchronisiert sich darauf neu. Und dieses Zeitfenster beginnt, genau
wie bei mir, bei 3/4 * Bitzeit. Nichts ist es mit festen Werten.
Wenn das in Deinem AVR-Programm nicht so ist, dann kann es auch nicht
funktionieren.
Wenn die Timer im AVR nicht auf den Quarztakt genau wären, dann müßte ja
meine Digitaluhr ohne DCF77 nach dem Mond gehen und mein Frequenzmesser
müßte auch ständig falsche Werte anzeigen, tun sie aber nicht.
Der Frequenzmesser ist 5-stellig und auf alle Stellen genau.
Und bei der Uhr sind erst nach einem Monat ein paar Sekunden Abweichung
feststellbar.
Der Mikrokontroller ist nun mal kein Mensch und braucht deshalb für die
selben Befehle immer genau die gleiche Zeit.
Peter
Och Peter
guck mal richtig hin.
>>;--------------------------------------------------------------------- -------->>; Warteroutine fuer 1/4 eine Biphasenbits = 444us = 444T bei 12Mhz>>; ;Aufrufcall 2T>>w444 lda #147 ; 3>>loop deca ; 3 A -1>> bne loop ; 3 6*0,5µs = 3µs/Schleife>> rts
Ich übersetze es Dir aber gerne.
w444 = Label
lda #147 = lade Akkumulator decimal 147
loop = label
deca = akkumulator --
bne loop = wenn akkumulator > 0 dann springe zum Label loop
rts = return subroutine
Wo ist das Zeitfenster?
Hier nochmal das Prog der C-Control
; RC5-Unterprogramm RC5.ASm
; nach einer Vorlage von Olaf Kaluza
PC .equ $01
Cnt .equ $0A3
Kon .equ $0A4
Adr .equ $0A5
Tas .equ $0A6
.org $101
Clr Kon
Clr Adr
Clr Tas
brset 0,PC,rc6
rc5 brset 0,PC,rc5 ;Warten auf Startbit
jsr w444 ;warten
brset 0,PC,rc5 ;Stoerimpuls
jsr w444 ;Naechsten Biphasenpegel
jsr w444
brclr 0,PC,rc5 ;Stoerimpuls
jsr w444
jsr w444
brset 0,PC,rc5 ;Stoerimpuls
jsr w444 ;Ok weiter
jsr w444 ;Kontrollbit einlesen
jsr getbit ;Kontrollbit hier im Carry
rol Kon
ldx #5 ;5 Adressbits
rcadr jsr w444
jsr w444
jsr getbit
rol Adr ;Bit merken
dex
bne rcadr
ldx #6 ;6 Datenbits
rcdat jsr w444
jsr w444
jsr getbit
rol Tas ;merken
dex
bne rcdat
rc6 rts ;Zurueck zum Hauptprogramm
;-----------------------------------------------------------------------
------
;Einlesen eines Bits, Rueckgabe in Carry
getbit lda #255 ;Timeout festlegen
sta Cnt
brset 0,PC,gethi ;Wird es ein Lowbit?
gbl1 brset 0,PC,gbl2 ;Auf Biphasensprung syncronisieren
dec Cnt
bne gbl1
bra biterr ;Timeout
gbl2 jsr w444
brclr 0,PC,biterr ;Fehler
clc ;Lowbit
rts
gethi brclr 0,PC,gethi2 ;auf Phasensprung syncronisieren
dec Cnt
bne gethi
bra biterr ;Timeout
gethi2 jsr w444
brset 0,PC,biterr ;Fehler?
sec ;Highbit
rts
biterr Clr Kon ;Fehler, alles löschen
clr Adr
clr Tas
clr Cnt
rts
;-----------------------------------------------------------------------
------
; Warteroutine fuer 1/4 eine Biphasenbits = 444us = 444T bei 12Mhz
; ;Aufrufcall 2T
w444 lda #147 ; 3
loop deca ; 3 A -1
bne loop ; 3 6*0,5µs = 3µs/Schleife
rts
.END
Mann, wenn Du meinst, in der Proc getbit wird ein Zeitfenster abgefragt,
i9rrst Du. Es wird lediglich abgefragt, ob eine Störung auf der Leitung
war. Wie gesagt, nicht reden machen. Bitte mach das doch bitte im AVR
eins zu eins. Sind doch nur ein paar Befehle. Solltest Du Fragen zu
einem Befehl haben, ich sage Dir gerne was welcher Befehl macht.
lg Peter
Also vor getbit wird 3 * w444 aufgerufen, damit ist erst 3/4 der Zeit
rum. Richtig ?
Dann in getbit steht:
getbit lda #255 ;Timeout festlegen
was soviel heißen soll, wie oberes Zeitlimit.
Dann kommt:
gethi brclr 0,PC,gethi2 ;auf Phasensprung syncronisieren
was soviel heißen soll, wie auf die Flanke synchronisieren.
Und darin wird wohl auch Dein Fehler liegen. Wenn, wie Du sagst, der AVR
100-mal schneller ist, müßte Dein Timeoutzähler dann ja auf 25500
gesetzt werden, d.h. ein Byte reich da nicht mehr.
Peter
Hallo Peter
wo liegt das Problem? Machs doch genau so im AVR. Und damit soll es nun
auch genug sein. Ich weis nicht, vielleicht drücke ich mich
unverständlich aus. Mach es genau so wie bei der C-Control. Wenn
es dann funktioniert, dann gebe ich mich geschlagen.
lg
Peter
Ich will Dich nicht schlagen.
Ich machs doch im Prinzip wie bei der C-Control.
Ob nun Timerinterrupt oder Delay-Loop ändert doch am Prinzip überhaupt
nichts.
Es macht nur die Implementierung leichter.
Statt:
.equ XTAL = 10000000 ;10Mhz
kann ich auch schreiben:
.equ XTAL = 4000000 ;4MHz
und es funktioniert auch sofort mit dem anderen Quarz.
Versuch mal, das C-Control-Programm nachzuvollziehen. Dann wirst Du
sehen, daß es genauso arbeitet, wie meine Routine.
Peter
Lieber Peter
ich habe das C-Control Programm erst exakt, dann in ich weis nicht wie
vielen Variationen umgesetzt. Es klapt eben nicht. Die Diskusion geht
langsam in eine Richtung, die keinen Erfolg verspricht.
Also, wenn du eine exakte Umsetzung des Programmes für den AVR hast, und
nicht etwas mit Zeitfenstern oder ähnliches, dann bin ich der Erste, der
zugibt, dass ich im Unrecht bin.
Solange ich das nicht sehe, sage ich:
1. Delays über Zeitschleifen mit festem Schleifenzähler kannst Du
vergessen. Dies wird auch unisono in den diversen Foren bestätigt. Lies
Dir vielleicht noch mal die Beiträge durch.
2. Auch mit dem Timercounter ist Vorsicht geboten. Auch dies wird in
anderen Foren bestätigt.
3. Ich sage nicht, woran das liegt, denn das weis ich nicht. Es gibt
eine Reihe von Möglichkeiten woran es liegen könnte. Auch diese sind in
den Beiträgen zu Warte-Befehl in Assembler aufgeführt.
lg Peter
Daß Dein AVR-Programm gar nicht gehen kann, weil der Timeout-Zähler für
die obere Zeitschwelle viel zu klein ist, hast Du wohl überlesen.
(Letzter Satz im 4.Beitrag über diesem).
Das ist diese Zeile in Deinem Programm:
ser r24 ;Cnt=255
Nötig wäre >700, d.h. 2 Register.
Peter
Langsam wird die Diskussion hier etwas diffus. Am Ende weiss wohl keiner
mehr wie die Timer und Interrupts bei der AVR Familie wirklich
funtionieren. Ich möchte
an dieser Stelle nur folgendes anmerken sowohl mit
reinen Zählschleifen als auch mit Timer-gesteuerten
Routine sind auf 1clk genaue Delays möglich es kommt
immer auf die Programmstruktur an.
@Peter:
1. Zu den Zeitschleifen:
Mach das Programm aus dem Anhang in einen AVR. Schließ ein Oszi an PB0
an. Freu dich über das wunderhübsche, jitterfreie Rechteck.
2. Zu den Timern:
Toggel ein Pin im Compare-Interrupt von Timer 1, schreib irgendwas
sinnloses kompliziertes in die Hauptschleife. Freu dich über das
wunderhübsche, mit vorhersagbarem Jitter versehene Rechteck.
Mehr gibt es zu dem Thema nicht mehr zu sagen.
Wenn dem so wäre, dass ich beim Timer gesteuerten Delay immer mit einem
Jitter leben müßte, hätte ich
den Einsatz Einsatz von AVR Prozessoren längst be-
endet bzw. hätte die Prozessorarchitektur nicht richtig verstanden.
Du mußt mit dem Jitter leben. Er entsteht dadurch, dass beim Auftreten
des Interrupts der aktuelle Befehl noch fertig abgearbeitet wird. Die
Zeitunterschiede sind natürlich minimal, aber bei sehr hohen
Interruptfrequenzen durchaus spürbar. Wenn du den Timer 0 ohne Prescaler
und mit manuellem Reload verwendest, setzt sich der Fehler sogar fort.
Das hat mich schonmal mehrere Stunden Fehlersuche gekostet...
Also ich nicht. Der Unterschied zwischen den Aus-
führungszeiten 1/2 Takte ist ja sehr gering und in
einer Interruptroutine sehr leicht ausgleichbar.
Ohne Prescaler ist auch das manuelle Reload ohne Jitter möglich. Da ich
ja immer eine genaue Kontrolle
über jeden einzelnen Taktimpuls habe. Etwas komplexer
werden die Korrekturen bei eingeschaltetem Prescaler.
Bei den neueren AVRs der MEGA-Familie hat Atmel zusätzlich die
Möglichkeit eines Prescaler Reset spen-
diert, welchses die Programmierung an dieser Stelle
erheblich vereinfacht.
In meinem Programm (DDS) wird der Interrupt alle 24 Takte ausgelöst, da
fallen ein oder zwei Takte Unterschied schon ins Gewicht.
Mit Prescaler hast du doch ewig Zeit den Timerwert zu setzen, ohne
Prescaler läuft der Wert schon weiter während du ihn ausliest. Wenn man
anstatt einen festen Wert zu laden den Zählerstand mit subi ändert,
sollte sich der Jitter theoretisch trotzdem eliminieren lassen. Ich hab
das damals erst so probiert, es gab jedoch irgendwelche Probleme die
mich zum Umstieg auf Timer 1 gezwungen haben. Müsste das Ganze
vielleicht irgendwann nochmal simulieren und vielleicht einen "Artikel"
dazu schreiben...
Ohne Prescaler und ohne weitere aktive Interrupts sorgt dieser
Kunstgriff für einen Ausgleich der 2
unterschiedlich Befehlslängen. Allerdings sind die
Möglichkeiten wie zusätzliche WAIT-States bei externem Speicher (ist mir
sowie zu langsam und maximal 4K
internes SRAM dürften wohl in jedem Fall reichen) nicht berücksichtigt.
in R16,TCNTx(L) ;R16 = aktueller Wert Timer 0,1,2
sbrc R16,0 ;Bit0 = 0 -> jump = 2 Takte sonst
;no JUMP = 1 Takt
sbrs R16,0 ;immer 2 Takte
Bei aktivem Prescaler ist die Sache mit der taktge-
nauen Synchronisation etwas aufwendiger, da ja hier
keinerlei Möglichkeit besteht, den Zählerstand des
Prescalers auszulesen.
Hi!
gerade mit Prescalers geht es am besten. bei zb.einem Prescalers von
1024 hast du genau 1024 Takte Zeit um dich um den Timerwert zu kümmern
ohne das Verfälschungen auftreten.
Gruss Uwe
Wenn der Wert des Timer-Register TCNTx von Bedeutung ist, hast du recht.
Wenn du aber z.B. ein Rechteck mit exaktem 50/50 Tastverhältnis an einem
Port via Timer-Interrupt erzeugen willst und z.B. noch Interrupts vom
UART und SPI autreten, wird's bei aktivem Prescaler richtig schwierig
dieses zu realisieren, da man ja mit unterschiedlichen Response-Zeiten
beim Timer-Interrupt rechnen muß.
Hallo,
wow was für thread !
ich fand es hochspannend die Beiträge zu verfolgen
eine Frage:
könnte von euch jemand die DCF-Decodierroutine
so in assembler schreiben das man sie in ein
Bascom-Basicprogramm einbinden kann?
Es gibt allerding einige Dinge die man dabei beachten
muß
Die Hilfebeschreibung dazu weiter unten
eine andere Möglichkeit wäre das Assemblerprogramm
einmal ausführlich zu kommentieren so das man es auch
als Basic/Turbo-Pascal-Programmierer versteht.
Dann könnte ich etwas äquivalentes in Basic programmieren oder wäre der
Basic-code nicht schnell
genug?
Vielen Dank schon im Voraus
viele herzliche Grüße
Stefan
Mixing ASM and BASIC
BASCOM allows you to mix BASIC with assembly.
This can be very useful in some situations when you need full control of
the generated code.
Almost all assembly mnemonics are recognized by the compiler. The
exceptions are : SUB, SWAP,CALL and OUT. These are BASIC reserved words
and have priority over the ASM mnemonics. To use these mnemonics precede
them with the ! - sign.
For example :
Dim a As Byte At &H60 'A is stored at location &H60
Ldi R27 , $00 'Load R27 with MSB of address
Ldi R26 , $60 'Load R26 with LSB of address
Ld R1, X 'load memory location $60 into R1
!SWAP R1 'swap nibbles
As you can see the SWAP mnemonic is preceded by a ! sign.
Another option is to use the assembler block directives:
$ASM
Ldi R27 , $00 'Load R27 with MSB of address
Ldi R26 , $60 'Load R26 with LSB of address
Ld R1, X 'load memory location $60 into R1
SWAP R1 'swap nibbles
$END ASM
A special assembler helper function is provided to load the address into
the register X or Z. Y can may not be used because it is used as the
soft stack pointer.
Dim A As Byte 'reserve space
LOADADR a, X 'load address of variable named A into register pair X
This has the same effect as :
Ldi R26 , $60 'for example !
Ldi R27, $00 'for example !
Some registers are used by BASCOM
R4 and R5 are used to point to the stack frame or the temp data storage
R6 is used to store some bit variables:
R6 bit 0 = flag for integer/word conversion
R6 bit 1 = temp bit space used for swapping bits
R6 bit 2 = error bit (ERR variable)
R6 bit 3 = show/noshow flag when using INPUT statement
R8 and R9 are used as a data pointer for the READ statement.
All other registers are used depending on the used statements.
To Load the address of a variable you must enclose them in brackets.
Dim B As Bit
Lds R16, {B} 'will replace {B} with the address of variable B
To refer to the bitnumber you must precede the variable name by BIT.
Sbrs R16 , BIT.B 'notice the point!
Since this was the first dimensioned bit the bit number is 7. Bits are
stored in bytes and the first dimensioned bit goes in the LS bit.
To load an address of a label you must use :
LDI ZL, Low(lbl * 1)
LDI ZH , High(lbl * 1)
Where ZL = R30 and may be R24, R26, R28 or R30
And ZH = R31 and may be R25, R27, R29 or R31.
These are so called register pairs that form a pointer.
When you want to use the LPM instruction to retrieve data you must
multiply the address with 2 since the AVR object code consist of words.
LDI ZL, Low(lbl * 2)
LDI ZH , High(lbl * 2)
LPM ; get data into R0
Lbl:
Atmel mnemonics must be used to program in assembly.
You can download the pdf from www.atmel.com that shows how the different
mnemonics are used.
Some points of attention :
* All instructions that use a constant as a parameter only work on the
upper 16 registers (r16-r31)
So LDI R15,12 WILL NOT WORK
* The instruction SBR register, K
will work with K from 0-255. So you can set multiple bits!
The instruction SBI port, K will work with K from 0-7 and will set only
ONE bit in a IO-port register.
The same applies to the CBR and CBI instructions.
You can use constants too:
.equ myval = (10+2)/4
ldi r24,myval+2 '5
ldi r24,asc("A")+1 ; load with 66
Or in BASIC with CONST :
CONST Myval = (10+2) / 4
Ldi r24,myval
How to make your own libraries and call them from BASIC?
The files for this sample can be found as libdemo.bas in the SAMPLES dir
and as mylib.lib in the LIB dir.
First determine the used parameters and their type.
Also consider if they are passed by reference or by value
For example the sub test has two parameters:
x which is passed by value (copy of the variable)
y which is passed by reference(address of the variable)
In both cases the address of the variable is put on the soft stack which
is
indexed by the Y pointer.
The first parameter (or a copy) is put on the soft stack first
To refer to the address you must use:
ldd r26 , y + 0
ldd r27 , y + 1
This loads the address into pointer X
The second parameter will also be put on the soft stack so :
The reference for the x variable will be changed :
To refer to the address of x you must use:
ldd r26 , y + 2
ldd r27 , y + 3
To refer to the last parameter y you must use
ldd r26 , y + 0
ldd r27 , y + 1
Write the sub routine as you are used too but include the name within
brackets []
[test]
test:
ldd r26,y+2 ; load address of x
ldd r27,y+3
ld r24,x ; get value into r24
inc r24 ; value + 1
st x,r24 ; put back
ldd r26,y+0 ; address of y
ldd r27,y+1
st x,r24 ; store
ret ; ready
[end]
To write a function goes the same way.
A function returns a result so a function has one additional parameter.
It is generated automatic and it has the name of the function.
This way you can assign the result to the function name
For example:
Declare Function Test(byval x as byte , y as byte) as byte
A virtual variable will be created with the name of the function in this
case test.
It will be pushed on the softstack with the Y-pointer.
To reference to the result or name of the function (test) the address
will be:
y + 0 and y + 1
The first variable x will bring that to y + 2 and y + 3
And the third variable will cause that 3 parameters are saved on the
soft stack
To reference to test you must use :
ldd r26 , y + 4
ldd r27 , y + 5
To reference to x
ldd r26 , y + 2
ldd r27 , y + 3
And to reference y
ldd r26 , y + 0
ldd r27 , y + 1
When you use exit sub or exit function you also need to provide an
additional label. It starts with sub_ and must be completed with the
function / sub routine name. In our example:
sub_test:
When you use local variables thing become more complicated.
Each local variable address will be put on the soft stack too
When you use 1 local variable its address will become
ldd r26, y+0
ldd r27 , y + 1
All other parameters must be increased with 2 so the reference to y
variable changes from
ldd r26 , y + 0 to ldd r26 , y + 2
ldd r27 , y + 1 to ldd r27 , y + 3
And of course also for the other variables.
When you have more local variables just add 2 for each.
Finally you save the file as a .lib file
Use the library manager to compile it into the lbx format.
The declare sub / function must be in the program where you use the sub
/ function.
The following is a copy of the libdemo.bas file :
'define the used library
$lib "mylib.lib"
'also define the used routines
$external Test
'this is needed so the parameters will be placed correct on the stack
Declare Sub Test(byval X As Byte , Y As Byte)
'reserve some space
Dim Z As Byte
'call our own sub routine
Call Test(1 , Z)
'z will be 2 in the used example
End
When you use ports in your library you must use .equ to specify the
address:
.equ EEDR=$1d
In R24, EEDR
This way the library manager know the address of the port during compile
time.
As an alternative precede the mnemonic with a * so the code will not be
compiled into the lib. The address of the register will be resolved at
un time in that case.
This chapter is not intended to learn you ASM programming. But when you
find a topic is missing to interface BASCOM with ASM send me an email.
Hallo Stefan,
mal als Tip:
Die Diskussion wird dadurch nicht gerade gut lesbar, wenn man riesige
Textbandwürmer mittendrin einfügt.
Besser ist es, dafür die Option "Dateianhang" anzuklicken.
Peter
Dem kann ich nur zustimmen. Zumal es sich hier um Auszüge aus einem
Handbuch handelt, würde ein entsprechender Link ausreichen. Auf der
BASCOM Hompage
findet sich übrigens auch ein entsprechendes DEMO-Programm zur DCF77
Decodierung in BASIC