Daten per RC5 auf LCD ST7920 übertragen

riesen

Mitglied
10. Sep. 2010
108
1
16
Hallo Bascom'er

Für einen Test, wollte ich eine kleine Datenmenge über eine kurze Distanz von einem ATmega328 Board
zu einem andern übertragen, und dann diese Daten auf dem LCD (ST7920) anzeigen.

Dies habe ich mit einer Art "Vergewaltigung" des RC5-Codes bewerkstelligt. Die einzelnen Zeichen werden
in zwei Halb-Bytes geteilt und so per RC5-Code übertragen. Eine definierte Start- und Stop-Sequenz
sorgt für einen geregelten Ablauf. Das Ganze könnte mit einer Prüfziffer noch sicherer gemacht werden,
aber darauf habe ich vorerst verzichtet.

Hardwaremässig habe ich eine IR-LED an PORTB.1 montiert, und beim Empfänger einen passenden
TSOP (z.B TSOP1838, TSOP4838) an PORTB.1. IR-LED und TSOP müssen die gleiche Wellenlänge haben.
Wer über grössere Distanzen übertagen möchte, muss der IR-LED einen Treiber-Transistor spendieren.

Das Beispiel enthält auch den Code für die grafische Ansteuerung eines ST7920 LCD's.

Viel Spass und Gruss
Thomas
 

Anhänge

  • IR_RC5_Send_Receive_Data.zip
    16,7 KB · Aufrufe: 34
Erklär mal genauer, das ZIP lad ich mir nicht aufs Mobile runter...

Müssen die Daten ein bestimmtes Format haben, oder kannst Du komplett Dein eigenes Ding stricken?
Die Sende-LED hast Du nur "mit einem Bein" am Controller?

Ich würde den Carrier für den TSOPxxxx mittels Timer-Output-Compare-Unit generieren lassen, und die Daten über den UART schicken. Die LED also zwischen TxD und OCPin.
Beim Empfänger den TSOPxxxx entsprechend auf RxD.
Wenn gewünscht geht das auch mit Paritätsbit, und natürlich kannst Du hinterher in SW auch irgendwelche weiteren Prüfungen vornehmen.

Sollte aufgrund der genutzten Hardware-Module den geringsten Aufwand darstellen...
 
Hallo

Ja, die IR-LED hängt nur mir einem Bein am Controller.

Wie der RC5-Code schlussendlich generiert wird, spielt keine Rolle. Meine Lösung sollte möglichst
einfach sein und die Bascom-Bordmittel , sprich RC5-Befehle, verwenden. Bascom unterstützt
zwei Modi, For- und Background.

Das Datenformat ist frei, da byteweise übertragen wird (2x Half-Byte), der Empfänger muss
logischerweise mit dem empfangenen String dann auch zurechtkommen. Die Start- und Stop-
Conditions bilden den Rahmen für die Datenübertragung.

Mein Programm ist keine weltbewegende Sache, aber vielleicht nützt jemandem die Grundidee.

Gruss
Thomas
 
Grundsätzlich möchte ich Dein Programm hier nicht schlechtreden, kritisieren - ich möchte nur andeuten, was da unter der Haube geschieht...
Meine Lösung sollte möglichst
einfach sein und die Bascom-Bordmittel [...] verwenden.
Ich beziehe "möglichst einfach" allerdings üblicherweise auf den Controller, Du auf den Hochsprachencode. Marc (oder wer auch immer) hat Dir quasi die Arbeit abgenommen (ist ja ok, dafür sind die Bibliotheken ja da), allerdings hat der Controller da viel mehr zu arbeiten.
Was ist RC-5 denn?
Ein Standard, mit dem Tastenbetätigungen von Fernbedienungen übertragen werden.
Ein Frame besteht aus:
  • 2 Startbits oder 1 Startbit und einem Fieldbit (welches den Kommandobereich verdoppelt)
  • 1 Steuerbit um zwischen wiederholtem und dauerhaftem betätigen der Taste zu unterscheiden
  • 5 Adressbits (also für 2^5=32 Geräte)
  • 6 Kommandobits (also 2^6=64 Kommandos (bzw mit dem Fieldbit 128))
Das ganze wird aber nicht einfach als Bitstrom ausgegeben, sondern biphasisch (Manchester). Das heißt, daß die Flanken des Frames mit den Flanken einer Clock zusammengefaßt (XOR) ausgegeben werden (also jedes Frame-Bit quasi einmal invertiert und einmal normal ausgegeben wird).
Ein Frame-Bit wird 1,778ms lang ausgegeben, jedes Halbbit also 889µs (entspricht 1,125kHz).
Zur Unterdrückung von Störungen wird das ganze auf einen 36kHz-Carrier moduliert.

Mir ist kein AVR bekannt, der ein RC-5 Hardware-Modul besitzt (definitiv kein Tiny), Bascom muß das also in Software umsetzen. Entweder komplett zu Fuß im Vordergrund (ein kompletter Frame hält dann das restliche Programm knapp 25ms an), oder Interruptgesteuert.
Für die Halbbits wären dann alle 889µs Interrupts notwendig.
Für den Carrier sogar alle 14µs (72kHz).

