Bascom NEC Code senden

richtig, jedes Paket ist aufgrund der Invertierung gleich lang, da jedes Bit einmal als 1 und einmal als 0 gesendet wird.

Ich verstehe Bonze eher so, daß er einen empfangenden TSOP simulieren will, also eine Applikation hat, die normalerweise mit einem TSOP ein trägerfrequenzbehaftetes IR-Signal empfängt, wobei der TSOP die Trägerfrequenz rausfiltert, und das reine biphasische (?) Signal weiterleitet.
Er will jetzt mit dem Rechenzwerg den TSOP ersetzen - selbst also ein äquivalentes biphasisches Signal auf die Applikation legen. logischerweise ohne Trägerfrequenz.

Zu meinem Programm: Da keine Trägerfrequenz gefordert war, hab ich da auch nichts umgesetzt.
Ich verwende den 16-Bit-Timer im frequenzkorrekten PWM. Als Überlaufpunkt wird das ICR verwendet (WGM=14), der OC1A-Pin wird beim Überlauf (automatisch) gesetzt, beim CompareMatch1A (automatisch) gelöscht (CompareOutputMode=2). Das geschieht alles in der Hardware des Timers im Hintergrund. Ich benutze ferner den OC1A-Interrupt, um mit dem ICR die Frequenz des PWM nach jedem Bit anzupassen -> also effektiv die low -Zeit festzulegen. Dafür habe ich 1.125ms (bei einer 0) bzw 2.25ms (bei einer 1) Zeit. Also mehr als genug.
Da man per PWM keinen konstanten lo-Pegel erzeugen kann, verwende ich während des Startbursts und der folgenden Pause den Pin als normalen I/O (CompareOutputMode=0). Das Umschalten von OCR1A stammt noch von dem Versuch, das komplett im COM2 zu fahren - könnte ich auch noch verändern.

Wenn ich jetzt mit einem 2ten Timer (Timer0) eine Trägerfrequenz erzeugen lassen würde (FastPWM im WGM=7), und OC0B als PWM-Ausgang verwende (COM0B=2), und mit OCR0B den DC vorgebe, muß ich as einmal initialisieren, und kann den Timer danach komplett vergessen - der erzeugt die Trägerfrequenz dann komplett unabhängig im Hintergrund.
Wenn ich stattdessen den COM oder die Datenrichtung von OC1A manipulieren will, muß das immer durch einen IRQ geschehen. Wegen der Asymmetrie (DC<>50) einmal zum setzen der hi-Anteils der Trägerfrequenz, einmal zu löschen. Ich muß also sowohl den OC0B-Interrupt verwenden, als auch den OC0A-/TOV0-Interrupt (treten ja gleichzeitig auf). Insbesondere werden jetzt also mit einer Frequenz von 38kHz 2 Interrupts angefordert (um den DC phasenverschoben).
Aber Bonze sagt, er braucht keine Trägerfrequenz...
 
@LotadaC, genauso ist es

wassoll ich denn jetzt nochmal mitdem LA prüfen ?
kann sein das er das Startbit abgeschnitten hat,. hab danich so aufgepasst
 
wassoll ich denn jetzt nochmal mitdem LA prüfen ?
kann sein das er das Startbit abgeschnitten hat,. hab danich so aufgepasst

-Den Code aus Beitrag 36
-ob der Startburst kommt, oder nicht (da müßten eigentlich derzeit vor der ersten steigenden Flanke (Kastenanfang) noch 36ms lo-Pegel sein, davor 72ms hi-Pegel (alles 8mal so lang, siehe nächsten Punkt))
-ob Deine Fusebytes stimmen - der LA-Mitschnitt läßt auf eine gesetzte CKDIV8-Fuse schließen, und damit auf einen effektiven Takt von 1MHz. Damit sind wir dann halt auch im den Faktor 8 zu langsam.

