Also erstmal - Glückwunsch, dass D'es hingebracht hast - Du meintest bestimmt 50 Timerinterrupts / Sekunde.dreamon hat geschrieben:Also ich hab jetzt nochmal einen Timer, blauäugig gesetzt. Und der tut sogar. 924mal in 2Sekunden. (hab nen Counter mitlaufen lassen also nur ne Schätzung.)
Aber wenn man grob 500 Timer Interrupts Pro sekunde rechnet kommt man mit 20ms ganz gut hin. Erfasse nun alle 3 Takte auf auf einmal. Mit ByteNeu&~ByteAlt geht das ganz gut.
Ich werd mal die Praxistauglichkeit testen. Aber immerhin läuft es. Hab nen avr-gcc fehler entdeckt. Der hat mich heute bestimmt 3Stunden gekostet. Hab immer gedacht ich hab nen Programmierfehler gemacht. Der weil hat gcc mir nen Streich gespielt.
Naja.. Was soll.
Mal schauen wies weitergeht. Mich würde noch interessieren was man machen muß das der Browser der den Webserver anzeigt regelmäßig refresht so alle 50Sekunden wäre was.
Lösung:norbert_w hat geschrieben:Wegen dem Autorefresh, soviel ich bisher weiss geht das entweder vom Server aus, oder über ein Plugin im Browser (für Firefox dürfte da was zu finden sein). Ich muß bei einem Kunden noch Web-Bedienplätze mit Webserver (MS Server & IIS) in Betrieb setzen, und stehe da vor einem ähnlichen Problem - Aktualisierung (Rate im Webserver einstellbar) und kein automatisches LogOff...??
Code: Alles auswählen
PCICR |= (1<<PCIE2);
PCMSK2 |= (1<<PCINT21); //Port C5 ist Interrupteingang für Drehstrom-zähler (S0)
// Timer2 misst Millisekunden
TCCR2B = 0 | (1<<CS11 | 1<<CS12); //prescaler 256
TIMSK2 |= (1 << TOIE2);
ISR (TIMER2_OVF_vect) // Erzeugt Millisekunden
{ // Bei 16 MHz Prescaler 255 4,08 ms pro 255-Durchlauf oder Periode
TCNT2 = 255-62; //eigentlich 62,5
strommsek++;
}
/******************************
// 1kWh = 3600 kWs = 3600000 Ws
// Je kWh gibt mein Zähler 1000 Ticks ab
// Zur Veranschaulichung:
// Wenn alle 1000 ms (jede Sekunde) ein Tick kommt, beträgt die aktuelle Leistung Pab 3600000Ws : 1s : 1000 = 3600 Watt
// Würde die Zeit zwischen 2 Ticks 2 Sekunden betragen, wäre die Leistung 3.600.000Ws : 2s : 1000 = 1800 Watt
SIGNAL(SIG_PIN_CHANGE2) // Drehstrom-Zähler S0 Ausgang
{
if (strommsek > 200) // Kürzere Impulszeiten werden herausgefiltert, PinChange reagiert bei steigender und fallender Flanke
// Käme alle 200 ms ein Impuls, wäre die aktuelle Leistung 5 x 3600 W = 18000 W
{
Pab = 3600000 / strommsek; // Der Zähler liefert 1000 Ticks / kWh
Etticks++;
strommsek = 0;
}
}
******************** PIN CHANGE
Code: Alles auswählen
TCCR2B |= (1<<WGM22) | (1<<CS20 | 0<<CS21 | 1<<CS22);
TCNT2 = 0;
TIMSK2 |= (1 << OCIE2A);
// Vielleicht kann mir einer sagen was ich da genau gesetzt hab. Welchen Takt? ;-)
Eventuell kann mir auch einer sagen, wie man ihn errechnen kann. Das Datenblatt ist
mir zu hoch. Die Beispiele von euch waren sehenswert aber ließen immer noch Fragen offen.
----------------------------------------------------------------------------------------
//Timer Interrupt
ISR (TIMER2_COMPA_vect)
{
Testbit++; // zählt die Einsprünge .. Unwichtig.
Merke = Impuls_Port_Read; // PortA Auslesen (Bit 1,2,3)
if (Merke!=Muster) // Abkürzen wenn sich nichts getan hat.
{
patt = Merke&~Muster; // patt !=0 -> Ein oder mehrere Pins springen auf High.
if (patt) { if (patt & 1) {StromZaehler1++;}
if (patt & 2) {Strom2++;} // Wegen Compilerfehler umbenannt!
if (patt & 4) {StromZaehler3++;}
}
Muster=Merke; // neues Muster merken!
}
}
In der Main steht:
Lcd_print(1,0,"T:%4i|%4i|%4i", StromZaehler1, Strom2, StromZaehler3);
Wenn ich hier den int Strom2 in Stromzaehler2 umbenenne, (natürlich auch oben im Timer Interrupt) dann fehlt mir die Ausgabe der Variable. Hab schon mehrfach Probiert. Da macht avr-gcc einen Fehler. Nur das Umbennen führt zu einer korrekten Ausgabe. Ganz schlimm wird es wenn ich aus "int" long int mache, dann kann ich umbenennen wie ich will. Die 2
Variable wird nicht ausgeben. 0000 tzzz. Obwohl der Inhalt korrekt ist. Wenn ich z.B. nur Strom2 ausgebe geht es.
Code: Alles auswählen
volatile uint16_t wattstunden1 = 0; // Zähler bis 1000 Wattstunden
volatile uint16_t kilowattstunden1 = 0; //Zähler bis 65535 kWh
in der ISR dann:
if(patt)
{
uint16_t Tausend = 1000; // Register mit 1000 laden für mehrere Vergleiche
if(patt & 1)
{
wattstunden1++;
if(wattstunden1 > Tausend)
{
kilowattstunden1++;
wattstunden1 -= Tausend;
}
}
}
und ich nie bezweifelt, dass nur schöner Code funktioniertIch hab nie behauptet das ich schönen Code Programmiere!!!
volatile heisst nicht unwichtig, sondern flüchtig. Damit wird dem Compiler mitgeteilt, das er vor einer Operation den Inhalt der Variablen neu einlesen soll. Er könnte den Befehl weg optimieren, weil er sich in einer Routine nicht verändert wird. volatile sagt, obachtt, die Variable wird Hardwaremässig oder in einem Interrupt geändert. Wirkt dann wie der Refreshbutton im Browser.Üübersetzt -> Heißt es "unwichtig". Na wenns unwichtig ist, dann weg damit.
Jetzt stell Dir mal vor, Dein mega hat 'nen Quarz mit 16Mhz. Das bedeutet, dass er theoretisch 16 Millionen Befehle per Sekunde abarbeitet (die meisten Befehle brauchen 1 Takt, Speicherzugriffe (dazu zählen auch absolute Sprünge und Funktionsaufrufe) meistens 2 Takte. In 20 ms sind das immer noch 80000 Befehle.Aber das mit den 1000 umrechnen usw., werd ich nicht in die Timer Rutine tun. Die soll so kurz
wie möglich sein, nicht das sich Timer überschneiden. Jedes Byte ist eines zuviel in der Timer Runtine..
Im EEPROM, in der cmd.c wird z.Bsp die IP-Adresse im EEprom gespeichert oder aus dem EEprom gelesen, Versuche mal dort mit dem Howto zu beginnen. Ansonsten auf mikrocontroller.net gibt's auch ganz nette Tutorials.Weißt du zufällig ob es möglich ist Variabeln dauerhaft zu sichern ?
Mistverständnis befürchtet: ich meinte diese ZeileFür deinen Tipp mit dem doppelten if (patt) kann man vermutlich mit switch(){ case 1: } optimieren, bin ich dir dankbar.
Code: Alles auswählen
if (Merke!=Muster) // Abkürzen wenn sich nichts getan hat.
Ich heisse Birger -- und nicht googleBilgert:
Könntest du mir die paar Seiten aus dem Buch einscannen? Das mit dem Timer/Interrupt würd ich schon ganz gern mal versehen. Könnten uns eventuell mal per ICQ, Yahoo, MSN in kontakt treten