PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ein paar Fragen zum Timer !!!



Nicole01
08.02.2017, 21:57
Hallo zusammen,

ich bin die neue hier :cheesy:

Habe ein paar Fragen an euch Profis.

Und zwar möchte ich gerne mit dem 8-bit Timer von einem Attiny85 ein Signal erzeugen.
Es soll ein PWM Signal sein mit 1 kHz.

Signale kann ich bereits erzeugen nur leider nicht die richtigen :(
Jetzt meine Frage an euch:

Für ein 1 kHz Signal sollte man doch den Fast PWM Modus wählen richtig ?
Reicht es wenn ich die Takt Frequenz vom Attiny im Code setze oder muss ich noch etwas in den Fuses verändern ?

Kann mir vielleicht auch jemand genau erklären wie ich am einfachsten auf die richtige Wunsch Frequenz komme ?
Damit meine ich, gibt es keine einfache Rechnung um das ganze leicht zu errechnen?

Es gibt so viele Formeln, nur so ganz leicht zu verstehen finde ich sind die nicht :MistPC

Ich würde mich sehr freuen wenn Ihr mir weiter Helfen könntet.

Vielen Dank im Voraus.

Nicole

Ceos
09.02.2017, 06:08
ein Timer braucht einen Takt, der Takt durchläuft einen sog. Prescaler, der den Takt herunterteilt (siehe Datenblatt für die Divisoren des verwendeten Timer).

Wenn du also einen 1MHz Takt hast und einen Prescaler von 1, zählt dein Timer 1 Schritt pro Takt also 1 mio Schritte pro Sekunde.

Ein 8bit Timer kann 2^8 = 256 Schritte machen und läuft dann über. Im Fast PWM bedeutet das wenn du Set on Overflow und Clear on Compare benutzt dass dein Ausgang alle 256 Schritte auf An gesetzt wird und je nachdem wie du dein Compare Register programmierst länger oder kürzer an bleibt bis Count == Compare ist.

Du kannst auch Toggle on Overflow/Compare benutzen, dann schaltet dein Ausgang immer um wenn er einmal durchgelaufen ist.

Angenommen wir machen Clear on Compare mit Prescale 1: 1.000.000 Takte/Sekunde / 256 Takte/Überlauf = 3906,25 Überläufe pro Sekunde

also 3.9kHz ca.

das ist ziemlich krumm ... nehmen wir mal statt Fast PWM & Overflow on Top die Konfiguration PWM & Overflow on Input Compare!
Damit kannst du über das Input Capture Register einstellen WANN er überlaufen soll ... manchmal benutzt er dafür auch einen der Output Compare Register für den Timer, das kommt auf den Chip und den Timer an, siehe Datenblatt.

Setzen wir den Overflow also auf 250 (denk dran, dass der Timer immer genau EINEN Prozessortakt braucht wenn er den Zielwert erreicht hat um das REgister auf 0 zu setzen BEVOR er weiter zählt)

Input Capture = 248 (von 0 bis 248 sind es 249 Takte + den Reset Takt = 250)

1.000.000 / 250 = 4000

das sind schonmal solide 4kHz

Also nehmen wir einen Prescaler von 4 (sofern verfügbar) 1.000.000 / 4 => 250.000 / 250 = 1000

Wunderbar ... FAST ... der Prescaler ist 4 damit sind es 4 Takte pro Zählschritt, das Nullsetzen braucht aber nur EINEN Takt, also sind es nicht mehr 250 Schritte sondern 249.25 ... aber der Oszillator hat in der Regel auch einen gewissen Fehler, also kannst du mit Hilfe des Input Capture und einem Oszilloskop ein wenig nachtrimmen wenn du es exakt brauchst.

Nicole01
09.02.2017, 08:17
Guten Morgen Ceos,

vielen vielen Dank für deine Mühe.

Habe das ganze jetzt schon ein wenig mehr verstanden.

Ich zeige Euch mal meinen Code mit dem ich eigentlich ein 1 kHz Signal erzeugen wollte.


#include <avr/io.h>
#define F_CPU 1000000


int main(void)
{
DDRB |= (1<<PB1);
OCR0A = 999;
OCR0B = 370;

TCCR0A = (1<< COM1A1) + (1<< WGM01) + (1<< WGM00);
TCCR0B = (1<<WGM01) + (1<< WGM02) + (1<< CS13);

while (1)
{
asm ("NOP");
}
}



Laut Datenblatt stehen mir diese Prescaler Optionen zur Verfügung 2,4,8,16,32,64,128,256.
Habe ich das richtig erlesen ?

Ich teste jetzt deine Tips und melde mich später wieder.

Viele Grüße und vielen Dank.

Nicole

wkrug
09.02.2017, 08:27
Brauchst Du tatsächlich eine PWM, oder würde auch ein symetrisches 1kHz Signal reichen?
Dazu könnte man einen normalen PWM Modus nehmen und den Timer mit der CTC Option zurücksetzen.
Das bedeutet der Timer läuft bis zum Wert des Comparematch Registers und wird dann auf 0 gesetzt.
Dadurch wird dann der Ausgang OCxx getoggelt.
Damit ist dann die Frequenz des des symetrischen Ausgangssignals in Grenzen einstellbar.

Fast PWM nehm ich persönlich nicht so gerne, weil immer ein kleiner Spike übrig bleibt auch wenn das Comparematch Register auf 0 steht -
Beziehungsweise bei inverse PWM immer eine kleine Lücke im Ausgangssignal bleibt.

Ceos
09.02.2017, 08:37
da sehe ich schon mal die ersten Fehler, wahrscheinlich nicht kritisch, aber das ist Prozessorspezifisch nicht ungefährlich

du verwendest die Timer1 Flags in den Timer0 Registern COM1A1 ist für Timer1 du brauchst COM0A1 für TCCR0

Die Config sagt mir Fast PWM mit OCRA als TOP und OCRB als COMPARE ... aber du hast OCR1A als Ausgang konfiguriert, was nicht geht weil du Timer 0 verwendest und obendrein das OCRA Register durch die TOP Funktion blockierst! Du musst COM0B1 setzen und OC0B auf PB1 benutzen(Glücklicherweise zufällig derselbe Pin).

Im TCCR0B Register gibt es das WGM01 Flag garnicht, das gehört da nicht hin und CS13 gehört ebenfalls nicht zum Timer0 sondern Timer1 bzw. e gibt garkein CSx3 Flag, keine ahnung wieso der das überhaupt akzeptiert.

also:



TCCR0A = (1<<COM0B1) + (1<<WGM01) + (1<<WGM00)
TCCR0B = (1<<WGM02) // + gültige CS Bits


WTF ... dein Compiler sollte dich eigentlich mit Warnings erschlagen

Du verwendest einen 8Bit Counter der bis 256 Zählen kann und fütterst ihn mit Werten wie 999 und 370? Das KANN nicht gehen

EDIT: Der Vollständigkeit ein theoretisch funktionierender Code :)


