PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 40 Khz Frequenz erzeugen Ultraschallsender



Lenox
08.07.2007, 14:00
Ich versuche die ganze Zeit eine 40 Khz Frequenz zu erzeugen, bekomme es aber einfach nicht hin.

Mit


Config Timer1 = Timer , Compare A = Toggle , Prescale = 1
Pwm1a = 1023


kommte ich leider nur auf ca. 1,7 ms, also 3,4ms Periodendauer.
Ich weiß leider nicht so wirklich weiter.

Der AtMega8 läuft auf 16 Mhz.

Wichtig wäre es außerdem noch, dass der Timer nur für eine einstellbare Zeit läuft (also wärend die Kapsel sendet).

Rofo88
08.07.2007, 16:21
Wie Du auf den Wert kommst "Pwm1a = 1023" ???

Soweit ich weis Toggelt der den PIN bei 1023 aber der Timer läuft ja einfach weiter oder sehe ich das falsch?


Also ich würde es so machen ganz ohne Timer.
Ein Toggeln erfolgt aller 200 Takte

1 / 16MHz * 200 * 2= 25µs
1 / 25µs = 40kHz

Und die Zeit kannste auch einstellen halt wie oft die Schleife durchlaufen wird.



$regfile = "m8def.dat" 'ATMega8
$crystal = 16000000 'Quarz: 16 MHz



Dim X As Byte


For X = 1 To 20
Waitus 11
nop
nop
nop
nop
nop
Toggle Portb.0
Next X

Lenox
08.07.2007, 17:52
Oky danke, ich habs jetzt mit so nem RN Tool gelöst.


Config Timer1 = Timer , Prescale = 1

Config Pinb.1 = Output

Sender Alias Portb.1


On Timer1 Timer_irq

Const Timervorgabe = 65136


Enable Timer1
Enable Interrupts


Do

Loop


Timer_irq:
Timer1 = Timervorgabe
Toggle Sender
Return

Rofo88
08.07.2007, 18:02
nur das nach deinem Programm 20 kHz rauskommen :-b

Lenox
08.07.2007, 19:56
Schade, und ich dachte schon ich hab ein außergewöhnliches Gehör :cheesy:
Was muss den für 40Khz dahn?

PICture
09.07.2007, 00:37
Hallo Lenox!

Wenn die Frequenz nicht sehr stabil seien muss, würde ich sie mit Hardware (z.B. 2 Transistoren oder Logikgätter) generieren und mit dem Mega nur an- und ausschalten.

Wenn sie sehr stabil seien muss, würde ich ein 400kHz Piezoresonator mit 10:1 Teiler verwenden.

MfG

Lenox
09.07.2007, 09:48
Hi,
ich wollte es vorerst eig. mit dem AVR probieren, später könnte ich das immernoch nachrüsten.
Mein Problem ist es nur zu messen wie hoch die derzeitige Frequenz ist.
Halt wegen diesen variables Poti am Oskar.

Hanni
09.07.2007, 10:00
Naja, ich an deiner Stelle würde einfach einmal einen Blick ins Datenblatt werfen. Speziell das Kapitel mit den Timern würde ich mir genauer ansehen.

Anschließend würde ich einen Timermodus wählen, welcher mir eine PWM an einem der dafür vorgesehenen Pins ausgibt und dessen Timer Endwert frei definierbar wäre.

Als Endergebnis hätte zumindest ich einen 40 kHz Rechteckgenerator der guasi so ganz nebenbei auf dem Mikrocontroller läuft.

Naja, zumindest ich würde es so machen ...

Grüße,
Hanni

Lenox
09.07.2007, 10:16
Ja, aber das Problem ist ja das ich es nicht hinbekomme ;)
Ich hab schon sehr viel über Timer gelesen, so ist es nicht.

Mich wundert aber auch das keiner einen Codeschnipsel oder so postet, anscheinend ist es doch nicht so einfach.

Dirk
09.07.2007, 17:46
Hallo Lenox,


Mich wundert aber auch das keiner einen Codeschnipsel oder so postet, anscheinend ist es doch nicht so einfach.

Wieso, dein Code vom 8.7. klappt doch im Prinzip!

Nur die Frequenz noch nicht.
Erklärung: Wenn du 40000x pro Sekunde toggelst, bekommst du nur die Hälfte deiner gewünschten Frequenz.

Probier 'mal: Startwert = 65389

Gruß Dirk