Durch Rolfs Kommentare werde ich aber das ganze nochmal etwas optimieren (mit dem OCR1A und so...).

Woher bekommt der Tiny jetzt eigentlich seine Informationen, was er senden soll?
Was soll noch rein?

An interner Hardware steht Dir noch zur Verfügung:
-ein echter Hardware-UART (serielle Schnittstelle)
-eine USI (serielle Schnittstelle ->TWI mit etwas Software möglich)
-2 externe Interrupts
-1 8bit-Timer mit 2 PWM-Kanälen, OC0A kann aber auch zur Frequenzkorrektur verwendet werden
-der analog-comperator
-bis zu 16 I/O-Pins, von denen 7 einen (gemeinsamen) PCINT auslösen können

Bisher verwenden Bascom und ich zusammen ca. 14% des Flash, ich verwende 3 Variablen (Bytes ) im SRAM, für den Stackpointer & co hast Du zusätzlich (?) weitere 50 Bytes reserviert (der Tiny hat 128), von den 128 Eeprom-Bytes verwenden wir gar nichts. Du hast also noch jede Menge Luft...
 
um genauer zu sein, der tiny ist via Uart mit nem Ibus transciever verbunden,.
er soll die Codes der Lenkrad FB umsetzen, das ich diese dann ins Autoradio (kenwood) einspeisen kann :)
 
Gehe ich recht in der Annahme, daß sich das Adressbyte zur Laufzeit nicht mehr ändert, also immer an dieselbe Adresse gesendet wird?
Ich habe das mit dem OCR1A-anpassen jetzt rausgenommen, das INC durch ein ADIW ersetzt (falls bei dem Inc XL überläuft, stimmt XH sonst nicht).
zu dem Zeitpunkt war der Code sogar 14 Bytes kürzer.
Jetzt habe ich noch versucht, sowohl die INIT als auch den "Sendebefehl" in eine Subroutine zu packen -> derzeit sind wir bei 18% Flash
Code:
$crystal = 8000000
$regfile = "attiny2313.dat"
$hwstack = 20                                               'default use 32 for the hardware stack
$swstack = 20                                               'default use 10 for the SW stack
$framesize = 10                                             'default use 40 for the frame space
$baud = 19200

'****Interruptvektoren****
On Oc1a Oc1a_isr Nosave
'****Variablen****
Dim Bitzaehler As Byte
Dim Adress As Byte
Dim Kommando As Byte

'****Subs****
Declare Sub Initnec(byval Zieladresse As Byte)
Declare Sub Sendnec(byval Kommandobyte As Byte)

Call Initnec(&B10011101)
Enable Interrupts                                           'Interrupts freigeben


Call Sendnec(&B00101000)                                    'ein Paket senden
'******Hauptschleife******
Do
  'leer
Loop

'*****************Subroutinen*******
Sub Initnec(zieladresse As Byte)
   Tccr1a = 2                                               'für normale I/O und WGM=14
   Ocr1a = 4499
   Icr1 = 17999
   Ddrb.3 = 1                                               'PortB.3 (OC1A) ist Ausgang
   Bitzaehler = 39
   Adress = Zieladresse
   Enable Oc1a
End Sub
Sub Sendnec(kommandobyte As Byte)
'*************************hier warten, falls noch gesendet wird*****
   Kommando = Kommandobyte
   Tccr1b = 25                                              'Startburst wahrscheinlich Takt zu lang
   SBI PORTB, PORTB3                                        'ggf TCNT vorladen (auch in ISR)
