IR-Modul / LED für Staubsaugerroboter

spelli

Neues Mitglied
12. Nov. 2011
68
0
0
Sprachen
Hallo,

ich möchte sehr klein und flach ein Modul bauen, welches mir auf 940nm eine Frequenz von 38 kHz erzeugt und
mit 1 kHz moduliert ein- und ausgeschaltet wird. Gerne auch eine fertige Mini-Platine mit einem Attiny drauf.

Welche IR LEDs sind da zu empfehlen?

Und ganz frech frage ich jetzt einfach mal nach nem Codeschnipsel in Bascom...

Weitere Info:

http://knx-user-forum.de/170142-post72.html
 
Sofern ich mich erinner, ziehen die meisten IR-LEDs mit brauchbarer Leistung um die 50mA. Zu viel für die internen Pin-Treiber. Sonst könnte man die LED einfach zwischen 2 PWM-Ausgänge (einer mit 1, einer mit 38kHz) hängen. (Mit 'ner Schottky und 'nem Vorwiderstand in Reihe). Sollte natürlich auch mit 2 komplementären Transistoren/FETs gehen.

Oder man läßt nur den 38kHz-Carrier durch HW-PWM erzeugen, und nutzt vom 2ten Timer einen Interrupt, wo dann der Output aus-/angeschaltet wird. Compare Output Mode. Dann reicht ein externer Transistor (+etwas Hühnerfutter).

Es geht doch um die "Wand", oder?
Du kannst natürlich auch den Nutzsignal-Timer umsetzen, aber das wird dann schon wieder komplizierter - da würde ich eher nach so'nem IC aus IR-Fernbedienungen suchen-falls sich da was passendes finden läßt...
 
Hallo,

dass
Oder man läßt nur den 38kHz-Carrier durch HW-PWM erzeugen, und nutzt vom 2ten Timer einen Interrupt, wo dann der Output aus-/angeschaltet wird. Compare Output Mode. Dann reicht ein externer Transistor (+etwas Hühnerfutter).
hört sich gut an. Ja, es geht um die "Wand" bzw. die "Virtual Wall", die den Staubsauger (Irobot Roomba) nicht durchfahren lässt...
 
...sehr klein und flach ein Modul...
Grad gesehen, der Tiny10 hat nur einen Timer. Könnte man trotzdem den Carrier erzeugen lassen, und die Überläufe (IRQ) zählen (19), und dann den Output zu Fuß an-/ausschalten. Als Treiber dann 'n Kleinsignaltransistor (Dino?), dann sollteste mit 2 SOT23 auf ein bis zwei Quadratzentimeter kommen.
Allerdings mußte den Tiny10 erstmal programmieren können...
 
Hi,

Grad gesehen, der Tiny10 hat nur einen Timer. Könnte man trotzdem den Carrier erzeugen lassen, und die Überläufe (IRQ) zählen (19), und dann den Output zu Fuß an-/ausschalten. Als Treiber dann 'n Kleinsignaltransistor (Dino?), dann sollteste mit 2 SOT23 auf ein bis zwei Quadratzentimeter kommen.
Allerdings mußte den Tiny10 erstmal programmieren können...

also Kleinsignal ist glaube ich irgendwas mit BC848 oder BC858 in SOT23. (aus dem Gedächtnis).

Gruß
Dino
 
Vorsicht: :offtopic:

... Als Treiber dann 'n Kleinsignaltransistor (Dino?), ...
... also Kleinsignal ist glaube ich irgendwas mit BC848 oder BC858 in SOT23. ...

Damals, da hatte ich mal vom Arbeitskollegen eine CD (mit für früher sagenhaften 700MB!) bekommen. Sau teuer. Nannte sich A.L.A.B.E.L. (all about electronic) und war voll bis oben hin mit sämtlichen Datenblättern. Finde da keine Infos mehr zu im Netz.
Aber scheinbar wurde das Projekt jetzt umgetauft, aus Alabel wurde Dino, der Preis ist bei unbezahlbar geblieben :D
 
Hallo Spelli,

die 38kHz könnte man auch mit einem 555er (plus etwas "Grünzeug") erzeugen :
https://cdn-reichelt.de/documents/datenblatt/A200/NE555_SA555#STM.pdf

und dann den vom Tiny starten/stoppen lassen. Der Ausgang vom 555er ist bis 200 mA belastbar.