izaseba
09.07.2007, 18:56
Ist Dir der Timer 1 nicht zu schade für sowas ? Hast Du Timer 2 noch frei ? wenn ja mach folgendes :
Im Register TCCR2 folgende Bits setzen: CS21, WGM21,COM 20
Damit stellst Du den Prescaller auf 8,schaltest Du CTC Modus am Timer 2 ein und Toggelst Du OC2 Pin bei jedem Compare Match.
Im Register OCR2 schreibst Du 25 rein.

Wenn ich nichts vergessen habe, erzeugst Du am Pin OC2 40 kHz, ganz in Hardware ohne ein Takt für die Erzeugung zu verlieren ;-).
Ich hoffe, daß Du den OC2 noch frei hast ?

Gruß Sebastian

Lenox
09.07.2007, 22:45
@Dirk
Const Timervorgabe = 65389
oder was meinst du? Wie bist du auf den Wert gekommen?

@izaseba
Es sind noch alle Timer frei.
Aber denk dran, der Timer soll nur für eine bestimmt zeit aktiviert sein, also brauch ich wohl 2 Timer oder ich muss was hochzählen.

Ist es sehr unverschämt wenn ich nach nem Codeschnipsel frage? #-o

Lenox
09.07.2007, 23:18
So ich habs einfach mal versuch...



$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Config Timer2 = Timer , Compare = Clear , Compare = Toggle , Prescale = 8
Ocr2 = 25

Do
Loop


Messe aber ca. 50µS..
Und hören tu ich ihn auch, aber die Reichweite hat sich deutlich erhöht =)

Lenox
10.07.2007, 14:45
Kann mir den echt keiner helfen?
Die Formal müsste doch folgendermaßen lauten:

Output Compare = ( 16000 / 8 ) * 0,025ms = 50

Aber egal ob ich Ocr2 = 25 oder Ocr2 = 50 einstelle ich sehe keine Veränderung.

Lenox
10.07.2007, 15:39
So hab grad nochmal was anderes probiert.
Hatte folgenden Text gefunden und für euch mal angepasst.

Bei 40 KHZ beträgt die Zykluszeit 1 / f = 1 / 40000 = 25µs. Bei einem 50% Duty-Cycle muß du das Signal 12,5 µs einschalten und 12,5 µs ausschalten.

Timer 0 kann sich bei 16 MHz alle 160 ns um eins erhöhen. Also in 12,5 µs ungefähr 200 mal.

Der Timer erzeugt beim erreichen von 255 auf 256 einen Overflow Interrupt. Wenn ich jetzt den Timermit 255 - 200 = 55 vorlade, erreichst ich alle 12,5 µs einen Interrupt..



$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Config Timer2 = Timer , Prescale = 1

On Timer2 Tim0_isr
Enable Timer2
Enable Interrupts

Do
Loop

Tim0_isr:
Tcnt0 = 130
Toggle PORTB.1
Return


Und heraus kam dieses ca. 12µS Gebilde:
http://files.stefan-reible.de/public/Flanke.JPG

Allerding nur wenn ich keine Last am Pin hatte.

Hätte nicht gedachte das es so schwer ist ne Frequenz zu erzeugen.

Stromi
10.07.2007, 18:09
Ich kann mir vorstellen, dass zur Lastansteuerung ein BS170 oder BS250 helfen würde.
Hattest du den US-Wandler direkt am Port-Pin angeklemmt?

Lenox
10.07.2007, 18:31
Ja hab ich, aber das muss am AVR liegen, wenn ich über Compare Toggle geht es.

Rofo88
10.07.2007, 18:44
Vielleicht mal den Pin als Output definieren?!

izaseba
10.07.2007, 19:14
Und Du bist Dir sicher, daß da 40 kHz rauskommt ?
Ich würde doch reine Hardware Lösung vorziehen, oder zumindest ohne Interrupt auszukommen!
Wenn es wirklich so ist, daß Basic alle Register + SREG bei ISR auf den Stack legt fehlen Dir ein paar Takte ;-)

Gruß Sebastian

Rofo88
10.07.2007, 19:21
Ja Bascom Sichert ne menge register in ner Interruprotiene. Laut Simulator Toggelt der PIN aller 259 Takte also aller 16,1875µs. Macht also nur 30,88kHz.

izaseba
10.07.2007, 19:48
hier, versuchmal die 4 Zeilen Assembler in Dein Programm einzufügen:


