Guten Morgen,
ich versuche mit einem Stm32F103 eine Frequenz zu messen.
Und das Ergebnis ist fast gut. Irgendwie ist die Messung immer um einen
1% zu niedrig. (gegenüber Oszilloskop)
die Init des Timers sieht so aus
Mit einem Programmfragment ohne Kommentare kann man nichts anfangen.
Ich gebe Dir ein Beispiel, wie man die Frequenz reziprok messen kann.
Vielleicht ist das eine Anregung für Dich.
Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"
Also meine Vermutung ist das ich die Zeit Basis nicht ganz Stimmt.
Ich Habe einen Hauptakt von 72MHz
Und Teile den mit htim3.Init.Prescaler = 71; das sollte eine division
von72 sein also sollte ich einen Timer Takt von 1us haben.
Ist diese Annahme richtig? weiters habe ich htim3.Init.Period = 99; dies
sollte bewirken das ich alle 100 100us einen überlauf meines Zählers
habe.
Ist das so richtig interpretiert?
Danke für die Hilfe
m.n. schrieb:> Mit einem Programmfragment ohne Kommentare kann man nichts anfangen.
Wie soll ich es aufarbeiten damit man was tun kann?
Lg
pegel schrieb:> Teiler und Periode sollten stimmen.>> Leite deinen internen Takt an den MCO und vergleiche was dein Oszi als> Frequenz anzeigt.
Bei einer Frequenz von 100Hz messe ich 99 und bei 1Herz eben auch nur
0.9 Herz
etwas muss ich falsch machen
123 Gast schrieb:> Wie genau ist das Oszi? Schon mal mit nem Frequenzzähler versucht?
Habe ich leider nicht.
Es ist ein Fluke105B Scopemeter
pegel schrieb:> Ich meine den MCO, um erst einmal den internen Takt mit deinem Oszi> abzugleichen.
Was ist der MCO?
Danke
Palmolive schrieb:> Was ist der MCO?
Master Clock Output.
Damit kannst du den internen Takt von verschiedenen Quellen über Teiler
an ein Pin nach aussen leiten.
Du hast CubeMX verwendet, stimmts?
Dann findest du unter Clock Configuration unten links die Einstellung
und in System Core -> RCC die Aktivierung des MCO.
Palmolive schrieb:> Irgendwie ist die Messung immer um einen> 1% zu niedrig.
Benutzt Du einen Quarz oder den internen RC Oszillator? Letzterer darf
um 1% auch bei Laborbedingungen falsch gehen, siehe Datenblatt.
Jim M. schrieb:> Benutzt Du einen Quarz oder den internen RC Oszillator? Letzterer darf> um 1% auch bei Laborbedingungen falsch gehen, siehe Datenblatt.
Ja ich verwende ein Quarz!
Hans schrieb:> Subtrahiere mal -1 vom Ergebnis des Timers. Sprich:>> frq_Hz = 1 / (pw_s - 1); // Frequenz in Hz
Kannst du mir den Grund dafür nennen?
werde es probieren
Danke
pegel schrieb:> Du hast CubeMX verwendet, stimmts?>> Dann findest du unter Clock Configuration unten links die Einstellung> und in System Core -> RCC die Aktivierung des MCO.
A ok wie dumm von Mir
Danke
Stelle bitte Deinen gesamten Code hier ein - Du kannst auch Anhänge hier
hochladen. Alternativ kannst Du Deinen Code auch bei Github oder sonstwo
einstellen, aber ohne Gesamtsicht ist das hier nur Raterei.
Insbesondere die Clocktree-Initialisierung wäre interessant.
Vielleicht liegt dort schon etwas im Argen.
Ein Bild vom Clocktree wäre ebenfalls nett - ich meine so etwas einmal
in dem Programm, mit dem man HAL programmiert, gesehen zu haben.
Viele Grüße
Igel1
Andreas S. schrieb:> aber ohne Gesamtsicht ist das hier nur Raterei.
Sag ich doch. Nicht einmal das Meßverfahren und der benötigte
Frequenzbereich sind klar.
Dennoch wundere ich mich über die vielen gut gemeinten Tipps.
100 Hz / 99 Hz sind 1%, 1,0 Hz / 0,9 Hz allerdings schon 10% Abweichung.
Mit Quarz oder nicht hat das nichts zu tun.
m.n. schrieb:> Sag ich doch. Nicht einmal das Meßverfahren und der benötigte> Frequenzbereich sind klar.> Dennoch wundere ich mich über die vielen gut gemeinten Tipps.> 100 Hz / 99 Hz sind 1%, 1,0 Hz / 0,9 Hz allerdings schon 10% Abweichung.> Mit Quarz oder nicht hat das nichts zu tun.
Ich werde jetzt ein Projekt anlegen das nur die Frequenzmessung hat.
Das Quarz funktioniert den der Canopen funktioniert.
Also bis gleich und danke für die Hilfe und Entschuldigung für meine
Unklarheit
Andreas S. schrieb:> Habe die ClockConfiguration aus Deinem *.zip-file entnommen.> Das sieht meiner Meinung nach korrekt aus.
Ich finde der fehler muss im Programm sein aber ich finde ihn leider
nicht.
Palmolive schrieb:> Andreas S. schrieb:>> Habe die ClockConfiguration aus Deinem *.zip-file entnommen.>> Das sieht meiner Meinung nach korrekt aus.>> Ich finde der fehler muss im Programm sein aber ich finde ihn leider> nicht.
Habe mir Deinen Code nun mindestens eine halbe Stunde angesehen, werde
aber nicht so recht schlau daraus.
Ich habe dabei 2 Probleme:
1.) Leider kenne ich mich mit HAL so gar nicht aus und
2.) Ich verspüre wenig Lust, gänzlich unkommentierten Code reverse
zu engineeren
Wenn Du hier die Funktionsweise Deines Code zumindest etwas erklären
könntest, so erhältst Du vielleicht von dem einen oder anderen noch
etwas Hilfe oder zumindest Hinweise.
Fragen wären z.B.:
- Wie funktioniert Dein Programm?
- Wie funktioniert Dein "overflow"-Mechanismus?
- Wie und wo genau wird die overflow-Variable gefüllt?
Weitere Fragen sind z.B.:
- Welche Frequenzen willst Du mit dem Teil messen?
- Woher nimmst Du die Messfrequenz, die Du untersuchst?
- Bist Du Dir 100%ig sicher, dass diese Messfrequenz stimmt?
- Spendiere und mal den Output Deines Programmes bei verschiedenen
Frequenzen: 1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 10kHz, 1MHz, 10MHz
Viele Grüße
Igel1
Andreas S. schrieb:> Ich habe dabei 2 Probleme:>> ............> 2.) Ich verspüre wenig Lust, gänzlich unkommentierten Code reverse> zu engineerenAndreas S. schrieb:> Wenn Du hier die Funktionsweise Deines Code zumindest etwas erklären> könntest, so erhältst Du vielleicht von dem einen oder anderen noch> etwas Hilfe oder zumindest Hinweise.
Zweimal Zustimmung zu dem schon geschriebenen.
Ich weiss warum ich HAL nicht mag obwohl man bei den neueren
Prozessoren fast nicht mehr drum herumkommt wenn man nicht
Bare Metal prgrammieren möchte. Für jedes Bit Setzen oder
Löschen eine HAL Call, auch die Interrupts werden schon mit
Callbacks "belastet", alles sehr unübersichtlich, jede HAL
Funktion wieder woanders suchen..... Und alles das bei einem
jetzt sehr kleinen Projekt ....
Ja ich habe mir das Zeugs heruntergeladen aber auch durch
HAL keine Lust das zu durchforsten ....
> Ich weiss warum ich HAL nicht mag obwohl man bei den neueren> Prozessoren fast nicht mehr drum herumkommt wenn man nicht> Bare Metal prgrammieren möchte. Für jedes Bit Setzen oder> Löschen eine HAL Call, auch die Interrupts werden schon mit> Callbacks "belastet", alles sehr unübersichtlich, jede HAL> Funktion wieder woanders suchen..... Und alles das bei einem> jetzt sehr kleinen Projekt ....
Was heißt nicht drumrum kommen. Es gibt auch die LL und die ist sogar
kombinierbar mit HAL.
Da alles auf Pulsdauer Messung beruht, bleibt nur der Berechnungsteil
als Fehlerquelle. Das hat nichts mit HAL zu tun.
inputCapture_A und inputCapture_B würde ich genauer unter die Lupe
nehmen, um zu sehen ob die Grundlage für die weitere Berechnung auch
stimmt.
Szenario: zwischen zwei Aufrufen der obigen ISR (nach meiner Berechnung
passiert das alle 100us) trudeln 80 Pulse rein.
Das entspricht einer Frequenz von 80/100us=800kHz und einer Pulsdauer
von 1/800kHz=1,25us.
Beim ersten Aufruf sei der Counter=10, beim nächsten Aufruf steht der
Counter auf 90, overflow gibt es keinen.
Dann ist nach meinen Überlegungen inputCapture_B=10 und
inputCapture_A=90.
Dann passiert in der Hauptroutine nach meinen Überlegungen folgendes:
1
#define MAX_CNT 100
2
if (update == 1)
3
{
4
// Igel1: zw_Erg=10-90=-80
5
zw_Erg = inputCapture_B - inputCapture_A;
6
7
if (zw_Erg >= 0) // Überlauf erkennung
8
{
9
pw_us = zw_Erg; // erg = (B-A)
10
}
11
else
12
{
13
// Igel1: wir landen in else-Zweig und pw_us=-80+100=20
Fazit: Nach meinen Überlegungen müsste eigentlich alles total
danebengehen:
50.000Hz Anzeige statt 800KHz.
Trotzdem berichtet der TO nur vor einer Abweichung von 1%.
Das heisst: ich muss wohl irgendwo sein Programm falsch nachvollziehen
...
Viele Grüße
Igel1
Andreas S. schrieb:> Fragen wären z.B.:>> - Wie funktioniert Dein Programm?
also ich habe den im InputCapture Interrupt auf fallender Flanke
eingestellt und im Interrupt des selben führe ich diesen
> - Wie funktioniert Dein "overflow"-Mechanismus?
wenn der zähler des selben Timer von 99 auf 100 geht zähle ich den
Overflow
> - Wie und wo genau wird die overflow-Variable gefüllt?>> Weitere Fragen sind z.B.:>> - Welche Frequenzen willst Du mit dem Teil messen?
Frequenzen bis 200Hz
> - Woher nimmst Du die Messfrequenz, die Du untersuchst?> - Bist Du Dir 100%ig sicher, dass diese Messfrequenz stimmt?> - Spendiere und mal den Output Deines Programmes bei verschiedenen> Frequenzen: 1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 10kHz, 1MHz, 10MHz
bei 100Hz = diese AUsgabe pw_us= 10100, Frequenz = 99.01 Hz OV=101
Die Funktionen sind alle inline und werden direkt auf die entsprechenden
register aufgelöst (kein overhead).
Die LL ist direkt mit dabei lässt sich auch im STMCube einstellen. So
wird nur LL verwendet und kein HAL.
Tut mir leid, Palmolive, Deine Erklärung ist alles andere als
verständlich - ich verstehe jedenfalls nach wie vor nur Bahnhof.
Du musst Dir schon etwas mehr Mühe mit der Erklärung der Funktionsweise
Deines Programms geben, sonst wird das hier nichts.
Viele Grüße
Igel1
123 Gast schrieb:> Wie soll er dass den auch noch schaffen.... Er meint nach wie vor dass> die Zeitbasis eines Oszis beliebig genau ist...
Ich traue einem guten Oszi mehr als meinem Programm.
Andreas S. schrieb:> Tut mir leid, Palmolive, Deine Erklärung ist alles andere als> verständlich - ich verstehe jedenfalls nach wie vor nur Bahnhof.>> Du musst Dir schon etwas mehr Mühe mit der Erklärung der Funktionsweise> Deines Programms geben, sonst wird das hier nichts.>> Viele Grüße>> Igel1
Habe den Fehler gefunden.habe den ersten Überlauf zu viel gzählt.
Jetzt geht es!
Schön das du den Fehler gefunden hast.
Palmolive schrieb:> Ich traue einem guten Oszi mehr als meinem Programm.
Du hättest aber schon lange HSE auf den MCO Pin ausgeben können, wenn
dann die 8MHz angezeigt werden, brauchst du nicht auf das Oszi
vertrauen, sondern kannst einfach messen.
Palmolive schrieb:> Habe den Fehler gefunden.habe den ersten Überlauf zu viel gzählt.Das war ja abzusehen, denn Palmolive schrieb:> bei 100Hz = diese AUsgabe pw_us= 10100, Frequenz = 99.01 Hz OV=101
Nur, was Du da programmiert hast, ist mir nach wie vor nicht klar.
Nicht, weil ich mich weigere diesen ganzen HAL-Klumpatsch durchzusehen,
sondern weil kein einziger Kommentar, keine einzige Erläuterung zur
gewünschten Funktion gegeben wurde.
Ebenfalls nicht zu verstehen ist, auf der einen Seite einen Zähler mit
dekadischem Überlauf zu programmieren und auf der anderen Seite
float-Berechnungen durchzuführen. Typischerweise läßt man einen 16 Bit
Zähler bis 65535 zählen, bevor ein Überlauf stattfindet. Der µC hat
keine zehn Finger, mit denen er ganz schnell zählen muß.
Morgen,
Zur Config interpretation:
Timer 2 alle 1ms Overflow,in dessen
Overflow ISR Callback alle 5 durchläufe
ein Pin Toggle. Dies ergibt 100Hz,
ist das die Frequenz die du aktuell an deinen Timer 3
Capture Input zum Messen gibst?
Timer 3 alle 100µs Overflow und Input Capture auf
Negative Flanke?
Beide Timer die selbe Clk Quelle,mehr oder minder Synchron.
1.) In Main deine Auswertung:
ZwErg = CapB - CapA
deklariert als
int32 = uInt16 - uInt16
wird nicht so funktionieren wie du dir das wünscht,
weil hier i.r. keine negativen Zahlen rauskommen werden.
uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl
ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.
Sprich du landest immer in deinem ersten If Zweig der auswertung.
z.B. uInt16 zuvor casten auf int32
Annahme obige Berechnung Korrigiert
Bsp: CaptureA = 99, Capture B = 49, OVR = 1 folglich 50µs
zwErg = B - A = -50 /folgt nun im If der zweig else
pwus = zwErg + 100(Max Capture Timer OVR Count) = 50
pwus = pw_us + (1* 100) = 150 -> eine Timer3 Overflow Periode zuviel.
Den Else Zweig kannst du dir sparen.
pwus = zwErg(-50) + (1*100) = 50 reicht.
Das dir der erste berechnungsfehler momentan nicht auf die
Füße fällt liegt wahrscheinlich auch daran das deine beiden
Capture A und B Werte (fast)immer gleich sind und die differenz
bisher nicht negativ wurde.
10ms Periode deiner Messfrequenz(100Hz) erzeugt mit dem selben Takt
zu deinen 100µs im Timer3 ist hier ein vielfaches.
Variiere hier mal und ich denke der Fehler wird auffallen.
2.) Capture ISR
-Negative Flanke, State = 1, Speicher Capture A
Capture WertA = 99, also 1µs Tick vor dem Overflow.
Nun kommt der Overflow und der Counter wird um 1 erhöht,
jetzt geht es mit etwas verzug in deine Capture ISR und
du nullst nun den Overflow Count, im grunde Race condition.
BSP:
A = 99 -> B = 49 ergibt 50µs Periodenzeit mit normal einem Overflow,
der aber hier aufgrund zeitlichen abläufen von deinem Programm
genullt wurde.
Auswertung: mit Korrigierten Berechnungen.
49 - 99 = -50 + (OVRCnt(0) * 100µs(CatureTimerOVR) = -50 -> falsch
-Negative Flanke, State = 0, Speicher Capture B
Capture WertB = 99, bis du in deiner Hauptschleife
die Auswertung beginnst ist der OVRCount hochgezählt worden
BSP.
Capture A= 49, CaptureB = 99, 50µs kein Overflow, aufgrund von verzug
bis in die Auswertung Overflow nun = 1
99-49 = 50 + (1*100) = 150 -> Falsch!
Um es abzukürzen:
Mino hat dir ein Link gepostet,schaue ihn dir an ich denke da kann
man vom prinzip her viel lernen.
Imho zeigt deine vorgehensweise lücken und tücken im Programm bin es
aber
nur kurz überflogen, vor missintepretation bin ich auch nicht gefeit.
FloMann schrieb:> Morgen,>> Zur Config interpretation:> Timer 2 alle 1ms Overflow,in dessen> Overflow ISR Callback alle 5 durchläufe> ein Pin Toggle. Dies ergibt 100Hz,> ist das die Frequenz die du aktuell an deinen Timer 3> Capture Input zum Messen gibst?
Genau war zu Hause ohne Funktionsgenerator eine einfache Möglichkeit zum
testen.
Ich habe den Code so umgebaut am Sonntag
Und auch mit dem Funktionsgenerator bis über 1KHZ keine Fehler und auch
hinter dem Komma genau.
War das Zufall?
FloMann schrieb:> 1.) In Main deine Auswertung:> ZwErg = CapB - CapA> deklariert als> int32 = uInt16 - uInt16> wird nicht so funktionieren wie du dir das wünscht,> weil hier i.r. keine negativen Zahlen rauskommen werden.> uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl> ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.> Sprich du landest immer in deinem ersten If Zweig der auswertung.> z.B. uInt16 zuvor casten auf int32
Ist das dann wircklich so?
Danke für die Hilfe
Palmolive schrieb:> FloMann schrieb:>> 1.) In Main deine Auswertung:>> ZwErg = CapB - CapA>> deklariert als>> int32 = uInt16 - uInt16>> wird nicht so funktionieren wie du dir das wünscht,>> weil hier i.r. keine negativen Zahlen rauskommen werden.>> uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl>> ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.>> Sprich du landest immer in deinem ersten If Zweig der auswertung.>> z.B. uInt16 zuvor casten auf int32>> Ist das dann wircklich so?>> Danke für die Hilfe
Ich kenne es so bei den von mir verwendeten Compiler.
C kümmert sich erstmal um die rechte seite von innen nach ausen.
Bsp siehe Bild, SDCC für 8051 Target.
Prüf es bei dir kostet keine Minute.
Das mit dem Video hätte man auch so lösen können das
man die gesammte Ausgabe sehen kann.
Auffällig:
OV ist 0
Capture Werte sind über 2^16 verteilt.
Wenn dein Timer3 alle 100µs überläuft kann das bei einer
Frequenz mit 1280,554Hz(T~781µs) nur schwer hinkommen.
Mir fehlt dazu das wissen der genauen STM32 Timer funktionen.
Deine Capture Werte liegen auch nicht wie ich erst dachte nur
zwischen 0-99, Timer Up Count auf == Top Wert dann Autoreload und
von vorne(0).
Warum:
Bei Capture Events wird oft der Zählerstand in das Snapshot register
gespeichert, da Timer Config auf 100µs OVR Zyklus dachte ich es werden
auch nur Werte in dem Bereich gezählt und gecaptured, entweder 0-99 oder
von startwert 2^16-100 zum überlauf hin.
Da mir genaueres wissen zum STM32 Timer hier fehlt kann
ich nicht weiterhelfen.
Nur irgendwas ist da inkonsistent, entweder weißt du es
selbst nicht was du genau machst und/oder müsstest mal mit
einer genauen erklärung rausrücken.
Bei z.B. den Timern im EFM8 den ich vor mir hab, der zählt im Capture
Mode immer kommplett rundum durch, was eh sinn macht da der Overflow
dann das increment des lsb der oberen 2Byte sind(32Bit betrachtet).