www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik CPU Auslastung messen


Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich versuche seit einiger Zeit, mir eine Methode ausdenken, wie man die
Auslastung der CPU mit einfachen Mitteln (sprich wenigen Befehlen)
ermitteln kann. Aber irgendwie stehe ich bei diesem Problem auf dem
Schlauch.

Ich denke mir zur Zeit, in einer Hintergrundaufgabe einen Zähler
hochzuzählen und diesen Zähler dann zu vergleichen. Aber womit
vergleichen? Was wäre die Basis für die Ermittlung der Auslastung?

Vielleicht hat ja jemand eine Idee, um mir auf die Sprünge zu helfen.
Beim Suchen im Internet bin ich bis jetzt nur auf Methoden gestossen,
die sich recht kompliziert angehört haben und IMHO selber bereits
reichlich Rechenzeit verbrauchen. Das wollte ich eigentlich vermeiden
:-)

Gruß
Thorsten

Autor: Fritz Ganter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach das bei mir so:

In der Haupschleife schicke ich den µC in den sleep, daraus wird er 128
mal in der Sekunde geweckt und dann fährt der Controller mit dem
Programm fort.
Jetzt setze ich vor dem Sleep einen Portpin auf low, nach dem Sleep
einen Portpin auf High. Dann mess ich mit dem Oszi das Portsignal, High
heisst dann er rechnet, low er schläft.
Man kann auch eine LED dranhängen und sieht an der Helligkeit wann er
grad wieviel rechnet.

Bei einzelnen routinen kann man es genauso machen.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Fritz,
danke für die schnelle Antwort.

Für die Laufzeitmessung einzelner Programmteile habe ich diese Methode
auch schon eingesetzt. Funktioniert einwandfrei.

Leider kann ich den µC nicht zum "Schlafen" schicken da er auch in
der Hauptschleife einiges zu tun hat und damit permanent arbeiten
muss.

Ich dachte eigentlich mehr an eine Berechnung, bei der hinten eine Zahl
zwischen 0 und 100 (oder was auch immer) rauskommt. Diese Zahl könnte
ich dann weiterverarbeiten.

Oder habe ich immer noch ein Brett vorm Kopf, dass mir der Zusammenhang
nicht auffällt?

Gruß
Thorsten

Autor: Thomas K (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also wenn er in der hauptschleife auch die ganze zeit was abarbeitet,
dann hat er meiner meinung nach 100% cpu auslastung :)

Autor: Azrael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde auch sagen(wie Thomas K.) das die CPU 100% last hat.

Wenn du jedoch in der hauptschleife nichts hast könntest du ja da einen
zähler hoch zählen lassen, und mit einem timer immer wieder auf 8 setzt.
Der Stand des zählers ist die prozesslast da ja die Interrupts die
Hauptschleife unterbrechen und die so nicht weiter zählen kann. so
müsstest du annähernd an 0-100% kommen.

Nachteil:
Hauptschleife muss frei sein,
ein timer wird benötigt.

aber im prinzip müsste es funktionieren, ohne oszi, ohne externer
hardware, oder irre ich micht?

mfg Azrael

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@all
Danke für die Antworten.

Ich habe gerade festgestellt, dass es gar nicht so leicht die richtige
Frage zu stellen. Ihr habt recht: Die Auslastung ist 100% bei der
Fragestellung!!!!!

Daher noch ein Versuch:

Ich habe zwei zyklische Tasks per Timer-Interrupt (eine schnell(50µs);
eine langsam (20ms)). Dazu kommen noch azyklische Interrupts von
verschiedenen Kommunikationen (USART, TWI, SPI). Ausserdem gibt es
Hintergrundaufgaben in der Hauptschleife.

Und jetzt die Frage:
Wie kann ich die Zeit messen (in %), die die Hintergrundaufgaben von
der CPU-Zeit zur Verfügung haben?