Die erzeugte Frequenz ist allerdings etwas abhängig von der Betriebsspannung und der Temperatur. Das kommt daher nur in Frage, wenn die Anwendung bei der Frequenz eine gewisse Toleranz zulässt.

Gruß
Pirx
 
Hallo,

ich wollte so wenig Bauteile wie möglich verwenden. Mit PWM tue ich mich ganz schwer... So würde ich ja die 38 kHz erzeugen können:

Code:
$regfile = "attiny13.dat"
$crystal = 4000000

Config Timer0 = Timer, Prescale = 1024

Config Pinc.2 = Output

Led Alias Portc.2

On Timer0 Timer_irq

Const Timervorgabe = 153

Enable Timer0
Enable Interrupts

Do
 stop Timer0
 waitms 1
 start Timer0
Loop


Timer_irq:
  Timer0 = Timervorgabe
  Toggle Led

  Return

Das "waitms 1" ist wahrscheinlich zu einfach gedacht für die 1ms Pause...?
 
Hi,

Hier hatte ich mal die Möglichkeiten des Timer1 eines Mega8 dargestellt und erläutert. Einige Beiträge vorher die Register erklärt. Der Tiny13 besitzt einen wesentlich schwächeren Timer, aber prinzipiell ist das ähnlich.

Du verwendet dann den Frequenzkorrekten fastPWM (Mode 7). Der Timer läuft dann also von 0 bis OCR0A, und dort automatisch über.
Mit dem Prescaler (grob) und OCR0A (fein) stellst Du jetzt die 38kHz Überlauf-Frequenz ein.
KanalB steht Dir für Dein Signal zur Verfügung. Wie und ob das entsprechende Bein jetzt an den Timer gekoppelt ist, bestimmt der Compare Match Output Mode (von Kanal B). Bei COM=0 ist das Bein normaler Pin, Du kannst es also als low-Ausgang einstellen. Mit COM=2 bzw 3 wird der invertierende/nicht invertierende PWM gewählt - der Timer über nimmt dann die Kontrolle über den Pegel.
Wenn dann im OCR0B der halbe Wert vom OCR0A steht, hast Du den Carrier.
Der Timer läuft jetzt also vollkommen autonom 38 mal pro Millisekunde bei OCR0A über, und erzeugt im Hintergrund den Carrier. Die Idee ist jetzt, den COM zwischen 0 (low-Ausgang) und 2 (Carrier) hin und Herzuschalten. Also jede Millisekunde einmal umschalten (1ms Carrier, 1ms Gnd, ... richtig?).
Und woher nimmst Du jetzt die Millisekunden? Nun, der Timer läuft ja jede Millisekunde 38 mal durch OCR0A über, OCR0A unterstützt einen CompareMatchInterrupt, welcher dann auch 38 mal pro Millisekunde auslösen kann. Zählst Du also in der ISR 38 Aufrufe, hast Du 'ne Millisekunde, und schaltest den COM um...

Idee soweit klar?
 
Hallo,

vielen vielen Dank für deine ausführliche Erklärung und den Link. Wenn ich ehrlich bin schnalle ich es nicht. Mit dem Timer zählen bzw. mir eine Zeit in der Routine ablaufen lassen kein Problem... Danach hörts bei mir auf... Ich glaube da sind dein meine Grenzen deutlich zu spüren... (ist alles nur ein abendliches Hobby)
 
Hi,

Danach hörts bei mir auf... Ich glaube da sind dein meine Grenzen deutlich zu spüren... (ist alles nur ein abendliches Hobby)

das ist es bei Cassio, mir, LotadaC, ... usw
auch nur. Ist nur ne Frage wie lange man das schon als Hobby hat.

Gruß
Dino
 
Genau!

Kann ja nochmal versuchen, das Timer-Modul des Tiny13 zu beleuchten - ist ja nicht soo viel. Schau erstmal selbst ins Datenblatt, dort insbesondere das Kapitel zum Timer0 ab Seite 58.

Der Tiny13 besitzt nur einen Timer. Dieser ist 8 Bit breit.
Das Zählregister (TCNT0) kann also von 0 bis 255 zählen, danach läuft es über. Schau Dir mal Figure 11-1 an. Dort siehst Du das Zusammenspiel der Register mit der Kontrolllogik. Hervorgehoben ist das Zählregister (TCNT0), darunter die beiden Output Compare Register (OCR0A/B), ganz unten die beiden Steuerregister (die den Rest beeinflussen) - lediglich die beiden Register für die Interrupts sind nicht dargestellt.