End Sub
'*****Interrupt Service Routinen****
Oc1a_isr:
      $asm                                                  'Assemblerblockanfang
      PUSH XH
      PUSH XL
      PUSH R16
      IN R16, SREG
      PUSH R16                                              'Register und SREG gesichert
      Loadadr Bitzaehler , X                                'X Enthält Bitzaehler -speicheradresse
      LD R16, X                                             'R16=Bitzähler
      DEC R16                                               'R16 dekrementiert
      ST X+, R16                                            'Bitzähler zurückgespeichert, X enthält Adress-Adresse
      BREQ naechstesVorbereiten                             'final wurde gesendet, Sprung (nächstes vorbereiten)
      CPI R16, 35                                           'Z=1 <==> Bitzaehler (jetzt)= 35
      BREQ burstAbschalten                                  'dann springe burstAbschalten
      cpi R16, 33                                           'Z=1<==>Bitzaehler=33, C=1<==>BZ<=33
      BREQ pauseEnde                                        'BZ=33 -> Pause Ende
      BRSH dasWars                                          '>33->dasWars (0,35,33 wurden bereits behandelt, bleiben die 32 Bits)
      CPI R16, 17                                           'Carry bei den letzten 17 also einem Endburst (R16=0) plus 16  Bits(R16=16..1)
      BRCC AdresseStimmt                                    'sonst überspringe
      adiw XL, 1                                            'X =Kommandoadresse

   Adressestimmt:
      LD R16, X
      LSL R16                                               'einmal nach links schieben, MSB wandert ins Carry
      BRCS EinsSenden                                       'bei 1 springe, bei 0 bleibe
      INC R16                                               'links wurde ne 0 rausgeschoben, deswegen wird die 0 hinten zur 1 invertiert
      ST X, R16                                             'Byte zurückgespeichert
      LDI R16, hbyte(8999)
      Out Icr1h , R16
      LDI R16, lbyte(8999)
      Out Icr1l , R16                                       'Icr Angepaßt
      RJMP dasWars                                          'Fall 0 erledigt

   Einssenden:
      ST X, R16                                             'die hinten eingeschobene 0 ist bereits invers zur 1 - Byte zurückgespeichert
      LDI R16, hbyte(17999 )
      Out Icr1h , R16
      LDI R16, lbyte(17999 )
      Out Icr1l , R16                                       'Icr Angepaßt
      RJMP dasWars                                          'Fall 1 erledigt

   Pauseende:
      LDI R16, 130
      Out Tccr1a , R16                                      'B3 wird PWM (lo->hi beim nächsten TOV)
      RJMP dasWars                                          '->dasWars

   Burstabschalten:
      CBI PORTB, PORTB3                                     'B3 -> lo
      RJMP dasWars                                          '->dasWars

   Naechstesvorbereiten:
      LDI R16 , 24
      Out Tccr1b , R16                                      'Timer Steht
      LDI R16, hbyte(17999)
      Out Icr1h , R16
      LDI R16, lbyte(17999)
      Out Icr1l , R16                                       'Icr1 Für Nächsten Start Vorbereitet
      LDI R16, 39
      STS {Bitzaehler},R16                                  'Bitzäehler reinitialisiert (39)
      LDI R16,0
      Out Tcnt1h , R16
      Out Tcnt1l , R16                                      'Timer = 0 (Reload, ggf anpassen)
      LDI R16, 2
      Out Tccr1a , R16                                      'COM1B=0 (I/O at PB3)

   Daswars:
      POP R16
      Out Sreg , R16
      POP R16
      POP XL
      POP XH                                                'SREG und Register (R16, XH, XL) wiederhergestellt
$end Asm
Return
initNEC (Adresse) initialisiert unseren NEC-PWM und legt die Zieladresse gleich mit fest
sendNEC (Kommando) startet das Senden dieses einen Kommandobytes (mit der initialisierten Adresse entsprechend Deiner Vorgaben aus Post1)
Bisher fehlt noch eine Kollisionserkennung/-vermeidung

Bitte mal mit dem LA testen, auch in Hinsicht auf den Startburst+Pause,
und überprüfe die CKDIV8.
Edit: invertiert so ein TSOP nicht das biphasische serielle Signal?
 