Zumindest den Carrier könnte man aber der Hardware, einem Timer übergeben. In Form von PWM.
Dazu gibt es sogar 'ne Application Note von ATMEL: AVR415
Der dort verwendete Tiny28L besitzt zwar eigentlich nur einen Timer ohne PWM, dafür allerdings ein Hi-Sink-Bein, welches modulliert werden kann (quasi die PWM-Ur-Form bei den AVR).
AVR mit PWM-fähigen Timern können das genauso über den Timer machen - was dann nur noch Interrupts für die Halbbits erfordert. Allerdings ist man dann auf einen OutputComparePin festgelegt.

Mein Vorschlag hatte sich ja auf den UART als Modul bezogen, unter Bascom könntest Du dann einfach mittels Print senden. Das birgt allerdings 2 Gefahren:
  • da das ganze auch über den 36kHz-Carrier geht, werden andere Empfänger beeinflußt - es wäre sogar möglich, daß zufällig ein Signal ausgegeben wird, welches irgendeinen konformen Frame mit einer gültigen Geräteadresse eines Gerätes entspricht, das Gerät dann also ansteuert.
  • die TSOPs sind ja eigentlich auf die biphasische Kommunikation ausgelegt, eigentlich kippt das Signal spätestens alle 1,778ms. Wenn man den UART drauflegt, kippt der nicht mehr zwangsläufig so, womit der TSOP dann klarkommen müßte. Andererseits könnte man da mit der Baudrate experimentieren...
Edit: am saubersten sollte es sein, das ganze mittels IRDA zu realisieren, genauer über SIR. Allerdings kann ich dazu auch nichts genaueres sagen/müßte mich erst einlesen...
 
Zuletzt bearbeitet:
Hallo LotadaC

Danke für de technischen Exkurs. Sicher gibt es fixfertige IRDA-Controller, die sind
aber recht teuer. Ich weiss nicht, was ich mit deinen Angaben anfangen soll, schreib
doch auch etwas Code zu deiner Idee, wäre spannend. Mein Code funktioniert auch
mit ATmega8, der kostet um einen $1.-- beim Chinesen. Mit dem internen Takt, ist
da ausser einem R/(C) für den Reset nichts notwendig, einfacher geht's kaum mehr.

Gruss
Thomas
 
Wenn Du den /Reset nicht als externen Reset(-Taster) nutzt, brauchst Du da keinen Kondensator (mMn brauchst Du gar keinen Kondensator dran, die interne StartUpTime macht doch dasselbe), wenn der /Reset gar nicht genutzt wird (also an dem Bein nichts weiter angeschlossen ist), brauchst Du auch keinen externen Pullup. Sobald C6 des Mega8 nämlich per Fusebit als Reset eingestellt ist, ist der interne Pullup per Override dauerhaft aufgeschaltet (das übersteuert auch ein eventuelles globales Pullup-Disable).
Der interne Pullup (Reset) sollte irgendwo zwischen 20 und 50kOhm liegen. Wenn am Bein 'ne lange Leitung angeschlossen ist, die sonst keinen Pegel bekommt (=Antenne), und die Umgebung "EM-verseucht" ist, könnte(!) der interne Pullup zu schwach sein - wenn nix angeschlossen ist (sehr kurze Antenne)...

Aber das nur am Rande.

Mit dem IRDA (SIR) meinte ich, das Deinem Mega8 zu implementieren - ähnlich der von Dir verwendeten RC-5-Bibliothek. Der Mega8 hat ja für beides keine integrierte Hardware an Bord, muß das per Software machen.
SIR macht das ähnlich dem seriellen UART, nur eben invertiert, und statt 'nem dauerhaften Hi (bei der "0") wird immer nur'n kurzer (3/16) Peak gesendet. Möglich sind dann Baudraten bis 115k2Baud.
RC-5 hätte mit den festgelegten Bitlängen ja um die 562Baud, und wesentlich mehr zu sendenden Overhead.
Ob irgendjemand IRDA (SIR) bereits mit Bascom realisiert hat, und'ne entsprechende Bibliothek bereitstellt, mußt Du selbst suchen - der Aufwand sollte ähnlich der RC-5-Bibliothek sein (Spekulation).