DDRB |= (1<<PB1);
OCR0A = 124; //siehe Rechenbeispiel in vorhergehendem Post und es gibt nur einen /8 Prescaler leider
OCR0B = 63; //ca. 50% Duty Cycle
TCCR0A = (1<<COM0B1) + (1<<WGM01) + (1<<WGM00);
TCCR0B = (1<<WGM02) + (1<<CS01); //WGM 111 (fast pwm), clear on match, set on bottom, PS /8


PPS: Sowas gibts bei mir nur ganz selten dazu, aber ich hab eh schon fast alles haarklein erklärt :)

PPPS: Fehler beim OCR0A REgister korrigiert ... hab die 0 nicht mitgezählt

Nicole01
09.02.2017, 08:44
Hallo wkrug,

danke für deine Antwort.

Es gibt ja mehrer PWM Moduse.
Ich dacht mal gelesen zu haben das wenn man eine hohe Frequenz erzeugen möchte es nötig sei den Fast PWM Modus zu nutzen.

Ist das falsch gedacht ?
Gerne versuche ich auch deine Version.

Nur glaube ich wäre es für mich auch sehr gut, wenn ich endlich verstehen würde wie man auf die gewünschte Frequenz kommt :Haue

Vielen Dank

Nicole

Searcher
09.02.2017, 08:58
Nur glaube ich wäre es für mich auch sehr gut, wenn ich endlich verstehen würde wie man auf die gewünschte Frequenz kommt :Haue


Hallo,

ich versuche mich mal an einer Erklärung - für die Fast-PWM.

Der Timer Counter (TCNT) eines 8-Bit Timers durchläuft im Normalmodus den Wertebereich eines 8-Bit Binärzahl, also von 0 bis 255.

Wie schnell er das macht, hängt von dem Systemtakt und dem Vorteiler ab (mal abgesehen von der Taktung des Timers durch einem externen Takt).

Jeder Taktimpuls, der den Timer erreicht, erhöht den TCNT um eins. Es braucht also 256 Timertakte um einen kompletten Timerzyklus im Normalmodus und auch im Fast-PWM Modus zu durchlaufen.
TCNT = 0 nach TCNT = 1 -> 1 Takt, 1 Takt total
TCNT = 1 nach TCNT = 2 -> 1 Takt, 2 Takte total
.
.
TCNT = 254 nach TCNT = 255 -> 1 Takt, 255 Takte total
TCNT = 255 nach TCNT = 0 -> 1 Takt, 256 Takte total -> TCNT Turn von 0 nach 0 nenne ich mal einen "Timerzyklus"

Bei einem Systemtakt von 1MHz und einem Vorteiler (Prescaler) von 1 wird der TCNT mit einer Frequenz von 1Mhz um 1 erhöht. Für einen Timerzyklus braucht er 256 Takte, die Timerzyklenfrequenz ist also 1000000Hz/256 = 3906,25Hz. Ist höher als Deine geforderten 1kHz. Kann man auch nicht so ohne Weiteres per CTC (Clear Timer on Compare) tiefer machen.

Also erstmal mit Prescaler den Timertakt heruntersetzten. Nach Datenblatt vom ATtiny85 ist der nächste Prescalerwert des Timers 0 nach 1 die 8. Damit erreicht man eine Timerzyklusfrequenz von (1000000Hz/8 )/256=488,28125Hz. Zu langsam! Bekommt man aber schneller, wenn man den CTC Modus einschaltet und in ein Compareregister den entsprechenden Wert hineinschreibt. TCNT läuft dann nur noch bis zu dem Comparewert bevor auf 0 gesetzt wird. Die Timerzykluszeit wird also schneller.

Der Timertakt mit dem Prescaler 8 ist 1MHz/8=125000Hz und eine Periode dauert dann 1/125000Hz=8µs. Alle 8µs wird also der TCNT um eins erhöht. Um auf eine Timerzyklusfrequenz von 1kHz zu kommen, muß die Timerzykluszeit 1/1kHz=1000µs sein. Dazu braucht der TCNT 1000µs/8µs=125 Zählschritte.

Also CTC Modus zum Fast-PWM einschalten und 124 ins Compareregister eintragen (Der 125ste Schritt kommt durch den Schritt von 124 nach 0 zustande). Das andere Compareregister dient dann zur Einstellung der Pulsweite.

Gruß
Searcher

Ceos
09.02.2017, 09:19
Der 125ste Schritt kommt durch den Schritt von 124 nach 0 zustande
whoops Panne XD hab ich in meiner Antwort oben total vergessen :D

Nicole01
09.02.2017, 12:45
Danke für die anderen Antworten und eure Hilfe.