Ich hoffe, die Frage diesmal richtig gestellt zu haben.

@Azrael
Ich denke du hast die geleiche Idee wie ich schon hatte: Einen Zähler
hoch zählen lassen und dann vergleichen. Aber womit vergleichen?!?!

Gruß
Thorsten

Autor: Azrael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int main(void){
  while(1){
     count++;

  }
}

SIGNAL(SIG_OVERFLOW1){
    prozent = (count/typ_count)*100
    count=0;
}

Ich hab das so gemeint.

In der Schleife im main zählst du den counter immer nach oben. Wenn
niemand etwas in der zwischenzeit macht, sollte immer der selbe wert
beim timer_interrupt sein(das währe typ_count) dieser Wert würde 100%
entsprechen. wenn jetzt andere interrupts rechenzeit verbrauchen sinkt
der count Wert. -> niedrigere cpu-last.

wenn immer irgend ein interrupt rechenzeit verbraucht kommt 0%raus(da
ja nie die Schleife abgearbeitet werden kann.

Ich habs noch nie ausprobiert, aber wenns funktioniert währe ich an dem
sourcecode interessiert, für ein paar benchmarks ;)

mfg Azrael

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke, der Zähler müsste genau anders herum funktionieren. Wenn
Maximum erreicht dann 0% Auslastung, da ja nichts anderes abgearbeitet
wird. Wenn dauernd ein Interrupt ansteht dann wird der Zähler nicht
mehr hoch gezählt und die CPU 100% Auslastung. Deine Rechnung würde
ergeben wieviel Prozent CPU-Zeit noch verfügbar ist. Eigentlich sind
beide Ergebnisse brauchbar.

Ich denke mir auch das ein Zähler (count) benötigt wird. Dieser wird
dann mit einem Vergleichswert (typ_count) verglichen. Kommt jetzt die
Frage worauf basiert der Vergleichswert? Ich sehe zur Zeit 2
Möglichkeiten:

1. Taktzeit der CPU: Jeder Takt, der nicht für den Zähler verwendet
wird, wird dabei als verbrauchte Rechenzeit gewertet. => inc count &
nop würden bereits eine Auslastung von 50% ergeben (ich programmiere in
Assembler :-) kann aber auch C lesen). => Dabei bereits 50% Auslastung:
Ergebnis unbrauchbar.

2. Durchlaufzeit der Hintergrundaufgabe: Die Durchlaufzeit der
Hintergrundaufgabe würde als Basis für den Vergleichswert dienen.
Dadurch würde die Hauptschleife (while(1)) nicht gewertet. =>
Unabhängig von der Hauptschleifenlänge ergibt sich eine Prozentzahl die
irgendwo zwischen 0-100% liegen müsste: Ergebnis schon weitaus
brauchbarer, nur es wird halt nicht die Hintergrundaufgabe bewertet.
Muss die eigentlich miteingerechnet werden oder darf man das
vergessen?

Vielleicht hat ja jemand noch eine Idee, wie dieser Vergleichswert
ermittelt werden kann.

@Azrael
Wenn jemals brauchbarer Code herauskommt, kann ich ihn gerne posten
:-)

Gruß
Thorsten

Autor: JOchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich würde sagen, man hat einen Zähler der durch einen Timer
hochgezählt wird, und immer die CPU in eine Funktion wo sie arbeiten
muss hüpft steht am anfang der Befehl TImer Stopp, und am Ende Timer
an. Wenn bereits ein Timer verwendet wird kann das ganze über ein flag
realisiert werden. Man muss also nur wissen welche funktionen als
Arbeit gelten und Welche nicht. Der Zähler hat dann die Zeit die die
CPU nicht mit Arbeit verwendet hat. Um jetzt die AUslastung zu kriegen
kann man jetzt
a) einen weiteren zähler hochzählen lassen der immer hochzählt und dann
teilen
b) am Anfang der Hauptschleife, den Arbeitlosenzähler entsprechend
auswerten

