Bascom Problem mit Timer

krake

Neues Mitglied
13. Juli 2009
6
0
0
Sprachen
Hallo erst mal,

ich möchte mit einem Timer (0) die Pulslänge von 4 Eingängen messen. (Funkempfänger Cannel 1 -4) Jedoch arbeiter der Timer0 nicht so wie er soll. Also habe ich ein Testprog geschrieben und die Werte aufgezeichnet.
Hier mal dasTestprogramm:

$regfile = "m168def.dat"
$crystal = 4000000
$hwstack = 32 'hardware stack
$swstack = 10 'software stack
$framesize = 40 'frame space

' für eine serielle Ausgabe
$baud = 57600 ' use baud rate
'------------------------------------------------------------------------------
Config Portd.7 = Output 'Rechtecksignal
'------------------------------------------------------------------------------

Dim C_10us As Integer '10x Counter
Dim T_reload As Integer
T_reload = 50

Rechteck Alias Portd.7

'Timer 0 configurieren
' The TIMER can have the systemclock as an input or the systemclock divided
' by 8,64,256 or 1024
' The prescale parameter excepts 1,8,64,256 or 1024
' Ohne prescale
Config Timer0 = Timer , Prescale = 1
On Ovf0 Tim0_isr 'Define the ISR handler
Timer0 = T_reload
Enable Timer0 ' enable the timer interrupt
Enable Interrupts 'allow interrupts to occur

' Main
Do
' nichts
Loop

'------------------------------------------------------------------------------
Tim0_isr:
' Interrupt Timer 0
Timer0 = T_reload 'Reset auf Anfanswert
Incr C_10us '10x Counter erhöhen
If C_10us = 100 Then
Toggle Rechteck ' und Ausgeben
C_10us = 0
End If
Return
End


Anschliessen habe ich die Rechtecksignale an PORTD.7 gemessen:
T_reload = 1 Puls (h+l) = 63ms
T_reload = 10 Puls (h+l) = 61,7ms -Delta = 1,3ms :D
T_reload = 20 Puls (h+l) = 59,7ms -Delta = 2ms
T_reload = 30 Puls (h+l) = 57,7ms -Delta = 2ms
T_reload = 40 Puls (h+l) = 55,7ms -Delta = 2ms
T_reload = 50 Puls (h+l) = 53,7ms -Delta = 2ms
T_reload = 100 Puls (h+l) = 43,9ms -Delta = 9,8ms
T_reload = 150 Puls (h+l) = 33,9ms -Delta = 10ms
T_reload = 200 Puls (h+l) = 30,9ms -Delta = 3ms :eek:
T_reload = 250 Puls (h+l) = 30,7ms -Delta = 0,2ms :eek:

Für mich ergeben diese Werte keinen Sinn.
Rechnerrisch müsste doch: 1 / 4.000.000 Hz = 250ns
Bei einer t_reload differenz von 50 müsste der Unterschied doch:
50 *250ns * 100 (Streckfaktor) = 1,25ms sein.Da ich high und low messe muss der Uterschied 2* 1,25ms sein. Dies ist aber nur bei dem wechsel derT_reload Werte von 150 auf 200 messbar.

Ich hoffe einer von euch kann mir weiterhelfen.
Ansnst noch an ale einen schönen Tag und
Servus
 
Hallo krake,
herzlich willkommen in diesem freundlichen Forum.

Ich bin mir nicht sicher, ob ich dich richtig verstanden habe, aber deine Berechnungen und dein Programm passen nicht wirklich zusammen.

Zunächst einmal benutzt du eine ungeeignete Konfiguration des Timers.
Der Timer zählt mit jedem Takt des µC hoch (Prescale=1). Wenn er jetzt überläuft, also von 255 auf 0 geht, wird die ISR aufgerufen. Dabei werden 53 Takte für das Sichern der Register benötigt. Danach steht dein Timer auf dem Wert 53. Nun setzt du ihn auf 50 zurück und lässt ihn von da aus wieder bid 256 (0) zählen. Das sind 206 Takte. Du rechnest aber mit dem Wert 50. Wenn du bei jedem 50. Takt einen ISR wolltest, müsstest du den Wert 206 laden.
Aber auch das geht nicht, da die restlichen Befehle der ISR und das Zurückspeichern der Register weit mehr als 50 Takte benötigt.