Bitte nicht gleich sauer sein aber so ganz verstehe ich das immer noch nicht :(

Ich hätte dazu bitte noch ein paar Fragen.

Wie oben schon gefragt, reicht es wenn ich die Takt Frequenz vom Attiny im Code eintrage oder muss ich auch noch etwas in den Fuses verändern?
Als nächstes würde mich Interresieren wo Ihr genau die ganzen Daten aus dem Datenblatt herbekommt ? :confused:

Damit meine ich sind das immer die gleichen Stellen die Wichtig sind ?
Z.b. Seite 10, 33, 52, 63 usw ( ist nur ein Beispiel )

Die CS Bits bestimmen die Quelle für den Timer/Counter richtig ?
Ist das auch gleichzeitig der Prescaler ?


Auch verstehe ich die Berechnung der Frequenz noch nicht ganz.

Wie genau hast Du das berechnet ?
Timerzyklusfrequenz von (1000000Hz/8 )/256=488,28125Hz

Ich verstehe es nur soweit, der Systemtakt beträgt 1Mhz ( 1000000 ) jetzt rechnet Ihr 1000000:256=3.906,25
Gut nur wie kommt Ihr auf dieses Ergebniss ?
(1000000Hz/8 )/256=488,28125Hz ???

Wie lautet hier der genaue Rechnungsweg ?

Entschuldigung für meine vielen Fragen :cry:

Ceos
09.02.2017, 13:10
in deinem konkreten Fall (angenommen wir haben dasselbe Datenblatt und nicht nur die "Summary" ... Dokumentnummer ist atmel-2586)

Kapitel 11.9 Register Description

11.9.2 TCCR0A – Timer/Counter Control Register A und folgend

Da sind die Bits beschrieben die die Ausgänge und den Countermodus steuern.

11.9.3 TCCR0B – Timer/Counter Control Register B und folgend

gehört immer zu dem anderen Register dazu, im konkreten Fall ist das WGM02 Bit Teil vom B-Register

Hier steht unter anderem auch welche Prescaler es gibt und wie sie ausgewählt werden.

Nicole01
09.02.2017, 13:31
Vielen Dank für deine Antwort.

Das Datenblatt ist das gleiche.
Danke für die Informationen.

Das habe ich soweit alles gefunden.
Nur z.B. auf Seite 80 sind die CS Bits zu finden.

Habe den Code jetzt geändert und das CS Bits 01 gewählt.
Frequenz ist auf fast genau 1 kHz ;) Vielen Dank.

Nur auf der Seite 83 steht auch was über CS Bits.
Aber diese kann ich doch bei meinem Attiny nicht nutzen ?

Vielen Dank mal wieder.

Nicole

Ceos
09.02.2017, 13:41
doch doch sicherlich, aber nur mit Timer1

Das ist Kapitel 12 Timer1 und nicht Kapitel 11 Timer0

Daher hab ich auch darüber gestutzt, dass du im TCCR0A die Bits für TCCR1A verwendet hast und im TCCR0B Das Bit für TCCR1B

Du hattest da wohl die beiden Timer ausversehen in einen Topf geworfen ... Wenn du dir die REgister ud die Bits ansiehst, merkst du auch schnell dass die Bits des T0 garnicht die gleiche Position haben im Register wie beim T1

PS: Als Faustformel bei Atmels gilt der Timer0 ist meistens am Funktionsärmsten aber dafür sind die Funktionen und Register fast überall gleich ... Den Code auf einen andern Controller zu wechseln geht also quasi ohne Änderungen ... alle weiteren Timer haben bei den unterschiedlichen Atmel Prozessoren alle ihre eigenheiten und müssen von Controller zu Controller anders programmiert werden

Nicole01
09.02.2017, 13:57
Danke für die Info.

Ja so ganz flüssig läuft es noch nicht #-o

Nochmals zu den CS Bits und den Prescaler.
Ist das jetzt das gleiche oder nicht ?

Ich glaube wenn man es mal verstanden hat ist es leicht.
Nur bis man es mal verstanden hat ist es sehr schwer ;)

Auch wäre es nett, wenn Ihr mir bitte nochmals irgendwie genauer sagen könntet wie Ihr die genau Frequenz berechnet ?

Searcher
09.02.2017, 14:07
Hallo,
da es Datenblätter zum ATtiny in verschiedenen Revisionen gibt, hier ein Link zu Atmel, damit wir das gleiche benutzen (Rev. 2586Q–AVR–08/2013): http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf
Gefunden über Google mit Suchbegriffeingabe: attiny85



Wie oben schon gefragt, reicht es wenn ich die Takt Frequenz vom Attiny im Code eintrage oder muss ich auch noch etwas in den Fuses verändern?
Ein nagelneuer, frisch gekaufter ATtiny85 ist auf einen Systemtakt von 1Mhz eingestellt: Interner Oszillator mit 8MHz, der durch die CKDIV8 Fuse im System Clock Prescaler (nicht Timer Prescaler) auf ein achtel, also auf 1MHz herabgesetzt wird (Datenblatt: "6.2.3 Calibrated Internal Oscillator" und "Table 20-5. Fuse Low Byte")



Als nächstes würde mich Interresieren wo Ihr genau die ganzen Daten aus dem Datenblatt herbekommt?
Ich schreib es dazu aber es wird Dir nicht erspart bleiben, jede Zeile, jede Tabelle und jede Fußnote selbst zu durchforsten, da so ein Datenblatt wirklich ganz gedrängt in jedem Buchstaben relevante Informationen beinhaltet :-)



Die CS Bits bestimmen die Quelle für den Timer/Counter richtig?
Ist das auch gleichzeitig der Prescaler?
Ja. Für Timer 0 gibt es im Datenblatt das Kapitel 11 und dort zum "11.9.3 TCCR0B" die Tabelle "Table 11-6. Clock Select Bit Description" Für Timer 1 in Kapitel 12 sieht die entsprechende Tabelle anders aus.



Wie genau hast Du das berechnet ?
Timerzyklusfrequenz von (1000000Hz/8 )/256=488,28125Hz
Ich bin von den Factory Default Einstellungen ausgegangen: 1MHz Systemtakt, bei den Timern in den Tabellen und im Blockdiagramm "Figure 6-1" wird er clk i/o genannt. Den Timerprescaler habe ich mit acht angenommen, da eins ja einen zu schnellen Zähltakt erzeugt hat. Also 1MHz geteilt durch acht ergibt 125000. 125000 geteilt durch die 256 Zählschritte für einen Timerzyklus ergibt die 488,28125Hz.