Von rechts landet die Timer-Clock (clkt0) auf der Logik. Diese kann entweder über einen Vorteiler (Prescaler) aus dem systemtakt abgeleitet werden, oder aus Flanken des T0-Beinchens. Festgelegt wird das in den Clock Select Bits (CS) in einem der Steuerregister.
Die Kontrolllogik kann einen Timer Overflow Interrupt anfordern, also das entsprechende Interrupt-Flag setzen. Wann das geschieht, hängt vom Waveform Generation Mode (Operationsmodus) ab, welcher auch in den Steuerregistern festgelegt wird.

Die Logik kann jetzt also den Zähler inkrementieren, dekrementieren oder löschen, dabei wird jetzt ständig der Zählerstand mit den Inhalten der beiden Output Compare Register verglichen. Bei Gleichheit wird das jeweilige Interruptflag gesetzt (IntReq), was einen Interrupt auslösen kann; außerdem können die OC0A/B-Beinchen automatisch manipuliert werden. Das wird natürlich auch in den Steuerregistern festgelegt - über den Waveform Generation Mode und den jeweiligen Compare Output Mode.

Der Vergleich TCNT0=0 liefert der Logik das Ereignis "Bottom" - kann je nach WGM das Überlaufflag setzen.
Das Ereignis "TOP" kann je nach WGM durch unterschiedliche Quellen ausgelöst werden.
Erstmal Durch einen Vergleich TCNT0=fixed TOP (fixed TOP ist beim Tiny13 immer 0xFF, also 255) - der Timer nutzt also die vollen 8 bit
Oder den Vergleich TCNT0=OCR0A - wodurch sich die Reichweite des Timers einschränken läßt.

Der Timer bietet 6 Operationsmodi:
  • nonPWM mit 0xFF als TOP, singleSlope (NormalMode)
  • nonPWM mit OCR0A als TOP, singleSlope (CTC)
  • fastPWM mit 0xFF also TOP, singleSlope
  • fastPWM mit OCR0A als TOP, singleSlope
  • phasenkorrektes PWM mit 0xFF als TOP, dualSlope
  • phasenkorrektes PWM mit OCR0A als TOP, dualSlope

Die phasenkorrekten Modi (dual Slope) interessieren Dich erstmal nicht, die benötigt man, wenn man das ON/OFF-Verhältnis ändert, und die ONs/OFFs symmetrisch bleiben sollen.
Da Du einfach und ohne viel Software Deinen Carrier ausgeben lassen willst, sind auch die nonPWM raus. Also fastPWM. Da Du die 38kHz nur mit dem Prescaler nicht triffst, reduzierst Du die Reichweite des Timers. nur eben nicht mittels preload irgendeines Wertes, sondern indem Du das OCR0A als automatischen Überlaufpunkt festlegst. Warum eigentlich 'n Systemtakt von 4MHz?

Also Mode7 (Tabelle1-8 auf Seite 72). KanalA ist wegen der Begrenzung nicht nutzbar, also nimmst Du KanalB. Wenn der Timer bis OCR0A läuft, und Du ein 1:1 ON/OFF-Verhältnis haben willst, muß OCR0B die Hälfte von OCR0A erhalten.
Jetzt zum Compare Output Mode - für fastPWM von KanalB gilt Tabelle 11-6 auf Seite 71. Mode=0 (beide Bits=0) wäre der Pin normaler I/O, nicht an den Timer gekoppelt. COM=1 (also 01binär) ist reserviert, bei 2 (0b10)und 3 (0b11) kontrolliert der Timer den Pegel - PWM eben. Für Dich sind die identisch, da ON/OFF = 1:1...

Bascom unterstützt die komplexeren Möglichkeiten der Timer nicht unbedingt mit Config Timer...
Du kannst aber auch unter Bascom die entsprechenden I/O-Register direkt beschreiben. In vielen Fällen ist das einfacher, da man mit dem Controller-Datenblatt weiß, was die Bits im konkreten Register bewirken. Bei irgendwelchen Config-Befehlen ist das nicht immer unbedingt ganz klar.