Edit: invertiert so ein TSOP nicht das biphasische serielle Signal?
Ja, der Ausgang ist ja durch einen PullUp hochgezogen und wird bei eintreffen eines Signals auf Low gesetzt.
NEC Codierung ist übrigens nicht Bi-Phase, sondern Pulsweiten moduliert. RC5 ist Bi-Phase.

Gruß

Rolf
 
Stimmt, RC5 ist biphasisch, NEC nicht. Aber PWM stimmt auch nicht ganz, da wir ja die frequenz manipulieren, und nicht die On-Time. Die Pulsbreite ändert sich ja nur relativ zur Periodendauer. Hier handelt es sich doch eher um eine ... ähm ... "Puls-Pausen-Modulation" (?), oder sowas.

Zu invertiert: dann muß Bonze klären, ob wir das noch invertieren müssen. Insbesondere bräuchte er dann auch einen externen Pullup, um bereits beim Reset den geforderten High-Ruhepegel zu haben. Das bei der Initialisierung "umdzurehen", und bei der Grenze Startburst-Pause, und den Compare Output Mode ist dann auch nicht das Ding...
Oder ein flottes Not-/Nand-Gatter...
 
Hier handelt es sich doch eher um eine ... ähm ... "Puls-Pausen-Modulation" (?), oder sowas.
In Neu-Deutsch heißt das Pulse-Distance und nicht Pulse Width, aber mir fiel keine bessere Übersetzung ein.
Hier gibt es eine gute Erklärung des ganzen Themas.
 
soo, eben mal getestet...

Raster 10ms
und fusebit steht jetzt nich mehr auf 8, sondern auf 1 ;)
 

Anhänge

  • Analyzer_0009_0001.gif
    Analyzer_0009_0001.gif
    5,3 KB · Aufrufe: 11
  • Analyzer_0011_0001.gif
    Analyzer_0011_0001.gif
    9,3 KB · Aufrufe: 13
+ Die Bitfolge scheint zu stimmen, oder?
+ Die Längen der 0en und 1en auch

- Der High-Peak der Bits erscheint zu kurz - vorher hatte das gestimmt und daran haben wir nichts geändert. Kommt der LA da an seine Grenzen, oder ist das ein generelles Problem mit der Frequenz? vielleicht siehst Du Dir das nochmal mit gesetzter Fuse an (um schon hier einen Fehler im Code auszuschließen)?
Kannst Du mit der LA-Software keine Zeiten messen? Streck doch mal die Puls-Anzeige.
-Du schaffst es so nicht, auf den beginn des Startbursts zu triggern, oder? Vielleicht sollten wir zum Testen einfach vorher einen weiteren Puls miteinbauen.

Hauptproblem:
-Die Pause ist 2ms zu lang. Dementsprechend wird der Startburst 2 ms zu kurz sein. Problem ist, daß ich zum Umschalte (hi->lo) den OCR1A verwendet habe, der natürlich 2ms vor dem Überlauf stattfinden soll (genau genommen 1,6875ms).
'ne andere elegante Lösung fällt mir erstmal nicht ein, also entweder den InputCapture Interrupt nutzen, oder wie vorher OCR1A umschalten...
Eventuell werd ich nachher doch noch mal den Rechner hochfahren - mir geistert noch eine Code-Optimierung im Kopf rum...
 
Jag' mal folgendes über den LA:
Code:
$crystal = 8000000
$regfile = "attiny2313.dat"
$hwstack = 20                                               'default use 32 for the hardware stack
$swstack = 20                                               'default use 10 for the SW stack
$framesize = 10                                             'default use 40 for the frame space
$baud = 19200

'****Interruptvektoren****
On Oc1a Oc1a_isr Nosave
'Variablen
Dim Bitzaehler As Byte
Dim Adress As Byte
Dim Kommando As Byte

'****Subs****
Declare Sub Initnec(byval Zieladresse As Byte)
Declare Sub Sendnec(byval Kommandobyte As Byte)

Call Initnec(&B10011101)
Enable Interrupts                                           'Interrupts freigeben