Ich verstehe es nur soweit, der Systemtakt beträgt 1Mhz ( 1000000 ) jetzt rechnet Ihr 1000000:256=3.906,25
Ja, aber mit dem angenommenen Timerprescaler von eins ist der Timerzyklus zu schnell für Deine geforderten 1kHz. Eigentlich ist die Rechnung (1000000/1)/256. Die 1 für den Timerprescaler eins habe ich vorher weggelassen.



Gut nur wie kommt Ihr auf dieses Ergebniss ?
(1000000Hz/8 )/256=488,28125Hz ???
Weil mit Timerprescaler von 1 der Takt zu schnell war, wird hier der Prescaler von 8 hergenommen. Die 8 muß also später mit den CS Bits eingestellt werden und nicht die 1.



Auch wäre es nett, wenn Ihr mir bitte nochmals irgendwie genauer sagen könntet wie Ihr die genau Frequenz berechnet ?


Ich kann es nicht genauer. Dieser und mein letzter Post haben mich erschöpft. Besser Du fragst konkret, was Du nicht verstanden hast.

Gruß
Searcher

Nicole01
09.02.2017, 17:06
Searcher,

mal wieder vielen Dank für deinen langen Text und deiner Mühe.

Wie man das ganze jetzt ausrechnet verstehe ich zu 80%.
Mein Problem ist nur, wie berechne ich die Frequenz die ich möchte ?

Z.b. 2,3 kHz ?
Oder 200 Hz ?

Im Datenblatt habe ich bei Timer0 diese Werte gefunden.
CS00, CS01, CS02
8, 64, 256, 1024

Ob ich die 1024 nutzen kann, bin ich mir nicht ganz sicher da ja hier kein CS mehr zu finden ist für 1024?

Jetzt zur Frequenz, der Attiny läuft mit 1MHz und er läuft alle 256 Schritte wegen dem 8 Bit Timer über.
Die 256 Schritte sind immer gleich und der 8 Bit Timer auch das kann ich ja nicht beeinflussen habe ich das soweit richtig verstanden ?

Wenn ja könnte ich nur die Geschwindigkeit vom Attiny ändern ( MHz ) oder den Prescale soweit richtig ?
Die Geschwindigkeit werde ich am Anfang nicht ändern !!!

Somit bleibt mir ja nur zur Berechnung der Frequenz die 1 MHz die 256 Schritte bis zum Überlauf und der Prescale.

Ich glaube ich denke einfach viel zu viel :shock:

Vielen Dank mal wieder.

Nicole

wkrug
09.02.2017, 17:28
Somit bleibt mir ja nur zur Berechnung der Frequenz die 1 MHz die 256 Schritte bis zum Überlauf und der Prescale.
Das hast Du genau richtig erkannt, aber so ein Timer kann ja noch mehr.
Da kommt nun der CTC Modus ins Spiel.
Man schreibt einen Wert in eins der OCR Register und aktiviert den CTC Mode. Der Timer TCNTx wird auf 0 gesetzt, wenn dieser Wert erreicht ist.
Dadurch kann man Frequenzen erzeugen, die der Timer durch den Takt und Prescaler nicht erreichen kann.
Ob das mit CTC und OCRxA und OCRxB zur Erzeugung von fast PWM, wie es im Beitrag #7 beschrieben wird, hab ich leider noch nicht ausprobiert.

Searcher
10.02.2017, 05:45
Searcher,
mal wieder vielen Dank für deinen langen Text und deiner Mühe.
.
Vielen Dank mal wieder.

Alles klar, für mich reicht das für den Rest meiner Beiträge ;):)



Wie man das ganze jetzt ausrechnet verstehe ich zu 80%.
Mein Problem ist nur, wie berechne ich die Frequenz die ich möchte ?

Z.b. 2,3 kHz ?
Oder 200 Hz ?
Die Frage ist eigentlich falsch gestellt, oder? Du gibst ja die Frequenz vor und möchtest die Konfigurationsparameter für den Timer finden. Da Du nur eine bekannte Größe hast, nämlich die gewollte Frequenz, must Du die anderen für den Timer selbst vorgeben.

Ich habe das in meinem ersten Post gemacht, indem ich den Systemtakt mit 1MHz angenommen habe. Dann habe ich den Timer Vorteiler, der mit den CS Bits eingestellt wird mit 8 angenommen. Mit Vorteiler = 1 ging Deine 1kHz im Fast-PWM nicht einzustellen. Mit Vorteiler = 8 ergab sich aber noch nicht genau die 1kHz. Deshalb noch den CTC Modus zur Hilfe genommen. (Datenblatt: 11.7.2 Clear Timer on Compare Match (CTC) Mode)

Man rechnet es sich also nicht direkt aus, sondern probiert gewissermaßen ein Stück weit in den Rechnungen mit den zur Verfügung stehenden Möglichkeiten des µC und kann dann mit den Gleichungen aus dem Datenblatt zurückrechnen, ob man richtig liegt. (Datenblatt Gleichungen stehen in den Unterkapiteln zu "11.7 Modes of Operation")



Im Datenblatt habe ich bei Timer0 diese Werte gefunden.
CS00, CS01, CS02
8, 64, 256, 1024

Ob ich die 1024 nutzen kann, bin ich mir nicht ganz sicher da ja hier kein CS mehr zu finden ist für 1024?

Stimmt fast, aber die Frage verstehe ich nicht. Grundlage zur Einstellung des Vorteilers für Timers 0 ist die "Table 11-6. Clock Select Bit Description" im Kapitel "11.9.3 TCCR0B – Timer/Counter Control Register B".

Im TCCR0B Register setzt man:
für Voteiler 8 das Bit CS01
für Voteiler 64 die Bits CS01 und CS00
für Voteiler 256 das Bit CS02
für Voteiler 1024 die Bits CS02 und CS00

also nicht ein CS Bit für einen Vorteilerwert; es werden auch Kombinationen von den CS Bits genutzt und es gibt auch den Vorteilerwert 1 mit dem Bit CS00, der in Deiner Aufzählung der Prescaler Werte fehlt.



