PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : MoBo PWM einlesen



Flo3578
13.10.2015, 12:53
Hallo!

Ich arbeite mit einem ATtiny45, und möchte mit diesem das PWM Signal eines Mainboards am Lüfterausgang einlesen.
Ich konnte zwar viele Infos zur Erzeugung eines PWM Signals mit einem ATtiny und Bascom finden, jedoch nichts zum Einlesen eines solches.
Das Programm soll letztendlich ab einem bestimmten Duty Cycle einen anderen Pin auf High setzen.
Wie stelle ich das nur an?
Einen Timer immer wieder die High / Low Zustände zählen lassen?

Infos zum Input:

Frequenzbereich:
25 kHz, acceptable operational range 21 kHz to 28 kHz

Spannung/Strom:
Maximum voltage for logic low: VIL = 0.8 V
Absolute maximum current sourced: Imax = 5 mA (short circuit current)
Absolute maximum voltage level: VMax = 5.25 V (open circuit voltage)

Vielen Dank im Voraus!

RoboHolIC
13.10.2015, 13:43
Wäre es ausreichend, das PWM-Signal auf einen Tiefpass zu geben und die resultierende Fast-Gleichspannung zu messen?

Flo3578
13.10.2015, 14:58
Die Idee klingt gut, wüsste in der Theorie auch nicht, warum das nicht klappen sollte.
Nur muss ich mir dann ein Poti besorgen, habe gerade leider keins zur Hand.
Der µC kann die Spannung doch nicht messen, sondern nur zwischen HIGH oder LOW unterschieden, oder täusche ich mich?

Wäre prima, wenn ich das mit dem µC und ohne Poti lösen könnte, also eine Auswertung des Signals durch den Controller.
Dahingehend keine Idee?

Erste Idee meinerseits:
-Den Oszi auf eine bestimmte Frequenz einstellen
-Dieses Signal als eine Variable definieren
-Dann mit einer If-Schleife die Länge des LOW- oder HIGH- Zustand des Pins mit dem PWM Signal abfragen.
Wen sich dieser z.B. LOW-Zustand über mehr Ticks erstreckt, als auf die Frequenz, die der Oszi eingestellt ist, dann schalte ich den anderen Pin HIGH.
Sonst eben nicht.

Ist das realisierbar? Kann der µC mit Bascom die Ticks im LOW-Zustand mit den Interrupts pro Sekunde des Oszi-Signals abgleichen, und dann darauf reagieren?

Peter(TOO)
13.10.2015, 18:09
Hallo,

Der µC kann die Spannung doch nicht messen, sondern nur zwischen HIGH oder LOW unterschieden, oder täusche ich mich?
Der ATtiny45 hat 4 Analog-Digital-Wandler, damit kannst du die Spannung messen.

MfG Peter(TOO)

021aet04
13.10.2015, 19:34
Eigentlich sollte es reichen wenn du steigende und fallende Flanke auswertest. Also in etwa so:

erster interrupt auf steigende Flanke: Timer au 0 setzten und starten
Interrupt auf fallende Flanke : Timer stoppen, timer auslesen, timer auf 0 stellen, timer starten
Interrupt auf steigende Flanke : gleich wie bei fallender Flanke

Somit hast du die Dauer von high und low. Der Controller ist schnell genug, da macht es nichts wenn etwas zeit vergeht (timer Start, stopp, 0 setzten,...)

MfG Hannes

Flo3578
20.10.2015, 10:44
Vielen Dank für all eure Anregungen!

Ich komme leider er jetzt wieder dazu, ich dem Projekt zu widmen.
Die Idee von 021aet04 kam mir sehr interessant vor, so habe ich versucht, mir nach dieser etwas zusammen zu basteln.
Problem / Denkfehler / whatever was nun auftritt: Wie kann ein Interrput Pin auf verschiedene Ereignisse reagieren?
Ich habe am tiny einen Interrupt Pin, an diesen hänge ich das PWM Signal.
Nun lege ich im Kopf des Programmes fest, dass bei steigender Flanke unterbrochen werden soll, nach der Idee von 021aet04.
Aber wie sorge ich jetzt dafür, dass der gleiche Pin anschließend auf eine fallende Flanke reagieren soll?
Ich kann diesen noch nicht im Programm umstellen?
Hier der bisherige Versuch, falls interessant für euch:
PS: In diesem Programm geht es probehaft erst einmal darum, eine LED anzuschalten, wenn der Duty Cyle kurz genug ist.