Call Sendnec(&B00101000)                                    'ein Paket senden
'******Hauptschleife******
Do
  'leer
Loop

'*****************Subroutinen*******
Sub Initnec(zieladresse As Byte)
   Tccr1a = 2                                               'für normale I/O und WGM=14
   Ocr1a = 17999
   Icr1 = 17999
   Ddrb.3 = 1                                               'PortB.3 (OC1A) ist Ausgang
   Bitzaehler = 38
   Adress = Zieladresse
   Enable Oc1a
End Sub
Sub Sendnec(kommandobyte As Byte)

'*************************hier warten, falls noch gesendet wird*****
   SBI PORTB, PORTB3
   Waitms 2
   CBI PORTB, PORTB3
   Waitms 4
'nur fuer LA zum triggern

   Kommando = Kommandobyte
   Tccr1b = 25                                              'Startburst wahrscheinlich Takt zu lang
   SBI PORTB, PORTB3                                        'ggf TCNT vorladen (auch in ISR)
End Sub
'*****Interrupt Service Routinen****
Oc1a_isr:
      $asm                                                  'Assemblerblockanfang
      PUSH XH
      PUSH XL
      PUSH R16
      IN R16, SREG
      PUSH R16                                              'Register und SREG gesichert
      Loadadr Bitzaehler , X                                'X Enthält Bitzaehler -speicheradresse
      LD R16, X                                             'R16=Bitzähler
      DEC R16                                               'R16 dekrementiert
      ST X+, R16                                            'Bitzähler zurückgespeichert, X enthält Adress-Adresse
      BREQ naechstesVorbereiten                             'final wurde gesendet, Sprung (nächstes vorbereiten)
      CPI R16, 34                                           'Z=1 <==> Bitzaehler (jetzt)= 34
      BREQ burstAbschalten                                  'dann springe burstAbschalten
      cpi R16, 33                                           'Z=1<==>Bitzaehler=33
      BREQ pauseEnde                                        'dann -> Pause Ende                                         
      BRSH dasWars                                          '>33->dasWars (0,33,34 wurden bereits behandelt, bleiben die 32 Bits)
      CPI R16, 17                                           'Carry bei den letzten 17 als einem Endburst (R16=0) plus 16  Bits(R16=16..1)
      BRCC AdresseStimmt                                    'sonst überspringe
      inc XL                                                'X =Kommandoadresse

   Adressestimmt:
      LD R16, X
      LSL R16                                               'einmal nach links schieben, MSB wandert ins Carry
      BRCS EinsSenden                                       'bei 1 springe, bei 0 bleibe
      INC R16                                               'links wurde ne 0 rausgeschoben, deswegen wird die 0 hinten zur 1 invertiert
      ST X, R16                                             'Byte zurückgespeichert
      LDI R16, hbyte(8999)
      Out Icr1h , R16
      LDI R16, lbyte(8999)
      Out Icr1l , R16                                       'Icr Angepaßt
      RJMP dasWars                                          'Fall 0 erledigt

   Einssenden:
      ST X, R16                                             'die hinten eingeschobene 0 ist bereits invers zur 1 - Byte zurückgespeichert
      LDI R16, hbyte(17999 )
      Out Icr1h , R16
      LDI R16, lbyte(17999 )
      Out Icr1l , R16                                       'Icr Angepaßt
      RJMP dasWars                                          'Fall 1 erledigt

   Pauseende:
      LDI R16, hbyte(4499)
      Out Ocr1ah , R16
      LDI R16, lbyte(4499)                                  'Ocr wieder Auf 562,5µs
      Out Ocr1al , R16                                      'wird erst nach dem nächsten TOV aktiv
      LDI R16, 130
      Out Tccr1a , R16                                      'B3 wird PWM (lo->hi beim nächsten TOV)
      RJMP dasWars                                          '->dasWars

   Burstabschalten:
      CBI PORTB, PORTB3                                     'B3 -> lo
      RJMP dasWars                                          '->dasWars

   Naechstesvorbereiten:
      LDI R16 , 24
      Out Tccr1b , R16                                      'Timer Steht
      LDI R16, hbyte(17999)
      Out Ocr1ah , R16
      Out Icr1h , R16
      LDI R16, lbyte(17999)
      Out Ocr1al , R16
      Out Icr1l , R16                                       'Ocr1a Und Icr1 Für Nächsten Start Vorbereitet
      LDI R16, 38
      STS {Bitzaehler},R16                                  'Bitzäehler reinitialisiert (38)
      LDI R16,0
      Out Tcnt1h , R16
      Out Tcnt1l , R16                                      'Timer = 0 (Reload, ggf anpassen)
      LDI R16, 2
      Out Tccr1a , R16                                      'B3 ist wieder I/O

   Daswars:
      POP R16
      Out Sreg , R16
      POP R16
      POP XL
      POP XH                                                'SREG und Register (R16, XH, XL) wiederhergestellt