Jetzt zur Frequenz, der Attiny läuft mit 1MHz und er läuft alle 256 Schritte wegen dem 8 Bit Timer über.
Die 256 Schritte sind immer gleich und der 8 Bit Timer auch das kann ich ja nicht beeinflussen habe ich das soweit richtig verstanden ?
Nein. Die 256 ist der Maximalwert. Der kann im CTC Modus veringert werden. Bitte Kapitel 11.7 Modes of Operation und speziell oben erwähntes Kapitel über den CTC Modus lesen.



Somit bleibt mir ja nur zur Berechnung der Frequenz die 1 MHz die 256 Schritte bis zum Überlauf und der Prescale.
Die 1MHz Systemtakt, OK! Würde ich auch erstmal nicht ändern.
Die 256 Schritte sind nicht fix. Siehe CTC Modus
Prescale, ja.
Aber es gibt noch die verschiedenen Moden des Timers. Kapitel 11.7. Der von wkrug erwähnte "11.7.4 Phase Correct PWM Mode" wird anders berechnet und läßt tiefere Frequenzen als Fast PWM zu.

Hier noch was zum Lesen aus dem Roboternetz-Wissen: http://rn-wissen.de/wiki/index.php?title=Timer/Counter_(Avr)
Ist für einen ATMega aber das Prinzip ist das Gleiche.

Gruß
Searcher

Nicole01
10.02.2017, 19:34
Hallo Searcher,

vielen vielen Dank für deine Mühe !

Ich glaube ich habe es jetzt verstanden ( Hoffe ich )

Wenn ich eine Frequenz von 1400 kHz benötige wären das 88 bei einem Prescaler von 8.
Ich hoffe das ist so richtig ;)

Bei 2100 kHz müssten es 53 sein.


Viele Grüße

Nicole

