Hey, ich will eine Zeitverzögerung mit dem runterzählen in einer schleife erreichen. Der code in bascom sieht so aus While A<>B B=B+1 Wend Die Bascom Simulation sagt mir das die schleife 71 Takte braucht (A und B als long) Berechnen ich nun A für 5 minuten und lasse solange zählen bis A=B (67605633) und lasse das auf dem Mikrocontroller laufen (danach geht eine led an) mit 16 Mhz laufen, dann komme ich auf ca. 5 min und 9 sekunden. Das ist ja schon arg ungenau. Stimmt das mit den 71 Takten wohlmöglich nicht?
ja, ich will es aber nicht mit timern machen, da ich alle 2 bis 3 mikrosekunden auflösung haben will und das hauptprogramm nicht unterbrochen werden soll.
@ Felix A. (flakki) >Hey, ich will eine Zeitverzögerung mit dem runterzählen in einer >schleife erreichen. Kann man machen, ist aber ungenau und nervig. Nimm einen Timer, ist 1000mal besser und gar nicht schwer. >Berechnen ich nun A für 5 minuten und lasse solange zählen bis A=B >(67605633) und lasse das auf dem Mikrocontroller laufen (danach geht >eine led an) mit 16 Mhz laufen, dann komme ich auf ca. 5 min und 9 >sekunden. >Das ist ja schon arg ungenau. Stimmt das mit den 71 Takten wohlmöglich >nicht? Siehe oben. MFG Falk
@ Felix A. (flakki) >ja, ich will es aber nicht mit timern machen, da ich alle 2 bis 3 >mikrosekunden auflösung haben will und das hauptprogramm nicht >unterbrochen werden soll. In BASCOM, is klar . . . "Iam just a dreeeeeeaaamer . . ."
wie sieht das aus wenn ich die while schleife in assembler machen? dann sollte es doch besser seien.
@ Felix A. (flakki) >wie sieht das aus wenn ich die while schleife in assembler machen? dann >sollte es doch besser seien. Es wird nur besser, wenn du dich mal über Netiquette informierst und auch beherrzigst. http://www.mikrocontroller.net/articles/Netiquette#Klare_Beschreibung_des_Problems
Ja, vielen dank für den Hinweis. Ich würd nun gern wissen wie der fehler zustande kommt. Mein Problem mit den Timern ist nur, das ich dann alle 3 Mikrosekunden einen interrupt im Hauptprogramm hätte. Das wollte ich nun mit dem runterzählen vermeiden.
@ Felix A. (flakki)
>Ja, vielen dank für den Hinweis.
..aber leck mich am Arsch. Aha.
Felix A. schrieb: > Mein Problem mit den Timern ist nur, das ich dann alle 3 > Mikrosekunden einen interrupt im Hauptprogramm hätte. Das wollte ich nun > mit dem runterzählen vermeiden. Wenn du dich mit dem Timer ernsthaft befaßt hättest, wüßtest du, dass das nicht so ist. Abgesehen davon: Wieso stört das dein Hauptprogramm, wenn du das Timing über Timer machst?
ja ok, der Timer unterbricht vielleicht nicht so oft, aber ich will/ muss alle 2 Mikrosekunden eine bedingung prüfen, die von dem Überlauf des Timers abhängig ist. Dann bringt es nichts wenn erst alle 10 mikrosekunden der überlauf da ist.
für den Mikrosekundenbereich wirst Du Dich wohl oder übel mit Assembler anfreunden müssen, evtl. geht es noch in C
Ok, also du meinst das ich mit der dieser schleife in Assembler genauer hinkomme...
Felix A. schrieb: > ja, ich will es aber nicht mit timern machen, da ich alle 2 bis 3 > mikrosekunden auflösung haben will Du mußt 5 Minuten lang warten mit einer Auflösung von 2 Mikrosekunden? > und das hauptprogramm nicht unterbrochen werden soll. Wärend deiner Warteschleife steht das Hauptprogramm doch komplett.
Felix A. schrieb: > da ich alle 2 bis 3 mikrosekunden auflösung Was glaubst du, was ein µC ist? Eine 3-GHz-Granate wie ein PC? Mit 16 MHz Taktung schafft der in 2 µs 32 Ein-Zyklus-Befehle. Was du da vorhast ist Unsinn. Ob Bascom, C oder Assembler. Wozu sollen 2-3 µs Auflösung überhaupt gut sein? mfg.
also vielleicht sollte ich das nochmal erklären: Ich will doch nur in einer schleife runterzählen bevor etwas passiert. Und bei 16 Mhz macht der doch einen befehl pro 0,0625 mikrosekunden. Damit kann ich sehr wohl mit 2 mikrosekunden genauigkeit arbeiten. Selbst mit der while schleife in bascom brauche ich für einen durchlauf nur 4,3 mikrosekunden. Ich will doch nur wissen, warum der Fehler auf dem Controller ensteht und was man dagegen machen kann.
Grummel... Netiquette Wenn dein "Befehl" alle 32 Takte ausgeführt werden soll kann der µP praktisch nichts anderes mehr machen, der Interrupt bringt ja auch noch etwas Overhead mit. Was hast du genau vor?
Felix A. schrieb: > Ich will doch nur wissen, warum der Fehler auf > dem Controller ensteht und was man dagegen machen kann. Was denn für ein Fehler? mfg.
Ich meine den Fehler von 9 sekunden (Post 1). Ich will nach einem Interrupt eine Einspritzdüse öffnen, dann xxx Mikrosekunden auf lassen, und dann wieder schließen. Die schleife beginnt also nach dem interrupt. Das Problem bei der düse ist dabei, das ich möglichst auf die Mikrosekunde genau einstellen können muss.
Ich hasse Salamitaktik. Wie oft (pro Sekunde) soll diese Düse angesteuert werden? Die Düse regelmäßig für 2µs zu öffnen ist mit etwas Assembler kein Problem, die Düse alle 2 µs anzusteuern schon.
das intervall ist ziemlich groß... 10-20 ms. (Zeit zwischen 2 Einspritzungen) Es geht wirklich nur darum sie wenige mikrosekunden anzusteuern.
10ms sind schon deutlich besser, mit einem Timer(interrupt) lässt das dem µC noch Zeit um andere Sachen zu machen. Die 2µs Wartezeit erreichst du am besten mit ein paar nops oder einer Zählschleife in Inline-Assembler. Guck in die Bascomanleitung und hier ins ASM-Tutorial. War ja mal wieder eine schwere Geburt.
Felix A. schrieb: > Ich will nach einem Interrupt eine Einspritzdüse öffnen, dann xxx > Mikrosekunden auf lassen, und dann wieder schließen. Sowas macht man nicht in einer Schleife. Dazu nimmt man einen Timer im CTC-Modus. Nach dem Interrupt schaltest du einen Port, startest den Timer und der schaltet nach der im Compare-Register eingestellten Zeit den Port wieder ab. mfg.
Kommen die 9s vielleicht durch irgenwelche Branch-Penalties in der CPU zustande, die die Bascom-Simulation nicht berücksichtigt?
dk schrieb: > Kommen die 9s vielleicht durch irgenwelche Branch-Penalties in der CPU > zustande, die die Bascom-Simulation nicht berücksichtigt? Das wäre zumindest eine logische erklärung, dann sollte es aber mit assembler in den griff bekommen zu sein.
Eine Einspritzsteuerung mit hingefrickelten Verzögerungsschleifen zu basteln ist krank!
wenn man sich wirklich mal überlegt wie die abfolge so einer Motorsteuerung aussieht, sind verzögerungen gar nicht mal so abwegig.
Felix A. schrieb: > Ich will nach einem Interrupt eine Einspritzdüse öffnen, dann xxx > Mikrosekunden auf lassen, und dann wieder schließen. Gut. Meine Lösung wäre: 16-Bit-Timer durchlaufen lassen. ICP-Interrupt benutzen, darin Düse aufmachen, ICP-Wert holen, Intervall draufaddieren, als Compare-Wert für Compare-Interrupt abspeichern, Compare-Interrupt freigeben. Im Compare-Interrupt Düse zumachen, Compare-Interrupt sperren. Das Hauptprogramm kann währenddessen die Drehzahl erfassen und daraus das optimale Intervall berechnen. In ASM kinderleicht, in C sicherlich auch, in Bascom wird das Timing verfälscht, weil der Interrupt-Aufruf auch die Register sichert, die nicht gebraucht werden. ...
Thomas Eckmann schrieb: > Sowas macht man nicht in einer Schleife. > > Dazu nimmt man einen Timer im CTC-Modus. > > Nach dem Interrupt schaltest du einen Port, startest den Timer und der > schaltet nach der im Compare-Register eingestellten Zeit den Port wieder > ab. > > mfg. es macht wohl wenig sinn wegen 2µs einen Timerinterupt aufzusetzen 2µs sind 64 Takte bei 16Mhz die paar Takte sind mit Initialisieren des Timers und Sprung in die ISR schon fast verbraten edit: ich würde einen 10ms Timer aufsetzen und in dessen ISR das Öffnen, warten und Schließen des Ventils unterbringen.
netiquette schrieb: > 10ms sind schon deutlich besser, mit einem Timer(interrupt) lässt das > dem µC noch Zeit um andere Sachen zu machen. > > Die 2µs Wartezeit erreichst du am besten mit ein paar nops oder einer > Zählschleife in Inline-Assembler. Guck in die Bascomanleitung und hier > ins ASM-Tutorial. > > War ja mal wieder eine schwere Geburt.
so ähnlich war meine erste idee auch... dann ist mir aber beim programmieren aufgefallen, das das programm gar nichts anderes machen braucht. und vielmehr zwischen do und loop umherspringt. Deswegen die idee mit der verzögerung. Im Prinzip soll es so klappen: (habe einen magneten am schwungrad) 1. Interrupt (magnet) erfassen > Zündzeitpunkt berechnen > schleife zählt bis zündzeitpunkt >zünden > schleife zählt aber weiter nach dem zünden bis zum 2. Magneten d.f. Drehzahlerfassung 2. Interrupt (magnet) > Berechnung der Öffnungsdauer > Düse öffnen > schleife zählt > dües schließen Und dann beginnt alles von vorne. Vorteilhaft an diesem konzept finde ich, das es eine feste Struktur hat und immer von oben nach unten abgearbeitet wird. Allerdings muss ich die Berechnungszeit des Zündzeitpunktes wieder vom Kurbelwinkel abziehen. Das ganze Konzept klappt dann aber nur wenn ich von den schleifen die anzahl der takte kenne. Deshalb auch meine Frage ganz oben in Post 1. Achso, es ist natürlich ein 4-Takter.
Felix A. schrieb: > Allerdings muss ich die Berechnungszeit des > Zündzeitpunktes wieder vom Kurbelwinkel abziehen. Und die Berechnungszeit ist nunmal variabel. Wenn die in die Zeit eingeht, dann gibt es Jitter. Frage: Wie lange muss die Düse etwa offen sein? ...
der Zündzeitpunkt soll ertstmal linear zur drehzhal sein, damit sollte die berechnungszeit immer gleich sein. die düse muss etwa 700 mikrosekunden auf sein. Sie ist aber sehr empfindlich, deshalb muss ich sie so genau einstellen. +-5 mikrosekunden wäre schon wieder zu ungenau.
Felix A. schrieb: > die düse muss etwa 700 mikrosekunden auf sein. Jetzt setze ich das "Wir-werden-verarscht"-Flag und steige aus. Oben war noch von 2µs die Rede, jetzt sind es 700, dazu Salamitaktik, mir reichts.
netiquette schrieb: > Felix A. schrieb: >> die düse muss etwa 700 mikrosekunden auf sein. > Jetzt setze ich das "Wir-werden-verarscht"-Flag und steige aus. Oben war > noch von 2µs die Rede, jetzt sind es 700, dazu Salamitaktik, mir > reichts Damit mein ich die genauigkeit....
Felix A. schrieb: > die düse muss etwa 700 mikrosekunden auf sein. Also was soll denn jetzt der ganze Aufstand? "etwa 700". 700,000 oder vielleicht doch 694? Mal wieder viel Lärm um nichts. mfg.
1 | Dim Delay_us As Word |
2 | Delay_us = 700 |
3 | Waitus Delay_us |
Ergibt 700,75µs, Einsprung in den Interrupt mit normaler Sicherung der Register dauert 0,375µs.
Thomas Eckmann schrieb: > Felix A. schrieb: >> die düse muss etwa 700 mikrosekunden auf sein. > > Also was soll denn jetzt der ganze Aufstand? > > "etwa 700". 700,000 oder vielleicht doch 694? > > Mal wieder viel Lärm um nichts. > > mfg. Also jetzt ist doch mal gut, meine Frage war von anfang an wie der Fehler (Post 1) zustande kommt. dafür ist es dann auch unerheblich wie lange ich die schleife durchlaufen möchte.
Sei so gut und tu dir selber den Gefallen und mache was Falk dir geraten hat. Der gute Mann hat von Mikrocontrollern mehr Ahnung als ein Uni-Professor und die 100 Andere die hier mitlabern. Aber ist klar - die Anfänger müssen immmer das Rad neu erfinden, das worüber sich tausende vor ihnen Gedanken gemacht haben und als gut erachtet haben ignorieren und wissen alles besser ... Anfänger eben.
Ich habe als Branch Penalty mal 2 Takte je schleifendurchlauf angenommen. Und siehe da, ich komme fast genau auf den verzögerungswert.
> Sei so gut und tu dir selber den Gefallen und mache was Falk dir geraten > hat. Der hat verschiedenes von sich gegeben. Eines war unanständig ...
tt2t schrieb: >> Sei so gut und tu dir selber den Gefallen und mache was Falk dir geraten >> hat. > > Der hat verschiedenes von sich gegeben. Eines war unanständig ... Er hat doch nur den Hinweis mit dem Timer gegeben oder hab ich was übersehen?
> Er hat doch nur den Hinweis mit dem Timer gegeben oder hab ich was > übersehen? strg-f falk
Felix A. schrieb: > also vielleicht sollte ich das nochmal erklären: > > Ich will doch nur wissen, warum der Fehler auf > dem Controller ensteht und was man dagegen machen kann. Der Fehler entsteht nicht auf dem Controller. Der fehler sitzt da, wo er meistens sitzt: Vor der Tastatur...
ja so ist es, also habe jetzt nochmal mehrere messungen vorgenommen. Es ist tatsächlich so das die schleife 2 takte länger braucht wegen den Branch penalties.
tt2t schrieb: >> Er hat doch nur den Hinweis mit dem Timer gegeben oder hab ich was >> übersehen? > > strg-f falk Ich glaube, Du interpretierst da was falsch. Falk hat damit zum Ausdruck gebracht, dass es sinnlos ist, Felix helfen zu wollen. Denn Felix sagt "Danke" und denkt "leck mich" und ignoriert alle gut gemeinten Hinweise. Er ist so auf seine Bascom-Schleife fixiert, dass er nicht erkennt, das es anders viel besser, zuverlässiger, genauer und einfacher geht. Da ich das inzwischen ähnlich sehe, habe ich meinen Beitrag mit einem etwas erweiterten Konzept wieder gelöscht. ...
Ich glaube Falk hat was falsch verstanden. Wenn ich "leck mich" sagen wollte hätte ich das geschrieben und nicht durch den Netiquette-Link angedeutet das sowas in ner diskussion auch nichts zu suchen hat.
Hallo. Ich hab nur den Anfang gelesen... Das Takte zählen klingt recht mühsam. einfacher wäre es doch wirklich wenn Du einen Timer antriggerst und wenn du schon busywaiting machst, weil sonst nix zu erledigen ist, dann könntest so machen, dass du wartest bis in der timer-isr en flag gesetzt wird (in pseudoC):
1 | gFlag = 0; |
2 | |
3 | void interrupt TIMER(void) // isr kommt wenn eingestellter wert erreicht |
4 | {
|
5 | gFlag = 1; |
6 | clr_timer_run-bit(); |
7 | timer_reg = 0; // zählt wenn du wieder antriggerst dann bei 0 weg |
8 | clr_isr_flag(); |
9 | }
|
10 | |
11 | |
12 | void main(void) |
13 | {
|
14 | ...
|
15 | gFlag = 0; |
16 | trigger_Timer(); // setze Run-bit |
17 | while(!gFlag); |
18 | // gFlag = 0; falls nötig
|
19 | ...
|
20 | }
|
oder stört dich da sogar die paar ns von MOV und BRA und paar cycles für isr-switch? wegen dem Fehler: BASCOM ist ja so interpreter-sache und ich hab keine ahnung wie/was das im hintergrund macht. Aus deinen beschreibungen erkennt man, dass du wahrscheinlich wirklich nicht so eine Ahnung hast von Timern, weswegen dann die Leute auch bissl zackiger sind. Na gut, Frohe Ostern LG, senor timer
Felix A. schrieb: > Ich will nach einem Interrupt eine Einspritzdüse öffnen, dann xxx > Mikrosekunden auf lassen, und dann wieder schließen. Warum meinst du, die Einspritzdüse bis zu 5 Sekunden lang auf 22 us genau ansteuern können zu müssen? Wo sitzt diese Einspritzdüse? In einem Motor? Dann hast du m.E. noch nicht allzuviel Ahnung von Motoren...
700 µs auf wenige µs genau geht entweder über einen 16-bit-Zähler oder einen 16-bit-Timer (700*16=11200, abzüglich Overhead für Port setzen und pollen). Was man nimmt, ist Geschmacksache, er pollt ja sowieso. Die Auflösung ist dann 4/32=1/8 µs, das dürfte genügen. Das geht aber nur in ASM oder C.
Felix A. schrieb: > ne ne alle 10-20 ms für etwa 700 Mikrosekunden... Gut, ich poste meinen zurückgezogenen Beitrag nochmal, mach' was draus oder lass' es bleiben: Felix A. schrieb: > der Zündzeitpunkt soll ertstmal linear zur drehzhal sein, Was meinst Du damit? Ist "Zündzeitpunkt" dasselbe wie das Öffnen der Düse? Oder gibt es auch noch eine Zündkerze? Wieviel Zeit muss/darf zwischen Auslösung durch Magnet und Öffnen der Düse vergehen? > damit sollte > die berechnungszeit immer gleich sein. Es kommt auf die Berechnung an. Addition und Subtraktion lässt sich (in ASM) taktgenau planen. Andere Operationen werden meist als Schleife ausgeführt, deren genaue Ausführungsdauer von den Operanden abhängig ist. Man sollte daher erstmal nicht davon ausgehen, dass eine Berechnung immer die selbe Anzahl von Takten braucht. > die düse muss etwa 700 > mikrosekunden auf sein. Na das ist doch ideal für die Compare-Einheit des 16-Bit-Timers. > Sie ist aber sehr empfindlich, deshalb muss ich > sie so genau einstellen. +-5 mikrosekunden wäre schon wieder zu ungenau. Ja und? Der Timer arbeitet auf den Controllertakt genau. Und die Interrupt-Aufrufzeit lässt sich mittels Sleep exakt konstant halten. Also nochmal wie ich das angehen würde: Controller läuft mit 8 MHz CPU-Takt (Quarz). 16-Bit-Timer läuft mit Vorteiler 1 zu 8, also im Zeitraster von 1 ms. Input-Capture-Interrupt erkennt Magnetsensor 1 und - schaltet Düse ein - nimmt Zeitstempel und sichert ihn für die Drehzahlberechnung - addiert Intervall (etwa 700) dazu und setzt damit den Termin für den Compare-Interrupt zum Ausschalten der Düse Compare-Interrupt (700 ms später als ICP-Interrupt) - schaltet Düse aus Externer Interrupt erkennt Magnetsensor 2 und - nimmt Zeitstempel vom Timer - bildet Differenz zum Zeitstempel des letzten ICP-Interrupts - errechnet daraus die Drehzahl - korrigiert evtl. das Intervall anhand der drehzahl Solltest Du noch eine drehzahlabhängige Verschiebung des Öffnens der Düse brauchen, dann kommt noch ein weiterer Compare-Interrupt hinzu. Das sieht dann etwa so aus: Input-Capture-Interrupt erkennt Magnetsensor 1 und - nimmt Zeitstempel und sichert ihn für die Drehzahlberechnung - addiert Intervall für Zündverzögerung (aus Drehzahl berechnet) dazu und setzt damit den Termin für den CompareA-Interrupt zum Einschalten der Düse - addiert Intervall für Düsen-Öffnungszeit (etwa 700) dazu und setzt damit den Termin für den CompareB-Interrupt zum Ausschalten der Düse CompareA-Interrupt (Zündverzögerung später als ICP-Interrupt) - schaltet Düse ein CompareB-Interrupt (700 ms später als CompareA-Interrupt) - schaltet Düse aus Externer Interrupt erkennt Magnetsensor 2 und - nimmt Zeitstempel vom Timer - bildet Differenz zum Zeitstempel des letzten ICP-Interrupts - errechnet daraus die Drehzahl - korrigiert das Intervall für Zündzeitpunkt anhand der Drehzahl, das wird bei der nächsten Zündung berücksichtigt - korrigiert evtl. das Intervall anhand der Drehzahl, das wird bei der nächsten Zündung berücksichtigt. Hauptprogramm: - Sleep Wenn sichergestellt ist, dass der zweite Magnetsensor erst erreicht wird, wenn die Düse garantiert wieder geschlossen ist, dann hat dieser externe Interrupt genügend Zeit zum Berechnen der Drehzahl und Intervallwerte für die nächste Runde. Da kann auch noch ein ADC-Wert eingelesen werden und mit der Drehzahl verglichen werden um das Düsenintervall zu steuern (Drehzahlregelung). Der Timer läuft nach 65,536 ms über, das sind etwa 15 Hz untere Grenze, also (beim 4-Takter) etwa 108 Rpm. Sollte es darunter noch funktionieren müssen, dann sollten die Compare-Interrupts aktiviert/deaktiviert werden. Und nein, ich habe keine Ahnung von Motor-Managment-Computer, ich habe mit Sicherheit einige wichtige Punkte vergessen. Denn ich habe nur das umzusetzen versucht, was Du als Anforderung salamimäßig (scheibchenweise) preisgegeben hast. Mit Bascom und Warteschleifen bist Du schlecht beraten, selbst mit "Waitus(xy)" in Bascom wird das sehr unzuverlässig. Auch mit Timer und Bascom wird es recht ruckelig, da Bascom unnötig Zeit verplempert um (unbenutzte) Register zu sichern und die Variablen im SRAM zu halten. Da bleibt eigentlich nur C (vom Mais-Teer programmiert) oder ASM. Aber reines ASM, kein Inline-ASM von Bascom... ...
Hallo Felix, wie kommst Du darauf mit BASCOM eine Motorsteuerung programmieren zu wollen? Ein Motorsteuergerät ist inzwischen so komplex, daß Du mit einer solchen festen Struktur keinen Motor richtig zum laufen bekommst. Schon mal über Signalabsicherungen nachgedacht? Vielleicht über Kennfelder? Die vielen Sensoren, die Du abfragen mußt? Das geht in Deiner festen Struktur nicht. Hol dir mal die gelben Bücher von Bosch zum Thema Motorsteuerung... und lerne wenigstens ANSI-C... Grüße, Thomas
Felix A. schrieb: > wegen den > Branch penalties. Auch wenn sich das Wort eventuell cool anhört ist es hier doch fehl am Platz. Eine mranch-penaltie gibt es nur im Zuge eines falsch vorhergesagtem Sprungs, bei der AVR-RISC gibt es so etwas aber nicht sondern ein Sprung braucht IMMER eine festgelegte Anzahl Taktzyklen, welche man im Datenblatt nachlesen kann...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.