$end Asm
Return
Jetzt sollten die verschobenen 2ms auch stimmen (hoffe ich).
Außerdem hab ich vor dem Senden "zu Fuß" noch einen 2ms Burst und eine 4ms Pause auf die Leitung gelegt, auf die Du Deinen LA triggern kannst.
Wie siehts jetzt aus?
 
sieht jetzt so aus, bei nem raster von 1ms
:)

lasst euch nich von der uhrzeit verwirren, an meinem bastel lappi, is die bios batt kaputt, und bin zu faul die uhr immer neu zu stellen,.
 

Anhänge

  • Analyzer_0015_0001.gif
    Analyzer_0015_0001.gif
    7 KB · Aufrufe: 11
Scheint doch ganz gut auszusehen, bis auf die beiden Peaks am Anfang (bei 352-353, und bei 358-359). Auffällig ist dort auch der rote Hintergrund. Was soll der bedeuten? (hängt dort der LA hinterher?)

Zur endgültigen Verwendung muß der Bereich dann wieder raus:
Code:
   SBI PORTB, PORTB3
   Waitms 2
   CBI PORTB, PORTB3
   Waitms 4
'nur fuer LA zum triggern
Allerdings mußt Du immer noch klären, ob wir das Signal invertieren müssen.
Mit der Initnec(Byte) initialisierst Du unseren NEC, dabei wird unter anderem die Adresse (Byte) festgelegt. Einmal. Ist das so ok?
Mit Sendnec(Byte) wird das Senden dieses einen Bytes (mit dem kompletten Paket) gestartet -> läuft dann mit den Interrupts weitgehend im Hintergrund. Dein Programm macht derweil im Vordergrund (ab und zu durch die Interrupts unterbrochen) weiter. Solange ein Paket noch gesendet wird, darfst Du kein 2tes losschicken - dann knallts. Da haben wir bisher noch keinen Schutz eingebaut. Kommt ja auch darauf an, wieviele Daten Du so durchjagen willst. Wenns nur ab und zu was sein soll, könnte man einfach vor dem Senden das TCCR1B (auf ungleich 25) pollen, und mit dem Senden solange warten.
Willst Du eher mehr senden, bzw mehrere Pakete hintereinander ("Strings"), könnte man einen (entsprechend zu dimensionierenden) Rinpuffer stricken, in der main-loop dann einen "Mechanismus", der solange Bytes aus dem Puffer liest (und mit Sendnec) losschickt, bis der leer ist (aber immer nur, wenn die Leitung wieder frei ist).
Denk Dir was aus...
 
nein will lediglich diese bitfolgen senden , event mehrmals hintereinander,.
je nach aktion, ich muss aber die vorbedingungen noch programmieren, bzw da bin ich mir noch nich ganz sicher, weil ich da ne tabelle hab , die ich auswerten muss,.
 

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