Searcher
11.02.2017, 06:42
Ich hoffe das ist so richtig ;)
:nö::(


Wenn ich eine Frequenz von 1400 kHz benötige wären das 88 bei einem Prescaler von 8.
Also wenn die 88 der Wert für den Maximalwert des Timers im CTC Modus sein soll, ist es vermutlich durch einen Flüchtigkeitsfehler trotzdem total falsch. Angenommener Flüchtigkeitsfehler bereinigt, ist die 88 der Wert, mit dem man der gewünschten Frequenz am nächsten kommt.\\:D/



Bei 2100 kHz müssten es 53 sein.
Gleicher Flüchtigkeitsfehler (?) und man kann mit einem anderen Wert als 53 wesentlich näher an die gewünschte Frequenz heran kommen.

Wenn Du die Rechnung mitlieferst und auch die Einheiten mit aufschreibst, kann man besser erkennen, wo der Hase im Pfeffer liegen könnte.

Das wird aber schon. Ich habe selbst viel durch ausprobieren "erforscht". Also einfach Programm in den µC und nachgeschaut was da raus kommt. Ich kenne Deinen Hintergrund und Deine Möglichkeiten nicht. Hier wäre ein Oszilloskop, Frequenzzähler oder ähnliches hilfreich. Bei den geringen Frequenzen täte es auch ein Soundkartenoszi.

Gruß
Searcher

Nicole01
11.02.2017, 12:44
Hallo Searcher,

danke für deine Antwort.

Ich habe die 1000000:8 und dan 125000:1400=89
Bei den 89 habe ich 1 abgezogen ( so wie Ihr mir das gesagt habt )

Somit kamm ich auf 88.

Du hast mir ja noch einen Link gegeben.

Dort steht:

( Nun wird mathematisch überprüft, ob der errechnete Wert aus dem vierten Punkt kleiner als der maximale Zählerwert ist. Trifft dies zu, so wird der errechneten Wert vom maximalen Zählerwert subtrahiert )

Wenn ich das so machen muss, würde bei mir ein Wert von 167 raus kommen.

Ein Oszilloskop zum testen habe ich hier.
Gestern habe ich es auch genau so gemacht wie Du es geschrieben hast.

Immer ein wenig probiert und sofort am Oszilloskop das Ergebniss angeschaut.

Nur leider gibt mein Attiny45 aus irgend einem Grund keinen Wert mehr aus ?
Habe es auch schon mit einem ganz neuen Attiny versucht.

Genau das leiche Problem.
Kann über den Port LED blinken lassen oder auch einen Taster steuern.

Nur das PWM Signal kommt nicht mehr raus.

Im Code kann ich keinen Fehler finden.
Bzw mit diesem Code hat es ja auch ohne Probleme funktioniert.


#include <avr/io.h>
#define F_CPU 1000000


int main(void)
{
DDRB |= (1<<PB1);
OCR0A = 124;
OCR0B = 63;

TCCR0A = (1<< COM0B1) + (1<< WGM01) + (1<< WGM00);
TCCR0B = (1<<WGM02) + (1<< CS01);

while (1)
{
asm ("NOP");
}
}

Vielen Dank mal wieder für die nette Hilfe.

Searcher
11.02.2017, 15:17
Ich habe die 1000000:8 und dan 125000:1400=89
Bei den 89 habe ich 1 abgezogen ( so wie Ihr mir das gesagt habt )
Somit kamm ich auf 88.

Das paßt auch aber Du hast die Einheiten nicht mitgeschrieben. Oben (https://www.roboternetz.de/community/threads/70208-Ein-paar-Fragen-zum-Timer-%21%21%21?p=635068&viewfull=1#post635068) stehen 1400kHz obwohl Du 1400Hz meinst;) Das ist das, was ich mit total falsch meinte. Die 88 sind für die ungefähr 1400Hz OK!

Die 53 stimmen aber nicht!


Immer ein wenig probiert und sofort am Oszilloskop das Ergebniss angeschaut.

Nur leider gibt mein Attiny45 aus irgend einem Grund keinen Wert mehr aus ?
Habe es auch schon mit einem ganz neuen Attiny versucht.
Kann über den Port LED blinken lassen oder auch einen Taster steuern.
Nur das PWM Signal kommt nicht mehr raus.

Oszilloskop verstellt? Tasköpfe guten Kontakt? Keine andere Masseverbindung als über Meßkabel zB über Programmer-PC-Schutzkontakt zum Oszi?

Im Programm kann ich auch erstmal keinen Fehler entdecken. Ich bin aber kein C Programmierer. Pluszeichen bei den Registerzuweisungen sind jedoch anscheinend unüblich, obwohl es wohl funktioniert. Es ist üblicher dort ein Veroderungszeichen zu setzen, also so:


TCCR0A = (1<< COM0B1) | (1<< WGM01) | (1<< WGM00);
TCCR0B = (1<<WGM02) | (1<< CS01);
while (1);

Ein unendliche while Schleife, in dem nichts passiert, kann man so meine ich, auch einfach mit Semikolon abschließen - aber absolut ohne Gewähr. Das ASM nop irritiert mich.

Wenn man den OCR0A Wert in dem Modus dem OCR0B Wert von oben annähert ist Obacht geboten, weil es ja irgendwann keinen Comparematch für die PWM geben kann, da der TCNT den OCR0B-Wert nicht mehr erreichen kann.

Gruß
Searcher

Nicole01
12.02.2017, 00:23
Hallo Searcher,

mal wieder vielen Dank für deine Hilfe.

Am Oszi lag es nicht.
Habe es mit einem Attiny 24 versucht.
Da geht es sofort.

Nochmals zwei neue Attiny 85 getestet ( kein PWM Signal ) komisch komisch.

Benötige ich zwingend die Minimal Beschaltung für den Attiny ?
Oder sollte es auch ohne funktionieren ?

Searcher
12.02.2017, 07:13
Benötige ich zwingend die Minimal Beschaltung für den Attiny ?


Hallo,
Was verstehst Du da genau drunter? Für mich würde das ein 10kΩ Widerstand von RESET nach Vcc und ein 100nF Kerko direkt an die GND Und Vcc Anchlüsse des Tiny bedeuten. Damit kannst Du jetzt Unsicherheiten ausschließen.

Ich habe gerade vor ein paar Tagen "gezwungenermaßen" :( das AVR-Studio installiert -programmiere sonst mit BASCOM- und auch ein ATTiny25 auf dem Steckbrett sitzen. Da habe ich jetzt Dein letztes Programm für den Tiny25 (habe keinen Tiny85 zur Hand, der ja außer einem größeren Speicher gleich ist und das gleiche Datenblatt hat) compiliert und es läuft trotz + Zeichen und ASM nop wunderbar. Ich benutze nur ein Steckernetzteil und auch keine Minimalbeschaltung. Also blank den Tiny ins Steckbrett und Strom dran. Es mag aber trotzdem bei Dir wegen zB anderer Stromquelle, Zuleitungen, Störungen, ... nötig sein. Du kannst das Oszi mal auf die Versorgung hängen und den Einfluß eines 100nF Abblockkondensators beobachten. Mir lief es eiskalt den Rücken runter und wenn irgendwas nicht geht, stecke ich so ein Ding als erstes dazu, wenn es nicht vorhanden ist.

Ist das ein Steckbrettaufbau? Da ist natürlich auch Schmutz in den Kontakten oder die Kontakte selbst eine Fehlerquelle. Vor dem Compilieren den richtigen µC ausgewählt? Ein Clean vor dem Build durchgeführt? (also Löschen früherer erzeugte Compiler Dateien im Projekt. Ich glaube so ist es sicher, hab ich aber bei meinem AVR Studio 4.19 noch nicht alles ausgetestet.)

Am Programm liegt das Problem nicht. Bei mir gab es statt 1kHz eine Frequenz von 1,054kHz. (Gemessen direkt am OC0B (PB1) ohne weitere Beschaltung des Pins) Liegt an dem internen Oszillator, den ich über den aktivierten CLKO (PB4) gemessen habe. Liegt bei 1,055MHz (kleine Meßfehler durch Oszi eingeschlossen)

Gruß
Searcher

Ceos
13.02.2017, 05:45
Das ASM nop irritiert mich
@Searcher das ist Deterministischer Programmierstil und immer zu Empfehlen! So hat man ein definiertes Verhalten, denn ein asm("nop"); kann nicht optimiert werden, wohingegen bei einer leeren Schleife nicht garantiert werden kann dass er es niemals wegoptimiert, weil es dafür keine Vorschriften gibt.

Warum der Tiny jetzt keinen Ton mehr von sich gibt ist äußerst seltsam ... aber nur zur Sicherheit gefragt, du hast den Programmieradapter abgezogen bevor du gemessen hast oder? PB1 ist auch der MISO Pin und soweit ich weis wird der fürs programmieren verwendet.

Searcher
13.02.2017, 06:00
@Searcher das ist Deterministischer Programmierstil und immer zu Empfehlen! So hat man ein definiertes Verhalten, denn ein asm("nop"); kann nicht optimiert werden, wohingegen bei einer leeren Schleife nicht garantiert werden kann dass er es niemals wegoptimiert, weil es dafür keine Vorschriften gibt.
Danke für den guten Tipp Ceos:Strahl

Nicole01
13.02.2017, 15:30
Habe jetzt mal alle Kabel von meinem Steckbrett getauscht.

Und siehe da, jetzt kommt auch mein PWM Signal wieder an =D&gt;
Das hat mich Zeit gekostet sag ich euch :p

Nochmals eine kurze Frage:

OCR0A = Ist für die Frequenz zuständig
OCR0B = für den Zeitabstand

Habe ich das soweit richtig verstanden ?
So kann ich es auf dem Oszi zumindestens sehen wenn ich die Daten ändere.

Ist es auch möglich, das ich einen Taster anschließe und bei jedem Tastendruck eine andere Frequenz angezeigt wird ?

Wenn ja, benötige ich dafür immer einen neuen Timer ?
Oder reicht es wenn man die OCR0A , OCROB Werte anpasst ?

Vielen Dank nochmals an alle für eure Hilfe.

wkrug
13.02.2017, 15:47
Oder reicht es wenn man die OCR0A , OCROB Werte anpasst ?
Es reicht, wenn man die beiden!!! Werte anpasst.
Der gültige Wertebereich von OCR0B ändert sich ja auch mit dem Ändern von OCR0A.

Ceos
14.02.2017, 05:48
Kurzeinführung Taster: Da du einen Atmel hast und wir den ganzen Schaltungskladderadatsch weglassen können brauchst du faktisch nur einen kleinen Kondensator und einen Taster.

Die Atmels haben alle sognenannte interne Pull Up Widerstände, in der Größenordnung 10-50kOhm soweit ich das in ERinnerung habe.

Du musst dafür den Pin für den Taster im DDR Register auf Eingang konfigurieren und im OUT Register den Pin auf High setzen. Dann schließt du den Kondensator an den Pin und nach Ground an (der Puffert ein wenig Energie wenn der Schalter prellt) und natürlich deinen Taster, ebenfalls nach Ground.

Wenn du den Taster also drückst, wird der Pin auf Ground gezogen und zeigt im IN Register eine 0, lässt du den Taster los, lädt sich der Kondensator über den Pull-Up Widerstand weider auf und zeigt dann im IN Register eine 1.

Du musst also in deiner nop-Schleife dann nur das IN-Register abfragen und je nachdem ob dein IN Register für den Pin eine 1 oder 0 anzeigt das OCR0B REgister für das Tasterverhältnis ändern oder das OCR0A Register für die Frequenz :)

Den Code habe ich zwecks Lerneffekt dieses mal weg gelassen :P

PS: Wkrug hat natürlich recht, wenn du OCR0A veränderst, musst du auch OCR0B entsprechend Ändern damit sich das Tastverhältnis nicht verschiebt :D

Nicole01
15.02.2017, 11:22
Neuer Versuch,


int main(void)
{
DDRB = (1<<PB1); // Ausgang PWM
DDRB &= ~(1<<PB0); // Eingang Taster
PORTB |= (1<<PB0); // Pull - Up aktivieren


OCR0A = 124;
OCR0B = 63;

TCCR0A = (1<< COM0B1) + (1<< WGM01) + (1<< WGM00);
TCCR0B = (1<<WGM02) + (1<< CS01);


while (1)
{
if (!(PINB & (1<<PB0)));
}
PORTB |= (1<<PB1);
}
if (PINB & (1<<PB0));
{
PORTB |= ~(1<<PB1);

}
}

}