Es könnte wie folgt aussehen

char flagarbeitlos;
unsigned int timer_arbeitlos,timer_gesamt;
unsigned char cpuaus;


void InitLastAusgabe()
{
  timer_arbeit=timer_gesamt=0;
  cpuaus=0;
}

void timer_isr()
{
  if(!flagarbeitlos)
    timer_arbeitlos++;
  timer_gesamt++;
  if(timer_gesamt==1000)

  cpuaus in %
  cpuaus=timer_arbeitlos/10;  //cpuaus=timer_arbeitlos*100%/1000
}

unsigned char GetCPUAus()
{
  return cpuaus;
}


//eine Funktion Arbeit kann wie folgt aussehen
//dabei kann das eine INterruptroutien oder ... sein hauptsache
flagarbeitlos wird gesetzt

void FktArbeit()
{
  // oft auch erst die Frage nach gibt es arbeit
  //nein return

  //ja
  flagarbeitlos=0;

  //Arbeit

  flagarbeitlos=1;
}


//WIchtig ist aber allerdings das flagarbeitlos immer gelöscht und
wieder gesetzt wird
//um auf nummer sicher zu gehen kann in bereichen die nicht als Arbeit
defeiniert sind immer wieder mal
//flagarbeitlos=0; stehen

Autor: JOchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh hab ich grad übersehen in der timer_isr bei
 if(timer_gesamt==1000)
 {
      cpuaus in %
      cpuaus=timer_arbeitlos/10;  //cpuaus=timer_arbeitlos*100%/1000
      timer_arbeitslos=timer_gesamt=0; //muss natürlich wieder aus null
gestetzt werden
 }

diese abfrage könnte man auch in die Hauptschleife stellen
jedoch dann mit
if(timer_gesamt>1000)
{
  cpuaus=timer_arbeitslos*100/timer_gesamt;
  timer_arbeitlos=timer_gesamt=0;
}

Autor: Jan Haan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist der CPU nicht immer voll ausgelastet? Ich meine, der macht doch
durchgehend was, selbst wenn der keine Aufgabe hat:

while(1)
{
}

Selbst dabei hat der dann doch durchgehend (Sprung-)befehle.

Ist aber nur ne Vermutung :)

Autor: JOchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja klar aber interesant ist ja ob er nur Sprungbefehle macht, oder ob er
was "rechnet"

Autor: JOchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn er nur sprungbefehle mach weiss ich ich kann ihn noch mehr mit
aufgaben belasten

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@JOchen
Wenn ich das ganze richtig verstanden habe, dann wird flagarbeitlos am
Anfang einer Routine gesetzt und am Ende wieder rückgesetzt. Damit
ergibt sich aber doch dass z.B. in einer ISR das flag gesetzt und
wieder rückgesetzt wird ohne das die Timer-ISR überhaupt etwas davon
mitbekommt, da ja ein neuer Interrupt erst abgearbeitet wird, wenn der
aktuelle fertig ist. So habe ich das mit den Interrrupts bis jetzt
jedenfalls verstanden. Damit würde timer_arbeitlos jedoch niemals
hochgezählt und die Auslastung wäre immer 0% und das wäre dann nicht
richtig. Wenn mir bei dieser Überlegung etwas entgangen ist, lass es
mich bitte wissen.

Aber mit dem flag könnte man z.B. einen Timer starten und stoppen und
mit einem Vergleichstimer vergleichen und so die Auslastung bestimmen.
Kostet halt einen Timer. Frage in dem Zusammenhang: Kennt jemand eine
Möglichkeit, den Zählerstand des Watchdog-Timers bei einem AVR
auszulesen? Ich denke, damit würde es relativ einfach werden, habe aber
dazu noch nichts gefunden.