Mein ursprünglicher Vorschlag bezog sich ja einfach auf den HW-UART für die Daten, und 'nen HW-PWM für den 36kHz-Carrier. In ASM würde man einfach die Register direkt füllen, in Bascom gibt's dafür irgend'n "Config Timer"-Befehl. Den UART brauchst Du ggf gar nicht weiter einstellen, wenn per Default/Direktive die entsprechende Baudrate usw eingestellt ist. (im Hintergrund nimmt Bascom die Vorgaben aus der eventuellen Direktive, und wenn die fehlt die Voreinstellung, und schreibt die entsprechenden Werte genauso in die Register (bzw fügt den dafür nötigen Code ein) - davon bekommst Du halt nur nichts mit...)
Die LED ist dann zwischen PWM-Ausgang und Tx des UART.
Das Byte wird dann einfach mit "Print..." gesendet.
Oben hatte ich ja bereits vorgeschlagen, die Baudrate experimentell zu wählen - irgendwo bei 9600Baud würde ich anfangen.
Klemmt man die LED mit der Kathode an den Tx, mit der Anode an den PWM, hat man 'n invertiertes Telegramm: ein logisches Hi läßt die LED aus, ein Lo läßt sie flimmern. Im Idle ist sie also aus.
Ein gesendetes 0-Bit (zB das UART-Startbit) läßt die LED also flimmern, der TSOP filtert den Carrier raus, und zieht seinen Ausgang auf Gnd -> 0 am Rx.
Ein gesendetes 1-Bit (zB das Stopbit bzw Idle) läßt die LED aus, der TSOP bekommt keinen Carrier und läßt seinen Ausgang auf Hi -> 1 am Rx.
Mit einem LogicAnalyzer könnte man als erstes mitloggen, wie der TSOP auf die unterschiedlichen Baudraten reagiert (also einen Kanal am Tx, und einen Kanal am TSOP-Ausgang) - und ob das ganze überhaupt geht...
 
Hallo LotadaC

Du gibst Dir sehr viel Mühle mit den Erklärungen, danke!. Mit dem Reset habe ich aber gar kein Problem, weiss nicht,
auf was Du da Bezug nimmst. Bei mir ist der Reset wirklich an einem Reset-Taster angeschlossen. Auch sehe ich noch
nicht, was mir Deine ganze UART-Sache bringt, ich habe mit wenig Code (zugegeben Hochsprachen Code) das Problem
der Übertragung von wenigen Zeichen über eine sehr günstige Hardware (IR-LED/TSOP) gelöst. Wie erwähnt, möchte
ich damit keine Megabytes übertragen, aber zu Steuerzwecken klappt das super.

Wenn du ev. einen C-Code, oder was auch immer, zu Deiner Idee hast, wäre ich sehr daran interessiert.

Dank und Gruss
Thomas
 
Hehe, LotadaC ist einer hier der nicht nur Dinge sehr gut erklären kann sondern sich auch sehr gut mit den AVRs selbst auskennt. Muss man auch wenn man sich für Assembler entscheidet.

Worauf er hinaus wollte ist eine Art optimierte Form.

Ich nehme mal ein einfacheres Beispiel.
Du willst eine LED 500ms an und 500ms aus haben.
Das könntest du so umsetzen (Pseudocode!):


CodeBox BascomAVR
Do
    LED = 1
    WaitMs(500)
    LED = 0
    WaitMs(500)
Loop

Es würde funktionieren. Aber es wäre nicht sonderlich Zeitgenau, außerdem würde die CPU zu 100% ausgelastet sein. Die komplette Zeit über. Da das Sleep in Software gelößt wird. Alles was du dann hast um Energie zu sparen ist somit fürs Sitzorgan. Auch würde die CPU selbst nichts Anderes mehr ausführen (können), außer Interrupts. Er hängt halt in der Schleife fest. Alles was da rein funkt verfälscht die Timings.

Aber es gibt immer mehrere Lösungen.
Du könntest beispielsweise einen Timer auf 500mS einstellen und in dessen ISR den Pin toggeln. In der Main Loop braucht denn nur ein Sleep drin zu stehen.
So würde der AVR nur alle 500mS aufwachen, den Pin toggeln und wieder einschlafen.

Ähnlich ist es mit deiner Lösung.
Sie funktioniert, bietet aber noch Optimierungspotential (indem man Hardwarekomponenten des AVR nutzt statt alles per Software umrechnen zu lassen; sei es nun UART oder SPI). Das ist im Quelltext natürlich etwas komplexer, da dir so nicht alles abgenommen wird, aber ... naja ... Quick&dirty und es läuft oder gut durchdacht und läuft :)
Wenns dir so reicht ist ja alles ok :)

Musst bei RC5 nur aufpassen dass du nicht aus Versehen deinen Fernseher hackst ^^
 
Du hattest geschrieben, daß Du bis auf einen externen Pullup (nebst Kondensator) außer LED am Sender / TSOP am Empfänger keine weitere Hardware verbaut hast. Wenn die Leitung zum Reset-Taster nicht sehr lang ist (Antenne) und die Umgebung nicht EM-verseucht, tuts auch der interne Pullup, der bei Verwendung des Pins als Reset automatisch aktiviert ist. Was ist der Sinn des Kondensators? Meiner Meinung nach braucht man im allgemeinen beides nicht.
(Aber ich will hier keinen Glaubenskrieg anzetteln...)