Es funktioniert so bis jetzt noch nicht.
Habe es auf meinem Steckbrett aufgebaut.

Könnt Ihr mir bitte einen Tip geben wo der Fehler sitzt ?

wkrug
15.02.2017, 16:15
while (1)
{
if (!(PINB & (1<<PB0)));
}
PORTB |= (1<<PB1);
}
if (PINB & (1<<PB0));
{
PORTB |= ~(1<<PB1);

}

Da stimmt schon mal die Syntax nicht

while (1)
{
if (!(PINB & (1<<PB0)))
{
// Taster ist zu PinB.0 =0
}

PORTB |= (1<<PB1); // Schaltet PORTB 1 auf 1, macht aber keinen Sinn, wenn das ein PWM Ausgang ist
PORTB &= ~(1<<PB1); // // Schaltet PORTB 1 auf 0, macht aber keinen Sinn, wenn das ein PWM Ausgang ist
}

Wenn der Taster gedrückt ist, musst Du doch die OCR Register ändern, siehe weiter oben.

Nicole01
15.02.2017, 23:12
Vielen Dank für die Info.

Das würde heißen ich schreibe nicht


if (!(PINB & (1<<PB0)))
sondern
if (!(PINB & (1<<OCR0A)))

Benötige ich dan nicht noch OCR0B ?

Und was ich nicht verstehe ist, wieso kann ich nicht wie bei einer LED den PB0 einschalten und abschalten ?
Wenn ich nur diese eine Funktion auf dem PB0 habe sollte das doch normal möglich sein oder ?

wkrug
16.02.2017, 06:53
Hallo, erstmal langsam.

Ein AVR hat 3 Register für die Ports PINx = zustand des Ports, wenn der extern angesprochen wurde.
DDRx = Data Direction Register eine 1 bedeutet es ist ein Ausgang eine 0 - es ist ein Eingang.
PORTx = gezieltes setzen eines Ports auf 0 oder 1. Wenn auf dem entsprechenden Bit im DDRx eine 0 steht, wird der interne Pullup bei einer 1 im PORTx Register aktiviert.
In deinem Mini Prog fragst Du den Zustand des PORTB.0 ( PINB &(1<<PB0)) ab.
Das ist ja kein aktives setzen des Ports, sondern eine Zustandsabfrage ( "if" ).
Wenn Du den Port setzen willst musst Du "PORTB | = (1<<PB0);" ( das entspricht PORTB | = 0b00000001; ) eingeben.
Das entsprechende Bit im DDRB muss dazu aber auch auf 1 gesetzt sein, sonst wird nur der Pullup des Ports aktiviert.

Auch wenn Du es nicht glauben magst - Datenblatt lesen hilft!

Nicole01
16.02.2017, 19:41
Würde es so jetzt passen ?



DDRB = (1<<PB1); // Ausgang PWM
PORTB |= (1<<PB1); // Port Auf Ausgang setzen
DDRB &= ~(1<<PB0); // Eingang Taster
PORTB |= (1<<PB0); // Pull - Up aktivieren

Ich könnte es auch so schreiben richtig ?


DDRB = 0b00000001; // Port auf Ausgang setzen
DDRB = (1<<PB1); // Ausgang PWM
DDRB &= ~(1<<PB0); // Eingang Taster
PORTB |= (1<<PB0); // Pull - Up aktivieren

Gibt es einen Vorteil wenn ich es per Binärzahlen schreibe ?