Hast Du Denn mal 'ne Möglichkeit, das auszuprobieren, und mit 'nem Logikanalysator zu kontrollieren?
Andere Sache: Wie ist das mit der LED dann gedacht? Abstrahlwinkel, ok, aber letztendlich stört die doch dann (Reflektion etc) alle Empfänger die dieselbe Trägerfrequenz und Wellenlänge nutzen, oder? Und wie soll das auf den Robot ausgerichtet werden? Du leuchtest ja quasi mit 'ner (infraroten Stroboskop-) Lampe 'n Lichtkegel irgendwohin - wie soll damit jetzt die Grenze definiert werden?
 
Guten morgen!

Danke nochmals für deine Erklärungen.

Also da muss ich mich in Ruhe durchlesen. Habs gerade überflogen...

Also Original sind diese Teile: http://www.conrad-electronic.co.uk/...9/1900/1900/1905/190555_BB_01_FB.EPS_1000.jpg

Die sind häßlich und groß (u. a. wegen 2x C-Zellen). Oben die LED mit der Linse ist damit der Roomba nicht gegen stösst und das Teil verschiebt. Neben der "Virtual Wall" gibt noch so ein durch den Roomba steuerbaren, und nach Zeit zu öffnenden, Zaun. Das sind die sog. "Lighthouses" bzw. der Modus. Hierfür sind 3 LEDs hinter der schlitzförmigen Blende verbaut. Der Zaun bzw. die "Wall" wird durch eine einzelne LED mit spitzem Öffnungswinkel ausgestrahlt. Praktischer Weise in einem Türrahmen o. ä. (da tut es im übrigen auch eine Holzlatte als Sperre). Allerdings gibts es natürlich Bereich die so ein Roomba einfach nicht anfahren soll - Schuhe, Kabel, Hundenapf etc. Da könnte man dann bei DIY eine einzelne "Virtual Wall" so verkabeln/installieren, dass das Ganze sehr klein ausgeführt und zugleich unsichtbare wäre.

Rundherum um den Roomba sind Empfänger installiert, die diese LED/Frequenz dann wahrnehmen... Die Ausrichtung spilet hier tatsächlich eine große Rolle.

Die Taktfrequenz hatte ich auf 4 MHz festgelegt - es war meine Ausgangssituation...

Hier noch mal ein Link zum Hersteller:

http://desupport.irobot.com/app/answers/detail/a_id/1282/~/was-sind-virtual-wall-lighthouses™-?
 
...Die Taktfrequenz hatte ich auf 4 MHz festgelegt - es war meine Ausgangssituation...
Wie das denn?
der Tiny13 kann keinen Quarz/Resonator treiben.
Der Tiny13 kann durch einen externen Takt (Oszillator) mit bis zu 20MHz (aktiv) getaket werden -> allerdings wiederspricht das "möglichst klein".
Der Tiny13 kann durch einen internen Oszillator mit 9,6MHz getaktet werden - dazwischen befindet sich ein Vorteiler (auf zweierbasis), Standardeinstellung ist 8. Also effektiv 1,2MHz. Aber den Vorteiler kannst Du mittels Fusebit auf 1 stellen. Oder zur Laufzeit auf diverse andere diskrete Teilerwerte.
Mir ist nicht ganz klar, ob der in den Fuses wählbare interne 4,8MHz-Oszillator in Wirklichkeit derselbe ist, nur mit 'nem anderen Standard-Vorteiler.
Außerdem kann man den Tiny13 durch den internen Watchdog-Oszillator betakten lassen (128kHz).
Datenblatt ab Seite 23.
Cave!: Der Aufbau ist wie folgt:
Über ein Multiplexer wird die gewählte Clocksource (extern, interner RC, Watchdog) auf den Prescaler gelegt. In den Fuses wird die Clocksource selbst, gewählt und festgelegt, welchen Wert der Prescaler beim Reset hat. Stellt man jetzt also auf den Watchdog-Oszillator um, und läßt den Vorteiler bei seinen default-8, wird der Tiny mit effektiv 16kHz getaktet.
Die ISP-Frequenz darf beim programmieren nur ein viertel der effektiven Taktfrequenz betragen, hier also 4kHz. Einige Programmer scheinen sich nun aber nicht auf diese langsame Frequenz einstellen zu lassen. Somit hätte man den Tiny dann gegen den Programmer ausgesperrt, wenn die Fuses via ISP-Programming wieder zurückgesetzt werden sollen.
Ist das mit dem Lichthaus so zu verstehen, daß das eigentlich auch nur 'ne Wand (gepulstes 38kHz Sperrfeuer) ist, nur daß das Gerät via Funk(?) mit dem Robot kommuniziert, und die Wand zeitweise abschaltet, um den Robot durchzulassen?
 