@Jan
wie JOchen schon sagte, die CPU hat immer was zu tun. Muss auch so
sein. Es geht nur darum, zwischen "sinnlosen" Befehlen (mit Hilfe von
Sprüngen warten in der Hauptschleife) und "sinnvollen" Befehlen (z.B.
abarbeiten eines Interrupts) zu unterscheiden. Siehe auch weiter oben.

Gruß
Thorsten

Autor: JOchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja stimmt schon das erst der Interrupt vom timer wieder abgearbeitet
wird wenn dieser interrupt fertig ist. Jetzt hast du 3 möglichkeiten:
1.Wenn der µC es zulässt kannst du mit unterschiedlichen interrupt
prioritäten arbeiten, d.h. timer hat eine hohe was natürlich bei sehr
zeit kritischen int's probleme macht da diese dann öfters unterbrochen
würden(kommt bei dir Thorsten ja nicht in frage)
2.Am ende einer interrupt routine die als arbeit gilt den zähler für
gesamtzeit um einen wert erhöhen, der der zeit entspricht die die cpu
zum abarbeiten der Interrupt routine braucht, dazu musst du die zeit
durch das T des Timers teilen, hier braucht man dann das flag nicht
setzten und löschen. nur interessant wenn der INT fkt nicht komplex ist
d.h. mal ist arbeit dann wieder nicht, mal nur 100µs mal 1ms

3.Interrupts einfach ignorieren, da allg. die zeit die die CPU in einer
int fkt ist eh so kurz wie möglich sein soll->wenn jedoch zu lang siehe
2. (kommt ja auch nicht in frage weil du ja nur in den Timer ints
steckst)

naja wenn du die mainloop, und die tasks mal hier rein stellst kann ich
dir mehr helfen, hab aber biss jetzt nicht so vorstellen wie den dein
Code aussieht

den biss jetzt wurd ich sagen das man ein timer einsparen kann, wenn
mann beide task durch einen Timer steuert. und man kann die task auch
so ablaufen lassen, das sie nicht als interrupts ausgeführt werden
Gruß Jochen

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde den Timer einfach laufen lassen. Es gibt dann eine globale
Variable die die Ticks des Timers zählt die als Arbeits-ISR's
abgearbeitet wurden. Dazu muß am Anfang jeder ISR der Timer ausgelesen
werden und am Ende auch. Die Differenz dieser Zählerstände wird
ermittelt und auf die globale Variable addiert. Man hat also in der
globalen Variable die Anzahl an Timer Ticks die in den ISRs verbraucht
wurden. Nun, in der Timer ISR, die ja exakt in einem festen Intervall
relativ zur MCU Taktfrequenz läuft, kann man nun die insgesammt
verbrauchten Timer Ticks ermitteln. Anteilmäßig davon stehen in der
globalen Variable die Anzahl der Ticks die in den Arbeits-ISR
verbraucht wurden. Es entsteht eine simple Verhältnissgleichung, mit
der man entweder Prozentual die Auslastung errechnen kann, oder aber
sogar das Verhältnis in Taktzyklen.

static int32_t ISR_Ticks = 0;

signal Arbeits_ISR() {
  ISR_Ticks -= TCCNT0;
... bla bla bla
  ISR_Ticks += TCCNT0 + Ticks_benötigt_für_Overhead_Berechnung;

}

static uint8_t Percent = 0;

signal Timer0_Overflow() {

  Percent = (Percent + 100 * (256 + TCCNT0) / ISR_Ticks) / 2;
  ISR_Ticks = 0;
}

Das funktionert weil auf AVR's normalerweise nur einen IQR Level
existiert. D.h. ISR's sind nicht verschachtelt sondern sequentiell.