Wenn ich den Port so auf Ausgang setze DDRB = 0b00000001 muss ich dan auch noch DDRB = (1<<PB1); schreiben ?

Ceos
17.02.2017, 06:46
beide Reihenfolgen sind okay, aber das manuelle bit-setzen macht den code unleserlich, weil niemand weis welcher Pin 0b00000001 ist. Wichtig ist aber eigentlich nur immer die Pins erst Konfigurieren(DDR), dann Setzen(PORT).

Lesen geht immer, auch wenns auf Ausgang steht, macht aber nur wenig Sinn!

Den PWM Ausgang in PORT Register zu setzen hat nur die Wirkung, dass der Pin so lange an ist, bis das Timer Register programmiert wird. Im Datenblatt steht, dass der Timer die Port Funktion übersteuert und wirkungslos macht wenn der Ausgang als PWM benutzt wird.

Ob du PB0 oder OCRA0 als Makro verwendest ist je nach Prozessor abhängig! PB0 ist IMMER Port B Pin 0 aber OCR0A kann auf einem anderen Pin liegen, je nach Layout. Zum lesen den PIN Register oder schreiben des PORT Register ist das schlecht, denn diese Register arbeiten nicht sinnvoll mit PWM zusammen! Aber für das DDR Register ist es wiederum gut, weil der Code so portierbar wird für Prozessoren mit anderem Pin Layout!

wkrug
17.02.2017, 07:13
Wenn ich den Port so auf Ausgang setze DDRB = 0b00000001 muss ich dan auch noch DDRB = (1<<PB1); schreiben ?
Bewirkt beides das gleiche:
DDRB = 0b00000010 = Schreibe in das DDRB Register den binären Wert 00000010;
DDRB = ( 1<<PB1 ) = Schibe ein 1 Bit um 1 Stelle nach links und schreibe das dann ins DDRB Register also 0b00000001 um 1 nach links verschoben wird 0b00000010
PB1 ist in einer Prozessorinitialisierung mit #define PB1 1 definiert, liefert als nach dem Compilieren den Wert 1.

Übrigens kann man in C alle Werte als dezimal Werte z.B.123 angeben, oder in hex Schreibweise 0x7B oder binär 0b01111011 angeben.
Alle 3 Beispiele hier liefern den selben Wert.
Ich nehm halt immer das was für das aktuelle Problem für mich das Übersichtlichste ist.
Tabellen für ein Lauflicht würde ich da in der Binärschreibweise erzeugen.

Nicole01
08.03.2017, 17:03
Bitte nochmals um eure Hilfe.

Wo genau sitzt der Fehler im Code ?


#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>




int main (void)
{
DDRB |= (1<<PB1);
DDRB = ~(1<<PB0);
PORTB |= (1<<PB0);


OCR0A = 999;
OCR0B = 370;

TCCR0A = (1<< COM1A1) + (1<< WGM01) + (1<< WGM00);
TCCR0B = (1<<WGM01) + (1<< WGM02) + (1<< CS13);


while(1)

{
if (!(PINB & (1<<PINB0)))
{
PORTB |= (1<<PB1);

}

else if (PINB & (1<<PINB0))
{
PORTB &= ~(1<<PB1);


}

}
}

Ihr sagt ich muss den PORTB ein und aus schalten.
Das mache ich doch in meinem Code.

Wieso funktioniert es dan nicht ?

Ich möchte wenn ich 1x mal den Taster drücke, das PWM Signal einschaltet.
Drücke ich nochmals auf den Taster, schaltet das PWM Signal wieder aus.

Ein kleines Beispiel wäre wirklich eine große Hilfe für mich.

Vielen Dank mal wieder.

wkrug
08.03.2017, 18:54
Ihr sagt ich muss den PORTB ein und aus schalten.
Das mache ich doch in meinem Code.
Nö, das machst Du eben nicht. Du schaltest nur den internen Pullup ein und aus.

Ich hab den Code mal umgeschrieben und im Simulator getestet:

#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>




int main (void)
{
DDRB |= (1<<PB1);
DDRB = ~(1<<PB0);
PORTB |= (1<<PB0);


OCR0A = 99;
OCR0B = 37;

TCCR0A = (1<< COM0B1) + (1<< WGM01) + (1<< WGM00);
TCCR0B = (1<<WGM02) + (1<< CS01);


while(1)

{
if (PINB & (1<<PINB0))
{
DDRB |= (1<<PB1);
}

else
{
DDRB &= ~(1<<PB1);
}

}
return (0);
}
Im Simulator läuft der Code nicht 100% fehlerfrei, das könnte aber auch ein BUG des Simulators sein.
Die Variablen OCR0A und OCR0B sind zu groß, da es sich hier nur um 8 Bit Register handelt = max. 255.
Bei Tastendruck ( PINB.0 = 0 ) wird die PWM abgeschaltet.
Bei offener Taste läuft die PWM.
Das toggeln kannst Du so machen wie Ich Dir in der PN geschrieben habe.
Probier mal aus ob es denn soweit läuft.

Nicole01
08.03.2017, 19:17
Vielen Dank mal wieder für deine Hilfe.

Das glaub ich jetzt nicht.
Es funktioniert sofort !!!

Ich habe viel zu weit gedacht :mad:
Dachte immer ich muss OCR0A abschalten.....

Das mit dem Toggeln teste ich sofort und melde mich nochmal.

wkrug
08.03.2017, 21:31
Ich habe viel zu weit gedacht :mad:
Dachte immer ich muss OCR0A abschalten.....
Wie schon mal geschrieben.
Durch setzen des DDRB.1 Registers auf 0 geht der Port auf Tri State.
Das bedeutet er ist hochohmig.
Wenn Du da nen FET oder was ähnliches dran schalten willst, solltest Du einen Pull Down Widerstand ( ein echtes Bauteil - keine Programmierung ) in die Schaltung einfügen.
Wenn Du das nicht magst, oder es einfach nicht mehr geht ( Layout fertig z.B. ) musst Du doch den Weg über die Abschaltung der OCR Ausganges machen und den Port auf einen festen Level, üblicherweise 0 legen.