push r16
ldi r16,26
out TCCR2,r16
ldi r16,25
out OCR2,r16
pop r16


zum ausschalten


push r16
clr r16
out TCCR2,r16
pop r16

Wie man Assembler in Basic einfügt, kann ich Dir nicht sagen, es soll aber sehr einfach sein.
Du mußt es nicht in einer Schleife laufen lassen einmal ausgeführt und Du hast am PB3 ein Takt von 40 kHz
Achso, vergiß nicht PB3 als Ausgang zu konfigurieren,

Gruß Sebastian

Rofo88
10.07.2007, 20:12
@izaseba

Ich glaube nicht das Bascom sich sehr freuen wird wenn man R16 so im Programm verändert. Also besser vorher ein Push R16 und danach ein POP R16.

izaseba
10.07.2007, 20:21
@rofo88,
Du hast recht, ich weiß nicht, welche Register man gefahrlos überschreiben kann, ich habe es oben geändert ;-)
Was mir noch einfällt, ich glaube gelesen zu haben, daß man die Register direkt beschreiben kann z.B

TCCR2 = 26
OCR2 = 25

Wenn das stimmt, wäre es noch einfacher :-)

Gruß Sebastian

Lenox
10.07.2007, 20:25
So habs mal mit dem Assembler code versucht:



$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Config Portb.3 = Output

$asm
push r16
ldi r16,26
out TCCR2,r16
ldi r16,25
out OCR2,r16
pop r16
$end Asm

Do
Loop


Leider hab ich nur 4µS bzw 8 pro Periode.

PS: ja das geht, mit dem direkt beschreiben.

Lenox
10.07.2007, 20:30
So habs grad nochmal mit der Interrupt Methode probiert, hatte doch tatsächlich vergessen den Ausgang zu definieren (danke für den Tipp).

Aber da kommt ich auch nur auf 6 µS aber das kann man Oskar liegen, ich weiß einfach nicht wie ich den Variables Poti einstellen muss :/
Ist ein Hameg HM 312.

izaseba
10.07.2007, 20:41
??? was heißt jetzt nur6µs oder 8 µs ?
bei 6 µs hättest Du 166 kHz und bei 8 125 ?
Oder versteh ich was falsch ?

Normal müßte der Assemblerschnipsel klappen weil
16000000/8/25 ergibt sehr genau 80kHz und da der Pin bei jedem Compare Match getoggelt wird hättest Du 40 kHz...
Komisch, das muß ich mal auf AvrStudio werfen, moment, ich verjage meine Frau von ihrem Winrechner :cheesy:

Gruß Sebastian

Lenox
10.07.2007, 20:54
Ja ist halt zu schnell.
Aber das Problem ist das ich bei meinem Oskar die x-Achse mit einem Poti justieren kann, deshalb ist die Messung sehr ungenau, es könnten genauso 20µS sein...

Ich hab dem Verkäufer (Ratber) mal ne PM geschrieben, aber werd mir wohl mal die Manual ziehn.
Wäre aber trotzdem schön wenn das mal einer im Simulator checken könnte.

izaseba
10.07.2007, 21:02
Tja, das mit dem Emulator war wohl Griff ins Klo :-( Jäger wurde zum Gejagtem ;-) ist nix mit Win Rechner, aber ich lass mich nicht so schnell entmutigen, habe eben meinen Frequenzzähler angeworfen, der Zeigt am PB3 etwas über 39 kHz, das Ding ist aber noch nicht richtig kalibiert.
Mithin würde ich eher sagen, es liegt am Oscar und der PB3 wirklich 40 kHz generiert ;-)
Schalte da einen Transistor dran und teste, ob es klappt ;-)

Gruß Sebastian

Lenox
10.07.2007, 21:21
So hab mir grad die ganze Manual reingezogen, das Poti muss ganz nach rechts auf Anschlag, also war meine Messung total fürn **** ;D

Übrigens wird die Röhre des hamegs mit 40Khz betrieben *g*

Ich messe jetzt etwa 13,8 µS =)

Vielen Dank!
Jetzt muss ich "nurnoch" das Signal für eine bestimmt Zeit senden.

Also war für das aktivieren:

push r16
ldi r16,26
out TCCR2,r16
ldi r16,25
out OCR2,r16
pop r16

und für das deaktivieren:

push r16
clr r16
out TCCR2,r16
pop r16

oky so? weil ich versteh davon echt keine Zeile

=P~