Gruß Hagen

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@JOchen
Bevor ich das ganze Programm poste, möchte ich eine kleine
Zusammenfassung geben. Es besteht zur Zeit aus 4 .asm Files mit
zusammen 64kB Dateigröße und ca. 2000 Zeilen. Dazu kommt noch ein
Makro-File mit 12kB. Das generierte .hex-File ist dann noch 13kB groß.
Dazu kommt noch, dass das ganze Projekt noch nicht fertig ist, d.h.
einige Stellen sind zwar angefangen aber funktionieren noch nicht. Wenn
du trotzdem einen Blick reinwerfen möchtest, kann ich es gerne
reinstellen.

Übersicht über das Projekt:

Aufgabe: Steuerung einer Eisenbahnanlage

µC: ATMega16 (zur Zeit betrieben mit internen 8MHz, um den Quarz zu
sparen :-), ist also noch was rauszuholen)

geplante Kommunikation: TWI zur Kommunikation mit weiteren AVR's, SPI
zur Porterweiterung (siehe WIKI)

geplante Tasks:
1. Timer1-ISR mit ca. 30-50µs (ergibt sich dann aus der CPU-Auslastung)
für SW-PWM mit 16 Kanälen (HW-PMW hat der µC ja leider "nur" 4).
Laufzeit dieser ISR ca. 20µs

2. Timer2-ISR mit 10ms, die dann über weitere Untersetzungen
verschiedene Aufgaben (z.B. Rampenberechnungen) zyklisch starten soll.
Laufzeit z.Z. unbekannt.

3. SPI-ISR. Ich denke im Moment an eine Frequenz von ca. 100kHz was
einen Interrupt alle ca. 100µs auslöst. Laufzeit der ISR selber ca.
2µs, die nachfolgende Auswertung ca. 20µs.

4. Hauptschleife. Als erstes wird das Interrupt-Flag vom TWI abgefragt.
Da ich bis jetzt noch nicht in der Lage war eine vernünftige ISR dafür
zu schreiben, muss ich das Flag halt abpollen. ISR kommt dann später
mal :-) Aber damit das funktioniert muss halt recht hochzyklisch
abgefragt werden. Ausserdem werden noch verschiedene andere Aufgaben
ausgeführt, die aber dann keine große Priorität haben.

Aus diesen Angaben ergibt sich bereits eine rechnerische Auslastung
allein aus 1. und 3. von 60% (bei Timer1-ISR=50µs) bis 87% (bei
Timer1-ISR=30µs). Daher kam dann die Frage nach der Online Berechnung
der CPU-Auslastung.

Ich hoffe, du kannst dir jetzt ein besseres Bild von der ganzen Sache
machen. Und wie gesagt, wenn du noch willst, kann ich den Code gerne
reinstellen .

@Hagen
Die Idee mit dem Timer gefällt mir eigentlich auch ganz gut. Ich
fürchte zur Zeit nur, dass es nicht mehr funktioniert, wenn ich auch
die Auslastung einer Hintergrundaufgabe mitmessen will. Irgendwann
unterbricht die ISR diese Aufgabe und die Berechnung der Timer-Ticks
kommt durcheinander. Sehe ich das richtig? Wenn nur ISR's gemessen
werden sollten, müsste es funktionieren. Entschuldige wenn ich mich
nicht klar ausgedrückt habe.

@all
Danke für die ganzen Anregungen und Ideen.

Gruß
Thorsten

Autor: Frankl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Erfahrung mit internen Osz. sind sehr schlecht, da sie meist nur
aus R&C bestehen und somit sehr temp. Abhängig sind.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Frankl,
stimmt schon dass die internen Schwingkreise nicht besonders gut sind.
Aber solange alles synchronisiert läuft (TWI, SPI) und auch sonst keine
Probleme auftreten, warum nicht? Z.B. beim USART-Betrieb sollte man
schon einen Quarz spendieren. Kann dann einige "unerklärliche"
Probleme vermeiden. Hab es selber erfahren müssen. :-)