Da dich eigentlich nur jeder 5000. Takt interessiert (50 * 100), solltest du mit einem höheren Prescale arbeiten, wodurch du den Fehler wesentlich kleiner bekommst.
Wenn du z.B. Prescale 8 benutzt und den Timer nach 125 Impulsen überlaufen lässt, dann sind dass schon 1000 µC Takte. dann noch die Variable C_10us bei 5 zurücksetzen, dann hast du exakt 5000 Takte.
Damit das wirklich exakt wird, solltest du nicht mit einem Reload Wert in der ISR arbeiten sondern dies die Hardware machen lassen. Man nennt dies den CTC Mode. Du konfigurierst dazu den Timer so:
Config Timer2 = Timer , Clear Timer = 1 , Compare = Disconnect , Prescale = 8
Enable Compare2
On Compare2 Compare2_isr
Enable Interrupts
Compare2 = 125 'oder auch OCR2 = 125

Deine Messungen der Rechtecksignale habe ich nicht verstanden. Vielleicht probierst du zunächst einmal, den Timer anders aufzusetzen.
Wenn du in ms messen möchtest, müssten es doch eigentlich 4000 Takte sein (bei 4MHz). Dann könntest du den Prescale auf 32 setzen und hättest bei einem Compare Wert von 125 genau die 4000 Takte, ohne in der ISR noch mal zu zählen.
 
Hallo,

erst mal vielen Dank für die ausführliche Erklärung. Eigentlich benötige ich ein 10us Taktsignal mit einer max. Timerperiode von min 22ms. Ich habe die Werte nur zum Messen hochgesetzt.
Nach deiner Beschreibung und nach suchen im Internet habe ich das Prog. folgendermaßen geändert:

$regfile = "m168def.dat"
$crystal = 4000000
$hwstack = 32 'hardware stack
$swstack = 10 'software stack
$framesize = 40 'frame space

' für eine serielle Ausgabe
$baud = 57600 ' use baud rate
'------------------------------------------------------------------------------
Config Portd.7 = Output 'Rechtecksignal
'------------------------------------------------------------------------------
Const Reload = 5
Rechteck Alias Portd.7
' Damit das wirklich exakt wird, solltest du nicht mit einem Reload Wert in
' der ISR arbeiten sondern dies die Hardware machen lassen. Man nennt dies
' den CTC Mode. Du konfigurierst dazu den Timer so:
Config Timer1 = Timer , Clear Timer = 1 , Compare A = Disconnect , Prescale = 8
Ocr1ah = High(reload)
Ocr1al = Low(reload) 'Reload für 10us
Tccr1a = 0 'Reset T1 nach Compare
Set Tccr1b.3

On Compare1a Compare1_isr
Enable Compare1a
Enable Interrupts

' Main
Do
nop 'nichts
Loop

'------------------------------------------------------------------------------
Compare1_isr:
' Interrupt Timer1
Toggle Rechteck ' und Ausgeben
Return
End

Leider ist der mit dem Ozzi gemessene Impuls an PORTD.7 121us lang.
Ich finde keine Lösung. :(

SERVUS
 
Hallo krake,
wenn du alle 10µs die ISR aufrufen willst, wird das so nichts werden.
Du könntest zwar die Nosave Option für den On Compare1a Befehl benutzen und könntest damit tatsächlich alle 10µs toggeln.
Aber du willst ja in deinem Programm auch noch die Pulslängen der 4 Eingänge abfragen und dann noch etwas tun. Das wird in der Zeit mit Bascom ganz sicher nicht gehen. Selbst mit ASM glaube ich da nicht dran, aber das können dir die ASM-Profis besser sagen.
Möglich wäre es, mit 100µs Auflösung oder mit einem 16MHz Quarz.
 
Hallo "HinterBlauenAugen",

da werde ich wohl auf 16MHz ausweichen. Ich möchte mit der steigenden Flanke des Chanels (1...4) die 10us Impulse hochzählen (Für jeden Channel getrennt) und mit der fallenden Flanke den Wert (Anzahl der 10us Impulse) wegspeichern. Anschließend soll noch die sortierte und bearbeitet Ausgabe der4 Channels als Summensignal an einem Ausgang erfolgen.
Könnte das vom Timing her klappen?
Jetzt schon mal vielen Dank für die bisherige Hilfestellung. :cool:

Ich wünsche eine „Gute Nacht“
 
So wie du das bisher gemacht hast, wirst du nicht wirklich auf die Flanken der Eingangssignale reagieren, sondern wohl eher in der ISR die Pegel der 4 Eingänge abfragen. Dann den Zähler erhöhen, wenn noch High anliegt. Das ist nicht wirklich schwer.
Aber wie ergibt sich das "Summensignal" aus den 4 Einzelsignalen?
 
Hallo,

Könnte das vom Timing her klappen?
das müßte man jetzt mal im Detail auf ein Blatt aufmalen und dann mal die Zeiten durchrechnen. Das dauert aber mal mindestens ne Stunde die man erst mal haben muß. Also nicht ungeduldig werden ;)