$regfile = "ATtiny45.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32

Pwm_mobo Alias Portb.2
Config Pwm_mobo = Input

Led Alias Portb.3
Config Led = Output

Config Timer0 = Timer , Prescale = 1
On Int0 Steigende_flanke 'Wenn Int0 ausgelöst wird, springe zu Label Steigende_Flanke
Config Int0 = Raising 'Int0 löst bei steigender Flanke aus

Enable Interrupts

Do
'Mit dem Hauptprogramm habe ich mich noch nicht befasst
If Tcnt1 > X Then 'X = Anzahl der Ticks ab der der Zustand der LED gedert werden soll
Led = 1
Else
Led = 0
Loop

Steigende_flanke:
Timer0 = 0 'Timer auf 0 setzen
Enable Timer0 'Timer starten
Return 'zutück ins Hauptprogramm springen

021aet04
20.10.2015, 11:58
Ich kenne mich mit Bascom nicht aus. Aber die Flanke kann man im Programm immer ändern. Du hast oben geschrieben "config int0 = raising ", das stellst du auf falling. Ich würde noch die Interrupts sperren (disable Interrupt) .

MfG Hannes

Flo3578
20.10.2015, 12:39
Stimmt, ich dann die Flanke ändern, jedoch aber nicht die Sprungmarke dazu.
Dann bringt mir ersteres doch auch nichts? :/

RoboHolIC
20.10.2015, 14:28
Du kanst hinter der fraglichen Sprungmarke eine Fallunterscheidung vorsehen:
- wenn INT bei steigender Flanke aktiviert ist, dann Zähler rücksetzen
- wenn INT bei fallender Flaanke aktiviert ist. dann Zähler auslesen und ggf. darauf reagieren

Das relevante Bit im Steuerregister kannst du direkt testen. Anscheinend musst du dafür das Datenblatt studieren, falls es keine Ausleseroutine gibt, die diesen Hardwarebezug so hübsch abstrahiert.

Flo3578
20.10.2015, 17:19
Du meinst also in etwa so?

$regfile = "ATtiny45.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32

Pwm_mobo Alias Portb.2
Config Pwm_mobo = Input

Led Alias Portb.3
Config Led = Output

Config Timer0 = Timer , Prescale = 1

On Int0 Sprungmarke 'Wenn Int0 ausgelöst wird, springe zu Label Sprungmarke

Enable Interrupts

Do
Config Int0 = Raising 'Int0 loest bei steigender Flanke aus

Config Int0 = Falling 'Int0 loest bei fallender Flanke aus

If Tcnt1 > X Then 'X = Anzahl der Ticks ab der der Zustand der LED geaendert werden soll
Led = 1
Else
Led = 0
Loop

Sprungmarke:
If Int0 = Raising Then
Timer0 = 0
Enable Timer0
Else
Stop Timer0
Return 'zutück ins Hauptprogramm springen

RoboHolIC
21.10.2015, 00:18
Zumindest nach dem Label 'Sprungmarke' geht es in die Richtung, die ich meinte.
Genaueres kann ich nicht sagen, weil ich keine Ahnung von BASCOM habe.

Sauerbruch
21.10.2015, 15:59
Ich sehe hier ein paar Probleme:



Do
Config Int0 = Raising 'Int0 loest bei steigender Flanke aus

Config Int0 = Falling 'Int0 loest bei fallender Flanke aus

If Tcnt1 > X Then 'X = Anzahl der Ticks ab der der Zustand der LED geaendert werden soll
Led = 1
Else
Led = 0
Loop



Erstens: Config INT0 = Falling und Config INT0 = Rising nacheinander ist ziemlich sinnlos, weil der zweite Befel den ersten überschreibt. Es resultiert also ein Interrupt auf eine fallende Flanke.

Zweitens: TCNT1 ist ja der Zählerstand des Timers 1, der kontinuierlich hochzählt. Irgendwann wird er zwangsläufig größer werden als die Variable X, und dann schaltet sich die LED ein.

