Hallo zusammen,
hatte schon mal einen Post erstellt bei dem ich dasselbe Problem
geschildert hab. Habe es aber noch nicht hinbekommen das Ganze zu lösen.
Also es geht darum die High-Pulslänge eines PWM Signals zu messen oder
die Duty Cycle das ist eig. egal. Hab da mal wieder im Internet etwas
recherchiert und etwas gefunden. Das funktioniert allerdings nur mit dem
ATmega16 bzw. 32. Ich würde das allerdings gerne mit dem Atmega328P
realisieren. Jetzt bräuchte ich Hilfe wie man den Code verändern muss um
das Ganze auf dem Atmega328P zum laufen zu bringen. Und welcher Pin dann
der "Input Capture Pin" an dem ATmega328P ist, also der Pin an dem ich
das PWM Signal anlegen muss. Am Ende sollen dann aufgrund der Duty Cycle
LEDs angesteuert werden.
Hier der Link zum
Originalartikel:https://www.electronicwings.com/avr-atmega/atmega1632-timer-input-capture-mode
Und hier meine Wandlung für den ATmega328P, die allerdings nicht
funktioniert ... (Hab alles was mit dem Display zu tun hat entfernt, das
brauche ich nicht und habe das Register TIFR in TIFR0 umbenannt da es
das beim ATmega328 nicht gibt)
Wäre sehr sehr sehr dankbar, wenn mir da jemand weiterhelfen kann...
Vielen Dank schon mal!!
1
/*
2
Measuring ATmega16 frequency and duty cycle using input capture
3
http://www.electronicwings.com
4
*/
5
6
7
#define F_CPU 1000000UL
8
#include<avr/io.h>
9
#include<util/delay.h>
10
#include<avr/interrupt.h>
11
#include<stdlib.h>
12
13
#define LED1 (1<<PD5)
14
15
16
intmain()
17
{
18
unsignedinta,b,c,high,period;
19
20
PORTD=0xFF;/* Turn ON pull-up resistor */
21
22
while(1)
23
{
24
TCCR1A=0;
25
TCNT1=0;
26
TIFR0=(1<<ICF1);/* Clear ICF (Input Capture flag) flag */
l. w. schrieb:> Und hier meine Wandlung für den ATmega328P, die allerdings nicht> funktioniert ...
Was funktioniert denn nicht?
Was erwartest du?
Und was passiert stattdessen?
> TCCR1B = 0; /* Stop the timer */
Funktionierende Programme gehen so: ein Timer wird 1x gestartet und dann
nur noch abgefragt und die Differenz zum letzen ausgelesenen Timerwert
ermittelt.
l. w. schrieb:> Also es geht darum die High-Pulslänge eines PWM Signals zu messen oder> die Duty Cycle das ist eig. egal. Hab da mal wieder im Internet etwas> recherchiert und etwas gefunden.
Aber eben nicht verstanden. Wie wärs mit selber mal drüber Nachdenken?
Ich verwende Code aus dem Internt nur, wenn ich ihn (wenigstens
grundlegend) verstanden habe. Sonst suche ich hinterher noch die Fehler,
die Andere gemacht haben.
Was ist übrigens aus meinem Vorschlag im
Beitrag "Servo-Pulssignalläge messen mit Atmega328p" geworden?
l. w. schrieb:> Kannst du mir bei der lesetimeraus() Funktion noch weiterhelfen.
Die sieht etwa so aus:
lesetimeraus( void) { return TCNT1; }
Muss das wirklich float sein? Das kostet richtig CPU-Zeit.
Vielleicht reicht ja:
1
intduty_cycle=(100*high)/period;
Beachte hier die Klammern: Erst Multiplikation, um große Zahl zu
erhalten, um sie dann durch die kleinere zu teilen. Damit rettest Du
immerhin zwei Dezimalstellen bei der Division, was im folgenden
vollkommen ausreicht, auch wenn Du später mit anderen Prozentzahlen als
nur 1 Prozent vergleichen möchtest, z.B. 25 für 25%, 50 für 50%, 75 für
75%.
Die Zeile:
1
if(duty_cycle>=1)
soll abfragen, ob der duty cycle größer gleich 1 Prozent ist? Wenn das
so gewollt ist, kann das so bleiben.
Die Zeile:
1
DDRD|=LED1;
kann komplett vor die while-Schleife gezogen werden. Es bringt überhaupt
nichts, dieses Bit immer wieder neu zu setzen.
Sonst kann ich mich nur Lothar anschließen: Was funktioniert denn nicht?
Was erwartest Du, was erhältst Du?
Lothar M. schrieb:> Was funktioniert denn nicht?> Was erwartest du?> Und was passiert stattdessen?
Nochmal zurück zu deinem Code Lothar. Sorry, dass ich nerve aber wär mir
echt wichtig das hinzubekommen...
Wie initialisiert man dann hier den Timer und würde das mit der Funktion
lesetimeraus so schon passen oder muss man da noch was ergänzen.
1
#define F_CPU 1000000UL
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<avr/interrupt.h>
5
#include<stdlib.h>
6
7
#define LED1 (1<<PD5)
8
9
lesetimeraus(void)
10
{
11
returnTCNT1;
12
}
13
14
intmain()
15
{
16
// Timer initialisieren
17
18
DDRD|=LED1;
19
20
intrcpinold,rcpin;
21
unsignedlongrisetime,pulsdauer;
22
23
while(1)
24
{
25
rcpin=(PIND&(1<<PD2));
26
if(rcpin!=rcpinold)
27
{
28
risetime=lesetimeraus();
29
}
30
else
31
{
32
pulsdauer=lesetimeraus()-risetime;
33
}
34
rcpinold=rcpin;
35
36
if(pulsdauer>=1)
37
{
38
PORTD^=LED1;
39
_delay_ms(500);
40
}
41
}
42
43
}
Ich würde gerne ein PWM-Signal an den PIN PD2 anlegen. Aus diesem
angelegten Signal soll der Mikrocontroller die HIGH-Pulslänge ermitteln.
Bei verschiedenen HIGH Pulslängen sollen LEDs mit verschiedenen
Funktionen angesteuert werden. Also z. B. bei einer High-Pulslänge von
1ms bis 1,5ms soll beispielsweise eine Doppelblitz ausgegeben werden und
von 1,5ms bis 2ms ein Dreifachblitz.
Frank M. schrieb:> Die Zeile: if(duty_cycle >= 1)> soll abfragen, ob der duty cycle größer gleich 1 Prozent ist? Wenn das> so gewollt ist, kann das so bleiben.
Damit wollte ich nur ausprobieren, ob das funktioniert ...
l. w. schrieb:> Ich würde gerne ein PWM-Signal an den PIN PD2 anlegen.
Tja, µC-Programmierung ist kein Wunschkonzert. Wenn du ein optimales
Ergebnis erwartest, dann musst du das Signal auch an den/die am besten
dafür geeigneten Pins anlegen, nicht an irgendeinen.
Da der Mega328P nur über einen Timer mit InputCapture-Funktion verfügt
und nur über eine Möglichkeit, das entsprechenden Signal an irgendeinen
Pin zu legen, wirst du eben diesen Pin benutzen müssen.
Und das ist nicht PD2, sondern PB0. So steht's im Datenblatt. Und es
führt überhaupt kein Weg darum herum. Jedenfalls keiner, der die
Eigenschaften der Zeitmessung nicht verschlechtern würde, weil du dann
halt nicht die dafür optimale Peripherie verwenden kannst.
Lies' das verschissene Datenblatt und lerne es zu verstehen.
Hallo,
du musst dich entscheiden. Soll es mittels Timer 1 Input Capture präzise
Takt genau gemessen werden, dann bist du wie c-hater schreibt auf Pin
PB0 (ICP1) festgenagelt. Muss es nicht 100% Takt genau sein, kannst du
auf die beiden Pin Interrupts INT0/1 ausweichen. Oder du nimmst die Pin
Change Interrupts. Laut deiner letzten Beschreibung muss das wohl nicht
so genau sein. Deswegen kannste locker die PCINTs verwenden und hast
freie Pinwahl.
Veit D. schrieb:> Muss es nicht 100% Takt genau sein, kannst du> auf die beiden Pin Interrupts INT0/1 ausweichen. Oder du nimmst die Pin> Change Interrupts. Laut deiner letzten Beschreibung muss das wohl nicht> so genau sein. Deswegen kannste locker die PCINTs verwenden und hast> freie Pinwahl.
Wenn es hilft, hier ein Beispiel mit INT0/INT1:
Beitrag "Stoppuhr – Geschwindigkeit – Pulsweite mit Atmega88"
Die Auflösung im µs-Bereich sollte doch reichen.
c-hater schrieb:> Und das ist nicht PD2, sondern PB0. So steht's im Datenblatt. Und es> führt überhaupt kein Weg darum herum.
Naja, man kann die Capture-Funktion auch auf den Analog-Comparator
routen und diesen wiederum auf einen Eingang des ADC.
Je nach Bauform ergibt das 8 bzw. 10 mögliche Pins als Capture-Eingang:
PB0, PD7, PC5..PC0, ADC7, ADC6
Peter D. schrieb:> Naja, man kann die Capture-Funktion auch auf den Analog-Comparator> routen und diesen wiederum auf einen Eingang des ADC.> Je nach Bauform ergibt das 8 bzw. 10 mögliche Pins als Capture-Eingang:> PB0, PD7, PC5..PC0, ADC7, ADC6
Stimmt, das wäre möglich. Aber PD2 ist immer noch nicht dabei...
Joachim B. schrieb:> war die korrekte Übersetzung von RTFM nicht mal?> "read the famos manual"
Was ist "famos"? Vermutlich gemeint war "famous". Aber auch das kann ich
nirgendwo finden im Zshg. mit "RTFM". Nein, das F steht schon für
"fucking" und "verschissen" ist durchaus schon ein deutlich entschärfte
Übersetzung.
Das müssen auch die zarten Seelen aushalten können!