izaseba
10.07.2007, 21:29
Ja,ja, wer viel misst... ;-)

Ja genau so ist das der erste Schnipsel schaltet 40 kHz am PB3 ein, der zweite schaltet den ab, Du kannst dazwischen ein wait**** einbauen, dann kriegst Du einen 40 kHz Impuls ....



oky so? weil ich versteh davon echt keine Zeile

Dann soltest Du mal hin und wieder in das Dattenblatt schauen, weil die Lösung manchmal trivial ist

Gruß Sebastian

Lenox
10.07.2007, 22:02
Oky mach ich auch so, ich bin gerade dabei die Spannungen einzulesen und in einem Array zu speichern.

Mal gucken ob der ADC vom M8 schnell genug ist, alternativ hätte ich noch ein I²C baustein hier ;)

izaseba
10.07.2007, 22:36
Ja dann viel Erfolg,
was hast Du weiter vor ?
mit ADC messen, bis der Schall zurückkommt ?
Gleichzeitig mit einem Timer die Zeit messen ?
Hm ich kann mir das jetzt schlecht vorstellen, leider hab ich bis jetzt nichts mit US Messung gemacht :-k
Vielleicht hilft ein Blick zum Asuro rüber, wie man das dort Softwaretechnisch
gelöst hat...
Perfekt wäre eine Funktion, die einem die Zeit zurückgibt, die der Schall gebraucht hat oder -1 wenn freie Sicht herscht ;-)
Berichte auf jedem Fall weiter...

Gruß Sebastian

Lenox
10.07.2007, 22:44
Ich hab grad ein Programm geschrieben das 400 AD Werte einließt und dann über RS232 zurück gibt.
http://rafb.net/p/oTBH1n30.html

Nur grad ist mir aufgefallen das meien Schaltung garkeine analoge Spannung liefert, sondern ein schwellwert Schalter ist :cheesy:

Das heißt ich muss die Zeit zwischen senden des Impulses und anstieg der Flanke mit nem Timer messen, und dann umrechnen s = 0,5*v*t.

Ist allerdings nicht so einfach die OPV sauber einzustellen.
Naja ich werd morgen mal weiter coden.

izaseba
10.07.2007, 23:13
Aha,
Ich muß Dich aber berichtigen, Der Assembler Code verwendet den Timer 2, Timer 0 hat keine Hardwareverbindung an irgendwelchen Pin...
Es ist also damit zu rechnen, daß irgendwann eine High(oder auch LOW) Flanke von Deinem US Empfenger kommt, und Du möchtest die Zeit zwischen Senden Ende und Flanke messen ?

Dazu hätte ich eine Idee, leider kann ich keine genauen Infos dazu liefern, weil ich mich damit noch nicht auseinander gesetzt habe, aber der Timer 1 hat einen schönen Eingang am Pin PB0(ICP1) und der ganze Quatsch hat was mit der Input Capture Unit zu tun.
Ich hab es eben überflogen(Dattenblatt M8 Seite 81), und es scheint so als wenn man den Timer 1 auf Null setzen könnte, sich zurücklehnt und in alle Ruhe auf den Inputcapture Interrupt warten könnte(eben Flankenwechsel an PB0).
In der ISR den Wert auslesen, und schon hat man die Laufzeit...

Schau mal in der Bascom Hilfe nach, vielleicht gibt es da schon was fertiges, damit würdest Du Dir den ADC Quatsch sparen....

Nur so als Vorschlag...

Gruß Sebastian

Lenox
10.07.2007, 23:36
Danke, hatte mich verschrieben.

In Bascom kann man ganz einfach ein Interrupt auf steigende oder fallende Flanken einstellen. An den Interrupt Ports.

Im Prinzip bräuchte ich 2 Interrupts.
Einmal einen für ein Timer, der beispielsweise jede µS eine Variable hochzählt, und den Interrupt bei steigender Flanke von den Operationsverstärker, der den Timer wieder deaktiviert.

Dann ist die Variable die Signallaufzeit in µS.

Das Problem wäre:
1. Muss ich den Timer so einstellen das er genau eine µS lang braucht, oder hast einen sonstigen Wert der bekannt ist.
2. Ich hätte 2 Interrups laufen, ich weiß nicht ob das so gut ist.