Wenn es mit den 16MHz immer noch nicht reicht, dann schafft der ATmega168 auch 20MHz.

So wie du das bisher gemacht hast, wirst du nicht wirklich auf die Flanken der Eingangssignale reagieren, sondern wohl eher in der ISR die Pegel der 4 Eingänge abfragen.
Wenn es vom Timing her immer noch Probleme gibt dann nimm die Hardware zur Hilfe. Der Mega168 kann mit PinChangeInterrupt an ALLEN!! Eingängen auf Flanken reagieren.

Gruß
Dino
 
Hallo krake,
in deinem Link ist ziemlich gut beschrieben, wie aus dem Summensignal wieder die Einzelsignale gemacht werden. Die sind dann auch zeitlich nacheinander.
Was interessant wäre, wie es im Sender aussieht. Wie liegen die einzelnen Kanäle zeitlich zueinander? Starten sie alle synchron mit ihrem 1-2ms Impuls oder sind die schon zeitlich so schön nacheinander angeordnet?
Ich meine mich zu erinnern, dass bei "alten" Fernsteuerungen die Signale zeitlich aufeinander folgen und daher einfach mit einem "Oder" zusammengeschaltet werden konnten, um das Summensignal zu bekommen. Geht das bei dir auch so?
Ansonsten wird die Sache schon ein wenig komplizierter.
 
Hallo „HinterBlauenAugen“,
du hast schon recht, bei den alten PLM –Empfängern konnte man einfach mit einem 8fach ODER das Summensignal erzeugen. Leider ist das bei den 2,4GHz Empfängen im PCM Modus anders. Hier gibt es keine Definition zum zeitlichen Anfang. Das macht jeder Hersteller anders. Ich möchte ja das Summensignal aus den 8 (4) einzelnen Kanälen bilden. Da ich nur die ersten 4 Kanäle benötige bin ich immer noch auf den Trichter die Impulslänge zu messen und dann entsprechend der Summensignaldefinition aneinander zu Reihen. Aber ich glaube ich bekomme hier wirklich ein unlösbares zeitliches Problem. Siehst du das auch so?
Servus
 