Du verwendest im Sender "rc5send", laut Online-Hilfe muß die LED dann an OC1A - Timer1 wird also sehr wahrscheinlich zur Generierung des Carriers via HW-PWM genutzt (siehe #4 - obwohl OC1B ggf besser wäre). Bascom fügt außerdem (Timerkonfiguration) für Dich den nötigen Code ein, der die Bits dann einzeln doppelt (wegen der biphasischen Codierung - RC-5) auf die LED legt, inklusive dem RC-5-Overhead (Adresse etc...).
Das ist für Dich halt nur deswegen einfacher, weil es schon wer anders programmiert hat, und Du es mit einem Befehl verwenden kannst.
Du erkaufst Dir das ganze mit einer Festlegung auf OC1A für die LED (und der festgelegten Nutzung des Timers), mit der festen Baudrate des RC-5 (562Baud) und eben der Controllerauslastung (speicher- und timingtechnisch).
Beim Empfänger ist es dann mit "getrc5" ähnlich, hier an Timer0 gebunden (bzw Timer2).

Wie gesagt - von der Benutzbarkeit her gesehen ist Dein Weg sicher "einfacher", insbesondere kannst Du über eine entsprechend gewählte RC-5-Adresse ausschließen, daß es zu Konflikten zwischen dieser Kommunikation und vorhandenen Fernbedienungen/Geräten kommt.

Ich wollte halt nur mal einen anderen,eventuell möglichen Weg vorschlagen, auf dem man das eben auch versuchen könnte, den ich(!) gegangen wäre. Im Prinzip ist mein Vorschlag nichts anderes als 'ne stinknormale serielle Verbindung zweier AVR über den Hardware-UART (sollte sich also in Bascom genau so mit Print und co umsetzen lassen) - nur eben, daß statt der Leitung (und Gnd) mit Licht übertragen wird.
Um beim Empfang eben auch die Vorzüge eines TSOP genießen zu können, muß ich dann eben auch (wie sendrc5) einen Carrier generieren lassen.
Der TSOP ist ja erstmal ein optischer Filter, der möglichst nur IR durchläßt. Außerdem filtert und verstärkt er die eingehenden Lichtimpulse -> im Idle legt er den Ausgang auf hi, erkennt er 'n 36kHz-Leuchtfeuer zieht er den Ausgang auf Gnd (vereinfacht gesagt).
Folglich muß ich mit meiner Baudrate deutlich unter den 36kHz bleiben (abgesehen davon, daß der Ausgang vielleicht nicht beliebig schnell schalten kann). Auf der anderen Seite ist der TSOP wegen der biphasischen Codierung möglicherweise auch darauf ausgelegt nicht dauerhaft auf Gnd ziehen zu müssen. Deswegen würde ich in etwa mit der zehnfachen Baudrate von RC-5 experimentieren - dann würde ein UART-Byte einem RC-5-Bit entsprechen, mit Start- und Stopbit hat man definitiv beide Pegel. Tx-UART-Idle = hi = LED aus = TSOP-Ausgang hi = Rx-UART-Idle paßt auch.
Sind aber alles nur Überlegungen - wenn sich das so machen läßt, wären beim Sender lediglich der Tx-Pin und der verwendete PWM-Pin als Ausgang festzulegen und der PWM-Pin auf die PWM-Ausgabe mit 36kHz einzustellen (Config Timer blablub und vorher das OCR-Register zu beladen (-> Frequenz))
Die Verwendung des UART macht Bascom für Dich mit Print, wobei die Baudrate natürlich passen muß (entweder über die Defaults in den Compiler Settings, oder über die Direktive).
Im Empfänger entfällt der Carrier-Kram (macht ja der TSOP) - da beschränkt sich das ganze also auf den seriellen Empfang mit den entsprechenden Bascom-Methoden (ischarwaiting, inkey oder Input oder so...)
 
War das nicht so dass früher ein C am Reset für ein PowerOn Reset sorgte?
Wie bei den 8051ern?

Den braucht man aber nicht mehr. Den Reset lasse ich immer frei (abgesehen vom ISP Anschluss). Kondensatoren daran können sich sogar stark zum Nachteil auswirken solltest du irgendwann mal debugWire nutzen wollen. Ein Kondensator an der (dann) Datenleitung ist keine gute Idee ;)

Probleme hatte ich eher mit fehlenden Abblockkondensatoren statt fehlenden PullUps. Mit letzterem in der Tat nur ein Mal, das betraf aber nicht Reset sondern I2C/TWI :)
Ach ja, und mit fehlendem PullUp an der SPI CS Leitung ^^
 
Naja... bei meinen Erklärungen ufert das sehr oft ziemlich aus... Dino bringt das eher auf den Punkt. Und was Elektronik angeht... Alabel halt...;)
Offtopic: das mit Deinem fehlenden Pullup war das mit der Spiegelschrift, oder? Wegen dem "gehackten Fernseher": Hatte ich Dir nicht auch mal 'n Tiny irgendwelche seriellen Daten senden lassen, den Du dann an Deinen Rechner geklemmt hattest, woraufhin Dein Mauszeiger durchgedreht ist?? Irgendwas in Verbindung mit Deinem Multimetertool muß das damals (ganz am Amfang) gewesen sein.