Ist das mit dem Lichthaus so zu verstehen, daß das eigentlich auch nur 'ne Wand (gepulstes 38kHz Sperrfeuer) ist, nur daß das Gerät via Funk(?) mit dem Robot kommuniziert, und die Wand zeitweise abschaltet, um den Robot durchzulassen?

Augenscheinlich fährt der Roomba los und versucht per 2,4 GHz (Xbee oder so) eine Art Broadcast zu senden. Dann wird durch die Lighthouses per IR "Kontakt" hergestellt (der Roomba orientiert sich so und nummeriert die wohl auch durch) - genau, das "Sperrfeuer" kann dann entsprechend ab- und angeschaltet werden. Der Roomba sperrt sich dann bspw. selbst in einem Raum ein, lässt da sein "Rum-Fahr-Algorithmus" laufen und lässt sich dann irgendwann wieder raus...
 
Hmm...
trotzdem stelle ich mir das mit dem Selbstbau schwierig vor. Also insbesondere die Leistungsanpassung und Dimensionierung. Die Fernbedienung vom Fernseher kannste sonstwohin richten - Wand, Decke Boden, rückwärts... manchmal sogar um die Ecke aus'm anderen Raum. Das ist auch IR. Auf 'nem 36kHz Carrier, die Bits Manchester-codiert. Jedenfalls sieht der Fernseher das IR-Licht auch indirekt, warum soll das hier nicht auch so sein (Streulicht wegen Reflexionen...)? Also mußt Du die Leistung einstellen können. Und da Du selbst das nicht siehst (ok, mit 'ner Digicam gehts) und die Empfindlichkeit nicht kennst, wirst Du rumprobieren müssen...

Der eigentliche Code für das Sperrfeuer sollte eigentlich relativ unproblematisch sein... ich sehe mich hier schon wieder meine Testschaltung in Betrieb nehmen...
 
spelli scheint irgendwie nicht mehr weiterzumachen, um das trotzdem mal zum Ende zu bringen, fange ich jetzt einfach mal an:
Code:
;*********************************************************************************************
;*                                      IR-Sperrfeuer                                        *
;*********************************************************************************************
;                      zur Erzeugung einer "Virtual Wall" für Staubsaugerrobotter
;
;verwendet wird ein ATtiny10, welcher einen 38kHz Carrier erzeugt, auf den ein 1kHz Signal
;moduliert wird.
;
;************verwendete Hardware*******
; -Timer0 erzeugt im fastPWM den Carrier, die Frequenz wird mit OCR0A korrigiert - WGM=15
; -PWM-Ausgabe ueber KanalB (OC0B bzw B1)
; -Das modulation des 1kHz-Signals wird aus dem 38kHz-Carrier abgeleitet, im OC0A-Interrupt
;  (also bei jedem "Überlauf" des PWM-Timers
;(-Auslasungsanzeige durch den OC0A-Interrupt über B2) 
;
;           +-----+
;          -|B0 B3|-!Reset
;       Gnd-|     |-Vcc
;Sperrfeuer-|B1 B2|-(Interrupt-Auslastung)
;           +-----+
;

;.include "tn10def.inc"	;MCU-Definitionsdatei, Angabe ab Studio5 nicht mehr sinnig
;************Interruptvektoren*********
.org 0x0000
	rjmp reset		;Resetvektor
;**********Resetvektor********************
reset:
;*************Hauptschleife****************
main:
	NOP
	rjmp main
Der Stackpointer ist beim Tiny10 bereits default RAMEND, brauchen wir uns also nicht drum zu kümmern.
Code:
	;Stackpointer ist default =RAMEND******
Der Tiny10 kann entweder durch eine externe Clock (scheidet wegen Größe aus), den internen Watchdog-Oszillator (mit 128kHz viel zu langsam) oder den internen 8MHz-Oszillator.
Default ist letzterer aktiv, mit einem Vorteiler von 8. Also effektiv 1MHz.
Der Tiny10 besitzt keine Clockselect-Fuses, und auch keine CKDIV8-Fuse oder so. Er startet immer mit den internen 8MHz/8, und kann zur Laufzeit durch das Programm verändert werden. Da der Vorteiler die erforderliche Genauigkeit einschränkt, verwenden wir als Main-Clock-Prescaler 1 bzw schalten den auf 1 um:
Code:
	ldi R16, 0xD8
	out CCP, R16			;unlock protected I/Os
	ldi R16, 0x00
	out CLKPSR, R16			;MainClockPrescaler=1

Jetzt etwas Mathe:
Mein Controller läuft jetzt also mit 8MHz, erreichen willst Du 38kHz. 8000kHz/38kHz ergibt rund 211. Der Timer soll also alle 211 Prozessortakte überlaufen. 211 ist selbst bei einem 8bit-Timer mit Prescaler=1 erreichbar, also wählen wir für den Timer Prescaler=1. Damit wissen wir auch gleich den nötigen Wert für OCR0A (211 Timertakte entsprechen mit Prescaler=1 211 Prozessortakten, entsprechen nach obiger Rechnung fast 38kHz): da der Timer einen Takt nach OCR0A auf 0 zurückgesetzt wird, ist also OCR0A=210 zu wählen. Um das ganze einfach anpaßbar zu machen, definiere man sich das erstmal als Präprozessor-Konstante, für das PWM-On-Off-Verhältnis auch gleich eine mit dem halben Wert (50%):
Code:
;*************Konstanten***************
.equ OCR0Avalue=210                    ;Frequenzkorrektur auf 38kHz
.equ OCR0Bvalue=OCR0avalue/2           ;PWM auf 50%
Da zur erzeugung des Signals der Compare Output Mode geändert werden soll, also dort immer ein/einige Bits getoggelt werden, und es keinen XORI-Befehl gibt, benötigen wir eine Bitmaske, für die wir ein Register reservieren. Außerdem müssen die Timerüberläufe gezählt werden, auch hierfür würde ich ein Register reservieren:
Code:
;**********Reservierte Register********
.def TOVcounter=R22
.def COM0BtoggleRegister=R23
Der verwendete Überlauf-Interrupt (geneuer das OC0A-Match-Event) muß in der Interrupt-Vektor-Tabelle mit 'ner Sprunganweisung in eine Interrupt-Service-Routine "angemeldet" werden:
Code:
.org OC0Aaddr
	rjmp carrierperiode
Und die ISR selbst zumindest erstmal als leerer Rumpf:
Code:
;***********carrierperiode*****************
carrierperiode:
	reti
Direkt vor dem Eintritt in die leere Hauptprogramm-Schleife werden die Interrupts global freigegeben:
Code:
SEI

Das ganze mal als fast leeres Gerüst zusammgesetzt, bisher:
Code:
;*********************************************************************************************
;*                                      IR-Sperrfeuer                                        *
;*********************************************************************************************
;                      zur Erzeugung einer "Virtual Wall" für Staubsaugerrobotter
;
;verwendet wird ein ATtiny10, welcher einen 38kHz Carrier erzeugt, auf den ein 1kHz Signal
;moduliert wird.
;
;************verwendete Hardware*******
; -Timer0 erzeugt im fastPWM den Carrier, die Frequenz wird mit OCR0A korrigiert - WGM=15
; -PWM-Ausgabe ueber KanalB (OC0B bzw B1)
; -Das modulation des 1kHz-Signals wird aus dem 38kHz-Carrier abgeleitet, im OC0A-Interrupt
;  (also bei jedem "Überlauf" des PWM-Timers
;(-Auslatsungsanzeige durch den OC0A-Interrupt über B2) 
;
;           +-----+
;          -|B0 B3|-!Reset
;       Gnd-|     |-Vcc
;Sperrfeuer-|B1 B2|-(Interrupt-Auslastung)
;           +-----+
;

;.include "tn10def.inc"	;MCU-Definitionsdatei, Angabe ab Studio5 nicht mehr sinnig
;************Interruptvektoren*********
.org 0x0000
	rjmp reset		;Resetvektor
.org OC0Aaddr
	rjmp carrierperiode
;*************Konstanten***************
.equ OCR0Avalue=210                    ;Frequenzkorrektur auf 38kHz
.equ OCR0Bvalue=OCR0avalue/2           ;PWM auf 50%
;**********Reservierte Register********
.def TOVcounter=R22
.def COM0BtoggleRegister=R23
;**********Resetvektor
reset:
	;Stackpointer ist default =RAMEND******
	ldi R16, 0xD8
	out CCP, R16			;unlock protected I/Os
	ldi R16, 0x00
	out CLKPSR, R16			;MainClockPrescaler=1

SEI
;*************Hauptschleife****************
main:
	NOP
	rjmp main
;***********carrierperiode*****************
carrierperiode:
	reti
erzeugt bisher 20 Bytes Code (2% Flash).
wie gehts weiter?
  • verwendete Beinche als Ausgänge definieren
  • Timer0 konfigurieren
    • WGM
    • COM0B
    • CS
    • COM0A-IRQ
    • COM0Btoggleregister und TOVcounter mit sinnigen Startwerten beladen
  • ISR implementieren, dabei die Auslastung signalisieren, Aufrufe zählen und ggf COM0B toggeln
Und dann mal die Hardware zusammenstecken, und ausprobieren... aber nicht mehr vor der Kaffeepause...
vielleicht mach ich heute abend weiter...
 
Und weiter gehts...
Die beiden reservierten Register werden mit sinnigen Startwerten beladen:
Code:
ldi TOVcounter, 38
ldi COM0BtoggleRegister, (1<<COM0B1)
selbsterklärend:
Code:
	;B2 und B1 zu Ausgaengen machen********
	ldi R16, (1<<DDB2)|(1<<DDB1)
	out DDRB, R16
Jetzt wird der Timer konfiguriert,
die beiden verwendeten Compare-Register werden mit den oben per Konstante festgelegten Werten beladen:
Code:
	ldi R16, low(OCR0Avalue)
	out OCR0AL, R16         ;Frequenzkorrektur des Timers
	ldi R16, low(OCR0Bvalue)
	out OCR0BL, R16         ;PWM-Verhaeltnis
der verwendete Interrupt des Output Compare A Events ("Überlauf") wird scharfgemacht:
Code:
	ldi R16, (1<<OCIE0A)
	out TIFR0, R16          ;OC0A-IRQ scharf
Die untersten Bits des WGM=15 (0b1111) werden hier gesetzt:
Code:
	ldi R16, (1<<WGM01)|(1<<WGM00)
	out TCCR0A, R16         ;WGM=15(1von2)
Die oberen beiden (0b1111) und der Prescaler hier:
Code:
	ldi R16, (1<<WGM03)|(1<<WGM02)|(1<<CS00)
	out TCCR0B, R16         ;WGM=15(2von2), Prescaler=1
	;Timer läuft
Jetzt noch die ISR.
Wir dekrementieren das reservierte Zählregister:
Code:
	dec TOVcounter
dec beeinflußt das Zero-Flag, falls das Ergebnis gleich Null ist, wird Z gesetzt (sonst gelöscht). Hier ist das nach dem 38sten dec der fall. Wenn Z nicht gesetzt ist, überspringen wir den Rest der ISR:
Code:
	BRNE carrierperiode_done
	;...
	carrierperiode_done:
	reti
Der Code dazwischen wird also nur ausgeführt, wenn der TOVcounter auf 0 dekrementiert wurde. In diesem Falle wird der Counter erstmal wieder zurückgesetzt, und der CompareOutputMode von KanalB getoggelt (Read Modify Write):
Code:
	   ldi TOVcounter, 38       ;Zaehler zuruecksetzen
	   in R16, TCCR0A
	   EOR R16, COM0BtoggleRegister
	   out TCCR0A, R16          ;und COM mittels RMW toggeln
Es wird in der ISR R16 verwendet und das SREG manipuliert. Da das Hauptprogramm leer ist, müssen beide zwar nicht gerettet und wiederhergestellt werden, der Vollständigkeit aber trotzdem retten:
Code:
	push R16
	in R16, SREG
	push R16
und in umgekehrter Reihenfolge wiederherstellen:
Code:
	pop R16
	out SREG, R16
	pop R16
Letztlich sollte die Interruptverwendung noch sichtbar gemacht werden, nach dem Eintritt in die ISR also B2 anschalten, und vor dem Austritt ausschalten:
Code:
	sbi PORTB, PORTB2
	;...
	cbi PORTB, PORTB2
Nochmal alles zusammen:
Code:
;*********************************************************************************************
;*                                      IR-Sperrfeuer                                        *
;*********************************************************************************************
;                      zur Erzeugung einer "Virtual Wall" für Staubsaugerrobotter
;
;verwendet wird ein ATtiny10, welcher einen 38kHz Carrier erzeugt, auf den ein 1kHz Signal
;moduliert wird.
;
;************verwendete Hardware*******
; -Timer0 erzeugt im fastPWM den Carrier, die Frequenz wird mit OCR0A korrigiert - WGM=15
; -PWM-Ausgabe ueber KanalB (OC0B bzw B1)
; -Das modulation des 1kHz-Signals wird aus dem 38kHz-Carrier abgeleitet, im OC0A-Interrupt
;  (also bei jedem "Überlauf" des PWM-Timers
;(-Auslastungsanzeige durch den OC0A-Interrupt über B2) 
;
;           +-----+
;          -|B0 B3|-!Reset
;       Gnd-|     |-Vcc
;Sperrfeuer-|B1 B2|-(Interrupt-Auslastung)
;           +-----+
;

;.include "tn10def.inc"	;MCU-Definitionsdatei, Angabe ab Studio5 nicht mehr sinnig
;************Interruptvektoren*********
.org 0x0000
	rjmp reset		;Resetvektor
.org OC0Aaddr
	rjmp carrierperiode
;*************Konstanten***************
.equ OCR0Avalue=210                    ;Frequenzkorrektur auf 38kHz
.equ OCR0Bvalue=OCR0avalue/2           ;PWM auf 50%
;**********Reservierte Register********
.def TOVcounter=R22                    ;zählt die Überläufe um von 38kHz auf 1kHz zu teilen
.def COM0BtoggleRegister=R23           ;Maske zum toggeln des CompareOutputModes von KanalB
;**********Resetvektor
reset:
ldi TOVcounter, 38
ldi COM0BtoggleRegister, (1<<COM0B1)   ;inverting Mode
	;Stackpointer ist default =RAMEND******
	ldi R16, 0xD8
	out CCP, R16			;unlock protected I/Os
	ldi R16, 0x00
	out CLKPSR, R16			;MainClockPrescaler=1
	;B2 und B1 zu Ausgaengen machen********
	ldi R16, (1<<DDB2)|(1<<DDB1)
	out DDRB, R16
	;Timer0 konfigurieren******************
	ldi R16, low(OCR0Avalue)
	out OCR0AL, R16         ;Frequenzkorrektur des Timers
	ldi R16, low(OCR0Bvalue)
	out OCR0BL, R16         ;PWM-Verhaeltnis
	ldi R16, (1<<OCIE0A)
	out TIMSK0, R16          ;OC0A-IRQ scharf
	ldi R16, (1<<WGM01)|(1<<WGM00)
	out TCCR0A, R16         ;WGM=15(1von2)
	ldi R16, (1<<WGM03)|(1<<WGM02)|(1<<CS00)
	out TCCR0B, R16         ;WGM=15(2von2), Prescaler=1
	;Timer läuft
SEI
;*************Hauptschleife****************
main:
	NOP
	rjmp main
;***********carrierperiode*****************
carrierperiode:
	sbi PORTB, PORTB2
	push R16
	in R16, SREG
	push R16
	dec TOVcounter              ;Zaehler runterzaehlen
	BRNE carrierperiode_done    ;bis 38, nur dann
	   ldi TOVcounter, 38       ;Zaehler zuruecksetzen
	   in R16, TCCR0A
	   EOR R16, COM0BtoggleRegister
	   out TCCR0A, R16          ;und COM mittels RMW toggeln
	carrierperiode_done:
	pop R16
	out SREG, R16
	pop R16
	cbi PORTB, PORTB2
	reti
Sind 76 Bytes Code, 7,4% des Flash...
 
Ergebnis:
attachment.php

Die Differenz T2-T1 ist 2,06ms lang, die Pause (Doppelpfeil) 1,03ms
reicht das?
Etwas reingezoomt:
attachment.php

Der Carrier hat knapp 37kHz, die ISR nutzt jedesmal ca 2 der ca 27µs.
 

Anhänge

  • Sperrfeuer.png
    Sperrfeuer.png
    47,5 KB · Aufrufe: 35
  • Sperrfeuer2.png
    Sperrfeuer2.png
    40,3 KB · Aufrufe: 36

Ü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)