Gruß
Thorsten

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann bleibt dir nur eines übrig:
In deimem Program MUSS es ja eine Hauptschleife geben. Diese pollt
verschiedene Ereignisse solange bis diese eintreffen. Nun, beim Start
dieses Pollen wird der aktuelle Timer ausgelesen und gespeichert.
Sobald nun ein Ereignis beim Pollen zutrifft wird wiederrum der Timer
ausgelesen und mit dem Startwert zu einer Differenz subtrahiert. Da du
aber ganz exakt die Taktzyklen die das Pollen benötig ausrechnen
kannst, und den Prescaler des Timers kennst, hast du nun die
Möglichkeit exakt auszurechnen wie lange deine ISR zum Zeitpunkt des
Pollens benötigt haben. Die anderen Task, die ja durch das Pollen
angesprungen werden, würden in dieser Rechnung mit einfließen können,
je nachdem wie du dir das wünscht.

Wichtig ist eben nur eines, der Timer muß laufen, egal ob ISR oder
Hauptschleife. Nur mit hilfe des Timers hast du eine sichere Taktzyklen
basierte Methode.

Zb.

// Hauptschleife

uint16_t TimerWert = TCCNT0;
while (1) do {
  uin16_t r,t = TCCNT0;
  r = t;
  if (r <= TimerWert) r +=256;
  r -= TimerWert;
  TimerWert = t;
  uint16_t Percent = (t - X) / 256 * 100;

  if (Polled) {
  }
}

Nun, wichtig ist oben das X, es gibt an wieviele Ticks das Pollen samt
Timer auslesen in der Schleife dauert. Sollte zB. der PreScaler vom
Timer0 auf 1 stehen, so würde X exakt die Taktzyklen angeben. In t muß
also immer mindestens die Dauer in Ticks die für das Pollen in der
Hauptschleife benötigt wird stehen. Dies wären dann 0 Prozent. Sobald
aber t größer ist als X heist dies das entweder eine ISR ausgeführt
wurde oder aber eine Unterfunktion aus der Hauptschleife heraus
aufgerufen wurde. In diesem Falle ist t > X und somit Percent > 0.
Mit dieser Methode würdest du die Gesamtauslastung der MCU messen, je
kleiner Percent um so häufiger wurde die Hauptschleife durchlaufen im
gleichem Zeitraum.
Ein andere Methode wäre den Timer0 auf Zb. exakt 1 Sekunde
einzustellen. Nahc dieser Sekunde wird in der Timer ISR ein Zähler
ausgewertet. Etwa so

uint16_t Counter = 0;
uint16_t Percent = 0;

signal Timer0() {  // alle 1 Sekunde
  Percent = (Percent + Counter / MaxCounter * 100) / 2;
  Counter = 0;
}


void Main() {
  while (1) {
    Counter++;
    if (Polled) {
      bla bla...
    }
  }
}

MaxCounter musst du nun so berechnen das dort die Anzahl an
Schleifendurchläufen pro 1 Sekunde drinnensteht die die Mainloop
MAXIMAL durchlaufen kann. Diese ließe sich von Hand berechnen oder aber
du deaktivierst ALLE ISR's bis auf den Timer0 und rufts un Mainkloop
keine Unterfunktionen auf. Daraus ergibt sich also die Maximale Anzahl
an Aufrufen von Counter++ in der Mainloop pro Sekunde, wenn NICHTS
anderes durch die MCU ausgeführt wird.

Gruß Hagen

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Diese ließe sich von Hand berechnen oder aber
>du deaktivierst ALLE ISR's bis auf den Timer0 und rufts un Mainkloop
>keine Unterfunktionen auf.

Da könnte man doch eigentlich auch eine init-Unterroutine aufrufen, die
den Timer inkl. Interrupt aktiviert und eine fest definierte Schleife
durchlaufen. Am Ende der Routine wird der Zählerstand des Timers
ausgelesen und weis, wie viele Durchläufe pro festgelegtem Zeitraum
überhaupt möglich sind. In der Hauptschleife kann man diesen Wert dann
als Referenz verwenden.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@OldBug, korrekt.
Man könnte aber auch den Wert von MaxCounter abhänig vom Counter
ermitteln. Etwa so