Backtotopic:
Hab grad' mal im Keller gekramt - so auf die Schnelle find ich hier keinen TSOPxxxx, und irgendwas schlachten will ich auch grad nicht. Irgendwelche IR-LEDs hab ich. Trotzdem würde mich natürlich interessieren, ob mein Weg gehen würde - wenn sich jemand findet, der das mit 'nem LogicAnalyzer ausprobiert, könnte man 'n paar einfache Testprogrämmchen stricken (am einfachsten/schnellsten in ASM).
 
Das schätze ich aber auch so an dir, man lernt sehr viel ;)
Ist nur vielleicht für manche die noch nicht so in der Hardware drin stecken zu viel Input auf einmal.

Und ja, du hast bei allem recht. Der Tiny wurde als serielle Microsoft Maus erkannt und hat dann wild hin und her geklickt ^^
War wegen dem "komischem" Format mit 2400/7/O/1 was ich irgendwie nicht hin bekommen hatte mit LunaAVR.
Falls es wen interessiert: Hier ist der Thread dazu ;)
Fun Fact danach:
Das dämliche Dongle konnte ich eh nur mit 2400/8/N/1 initialisieren. Musste das Parity Bit also eh in Software auswerten / verwerfen. So macht es die originale Software auch. Ist halt Sch.... wenn man für nix Dokumentationen hat. Japanesien halt.

Das Bild mit der Spiegelschrift hatte ich mit verlinkt. Muss immer noch drüber schmunzeln ^^ Das war mit fehlendem PullUp am CS beim SPI. Da hat der Flashvorgang das Display gleich mit angesprochen da der Pin TriState, also 0V war. Und auf irgendwas hat es wohl reagiert. Undokumentierte Funktionen oder so.
 
Hallo zusammen
Da hat sich ja eine sehr interessante Diskussion entfacht. Kurz zur Sache mit dem Reset: Das (C) hätte ich nicht nur in
Klammern setzen sollen, sondern ganz streichen sollen. Ich verwende selber nur den 10K Pull-Up und dann einen Taster
gegen GND. Bei den verwendeten Arduino-Boards (Chinesendinger Mini Pro für $2.5 mit Mega328) hat es manchmal noch
ein C am Reset.

Ich bin kein "gelernter" Elektroniker, und betreibe das alles wirklich nur als Hobby, leben könnte ich von meinen
Basteleien wohl nicht :) .... aber es macht ja dennoch Spass, sich Herausforderungen zu stellen. In dem Sinne wäre das
schon spannend mit der UART-Übertragung über IR, denn die genannten "Nachteile", z.B. Verwendung Timer1 OC1A,
sind so vorhanden.

Hardware TSOP's und diverse IR-LED's hätte ich hier herumliegen, könnte dir, LotadaC, gerne welche zusenden. Ich selber
komme leider in absehbarer Zeit nicht zum Pröbeln mit UART/IR, es stehen noch einige andere Projekte (z.B. ein mobiles
Gerät mit ATmega128, TFT ILI9341, ESP8266, BMP180 und DS3231) an. Dann auch wieder mal was mit Nixi-Röhren ...

Dank und Gruss
Thomas
 
So, hab jetzt doch noch so'n Dreibeiner (keine Ahnung, wo ich den ausgebastelt hatte) und'ne LED gefunden. Prinzipiell geht's:
IRUART.png
Gelb ist die LED (bei Lo leuchtet sie, bei Hi ist sie aus), Schwarz ist das Ausgangssignal des Empfängers.
Als ersten Test hatte ich abwechselnd lo und hi auf den Carrier gelegt (also 2ms flimmern, 2ms aus usw...), das macht mein Empfänger zwischen 6s und 14s mit, danach bleibt er dauerhaft hi. wenn man ihn dann abschattet, geht's wieder 'n paar Sekunden...
Für diesen Test (Bild) hab ich Timer2 'n 32ms-IRQ generieren lassen, der jedesmal zwei Bytes in den UART stopft (zwei, da UDR gepuffert ist, ich mich also nicht um irgendwelche Timings kümmern muß)
Erstmal konstant 0x55 ausgegeben (=worstcase, da die Bits zappeln) - bei 9600Baud hat er meine Bits komplett mitrausgefiltert (also der Ausgang war das ganze Byte lang low).
Bei 4800Baud schien es zu gehen, ab und zu waren aber Fehler drin.
Bei 3000Baud ist mir nichts aufgefallen.
Jetzt hab ich einfach mal das auszugebende Byte zwischendurch inkrementieren lassen...
@risen: wenn Dein TSOP hier ankommt, kann ich den ja mal ausprobieren.

P.S.: mein Test-Code


CodeBox Assembler
/*
* IRUART.asm
*
*  Created: 23.09.2015 14:49:10
*  Author: LotadaC
*
* Timer0 erzeugt den 36kHz Carrier, Ausgabe auf OC0B=D5 (LED-Anode)
* Timer2 erzeugt IRQs, in denen je zwei Zeichen über den UART ausgegeben werden
* TxD0 sendet serielle Daten (LED-Kathode)
*/
.equ baudrate=3000