izaseba
10.07.2007, 23:59
Ich weiß nicht, welche Laufzeiten zu erwarten sind, welche Entfernungen relevant sind ?
Du mußt ja keinen Meter messen, oder ?
Wie lange braucht der Schall bei z.B. 10 cm, so als Richtwert ?(Ich habe keine Lust nachzurechnen...)
Ein Takt bei 16 Mhz dauert 62,5 ns bei Timer 1 mit prescaller 1 hättest Du theoretisch den Bereich 62.5ns - 4ms wenn man die Timerüberläufe mitzählt entsprechend mehr.
Timer auf genau 1µs zu stellen ist genauso einfach/schwer wie 40kHz Takt zu erzeugen ;-)
Dein Ansatz mit dem µs Tick und warten, bis externer Interrupt kommt ist sicher richtig und Wert ausprobiert zu werden, ich habe die Input Capture Geschichte zur Sprache gebracht, weil es mir sehr ellegant erscheint, und auch saugenau, weil man bis auf ein Takt genau messen könnte (jaja Theorie und Praxis).
Und warum sollen 2 Interrupts nicht gut sein ?
Im Notfall kanst Du auch den Interruptflag pollen, ohne Interrupt auszulösen, aber mach es erstmal nach Deiner Nase, bin mal gespannt, was dabei rauskommt.

Gruß Sebastian

P.S.
Ich merke es gerade, wo Dein Problem mit 1µS ist, man hat genau 16 Takte Zeit um alles abzuarbeiten, also vergiß Interrupt, das dauert zu lange, da bietet sich eher Timer 2 mit prescaller 1 und OCR2 = 16 in CTC Mode, damit man keine Zeit mit Vorladen verliert und den Comparematch Flag pollen um
eine Variable hochzuzählen, das würd gehen, ist aber wirklich kritisch...

Lenox
11.07.2007, 10:16
Es sind Entfernungen von 20cm bis ca 3m relevant.

Zur Signallaufzeit, das steht alles auf der Seite woher ich auch den Schaltplan hab:
http://www.mikrocontroller.net/articles/Entfernungsmessung_mit_Ultraschall
Ich hab Variante 2 (ganz unten).
Wenn ich 2 Interrupts hab, wovon einer alle 1 µS ein Overflow hat, ich glaub was wird was kritisch, aber ka.

Wie meinst du das mit Timer 2 eine Variable hochzählen ohne Interrupt?
Timer2 = Timer, Prescaller = 1 , Compare = Clear , Incr I
OCR2 = 16

Das geht so nicht, also die Incr I da reinpacken.
Ich verseh auch nicht was du mit "Comparematch Flag pollen um
eine Variable hochzuzählen" meinst :(

izaseba
11.07.2007, 17:36
Wenn ich 2 Interrupts hab, wovon einer alle 1 µS ein Overflow hat, ich glaub was wird was kritisch, aber ka.

Das kannst Du vergessen, wie ich schon oben geschrieben habe bekommt man alle 16 Takte einen Interrupt und ich behaupte mal es ist nicht machtbar, da mitzukommen.
Dafür kann man den Interruptflag pollen, aber wenn Du nicht weiß wovon ich rede, lasse ich das lieber.
Hast Du wegen Capture Unit geguckt ?
Ich habe es ausprobiert, und muß sagen es ist erste Sahne.
Man setzt den Timer1 auf Null und wartet auf eine Flanke auf dem IC1 Pin.
Wenn Die kommt wird Captureinterrupt ausgelöst, wo man sich den Wert einfach holt und fertig.
Ich sag mal Timer1 mit Vorteiler 8 ergibt einen Tick von 500 ns damit kannst Du Laufzeiten zwischen 500 ns und etwas über 32 ms messen, mit Auswertung des Überlaufs natürlich mehr.
Nur wie man das im Basic macht, mußt Du schonmal selber rausfinden, ich kann Dir höchstens sagen welche Register, wie einzustellen sind.

Gruß Sebastian

Lenox
11.07.2007, 23:07
Sorry ich find nichts dazu, ich muss allerdings auch sagen das ich mit Dial-up Speed surfe (schon seit eienr Woche) da Net Cologne einfach nichts auf die Reihe bekommt.
Ich lad teilweise 1 min für google das ist echt zu kot*** naja...

Kann ich dein ASM Code nicht einfach in Basic reinklatschen?

Ich lad aber grade nochmal das DB herunter, in 15min hab ichs -.-

Lenox
11.07.2007, 23:16
So nachdem ich mir die Bascom Hilfe nochmal durchgelesen hab hab ich es doch gefunden:

CAPTURE EDGE = FALLING/RISING

Das war das was ich weiter oben im Thread meinte.

Also folgendes soll ja passieren:

-Frequenz starten (geht)
-2µS warten (geht)
-Frequenz stoppen (geht)
-Timer1 starten (enable timer1?)
-auf steigende Flanke warten (Capture Edge = Rising)
-Durchgänge in eine Variable schreiben (woher soll ich wissen wie oft der jetzt durchlief?)

Lenox
12.07.2007, 00:49
So das ist der aktuelle Stand:



$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Config Timer1 = Timer , Prescale = 1 , Capture Edge = Rising 'Timer1 für emfang
Disable Timer1
On Timer1 Timer1_isr

Config Portb.3 = Output 'Port für Pulsausgabe

Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.6 , Db7 = Portd.5 , E = Portc.2 , Rs = Portc.3
Config Lcd = 16 * 2
Cls
Cursor Off

'/////////Sub Deklarieren\\\\\\\\\\\\\
Declare Sub Send_puls(byval Ms As Byte)

Dim I As Double
I = 0

Call Send_puls(3)
Enable Timer1
Enable Interrupts
Wait 2
Lcd I

End

Sub Send_puls(byval Ms As Integer) 'Timer2
$asm
push r16
ldi r16,26
Out Tccr2 , R16
ldi r16,25
Out Ocr2 , R16
pop r16
$end Asm

Waitms Ms

$asm
push r16
clr r16
Out Tccr2 , R16
pop r16
$end Asm
End Sub

Timer1_isr:
Incr I
Return


Leider nörgelt meine alte Bascom Version noch rum, un meine Update ist noch nicht freigeschaltet...

izaseba
12.07.2007, 18:10
Hallo Lenox,
Sieht schon mal gut aus, würde ich mal sagen nur was ist das für ein Interrupt:



On Timer1 Timer1_isr


Overflow Interrupt ?
Timer 1 hat mindestens 4 Interrupts Du brauchst den Capture Interrupt und zwar so:
-Puls an
-warten
-puls aus
-Timer1 reseten
-Timer1 starten
-Bei steigender Flanke wird der Capture Interrupt ausgelöst in dem Du
-Capture Register (Zeitstempel, wann die Flanke kam) auslesen
-Timer 1 stopen
-signalisieren daß Du Fertig bist
-in der hauptschleife die Capture werte verschicken.

Fertig,
versuch das mal, wenn Du nicht weiter kommst melde Dich

Gruß Sebastian

Lenox
12.07.2007, 19:10
Hi,
ich hab das von der Logik alles verstanden ;)
Das steht soweit auch alles oben im Code, nach dem senden wird der Timer1 gestartet, der bei jeden Durchlauf (Prescaller von 1) I um eins erhöht.
Bei steigender Flanke soll dann ein Capture Interrupt den Timer1 wieder stoppen.
Anschließend hab ich in I die Anzahl der Durchläufe.

Das Problem ist, dass ich es einfach nicht programmiert bekomme das bei steigender Flanke der Timer1 wieder gestoppt wird.
Ich saß gestern Abend noch Stundenlang mit nem Kumep daran, aber wir haben es einfach nicht hinbekommen :/

Ich weiß leider nicht weiter, ich wüsste auch sonst keinen der davon richtig Ahnung hat (bzw sich hier mal meldet).

Lenox
12.07.2007, 19:35
Grad noch mal mit Bascom rumgespielt:

Do
Pulseout Portb , 1 , 50
Waitus 11
Loop

erzeugt auch ne 40Khz Frequenz ;)

izaseba
12.07.2007, 19:39
Das Problem ist, dass ich es einfach nicht programmiert bekomme das bei steigender Flanke der Timer1 wieder gestoppt wird.

Du hast ja nur den Overflow Interrupt in Deinem Programm drin !
Mal angenommen Deine Hardware liefert eine saubere Flanke und


Config Timer1 = Timer , Prescale = 1 , Capture Edge = Rising
capture unit einschaltet, die bei einer steigenden Flanke einen Zeitstempel macht, brauchst Du noch den entsprechenden Counter1 Capture Event Interrupt, wo der µC auch hinspringen kann, wenn die Flanke gekommen ist.
Dort kannst Du dann ruhig den Timer 1 stopen und die Captureregister auslesen...
Es handelt sich um Vektor 5, wenn es Dir helfen sollte, irgendwie wird der ja bei Basic genannt sein...