uint16_t Counter = 0;
uint16_t MaxCounter = 1;
uint16_t Percent = 0;

signal Timer0() {  // alle 1 Sekunde
  if (Counter > MaxCounter) {
    MaxCounter = Counter;
    Percent = 100;
  }
  Percent = (Percent + Counter / MaxCounter * 100) / 2;
  Counter = 0;
}


void Main() {
  while (1) {
    Counter++;
    if (Polled) {
      bla bla...
    }
  }
}


Nun würde das System schon während der Laufzeit die eigenen Schranken
ermitteln. Nach wenigen Sekunden hätte sich MaxCounter so stabilisert
das er die größt mögliche Dauer angibt die in der Main Loop ohne
weiterem zusätzlichen Code verbracht wurde. Dieses System würde sich
selbst kalibrieren.

Percent gibt natürlich hier den Prozentsatz an in dem die MCU nichts
tut. D.h. 100% bedeutet die Freizeit die die MCU hat, bei 0% ist die
MCU voll ausgelasstet.

Gruß hagen

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorteile der obigen Methode liegen auf der Hand. Ob man den 8 oder 16
Bit Timer benutzt oder in welchem Interval die Timer ISR aufgerufen
wird ist fast egal. Wichtig ist nur das im Durchschnitt Counter++ in
der Mainloop häufiger aufgerufen wird als die Timer ISR.
Nachteil ist allerdings das die Timer ISR durch höherpriveligierte ISR
blockiert werden kann. D.h. gerade zum zeitpunkt wenn ein Timer OVR
eintritt wird eine längrdauernde ISR ausgeführt. In diesem Moment würde
eine Verfälschung entstehen. Man könnte das kompensieren indem man
TCCNT0 abfragt in der Timer ISR.
Desweiteren wird auch durch das Sperren der IQR's mit CLI die Methode
verfälscht. Man kann dies durch eine andere Methode verhindern:

void Main() {
  uint16_t Ticks, Percent, MinTicks = 0xFFFF, WaitCount = 0;

  Ticks = TCCNT0;
  while (1) {
    if (++WaitCount = 100) {
      WaitCount = 0;

      Ticks = TCCNT0 - Ticks;
      if (Ticks == 0) Ticks += 256;

      if (Ticks < MinTicks) {
        MinTicks = Ticks;
        Percent = 100;
      }

      Percent = (Percent + MinTicks / Ticks * 100) / 2;
    }

    if (Polled) {
      bla bla...
    }

  }
}

Vereinfacht dargestellt und als ungetesteter Vorschlag. Hier benötigen
wir keine Timer ISR mehr.

Gruß Hagen

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@all
Danke für alle Amregungen und Ideen. Ich versuche mich jetzt mal an der
Realisierung der Auslastungsberechnung. Wie versprochen werde ich das
Ergebnis dann hier posten.

Gruß
Thorsten

Autor: Thorsten (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo allerseits,
im Anhang ist das Ergebnis der Diskussion. Es ist das komplette
Testprogramm für die Routine der Auslastungsberechnung. Funktioniert
eigentlich ganz gut. Ich hoffe es ist ausreichend kommentiert. Meine
Makros habe ich drin gelassen. Dadurch sollte die Lesbarkeit erhöht
werden.

Getestet im AVR-Studio 4.08 auf ATMega16-Plattform mit verschiedenen
Frequenzen. Außerdem verschiedene Belastungen und Berechnungszyklen
eingestellt. Das Ergebnis sah plausibel aus.

Es sollten nicht mehr allzu viele "Leichen" drin sein:-)

Wer mag, viel Vergnügen.

Thorsten

PS: Eingestellte Tab-Breite = 2.

Autor: Thorsten (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
und die Makros

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.