.equ baud=8000000/16/baudrate-1
.org 0x0000
rjmp reset
.org OVF2addr
rjmp TOV2_ISR

reset:
;Stackpointer ist Ramend
;OC0B und TxD als Ausgang, Hi
ldi r16, (1<<PD5)|(1<<PD1)
out portd, r16
out ddrd, r16
;UART0 konfigurieren (8N1)
ldi r16, high(baud)
sts UBRR0H, r16
ldi r16, low(baud)
sts UBRR0L, r16 ;Baudrate
ldi r16, (1<<TXEN0)
sts UCSR0B, r16 ;Transmitter aktiviert
;Timer2 konfigurieren
;TOV-IRQ aktivieren (33ms)
ldi r16, (1<<TOIE2)
sts TIMSK2, R16
;Prescaler=1024
ldi r16, (1<<CS22)|(1<<CS21)|(1<<CS20)
sts TCCR2B, r16 ;Timer läuft
;36kHz-PWM auf OC0B
;fastPWM bis OCR0A, OC0B als Output (WGM=7)
ldi r16, (1<<COM0B1)|(1<<WGM01)|(1<<WGM00)
out TCCR0A, r16
;OCR0A=221
ldi r16, 221
out OCR0A, r16
;OCR0B=110
ldi r16, 110
out OCR0B, r16
;WGM=7, Prescaler=1
ldi r16, (1<<WGM02)|(1<<CS00)
out TCCR0B, r16 ;Timer0 läuft mit PWM
sei
ldi r16, 0x55
loop:
rjmp loop
TOV2_ISR:
sts UDR0, r16 ;R16 senden
inc r16
sts UDR0, r16 ;und nochmal
reti

74 Bytes Flash
Achso, ist'n Mega88PA @8MHz intern (dieweil der hier grad rumkrabbelte)
 

Anhänge

  • upload_2015-9-23_16-48-46.png
    upload_2015-9-23_16-48-46.png
    72,8 KB · Aufrufe: 10
Mal ein kurzes Lebenszeichen - Ich bin noch drann, Riesen!!

Aber irgendwie ist das immer so'ne Sache mit Zeit und/oder Motivation... und daß ich da mehr oder weniger Bascom versprochen hatte tut ein übriges...
Die Testumgebung steht eigentlich schon:
index.php

Thomas meinte ja dazu
Hat mich grade wieder daran erinnert warum ich ausschließlich LCDs mit SPI verwende ^^
Ich hatte dann angedeutet, daß ich es mit entsprechenden Steckern versehen hätte, so in etwa:
IMG_7867_1.jpg
(wobei das hier allerdings der ISP ist - kann man dann sehr schön direkt aufs "Brot-Brett" stöpseln...)
 
Hallo LotadaC

Sieht ja recht spannend aus deine Testumgebung. Betreffend Zeit und Motivation sieht es bei mir in etwa gleich
aus. Zur Zeit entwickle ich für TFT-Displays (Treiber von Heiko) eine Art Framework, mit welchem recht schnell
individuelle Menus und Touch-Eingaben erstellet werden können.

Deinen Assembler-Code habe ich im Ansatz verstanden, eine Bascom-Variante wäre aber schon auch noch toll.
Hoffe, in den Wintermonaten hier auch wieder mal Zeit zu finden, um die IR-Geschichte weiterzutreiben.

Gruss
Thomas
 
So, hab mich mal aufgerafft - herausgekommen ist dieses Testprogramm:


CodeBox BascomAVR
$regfile = "m88pdef.dat"
$crystal = 8000000
Const F_carrier = 38000  'Carrierfrequenz in Hz
Dim Baudrate As Dword  'initiale Baudrate
Baudrate = 2400
Const Baudrate1 = _xtal / 16
Const Teststring = "llsdfkndmbvs,mshfsdb jsbfmerbfm8264812r4q33gkj,dsgvbsdmfbgsrj,hg,dnhµhg,asgjfmh"
Dim Rec As String * 254
Dim Ubrrvalue As Dword
Dim Temp As Word

'initialisiere LCD  --- sollte eigentlich selbsterklärend sein
Config Lcd = 20 * 2
Config Lcdpin = Pin , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 , Db7 = Portc.3 , E = Portc.5 , Rs = Portc.4
Cls
Locate 1 , 1
Lcd "initialisiere..."

'3 Taster gegen Gnd D2, D3, D4
Set Portd.2  'mit internen Pullups
Set Portd.3
Set Portd.4
Nunter Alias Pind.2  'klingende Namen
Losloszackzack Alias Pind.3
Nuff Alias Pind.4

'UART Transmitter  --- Kathode der LED an TxD,Hi bevor der Carrier loslegt
Set Portd.1
Set Ddrd.1

