Grüß Gott zusammen, es geht um einen attiny13a und den CTC-Mode (Assembler). Ziel ist es, den Port PB0 bzw. OC0A kurz ein- und dann wieder auszuschalten. Dazu wird der timer0 im CTC-Mode verwendet. Das funktioniert auch im Simulator, aber nicht auf einem echten Chip, wenn ich das über COM0A0=1 und COM0A1=1 mache. Anbei zwei Codes - der eine mit, der andere ohne gesetztes COM0A0 bzw. -1. Aus dem Datenblatt: Compare output mode, non-PWM Mode: WGM01=1, COM0A0=1 und COM0A1=1 => CTC-Mode mit "Set OC0A on Compare Match" Wenn ich nur WGM01=1 setze und den Pin PB0 über die Interrupts der compare-matches oc0a und oc0b setze, läuft alles wie erwartet, sowohl im Simulator als auch auf echter Hardware. Im anderen Fall bleibt der Pegel auf einem echten Chip am Port PB0 permanent high, im Simulator zeigt das Oszilloskop jedoch in beiden Fällen genau das gleiche. Beide Codes sollten vom Ergebnis her genau das gleiche liefern, oder? Beim einen setze ich den Port manuell, beim anderen sollte das automatisch gemacht werden. Die Frage ist - was mache ich beim Code "funktioniert nicht" falsch?
Du kannst entweder auf den Port schreiben (SBI/CBI), dann sind COM0A0=0 und COM0A1=0 -> "Normal port operation, OC0A disconnected." ODER Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen Einfluss mehr. Siehe im DaBla auch Kapitel: Alternate Port Functions - vor allem das Signal PVOExn Wenn ich das richtig sehe, schaltest Du den Portpin immer an und aus. Wäre dann nicht ein PWM-Mode die richtige Wahl? Dann geht es auch ohne IRQ. Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was Du möchtest, da Du nicht Dein Problem, sondern das Problem Deiner Lösung beschrieben hast. Gruß Jobst
Jobst M. schrieb: > Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was > Du möchtest Ich auch nicht.
Jobst M. schrieb: > Du kannst entweder auf den Port schreiben (SBI/CBI), dann sind COM0A0=0 > und COM0A1=0 -> "Normal port operation, OC0A disconnected." > > ODER > > Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und > COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen > Einfluss mehr. Vielen Dank für die sehr erhellende Antwort. Dann scheint der Simulator das schlicht falsch wiederzugeben, denn dort funktioniert das. > Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was > Du möchtest, da Du nicht Dein Problem, sondern das Problem Deiner Lösung > beschrieben hast. Ich verfolge derzeit keine konkreten Ziele, ist nur ein reines Hobby. Ich möchte nur im Detail nachvollziehen können, was genau da im Controller wie warum passiert und nebenbei mein bißchen Assembler vertiefen. Deine Antwort hat mich weiter gebracht, danke dafür.
Stephan E. schrieb: > (...) und nebenbei mein bißchen Assembler vertiefen. Stapel richtig benutzen, das Retten der Register über Register macht man nur in Ausnahmefällen und 64 Bytes SRAM sollten laut Datenblatt bei diesem Baby-µC vorhanden sein, sonst wird man bald schnell in Teufels Küche kommen. Hier ist es sogar so, dass man in den beiden Interruptroutinen gar nichts retten müsste, weil SBI und CBI weder Flags noch Arbeitsregister beeinflussen – man sollte es sich aber von Anfang an angewöhnen, es richtig mit Stapel zu machen, denn dabei lernt man die richtige Schreibweise des Pro- und Epilogs, die ja – wie bei einem Kartenstapel – in umgekehrter Reihenfolge vollführt werden muss, damit am Ende alles wieder an seinem Platz ist. Ferner macht man sich mit µControllern mit so kleinen Ressourcen in der Regel das Leben selbst unnötig schwer – in PDIP8 gibt es z.B. auch den ATTINY85, mit dem man weniger komische Akrobatik wegen Ressourcenmangel vollführen muss.
:
Bearbeitet durch User
Gregor J. schrieb: > Ferner macht man sich mit > µControllern mit so kleinen Ressourcen in der Regel das Leben selbst > unnötig schwer – in PDIP8 gibt es z.B. auch den ATTINY85, mit dem man > weniger komische Akrobatik wegen Ressourcenmangel vollführen muss. Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer wieder fasziniert, was mit diesem Minimalisten so alles möglich ist. Damit habe ich beispielsweise schon ein Bewässerungssystem mit kapazitivem Feuchtigkeitssensor gebastelt und dabei recht viel gelernt (minimaler Stromverbrauch, Watchdog, ADC). Oder diese billigst-Lichterketten mit einigen Blinkmustern (inklusive Morsebotschaft und z.B. auto-save des letzten Programms) versehen. Der Weg ist das Ziel, und nach oben geht's immer. Wenn man erst mal die Grundlagen kennt ist es ein leichtes, auch einen größeren der AVR-Familie zu verwenden (dann aber in C). Und wie gesagt - ich mache das nur als reines Hobby und bin sehr, sehr weit vom Profientwickler weg.
Stephan E. schrieb: > Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer > wieder fasziniert, was mit diesem Minimalisten so alles möglich ist. Ein sehr kleiner µController ist oft – zwar auf eine andere Art – aber dennoch genauso schwierig zu handhaben wie ein großer, vor allem in Assembler, wo alles sehr knapp bemessen ist, man für alles selbst sorgen muss und die Pinanzahl zusätzlich noch extrem begrenzt ist. Wie man gut sehen kann, bist Du hier schon einfach an einem Portpin eines Timers gescheitert, weil Dir die Grundlagen zu den Betriebsmodi fehlen, obwohl das alles sehr gut im Datenblatt erklärt und sogar mit Beispielen, Bildern und Zeitdiagrammen unterstützt wird. Normalerweise nimmt man am Anfang etwas Moderates aus der Mitte der Produktpalette, nichts Extremes – also weder zu klein noch zu groß – arbeitet sich dann nach und nach durch die Themen mit Oszilloskop und Voltmeter ausgestattet durch und kann dann bei Bedarf in der Regel auf etwas sowohl Kleineres als auch Größeres übergehen. Die ausgewogene Mitte bildet hier oft der ATMEGA328P – wenn man den vollständig durchgearbeitet und begriffen hat, kann man praktisch alle ATMEGAs und die älteren ATTINYs. Es gibt genügend Speicher, Portpins etc. – die ganzen besonderen, schwierigen Umstände für einen Assembler-Einstieg hat man hier nicht, man kann sich auf das Wesentliche konzentrieren. Und die hier in diesem Forum oft Verwendete Redewendung „ich hatte es gerade in der Bastelkiste” ist in so einem Zusammenhang völliger Unfug, denn man kann sich heutzutage für 2 Euro etwas Passenderes besorgen. ____________ > Wenn man erst mal die Grundlagen kennt (...) Das mit dem richtigen Gebrauch des Stapelspeichers sind Grundlagen, die man sich unbedingt zuerst aneignen sollte, und Du hast einfach nur Glück, dass es bei den AVRs per default keine verschachtelten Interrupts gibt, also wo innerhalb eines Interrupts ein weiterer ausgeführt werden kann, denn dann wärst Du mit dieser Methode Register zu retten bereits geliefert. Wenn man nicht weiß, wie es geht, kann man sich auch das vom Compiler generierte anschauen (im Anhang ein Beispiel), es gibt auch genügend Beispiele im Netz. Leider auch falsche – irgendein Guru macht etwas vor und alle ahmen und vervielfältigen seinen Blödsinn kritiklos nach – das Forum ist leider auch damit verseucht bzw. davon betroffen. ____________ > Und wie gesagt - ich mache das nur als reines Hobby und bin sehr, sehr > weit vom Profientwickler weg. Ob Hobby oder Professionell – Assembler und die Grundlagen dazu sind auf allen Ebenen gleich, auch die Fehler, die man damit machen kann, sind gleich, insofern kann das niemals eine Rechtfertigung für schlechte Angewohnheiten oder nicht durchgearbeitete Themen sein – es ist einfach eine Ausrede, ein Ausweichen. Viel Erfolg auf dem langen und steinigen Weg wünsche ich trotzdem.
:
Bearbeitet durch User
Hier noch ein Beispiel wie ein Mensch es schreiben würde, weil ein Compiler in der Regel immer einen unnötigen Überhang mit Null-Register etc. generiert – wenn man es selbst in Assembler schreibt, rettet man nur das, was auch wirklich in der Interruptroutine angefasst wird (und das ist ja bekannt, weil man es selbst schreibt), in der Regel also das Statusregister und die Register, die man verwenden möchte – je weniger man braucht, desto besser für die Performance und den Speichergebrauch, denn es wird alles auf dem Stapel abgelegt und später in umgekehrter Reihenfolge wieder dort abgeholt – nach dem Verlassen der ISR muss alles wieder so hergestellt worden sein, wie es vor dem Einsprung der Fall war. Da es bei diesen AVRs keine expliziten PUSH/POP-Befehle für das Statusregister gibt, muss das über ein Hilfsregister erledigt werden – dieses Hilfsregister muss dementsprechend vorher gerettet werden und beim Epilog muss das entsprechend wieder alles umgekehrt gemacht werden. Und wie ich bereits sagte, bei CBI und SBI bräuchte man eigentlich gar nichts retten, denn es sind sehr besondere Befehle, obendrein ist der Zugriff auch noch atomic (unteilbar), also extrem wichtig und nützlich.
:
Bearbeitet durch User
Gregor J. schrieb: > Stephan E. schrieb: >> Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer >> wieder fasziniert, was mit diesem Minimalisten so alles möglich ist. > > Ein sehr kleiner µController ist oft – zwar auf eine andere Art – aber > dennoch genauso schwierig zu handhaben wie ein großer, vor allem in > Assembler, wo alles sehr knapp bemessen ist, man für alles selbst sorgen > muss und die Pinanzahl zusätzlich noch extrem begrenzt ist. Wie man gut > sehen kann, bist Du hier schon einfach an einem Portpin eines Timers > gescheitert, weil Dir die Grundlagen zu den Betriebsmodi fehlen, obwohl > das alles sehr gut im Datenblatt erklärt und sogar mit Beispielen, > Bildern und Zeitdiagrammen unterstützt wird. Ja, stimmt. Mir hat einfach das "ODER" gefehlt, welches Du in Deinem Posting weiter oben genannt hast. Ich bin halt davon ausgegangen, daß ich den Pin per sbi/cbi auch im genannten ctc-Mode setzen oder löschen kann. Ich habe mich wohl geirrt, aber jetzt weiß ich's. > Das mit dem richtigen Gebrauch des Stapelspeichers sind Grundlagen, die > man sich unbedingt zuerst aneignen sollte Auch das ist richtig. Und ja, ich bin schon über einen nicht initialisierten Stackpointer oder ein vergessenes "pop" am Ende der Routine geflogen. > Viel Erfolg auf dem langen und steinigen Weg wünsche ich trotzdem. Danke, und das nicht zuletzt auch nochmal für Deine hilfreichen Antworten.
Gregor J. schrieb: > Wenn man nicht weiß, wie es geht, kann man sich auch das vom > Compiler generierte anschauen (im Anhang ein Beispiel) Wobei das Beispiel offenbar mit einem total veralteten Compiler (v7 oder älter) erstellt wurde und viele unnötige Instruktionen enthält. Ab v8 (Release 2018) ist das nicht mehr der Fall.
> Mir hat einfach das "ODER" gefehlt, welches Du in Deinem > Posting weiter oben genannt hast. Na, wir wollen festhalten: Gregor J. mag zwar sehr viel geschrieben haben, aber das "ODER", bzw. der entscheidende Hinweis, kam gleich zu Beginn und kurz gehalten von Jobst M.! Allenfalls könnte man noch den Abschnitt aus 'Compare Match Output Unit' ergänzen.
Johann L. schrieb: > Wobei das Beispiel offenbar mit einem total veralteten Compiler (v7 oder > älter) erstellt wurde und viele unnötige Instruktionen enthält. Ab v8 > (Release 2018) ist das nicht mehr der Fall. Das spielt keine Rolle, denn es geht darum zu zeigen, wie und was der Compiler macht, dass er die Register über den Stapelspeicher rettet, und richtig/konsistent ist es trotzdem, was der Compiler gemacht hat, egal wie viele unnötige Instruktionen hinzugefügt werden, was ich übrigens auch erwähnt habe, dass er das macht. Die Menge des Überhangs hängt auch immer davon ab, welche Optimierungsstufe man gewählt hat, was genau man in der ISR macht und wie umfangreich das ganze Programm selbst ist. Fürs Verständnis und zum Lernen ist das zweite Beispiel angefügt, wo gezeigt wird, wie ich es mit dem Statusregister und zwei Registern gemacht habe, weil ich auch nur zwei Register in der ISR benutze – man macht es in der Regel so, dass die Register immer wieder für verschiedene Aufgaben benutzt werden, um deren Anzahl insgesamt zu minimieren, denn dann wird es performant und man geht nicht so in die Tiefe mit dem Stapelspeicher, denn auch jede Subroutine bewirkt das, und wenn die Subroutinen auch noch verschachtelt werden, addiert sich alles zu einem Gesamtgebrauch, der bei einem kleinen SRAM, wo auch noch von unten nach oben Variablen platziert werden, zu Problemen führen kann, wo es dann bei zu großer Stack-Tiefe unglücklich zusammenlaufen kann.
:
Bearbeitet durch User
Stephan E. schrieb: > Auch das ist richtig. Und ja, ich bin schon über einen nicht > initialisierten Stackpointer oder ein vergessenes "pop" am Ende der > Routine geflogen. Der Stackpointer muss immer als erstes initialisiert werden (Beispiel von mir mit einem 16-Bit langen Pointer als Screenshot), das ist quasi der Startschuss im Programm, die Anzahl der PUSHs und POPs muss immer gleich sein und die Reihenfolge (wie bei einem Kartenstapel) in der ISR auch immer umgekehrt gemacht werden, damit alles am Ende passt, weil jeder Fehler sofort zum Absturz oder einer Fehlfunktion führen wird – das macht man aber mit dem Stapelspeicher seit mindestens 50 Jahren bei quasi allen Mikroprozessoren so, denn genau dafür wurde er von den Ingenieuren entwickelt und genau deswegen gibt es bei µControllern in der Neuzeit auch die entsprechenden Instruktionen im Befehlssatz und genau deswegen macht auch der Compiler davon Gebrauch. Wenn man es einmal richtig verstanden hat, ist es im Grunde genommen relativ einfach und man kann auch das schon einmal richtig Geschriebene in den eigenen, neuen Assemblerprojekten immer wiederverwenden, ggfs. auch leicht erweitern – das Muster ist immer gleich und man muss das Rad nicht immer wieder neu erfinden. Den Stapelspeicher kann man übrigens auch lokal und temporär als Zwischenspeicher benutzen, wenn es mit den Registern eng wird oder man Parameter an Subroutinen übertragen möchte; auch innerhalb von Subroutinen, um die Registerinhalte nicht zu zerstören – nach dem Gebrauch muss aber auch hier alles wieder konsistent in puncto Stack sein. ______ > Danke, und das nicht zuletzt auch nochmal für Deine hilfreichen > Antworten. Sehr gerne.
:
Bearbeitet durch User
Gregor J. schrieb: > Der Stackpointer muss immer als erstes initialisiert werden Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig. Selbst beim alten ATtiny13 zeigt er schon richtig auf 0x9F.
Jobst M. schrieb: > Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und > COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen > Einfluss mehr. Dafür gibt es auch die Bits FOC0A, FOC0B. Damit kann man ein sofortiges Compare Match erzwingen und so die Ausgänge setzen. "The OC0A output is changed according to its COM0A1:0 bits setting."
>> Der Stackpointer muss immer als erstes initialisiert werden > Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig. Aber auch z.B. noch beim ATmega16 und dessen Geschwistern (ATmega32, ATmega8).
Peter D. schrieb: > Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig. > Selbst beim alten ATtiny13 zeigt er schon richtig auf 0x9F. Darauf sollte man sich nicht verlassen, denn eines Tages erwischt es einen doch, d.h. man sollte das auch von Anfang an richtig lernen, selbst der Compiler macht das, er löscht sogar noch das Statusregister beim Start. Aber ich habe noch ein andere, wichtigere Nachricht für Dich & Co: wir sind hier nicht bei C und auch nicht beim Compiler, sondern beim Assembler, wo man alles selbst schreibt und auch alles selbst bestimmen darf, d.h. je nach Konzept möchte man den Stapel auch mal woanders im SRAM haben, nicht unbedingt an seinem Ende. Auch die eigenen Variablen darf man dort platzieren, wo es einem am besten passt – und das muss nicht immer der Anfang vom SRAM sein.
Gregor J. schrieb: > wir sind hier nicht bei C und auch nicht beim Compiler, sondern > beim Assembler, wo man alles selbst schreibt Besser gesagt: "... wo man den ganzen lästigen Verwaltungskram selber schreiben und überprüfen muß". Das war für mich einer der Hauptgründe, nicht länger Zeit mit Assembler zu vertrödeln.
Peter D. schrieb: > Das war für mich einer der Hauptgründe, nicht länger Zeit mit Assembler > zu vertrödeln. Für mich auch, ich war einfach müde davon und wollte mich auf das Wesentliche beim Programmieren konzentrieren. Hinzu kommt noch, dass man für komplexe Berechungen etc. einen enormen Zeitaufwand benötigt, um es zu schreiben – in C schreibt man die Berechnung einfach so hin in einer Zeile und der Compiler kümmert sich dann um den üblen Rest und der kann wirklich manchmal übel lang und kryptisch aussehen, wenn man sich das mal in der Assemblerdatei anschaut. Beim STM32 empfehle ich niemandem, irgendetwas in Assembler zu schreiben – wenn man es doch macht, was ja nicht verboten ist, wird man schon sehen (manchmal sehr selten sehen :), was man da angerichtet hat. Der Compiler kennt die Ausnahmen im Code und verwendet bestimmte Codeausdrücke bzw. Codekombinationen nicht, weil er mit den nötigen Informationen gefüttert wurde.
:
Bearbeitet durch User
Gregor J. schrieb: > selbst der Compiler macht das [...] beim Start. Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des internen RAMs, sondern auf den Wert des Symbols __stack (welches wiederum den default Wert auf das Ende des internen RAMs hat). Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird, deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der Anwender behält die Möglichkeit, __stack passend zu setzen.
:
Bearbeitet durch User
Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen, falls z.B. ein wilder Pointer über den Resetvektor läuft. Dann kann man z.B. eine Debugmessage versenden oder im EEPROM speichern, daß noch dringend nachgearbeitet werden muß.
Johann L. schrieb: > Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des > internen RAMs, sondern auf den Wert des Symbols __stack (welches > wiederum den default Wert auf das Ende des internen RAMs hat). > Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird, > deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der > Anwender behält die Möglichkeit, __stack passend zu setzen. Wenn der Wert default bleibt, was ja bekannt ist, bräuchte er das nicht machen, könnte das überspringen, was aber offensichtlich nicht so ist. Dann musst Du jetzt nur noch erklären, warum er das Statusregister nullt.
:
Bearbeitet durch User
Peter D. schrieb: > Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den > Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen, > falls z.B. ein wilder Pointer über den Resetvektor läuft. Abstürze geschehen nicht nur aufgrund von Programmierfehlern, sondern auch durch falsche Arbeitsbedingungen, die unerwartet (oder auch durch Unwissen und/oder Fahrlässigkeit des Entwicklers) eintreten können – z.B. das temporäre Absinken der Versorgungsspannung bei ungünstigen Umgebungstemperaturen, wo es dann bei zu hoher Arbeitsfrequenz zu Flashlesefehlern und dementsprechend unkontrolliertem Lauf über den ganzen Programmspeicher kommen kann. Nicht richtig oder ordnungsgemäß angeschlossene Quarze können auch scheinbar magische oder unerklärliche Taten diesbezüglich vollbringen.
:
Bearbeitet durch User
Gregor J. schrieb: > Johann L. schrieb: >> Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des >> internen RAMs, sondern auf den Wert des Symbols __stack (welches >> wiederum den default Wert auf das Ende des internen RAMs hat). >> Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird, >> deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der >> Anwender behält die Möglichkeit, __stack passend zu setzen. > > Wenn der Wert default bleibt, was ja bekannt ist, bräuchte er das nicht > machen, könnte das überspringen, was aber offensichtlich nicht so ist. Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen zu linken (oder eben nicht). Oder wie sollte der Startup Code der AVR-LibC umgeschrieben werden, um dies zu erreichen?
Johann L. schrieb: > Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es > ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen > zu linken (oder eben nicht). Also ich schon. Beim Atmel-Assembler ist das überhaupt kein Problem. Schon deshalb, weil es da keinen Linker gibt und auch keinen braucht. Es gibt da nur einen (hoffentlich) kompetenten Programmierer. Und wenn es den gibt, dann kontrolliert er mit den Sprachfeatures des Assemblers die gesamte Codegenerierung. Natürlich u.A. auch, ob ein bestimmter Programmteil abhängig vom Wert oder der Existenz eines Symbols übersetzt wird oder nicht. Und das genügt. Der unnütze Schritt des "Linkens" entfällt hier ja komplett.
Hi Weil es deine Aussage >Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es >ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen ad absurdum führt. MfG Spess
Im GNU Assembler ist das auch kein Problem, sofern das Symbol zur Assembler Zeit bekannt ist. Es ist aber erst zur Link Zeit bekannt, ein Konzept, das nicht mal existiert im Atmel Assembler. Von daher sehe ich nicht, wie Nennung des Atmel Assemblers weiter helfen könnte wie so ein Feature (bedingte Codeerzeugung abhängig von einem erst zur Linkzeit bekannten Symbol) mit den GNU Tools zu realisieren ist.
:
Bearbeitet durch User
Gregor J. schrieb: > Peter D. schrieb: >> Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den >> Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen, >> falls z.B. ein wilder Pointer über den Resetvektor läuft. > > Abstürze geschehen nicht nur aufgrund von Programmierfehlern, sondern > auch durch falsche Arbeitsbedingungen, die unerwartet (oder auch durch > Unwissen und/oder Fahrlässigkeit des Entwicklers) eintreten können – > z.B. das temporäre Absinken der Versorgungsspannung bei ungünstigen > Umgebungstemperaturen, wo es dann bei zu hoher Arbeitsfrequenz zu > Flashlesefehlern und dementsprechend unkontrolliertem Lauf über den > ganzen Programmspeicher kommen kann. Nicht richtig oder ordnungsgemäß > angeschlossene Quarze können auch scheinbar magische oder unerklärliche > Taten diesbezüglich vollbringen. Solange Fehler nur außerhalb der von Dir geschriebenen Software passieren können, wünsche ich Dir schon mal viel Spaß bei der Zielerreichung. Ich finde auch nach 40J programmieren die Fehler zu 99.999% in meinem Code und nicht im Compiler/Betriebssystem/Hardware.
Carl D. schrieb: > Solange Fehler nur außerhalb der von Dir geschriebenen Software > passieren können, wünsche ich Dir schon mal viel Spaß bei der > Zielerreichung. > Ich finde auch nach 40J programmieren die Fehler zu 99.999% in meinem > Code und nicht im Compiler/Betriebssystem/Hardware. Die Textinhalte zu verdrehen ist einfach, sie aber richtig zu deuten und zu verstehen, erfordert schon etwas Anstrengung – vielleicht solltest Du da erstmal ansetzen und mit der Fehlerfindung dort beginnen.
Das ein oder andere Grundlagenbuch kann schon hilfreich sein. Oft haben die auch einen didaktischen Aufbau und andere Goodies, so dass man gewisse Schritte gut verdauen kann und am Ende schneller lernt und mehr gelernt hat.
Stephan E. schrieb: > Grüß Gott zusammen, > > es geht um einen attiny13a und den CTC-Mode (Assembler). > Ziel ist es, den Port PB0 bzw. OC0A kurz ein- und dann wieder > auszuschalten. > Dazu wird der timer0 im CTC-Mode verwendet. Das funktioniert auch im > Simulator, aber nicht auf einem echten Chip, wenn ich das über COM0A0=1 > und COM0A1=1 mache. > Anbei zwei Codes - der eine mit, der andere ohne gesetztes COM0A0 bzw. > -1. > > Aus dem Datenblatt: > Compare output mode, non-PWM Mode: > WGM01=1, COM0A0=1 und COM0A1=1 => CTC-Mode mit "Set OC0A on Compare > Match" > > Wenn ich nur WGM01=1 setze und den Pin PB0 über die Interrupts der > compare-matches oc0a und oc0b setze, läuft alles wie erwartet, sowohl im > Simulator als auch auf echter Hardware. Im anderen Fall bleibt der Pegel > auf einem echten Chip am Port PB0 permanent high, im Simulator zeigt das > Oszilloskop jedoch in beiden Fällen genau das gleiche. > > Beide Codes sollten vom Ergebnis her genau das gleiche liefern, oder? > Beim einen setze ich den Port manuell, beim anderen sollte das > automatisch gemacht werden. > Die Frage ist - was mache ich beim Code "funktioniert nicht" falsch? ALso: CTC MODE werden die COMBits nur zum setzen genutzt heißt aktiver Zustand bleibt bis Manuell die Bits irgendwann negiert. im CTC Modus ist ein toggeln nicht vorgesehen oder PWM Mode denn ein Spike ist nichts weiter als Tastverhältnis togglen ist vorgesehen oder Timer MODE 0!! Timer läuft immer durch und toggelt bei erreichen von OCRx das jeweilige Bit. https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATtiny13A-Data-Sheet-DS40002307A.pdf ab Seite 76-79 able 11-8. Waveform Generation Mode Bit Description 0 0 0 0 Normal 0xFF Immediate MAX 1 0 0 1 PWM (Phase Correct) 0xFF TOP BOTTOM 2 0 1 0 CTC OCRA Immediate MAX 3 0 1 1 Fast PWM 0xFF TOP MAX 4 1 0 0 Reserved – – – 5 1 0 1 PWM (Phase Correct) OCRA TOP BOTTOM 6 1 1 0 Reserved – – – 7 1 1 1 Fast PWM OCRA TOP TOP Table 11-2. Compare Output Mode, non-PWM Mode COM0A1 COM0A0 Description 0 0 Normal port operation, OC0A disconnected. 0 1 Toggle OC0A on Compare Match !!!!!!!!!! 1 0 Clear OC0A on Compare Match 1 1 Set OC0A on Compare Match Hinweis https://www.roboternetz.de/community/threads/67800-Tiny-2313-Bibliothek hier mal einfach die Struktur anschauen denn in deinem CODE ist OCRB gesetzt obwohl das DDR dazu nicht genutzt wird ebenso die COM0By:x... Absicht?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.