Gruß Sebastian

Lenox
12.07.2007, 20:04
Hi,
ich glaub ich hab es jetzt, aber mit nem ganz normalem Interrupt der den Timer beendet.
Leider kann ich es nicht ausprobieren da ich total sinnlose Fehler erhalte.
Ich glaub das liegt an meiner alten Bascom Version (beim Kumpel geht das Compilieren).
Mein Update Acc ist leider noch immer nicht freigeschaltet :/

Hier der Code, ich hoffe er ist zu verstehen:


$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.6 , Db7 = Portd.5 , E = Portc.2 , Rs = Portc.3
Config Lcd = 16 * 2
Cls
Cursor Off

Config Portb.3 = Output

Dim I As Double

Config Timer1 = Timer , Prescale = 1 'Zählt Variable in ISR hoch
Disable Timer1
On Timer1 T1_isr

Config Int0 = Rising 'bei steigender Flanke
Disable Int0
On Int0 Int0_isr

Do

$asm
push r16
ldi r16,26
Out Tccr2 , R16
ldi r16,25
Out Ocr2 , R16
pop r16
$end Asm

Waitms 2

$asm
push r16
clr r16
Out Tccr2 , R16
pop r16
$end Asm

I = 0
Enable Interrupts
Enable Timer1
Enable Int0

Wait 2 'Programm wartet und Interrupts laufen

Lcd I 'Ausgabe auf LCD
Waitms 500
Cls

Loop

T1_isr: 'I wird imemr um eins erhöht
Incr I
Return

Int0_isr: 'bei steigender Flanke schaltet die ISR vom Interrupt alles ab
Disable Interrupts
Disable Timer1
Disable Int0
Return

End

izaseba
12.07.2007, 20:19
Ja gut mit externen Interrupt geht es ja auch.
Wenn es brauchbare Werte liefert ist dann alles in Butter ;-)

Gruß Sebastian

DanielSan
24.08.2009, 01:48
Hi,

sry das ich diesen alten Thread wieder hoch hole, aber ich hätte da noch eine Frage.

Ich muss mit einem ATmega8 eine Frequenz von 38kHz erzeugen.
Ich habe mal kurz in ein Assembler Tutorial reingeschaut und weiss jetzt ungefähr wofür push, ldi und out steht. Allerdings verstehe ich die Wirkungsweise noch nicht ganz.

Kann ich auch für TCCR2 und OCR2 die von PB1 nehmen? Also TCCR1 und OCR1?

Muss ich nur die "25" ändern oder auch die "26" um meine Frequenz auf 38kHz zu bekommen?
Die Formel zur Berechnung war ja weiter oben schon angegeben, demnach müsste ich ja die 25 in eine 13 ändern, mein Prozessor läuft auf 8Mhz. Wenn ich nicht genau 38kHz erwische ist das nicht so wild (vermute ich jedenfalls momentan)


$asm
push r16
ldi r16,26
Out Tccr2 , R16
ldi r16,25
Out Ocr2 , R16
pop r16
$end Asm

Waitms 2

$asm
push r16
clr r16
Out Tccr2 , R16
pop r16
$end Asm

Der ablauf des Codes wäre doch hier:
Toggle für 2ms mit 40kHz oder?

Danke
MFG Daniel

recycle
24.08.2009, 02:18
Assembler kann ich nicht, aber da das hier ja eigentlich auch das Bascom Forum ist, schreibe ich mal wie man die Frequenz von 38kHz damit erzeugen kann.



$crystal = 8000000
Config Timer0 = Timer, Prescale = 1
On Timer0 Timerroutine
Enable Timer0
Enable Interrupts
Timerroutine:
Timer0 = 45
'diese Routine wird knapp 37900 mal pro Sekunde aufgerufen
Return

Wenn du die Timerroutine doppelt so oft aufrufst, sprich 76000 mal pro Sekunde und in der Routine einfach nur einen Pin toggles hast du an dem Pin ein Rechtecksignal mit ca. 38 khz
Dafür musst du in obigem Code nur "Timer0 = 45" durch Timer0 = 151" ersetzen und in die Timerroutine ein "Toggle Pinx.x" einfügen.

Mit Timer1 geht das natürlich auch, da das ein 16bit Timer ist, ergeben sich dafür allerdings andere Zahlenwerte.

DanielSan
24.08.2009, 09:48
Hi,