'Carrier - verwendet wird Timer1, Compare Match A  (=Anode)
'dafür gibts sicher irgendein "config timer1= blablub" in Bascom
Set Ddrb.1  'OC1A ist Ausgang
'WGM=15 (fastPWM bis OCR1A)
'  ||-----------------> COM1A1..0 -> Oc1a toggelt beim match
'  ||-----------> WGM11..0  -> WGM=15=&b1111
Tccr1a = &B01000011
'Frequenz berechnen lassen (Prescaler=1):
Const Ocrvalue =((_xtal / F_carrier) / 2) - 1
Ocr1a = Ocrvalue
'  ||--------------> WGM13..2 -> WGM=15=&b1111
'  |||-----------> CS12..0 -> Prescaler=1
Tccr1b = &B00011001

'UART vorbereiten
Config Serialout = Buffered , Size = 254
Config Serialin = Buffered , Size = 254

'Baudrate ausrechnen
Ubrrvalue = Baudrate1 / Baudrate
Ubrrvalue = Ubrrvalue - 1
Ubrr0 = Ubrrvalue
Temp = Ubrrvalue + 1
Baudrate = Baudrate1 / Temp

Cls
Locate 1 , 1
Lcd "UBRR=" ; Ubrr0 ; "->" ; Baudrate
Locate 2 , 1
Lcd "Bereit"
'schleife*********************************
Enable Interrupts
Do
If Nuff = 0 Then  'UBRR dekrementieren, Anzeige
  If Ubrrvalue > 0 Then
  Locate 2 , 1
  Lcd "  "
  Baudrate = Baudrate1 / Ubrrvalue
  Ubrrvalue = Ubrrvalue - 1
  Ubrr0 = Ubrrvalue
  Locate 1 , 1
  Lcd "UBRR=" ; Ubrr0 ; "->" ; Baudrate ; "  "
  Waitms 250
  End If
End If
If Nunter = 0 Then  'UBRR inkrementieren, Anzeige
  If Ubrrvalue < 4095 Then
  Locate 2 , 1
  Lcd "  "
  Ubrrvalue = Ubrrvalue + 2
  Baudrate = Baudrate1 / Ubrrvalue
  Ubrrvalue = Ubrrvalue - 1
  Ubrr0 = Ubrrvalue
  Locate 1 , 1
  Lcd "UBRR=" ; Ubrr0 ; "->" ; Baudrate ; "  "
  Waitms 250
  End If
End If
If Losloszackzack = 0 Then  'Teststring senden/empfangen/kontrollieren
  Locate 2 , 1
  Lcd "  "
  Print Teststring
  Waitms 750
  Input Rec Noecho
  Locate 2 , 1
  If Rec = Teststring Then Lcd "ok  " Else Lcd "Fehler"
  Clear Serialin
End If
Loop

Beschaltung sollte eigentlich klarsein (bzw dem Code zu entnehmen) - LCD, Taster.
Die IR-LED hängt mit der Anode am Timer-Compare-Pin (hier OC1A - wäre aber auch jeder andere möglich), mit der Kathode am TxD. Dazwischen ein Vorwiderstand - eigentlich Wurscht ab an der Anode oder an der Kathode. Wenn er aber an der Kathode hängt, kann man zwischen LED und R mit'nem LA verfolgen, wann die LED flimmert (siehe #14).
Der TSOP dann mit konventioneller Beschaltung, der Ausgang an RxD.

Du hattest mir ja diverse LEDs und (unter anderem) einen TSOP4838 geschickt:
Mit meinem Aufbau kann ich den obigen Text mit bis ungefähr 3500Baud durch den 4838 jagen, dann kommen ab und zu Fehler. Mit zunehmendem Tempo nimmt dann auch der Fehleranteil zu...
Hab mal den LA mitloggen lassen - der erkennt dann irgendwo 'n Frame-Error, wodurch dann ggf folgende Bytes auch nicht mehr stimmen.
Hmm... ob das auch das Frameerror-Bit des UART Triggern würde, hab ich mir jetzt noch nicht genauer angesehen - wüßte auch nicht, wie man das bei Bascoms "Input" auswerten könnte.
(In ASM bzw wenn man selbst den Rx-IRQ implementiert/die Bytes in den Buffer schaufeln läßt wärs klar - jedesmal FE0 in UCSR0A prüfen)

P.S.: ich habe den Code oben jetzt in keinster Weise optimiert etc. Wenn hier irgendein Bascom-Profi Änderungen vorschlagen will... immer her damit.
(ist nicht meine Welt;))
 
Hallo LotadaC

Wau, jetzt hast du aber Gas gegeben ... super ... vielen Dank!!!!

Einfach ein genialer Lösungsansatz, werde diesen gerne bei mir einbauen ... bitte sei mir aber nicht böse,
wenn das nicht grad in den nächsten Tagen möglich ist .... mein Framework muss nun endlich fertig werden ... :)

Dankende Grüsse aus der Schweiz
Thomas
 
Hmm... ob das auch das Frameerror-Bit des UART Triggern würde, hab ich mir jetzt noch nicht genauer angesehen - wüßte auch nicht, wie man das bei Bascoms "Input" auswerten könnte.
(In ASM bzw wenn man selbst den Rx-IRQ implementiert/die Bytes in den Buffer schaufeln läßt wärs klar - jedesmal FE0 in UCSR0A prüfen)
Wird vielleicht wie beim PC gehandhabt. Falsche Bytes / Parity Fehler werden mit einem bestimmten Byte (meißt "?", änderbar) ersetzt. Aber wie die es handhaben weiß ich auch nicht.