Wenn Du INT0 auf "Change" konfigurierst, löst jede Flanke einen Interrupt aus. Wenn Du am Anfang der ISR eine Abfrage des INT0-Pins machst, kannst Du unterscheiden, ob es eine steigende (PIN = 1) oder eine fallende (PIN = 0) Flanke war. Du bräuchtest dann nur noch ein geeignetes Vefahren, die Zeiten zwischen steigendrn und fallenden Flanken zu messen. Aber das ist auch kein Hexenwerk...

Ud in der ISR gibt´s auch ein paar Probleme:

"Enable Timer1" startet nicht den Timer, sondern aktiviert lediglich den Interrupt beim Überlauf des Timers. Zum Starten des Timers nimt man Start Timer1.

Und "If Int0 = Rising" geht auch nicht, das wird Bascom nicht kompilieren. Wenn, dann müsstest Du die niedrigsten beiden Bits im MCUCR-Register abfragen. Aber bei genauer Betrfachtung bauchst Du diese Abfrage gar nicht!

Flo3578
21.10.2015, 21:10
Danke für deine Antwort!


Erstens: Config INT0 = Falling und Config INT0 = Rising nacheinander ist ziemlich sinnlos, weil der zweite Befel den ersten überschreibt. Es resultiert also ein Interrupt auf eine fallende Flanke.

Du hast absolut recht.


Zweitens: TCNT1 ist ja der Zählerstand des Timers 1, der kontinuierlich hochzählt. Irgendwann wird er zwangsläufig größer werden als die Variable X, und dann schaltet sich die LED ein.

Es soll natürlich das Register von TIMER0 abgeglichen werden, also TCNT0.


Wenn Du INT0 auf "Change" konfigurierst, löst jede Flanke einen Interrupt aus. Wenn Du am Anfang der ISR eine Abfrage des INT0-Pins machst, kannst Du unterscheiden, ob es eine steigende (PIN = 1) oder eine fallende (PIN = 0) Flanke war.

Heißt, mit "Config INT0 = Change" springt er bei jeder Flanke (egal ob fallend oder steigend) zum Label, das ich beim "On INT0 ..." gewählt habe?
Damit das funktioniert muss ich Interrupts global aktivieren, nehme ich an, zusätzlich auch noch "Enable INT0"?

Am Label frage ich dann ab, ob der Pin 1 oder 0 ist, je nachdem setze ich Timer 0 auf 0 und starte ihn, oder stoppe ihn?
Der Abgleich des Registers des Timers, gehört der dann noch in die ISR oder ins Hauptprogramm?
In diesem würde dann ja nach jetzigem Stand ... nichts stehen? Oo


Du bräuchtest dann nur noch ein geeignetes Vefahren, die Zeiten zwischen steigendrn und fallenden Flanken zu messen. Aber das ist auch kein Hexenwerk...

Dazu würde ich dann wie oben beschrieben einen Timer auf 0 setzen und starten, bzw. stoppen und ggf. noch den Zählerstand mit einer Variablen abgleichen.


"Enable Timer1" startet nicht den Timer, sondern aktiviert lediglich den Interrupt beim Überlauf des Timers. Zum Starten des Timers nimt man Start Timer1.

Gut zu wissen, ein echtes Fettnäpfchen.


Und "If Int0 = Rising" geht auch nicht, das wird Bascom nicht kompilieren. Wenn, dann müsstest Du die niedrigsten beiden Bits im MCUCR-Register abfragen. Aber bei genauer Betrfachtung bauchst Du diese Abfrage gar nicht!

Ja, habe ich schon beim ersten Kompilieren bemerkt, aber wie du sagst, man braucht es tatsächlich nicht.

Code zum aktuellen Stand der Dinge:

$regfile = "ATtiny45.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32

Pwm_mobo Alias Pinb.2
Config Pwm_mobo = Input

Led Alias Portb.3
Config Led = Output

Config Timer0 = Timer , Prescale = 1 'Timer 0 wird konfiguriert
Config Int0 = Change 'Der Interrupt soll bei jeder Falke ausgelöst werden
On Int0 Sprungmarke 'Wenn Int0 ausgelöst wird, springe zu Label Sprungmarke

Enable Interrupts

Do
If Tcnt0 > X Then 'X = Anzahl der Ticks ab der der Zustand der LED geaendert werden soll
Led = 1
Else
Led = 0
Loop

End

Sprungmarke:
If Pwm_mobo = 1 Then
Timer0 = 0
Start Timer0
Else
Stop Timer0
Return 'zurück ins Hauptprogramm springen