danke für den Code. Ich würde gerne die Berechnung dazu nachvollziehen können. Kannst du mir da noch ein paar Infos zu geben?

Ich möchte jetzt nicht das mein Programm die ganze Zeit nur die 38kHz raushaut. Kann man das auch so machen das ich ihm eine bestimmte Zeit gebe in der er das machen soll?

Deswegen finde ich die Assembler Lösung schöner, da "schaltet" man das ja einfach nur an und nach ner bestimmten Zeit wieder aus. Oder sehe ich das falsche?

Danke
MFG Daniel

recycle
24.08.2009, 11:08
danke für den Code. Ich würde gerne die Berechnung dazu nachvollziehen können. Kannst du mir da noch ein paar Infos zu geben?

Da du Bascom zumindest schon mal probiert hast, kannst du eigentlich auch da in der Online Hilfe nachsehen.

Ein Timer zählt bei jedem Takt des Controllers eine Variable um eins hoch.
Timer0 ist ein 8 Bit Timer, und läuft daher bei 255 über, sprich er fängt wieder bei 0 an zu zählen.
Beim Überlauf wird ein Interrupt ausgelöst und für diesen Interrupt kannst du eine Routine schreiben die immer genau dann ausgeführt wird.
D.h. die Routine wird b ei einem 8MHz Quarz 8Mio/256 mal ausgelöst.
Wenn du dem Timer in der Interrupt Routine einen Wert > 0 zuweist, fängt er nicht bei 0, sondern bei diesem Wert an zu zählen, und läuft natürlich entsprechend schneller wieder bei 255 über.
Dadurch kannst du dir eigene Frequenzen erzeugen.
Z.B. 255 - 45 = 211 : 8MHz / 211 = 37.915 Hz

Timer1 ist ein 16 Bit Timer, d.h. der zählt bis 2^16 und läuft da über. Ansonsten ist es dasselbe.
Für niedrigere Frequenzen kannst du einem Timer noch einen Prescaler mitgeben.
Bei einem Prescaler von z.B. 64 zählt der Timer dann nicht jeden Controllertakt, sondern nur jeden 64. Controllertakt um eins hoch.

In obigem Beispiel kämst du dann auf die besagte 37,9kHz / 64.
Steht aber eigentlich alles mit Codebeispielen in der Bascom Hilfe.



Ich möchte jetzt nicht das mein Programm die ganze Zeit nur die 38kHz raushaut. Kann man das auch so machen das ich ihm eine bestimmte Zeit gebe in der er das machen soll?

Das ist doch gerade der Sinn der Sache. Der Timer läuft in obigem Beispiel alle 211 Takte über und ruft die Interruptroutine auf. Sobald die abgearbeitet ist, wendet er sich dann bis zum nächsten Interrupt wieder deinem Hauptprogramm zu.
Problem ist natürlich, dass er in 211 Schritten nicht besonders viel machen kann und deine Timerroutine auf jeden Fall weniger Schritte erfordern sollte.
Das ist aber ein generelles Problem bei so hohen Frequenzen daher ist es manchmal sinnvoller die Frequenz extern zu erzeugen.
Es gibt ja z.B. auch Ultraschallsender und Ultraschallsensoren, die die Frequenz selber erzeugen.
Wenn du die Frequenz nicht mehr brauchst, kannst du sie auch jederzeit mit "Stop Timer0" anhalten und mit "Start Timer0" neu starten.



Deswegen finde ich die Assembler Lösung schöner, da "schaltet" man das ja einfach nur an und nach ner bestimmten Zeit wieder aus. Oder sehe ich das falsche?

Ich glaube das siehst du falsch. Wie ein Timer funktioniert hat eigentlich nichts mit der verwendeten Programmiersprache zu tun.

In Assembler hast du mehr Kontrolle wie der Controller bestimmte Operationen durchführt und mehr Überblick wieviele Rechenschritte deine Routinen erfordern. Aber das erkaufst du dir ja auch recht teuer durch den viel höheren Programmieraufwand.

DanielSan
24.08.2009, 12:03
Das ist doch gerade der Sinn der Sache.

Ne eben nicht^^ Jedenfalls nicht für meine Anwendung. Ich brauche die 38kHz nur als burst für ein IR Signal. Vielleicht ist hier mein Ansatz ja auch nicht richtig.

Für RC5 gibt es ja fertige befehle aber ich brauche REC-80.

MFG Daniel