P.S.: ich habe den Code oben jetzt in keinster Weise optimiert etc. Wenn hier irgendein Bascom-Profi Änderungen vorschlagen will... immer her damit.
(ist nicht meine Welt;))
Du und Bascom, dass ich das noch erleben darf… :D
 
Hey... ich hab die Vollversion bestimmt schon seit 10 Jahren oder so...
Meine ersten Schritte waren Bascom - ich bin dann halt recht schnell zu ASM gewechselt (wie Du auch, wenn ich mich recht erinner - auch wenn Du inzwischen eher "den Mond anstarrst" :p).

Aber zum Thema (das ich genau genommen (mit riesen's Akzeptanz) gehijacked habe):
Jedesmal, wenn der entsprechende Taster betätigt wird jagt der AVR den String (mit der vorher eingestellten Baudrate) durch die LED, und empfängt was vom TSOP.
Ich habe einfach beide Strings auf komplette Gleichheit überprüft - und das ganze im AVR nicht weiter untersucht.

Wenn ein String nicht fehlerfrei erkannt wurde, sehe ich beim LA(!) auch FrameErrors. (wodurch späer folgende Bytes auch ohne FE falsch erkannt sein können). Das FE-Bit des HW-UART wird gesetzt, wenn das empfangene Stopbit des, als nächstes aus dem UDR abzuholenden ... "Zeichens" nicht "1" war.

Allerdings muß ich zugeben, daß auch der Carrier zu hoch ist - ca 39kHz. Würde ich jetzt auf den internen Oszi schieben. Damit wäre die tatsächliche Baudrate des AVR (TxD und RxD) tatsächlich höher als ich dem LA vorgebe.

Hmm... vielleicht sollte ich mal mit zwei Stopbits testen...

Jedenfalls hab ich ja im Code Serialin für den Empfang genutzt - Bascom legt 'n Empfangspuffer im SRAM an, und holt bei jedem RxComplete-IRQ das Byte aus dem UDR in den Puffer. Input holt dann den (nullterminierten) String aus dem Puffer.
Die gesetzten FE-Bits müßten aber bei jedem RxC-IRQ gecheckt werden - was wie gasagt Bascom-intern geschieht.
Klar könnte man das selbst übernehmen, oder irgendwelche anderen Analysen durchführen - mir(!) hat's jedoch gereicht, nur'n einfachen Verbindungsgeschwindigkeits-Test umzusetzen.

@riesen : Ich denke nicht, daß Du das ganze(!) bei Dir einbauen solltest - Du kannst damit eher einen zu verwendenden TSOP mit der korrespondierenden LED auf mögliche Transfergeschwindigkeiten testen.
Im tatsächlichen Einsatz reicht dann sicher eine (eben so vorher bestimmte) sichere feste Baudrate aus (die in Bascom mit "$baud" vorgegeben werden kann) - ohne den ganzen Rechenkram.

Ich habe den Teststring mit serialout senden lassen - mMn verwendet der den UDRE-IRQ. Sobaldletzte Zeichen aus dem UDR (Transmitter-Puffer) an den eigentlichen Transmitter übergeben wurde, und der Puffer leer ist, tritt der IRQ ein - das nächste wird im UDR (Transmitter) geparkt. Man sieht am LA, daß zwischen den einzelnen Bytes keine Pausen sind.
Auf der anderen Seite landen die dann natürlich (mit einer konstanten Verzögerung durch den TSOP) auch ohne Pausen im Rx-Puffer (was dann dort im UDR (Empfangspuffer) ausgelesen wird. Also Senden und Empfangen gleichzeitig - eben mit Hilfe der der Hardware-Puffer.

Das mußt Du natürlich nicht zwingend genauso handhaben - wenn nur gesendet oder Empfangen werden soll (ohne weitere Hintergrundaktivität), reicht auch das interruptfreie Polling der IRQ-Flags - wobei ich nicht weiß, ob Bascom sowas nutzt.

Zum Carrier: ich habe hier konkret auch OC1A verwendet, es hätte aber auch jeder andere OC des Controllers sein können.
Der Timer läuft mit fastPWM mit OCR1A als Top, und toggelt bei jedem Überlauf OC1A (deswegen das "/2" in Zeile 39).
Der OC1A-IRQ wird nicht verwendet - könnte man aber machen, hätte dann 'ne 38kHz-Zeitbasis.
Man könnte auch KanalB zusätzlich als PWM nutzen, halt festgelegt auf 38kHz PWM-Frequenz und mit einer durch OCR1A beschränkten Auflösung.
Machbar wäre das auch mit vielen anderen Modi der Timer - man kann also vorher berlegen was die Timer sonst noch so mit welchen Einstellungen können müssen, und dann sehen, wo sich dazwischen der Hardware-Carrier realisieren läßt

Falls Du noch Fragen hast...
 

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