Hallo krake,
unlösbar ist das sicher nicht, aber es wird auch ganz bestimmt nicht die leichteste Übung. Der Erfolg hängt auch ganz wesentlich von deinen Vorkenntnissen ab. Wenn dies dein erstes Projekt ist, könnte es leicht zu frustriertem Aufgabem kommen.
Aber noch einmal zurück zum Thema.
Die Messung der Impulslängen sollte schon ok sein. Wenn zwischen min. Impulslänge und max. Impulslänge 1ms besteht, heisst dies, dass du bei einer Auflösung von 10µs 100 verschiedene Stellungen der Knüppel unterscheiden kannst. Da macht es schon Sinn, bei diesen kurzen Abtastraten zu bleiben. Da du für die Ausgabe auch einen Timer mit 10µs Rate brauchst, lohnt es auch nicht, die Eingänge mit Interrupts abzufragen.
Wenn nun die Eingangsimpulse mehr oder weniger gleichzeitig kommen, wie soll dann die Ausgabe dazu angeordnet werden? Ich stelle mir das im Moment so vor:
  1. Zuerst kommt eine längere Synchronisierungspause
  2. Dann starten evtl. alle Impulse gleichzeitig, zumindest der erste Kanal muss aber starten
  3. Im selben Zyklus (Zyklus ist ein Durchlauf der Timer ISR) startest du den Ausgangsimpuls des ersten Kanals.
  4. Falls noch weitere Kanäle gestartet wurden, inkrementierst du deren Zeitvariable.
  5. Damit ist der erste Zyklus zu Ende.
  6. In weiteren Zyklen überprüfst du nun, ob der erste Kanal im noch "an" ist. Falls ja, passiert nichts. Falls nein, wird die Ausgabe des ersten Kanals beendet. Nun zählst du eine Variable von 50 an runter, die die 0,5ms Pause erzeugt. Ist sie bei 0 angekommen, setzt du sie wieder auf 50 und wechselst zum nächsten Kanal.
  7. Wenn in der Zwischenzeit ein Kanal zu Ende war, wird dessen Zählvariable einfach nicht mehr weiter erhöht.
  8. Mit dem Wechseln zum nächsten Kanal setzt du den Ausgang wieder hoch.
  9. In den folgenden Zyklen zählst du dessen Zeitvariable runter, bis sie bei 0 angekommen ist.
  10. Usw. usf.
Ob du es schaffst, dies in den 160 Takten unterzubringen, ist schwer zu sagen. Du wirst wohl zuviele Takte durch die Unterbrechung und dem damit verbundenen Speichern und Zurückladen der Register verlieren.
Ich nehme mal an, dass dein µC eh nichts anderes machen kann als das Summersignal zu erzeugen. Daher kannst du das ganze auch in der Hauptschleife machen und ganz auf Interrupts verzichten. Die Synchronisierung musst du dann auch über einen Timer machen, aber du hast dann etwas mehr Zeit.
 
Hallo,

ich habe mal versucht das Programm zu schreiben. (Testen kann ich noch nicht da mir der16MHz Quarz fehlt :()
Anhang anzeigen sum_2.bas

Würde mich freuen (und wahrscheinlich auch weiterhelfen) :) wenn Ihr dazu euere Meinung abgebt.

DANKE und
Servus
 
Hallo krake,
hier einige Bemerkungen, ohne dies jetzt schon im Detail angesehen zu haben.
Versuche komplett ohne Word oder Integer Typen auszukommen. Die Verarbeitung von Byte Typen dauert nur knapp die Hälfte der Zeit.
Bei deiner Auflösung von 10µs und einer max. Impulslänge von 2ms sollten die Counter C_1 bis C_4 nie größer als 200 werden, was in ein Byte passt. Gleiches für die Variablen T_1 bis T_4.
Bit Variablen können in der Verarbeitung tatsächlich auch länger dauern als Bytes.
Schau mal, ob du nicht auch mit dem Timer0 oder Timer2 hinkommst. Die sind auch nur 8-Bit Timer und sollten eigentlich reichen. Evtl. machst du noch einen 2. Timer der dir die 20ms Gesamtzeit misst, falls du die nicht aus den Eingangssignalen ableiten kannst.
Ich bin sicher, dass du mit dem Setup "Hauptschleife mit eigentlichem Programm" und Timer_isr nicht hinkommen wirst. Am wenigsten Overhead wirst du verplempern, wenn du alles in die Timer_isr packst und die Hauptschleife komplett leer lässt. Dann kannst du die ISR mit der Nosave Option aufrufen und brauchst trotzdem keine Register in der ISR sichern.
Und du hast einen schönen Takt durch die CTC. Steht dagegen alles in der Hauptschleife, musst du den Timerwert dauernd abfragen. Dies wird zu Ungenauigkeiten im Timing führen.

Und: Besorge dir einen 20MHz Quarz, ich schätze, du wirst ihn brauchen (erlaubt 200 statt 160 Takte).

Edit: Nachdem ich mir das mal skizziert habe bin ich mir sicher, dass man das auch in Bascom mit weit weniger als 160 Takten schaffen kann. Also reicht auch ein 16MHz Quarz.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)