Bascom NEC Code senden

Bonze

Neues Mitglied
16. Jan. 2010
516
0
0
Altenkirchen (Pfalz)
Sprachen
  1. BascomAVR
ich versuche nun schon länger ein Nec Code zusenden, finde aber nicht den richtigen ansatz..
mitn 1 oder 2 Timern, oder oder oder

geschickt waers ja mit 2 Timern 1, der die Pulse (1) und einer der die Pausen(0) zählt.

A 9ms leading pulse burst (16 times the pulse burst length used for a logical data bit)
' A 4.5ms space
' The 8-bit address for the receiving device
' The 8-bit logical inverse of the address
' The 8-bit command
' The 8-bit logical inverse of the command
' Final 562.5µs pulse burst to show end of message transmission.
' Logical '0' – a 562.5µs pulse burst followed by a 562.5µs space, with a total transmit time of 1.125ms
' Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms space, with a total transmit time of 2.25

nehmen wir an, ich hab den tiny2313 mit 8 mhz, dann wuerde ich die Timer so configurieren:
Code:
Config Timer0 = Timer , Prescale = 1024                     '0,01s bis ueberlauf
On Ovf1 Tim0_isr
Timer0 = 178
Config Timer1 = Timer , Prescale = 1024                     '0,01s bis ueberlauf
On Ovf1 Tim1_isr
Timer1 = 64286

der Code der gesendet werden soll, sieht so aus :
&b10011101 01100010 00101000 11010111

Nur wie soll ich das im Timer-Interrupt machen?
Hab mit solchen "Zeitkritischen" sachen noch nichts zu tun gehabt,.
 
'Ne erste fixe Idee wäre, Timer1 mittels CTC oder FastPWM (über ICR oder OCRA) auf 2,25ms festzulegen, OCRB setzt den korrespondierenden Pin bei 562,5µs von hi auf lo um.
Zu einem geeigneten Zeitpunkt muß jetzt (abhängig vom zu sendenden Bit) der Überlaufpunkt angepaßt werden. Ich müßte selbst nachlesen, ob das gepuffert wird (dann an den OCRB-IRQ), oder nicht gepuffert (dann im ICR bzw OCRA-IRQ). Vorgehensweise wäre dann: zu sendendes Byte schieben, Carry auswerten, und überlaufbeeinflussendes Register manipulieren.

Für die Startbedingung käme dann irgendwas mit 4*2,25ms hi und 2*2,25ms lo hinzu, Ende sind 562,5µs lo.

Hab jetzt aber noch nicht gerechnet, ob man das mit dem Timer hinbekommt - wäre nur meine erste Idee...
(P.S.: bei meinem Calculator hab ich bisher den 16bit-Timer noch nicht implementiert)
 
Hallo,

Zu einem geeigneten Zeitpunkt muß jetzt (abhängig vom zu sendenden Bit) der Überlaufpunkt angepaßt werden.
könnte man so machen. Also ein Timer der einem die Trägerfrequenz erzeugt und der zweite den man mit den Bitzeiten füttert.

Man könnte mit dem zweiten aber auch eine kleinste gemeinsame Zeitspanne für das Bit-Timing erzeugen. Als einfaches Beispiel: DCF77 ... 0,1s Puls = 0-Bit und 0,2s Puls = 1-Bit. Wenn man also eine Zeitspanne von 0,1s imTimer hat dann kann man einfach zählen. 1xHigh,9xLow = 0-Bit , 2xHigh,8xLow = 1-Bit.

Es gibt wohl mehrere Möglichkeiten :rolleyes:

Gruß
Dino
 
Nein, so meinte ich das nicht - ich wollte mit einem Timer auskommen... mit frequenzkorrektem PWM.
Allerdings mit einer festen Pulsdauer (?) (562,5µs) und, je nach Bitwert variierenden Periodenzeiten...
Edit: mal zur Verdeutlichung...

-der Controller läuft mit 8MHz - ein Takt dauert also 125ns
-mit Vorteiler 1 dasselbe bei Timer1 - der hat dann eine maximale Reichweite von 8192µs (bei einer Auflösung von 125ns)
-ein Lo-Bit soll dargestellt werden durch einen 562,5µs Hi-Pegel und anschließend 562,5 lo-Pegel. Gesamtdauer also 1125µs. Das entspräche also 4500 Takten Hi und 4500 Takten lo - zusammen 9000 Takten. Dementsprechend würde also OCR0A=4499 und ICR=8999 und der Timer mit Prescaler=1 im WGM14 mit CompareOutputMode2 permanent "Nullen" am OC0A-Pin generieren.
-ein Hi-Bit mit 562,5µs hi und 1687,5µs lo (zusammen 2250µs) entspräche dann 4500 Takten Hi, von insgesammt 18000 Takten. Also derselbe PWM, nur mit ICR=17999.
-Es muß also lediglich der Überlaufpunkt (ICR) verändert werden. und hier stellt sich die Frage, wann diese Veränderung wirksam wird. Wenn das sofort geschieht, kann man das direkt im Output-Compare-Interrupt (562,5µs) machen (Byte schieben, ICR entsprechend dem Carry umsetzen, bei TCNT=ICR erfolgt Überlauf, der den OC-Pin wieder setzt). Wird der ICR-Inhalt zwischengespeichert, kann man das bei Überlauf machen (ICR-Interrupt), NUR EBEN bereits für das nächste Bit - das wäre umständlicher...
Datenblatt ATtiny2313 S. 97 schrieb:
The procedure for updating ICR1 differs from updating OCR1A when used for defining the TOP value. The ICR1 Register is not double buffered. This means that if ICR1 is changed to a low value when the counter is running with none or a low prescaler value, there is a risk that the new ICR1 value written is lower than the current value of TCNT1. The result will then be that the counter will miss the compare match at the TOP value. The counter will then have to count to the MAX value (0xFFFF) and wrap around starting at 0x0000 before the compare match can occur. The OCR1A Register however, is double buffered. This feature allows the OCR1A I/O location to be written anytime. When the OCR1A I/O location is written the value written will be put into the OCR1A Buffer Register. The OCR1A Compare Register will then be updated with the value in the Buffer Register at the next timer clock cycle the TCNT1 matches TOP. The update is done at the same timer clock cycle as the TCNT1 is cleared and the TOV1 flag is set.
Ok, ICR-Änderungen werden sofort wirksam (paßt also) - OCR1A würde gepuffert werden, und erst nach dem Überlauf wirksam.
 
ok, d.h. ich gehe bit fuer bit aus meinem zusendenen code durch ?
ungefähr so?
tim1_isr:
incr i 'stelle des zu senden codes
toggle nec_out
return

do
if bit =1 then
lade timerwert=XX
else
laden timerwert= xy
endif
start timer

loop
 
Hmm... Nein.
Du bist zu sehr in der Hochsprache verwurzelt - mein Vorschlag zielt auf die Fähigkeiten der Hardware selbst ab (speziell des Timers).
Was meinst Du mit "Timerwert laden"?
Was kann so ein Timer überhaupt?
Der Timer ist ein Stück Controller-Hardware, der (einmal eingestellt) autonom arbeitet, dabei aber Möglichkeiten bietet, mit Deinem Hauptprogramm zu interagieren.
Er besitzt eine "Zählervariable" (1byte, oder 2byte breit), welche mit dem Timertakt inkrementiert oder dekrementiert wird (dual slope). Der Timertakt kann aus verschiedenen Quellen abgeleitet werden, insbesondere aus dem MCU-Takt (über einen Vorteiler). Erreicht der Zähler den TOP-Wert, läuft er entweder über (single slope), oder läuft zurück zu 0 (dual slope, phasenkorrektes PWM). An den Überlauf kann man einen entsprechenden Timer-Überlauf-Interrupt koppeln.
Je nach Timer können für TOP verschiedene Werte ausgewählt werden, zB 0x00FF, 0x01FF, 0x03FF und 0xFFFF. Außerdem gibt es noch 2 weitere Register ("Timervariablen"), die den Überlaufpunkt festlegen können. Das ist einerseits das Input Capture Register und das Output Capture Register A. Diese beiden "Variablen" werden im Hintergrund permanent mit dem Zähler verglichen, und können den Überlauf auslösen. Auch hier können separate Interrupts an den positiven match gekoppelt werden.

Mein Vorschlag zielte auf den PWM-Modus (single slope/fastpwm) ab, bei dem der Überlaufpunkt durch das Input Capture Register festgelegt wird. Der verwendete Output Compare Pin soll also erst Hi sein, durch das Compare-Match-A auf lo gesetzt werden (und beim Timerüberlauf wieder auf Hi). Das ist der nicht-invertierende PWM. Deine "Einsen" und "Nullen" haben identische Hi-Zeiten, aber variierende Gesamtzeiten. somit wäre das, die Hi-Länge beeinflussende Output Compare Register also konstant - der Überlaufpunkt des Timers von Durchlauf zu Durchlauf aber ggf anzupassen. Dazu würde ich den Output-Compare-Interrupt verwenden - entsprechend dem aktuellen Bit also das Input Capture Register neu festlegen (welches ja den Überlaufpunkt festlegt).

Jetzt zur Frage, ob das ICR mit dem Wert für "Eins" oder "Null" beladen werden soll.
 
Ich meinte: Wie realisiert man die Abfrage des jeweiligen Bits, und das folgende Setzen des ICR.
Wie sehen denn ein Paket eigentlich aus (Start- und Endbedingung erstmal außen vor):
Du hast 4 Bytes. 2 Adressbytes, und 2 Kommandobytes. Genau genommen sind das aber nur je ein Adress- und ein Kommandobyte - die anderen beiden sind ja je invertiert.
Trotzdem mußt Du natürlich 32 Bits übertragen, klar. Insbesondere muß man also mit irgendeiner "Zählvariable" das jeweilige Bit mitzählen. Oder man Zählt einfach die 32Bits durch. Also man greift nicht indiziert auf das n-te Bit zu, sondern "schiebt" einfach die ganze Kette zweiunddreißigmal um je ein Bit. Allerdings wegen der 2 Bytes, und deren beiden invertierten Bytes sollte man das vom Byte aus angehen.
Code:
Stell Dir einfach folgendes Adressbyte vor: 151 (dezimal). Das wäre binär :

       |1|0|0|1|0|1|1|1|

wenn man das ganze jetzt einmal nach links schiebt, fällt das most significant bit ins Carry-Flag,
und von hinten wird eine 0 eingeschoben:

C=|1|  |0|0|1|0|1|1|1|0| 

In Abhängigkeit vom C-Flag kannst Du jetzt 'ne Fallunterscheidung machen, und den Wert fürs ICR festlegen.
(Jede If-Anweiseng wird letztendlich über diese Flags umgesetzt. Das Stichwort lautet "bedingte Verzweigung").
Wenn das Carry gesetzt ist, ist also 17999 ins ICR zu laden, sonst 8999. Außerdem kann man dann gleich folgenden Trick in den
"Carry=0-Zweig" mit einbauen: addiere "1" (00000001bin) auf das geschobene Byte. Bei dem Beispiel da oben wären wir also derzeit im
"Carry=1-Zweig", und hätten (das ganze findet ja in der OCR1A-ISR statt) das ICR auf  17999 gesetzt. Der derzeitige lo-Pegel am
OC-Pin würde also 1687,5µs bleiben, dann würde der Timer überlaufen, und den OC-Pin (automatisch - PWM) auf Hi legen.
Bis der Timer 4500 erreicht hat (OCR1A->PWM fallende Flanke). Hier würde auch der nächste OCR1A-IRQ eintreten.
Dementsprechend würde die ISR das Byte wieder eins nach links schieben:

C=|0|  |0|1|0|1|1|1|0|0|

Folglich würde der "Carry=0-Zweig" bearbeitet werden: ICR=8999, und das addieren von 1 auf das Byte (man könnte auch inkrementieren, ist dasselbe).
Ergebnis:

C=|0|  |0|1|0|1|1|1|0|1|

Nach dem 8ten Schieben (und addieren) steht folgendes da:

C=|0|  |0|1|1|0|1|0|0|0|

Also das ganze nochmal achtmal, und das invertierte Byte ist gleich miterledigt. Der Bitzähler muß also nur verwendet werden um vom
Adressbyte aufs Kommandobyte umzuschalten (nach 16 Bits), und das Ende zu erkennen (nach 32 Bits). Möglicherweise findet sich aber auch
gleich 'ne clevere Lösung für die Start- und Stopsequenzen.
 
das hoert sich gut, aber ein bisschen kompliziert an,. gib mal bitte ein kurzes beispiel,. wie du das im fertigen code meinst,.
wie muss man den timer dafür konfigurieren? du nuzt also icr und ocr?
du willst also immer nur vorzaehler (ICR) anpassen, oder bin ich immernoch nicht auf dem richtigen weg ?
anstatt die bits durchzuzaehlen,
willste immer den code(an der stelle 1) behandeln, ist der durchlauf fertig, shift .....
 
Genau, mein Vorschlag verwendet das ICR und das OCR. Das ICR legt dabei die Periodendauer fast (wobei wir die ggf bei jeder Periode ändern), das OCR die On-Time des Pins ("Burst"), welche weitgehend konstant bei 562,5µs liegt (nur eben beim Start-Pulse nicht). Dabei wird der Interrupt des OCR verwendet, um das ICR zu manipulieren.
Ich würde das natürlich alles in ASM machen, aber Du willst ja sicher nochwas "drumrum" programmieren (in Bascom), also könnte man die ISR vielleicht als ASM-Block einbinden (kA, ob sich mein Vorschlag direkt in Bascom brauchbar umsetzen läßt).
Folgende Vorraussetzungen:
-Der Timer ist auf WGM14 und OutputCompareMode2 eingestellt
-Der Timer steht noch (Prescaler=0)
-Der OCR1A-Interrupt veweist mit nosafe auf eine ISR
-Es sind 3 Bytes im SRAM reserviert, eins für den Bitzähler, eins für die Adresse, eins für das Kommando (jeweils nicht-invertiert). Sie sollten aufeinanderfolgende SRAM-Adressen haben, die erste Adresse muß bekannt sein (könnte man mit "dim Name as byte at Adresse" machen, sicher gäbe es auch einen Weg, Bascom nach der Adresse zu fragen... egal erstmal)
-OCR1A und ICR1 mit sinnigen Werten für den Start-Burst beladen
Ganz grob sollte das dann in etwa so in der ISR aussehen
Code:
OCR1A_Label:

;Assemblerblockanfang - da gibts 'n passendes Schlüsselwort für
;verwendete Register und SREG sichern

LDI XH, high(bitCountAddr)
LDI XL, low(bitCountAddr)
LD R16, X                   ;R16=Bitzähler
DEC R16                     ;R16 dekrementiert
ST X+, R16                  ;Bitzähler zurückgespeichert, X enthält Adress-Adresse

;von hier bei Zero-Flag verzweigen zum Abschalten des Timers (Prescaler=0 und TCNT =0), außerdem OCR1A für den nächsten Start-Burst vorbereiten, ICR1 ebenso,  Bitzähler reinitialisieren (*)
;Nach erfolgreichem Vergleich von R16 (Bitzähler) und (noch festzulegenden) Konstanten zum Startburst und der Pause danach verzweigen (1 Vergleich mit CPI (***)=Sprung bei Z, (**)=Sprung bei C=0) (sowie 1Vergleich mit CPI (****) Sprung bei Carry=0)

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:
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, high(8999)
OUT ICR1H, R16
LDI R16, low(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, high(17999)
OUT ICR1H, R16
LDI R16, low(17999)
OUT ICR1L, R16              ;ICR angepaßt
RJMP dasWars                ;Fall 1 erledigt

;hier Einsprung von (*), und abarbeiten, danach Sprung nach dasWars
;hier Einsprung von (****), OCR1A (16bit, gepuffert) mit 4499 beladen, danach nach dasWars
;hier Einsprung von (***) zum abschalten des Startburst für die Pause
LDI R16, 0
OUT OCR1AH, R16
OUT OCR1AL, R16              ;PWM dauerhaft lo
dasWars:                     ;Einsprungpunkt, auch für (**)

;SREG und Register (R16, XH, XL) wiederherstellen
;Assemblerblockende
Return
Um dann was zu senden muß das Adressbyte in die definierte Adressvariable, das Kommandobyte in die Kommandovariable gespeichert werden, und der Timer gestartet werden (Prescaler auf 1 setzen). Das darf natürlich nicht geschehen während noch was gesendet wird (was am Bitzähler erkennbar ist - dieser ist also vorher zu pollen)
 
Code:
Dim Bitzaehler As Byte
Dim Adress As Byte
Dim Kommando As Byte

'Loadadr Bitzaehler , R16
'Loadadr Adress,
'Loadadr Kommando,


Do

Loop
End

Oc1a_isr:
'verwendete Register und SREG sichern
$asm
LDI XH, high(bitCountAddr)
LDI XL, low(bitCountAddr)
LD R16, X                   ;R16=Bitzähler
DEC R16                     ;R16 dekrementiert
ST X+, R16                  ;Bitzähler zurückgespeichert, X enthält Adress-Adresse

;von hier bei Zero-Flag verzweigen zum Abschalten des Timers (Prescaler=0 und TCNT =0), außerdem OCR1A für den nächsten Start-Burst vorbereiten, ICR1 ebenso,  Bitzähler reinitialisieren (*)
;Nach erfolgreichem Vergleich von R16 (Bitzähler) und (noch festzulegenden) Konstanten zum Startburst und der Pause danach verzweigen (1 Vergleich mit CPI (***)=Sprung bei Z, (**)=Sprung bei C=0) (sowie 1Vergleich mit CPI (****) Sprung bei Carry=0)

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:
   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, high(8999)
   Out Icr1h , R16
   LDI R16, low(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, high(17999)
   Out Icr1h , R16
   LDI R16, low(17999)
   Out Icr1l , R16                                          'ICR angepaßt
RJMP dasWars                                                'Fall 1 erledigt

'hier Einsprung von (*), und abarbeiten, danach Sprung nach dasWars
'hier Einsprung von (****), OCR1A (16bit, gepuffert) mit 4499 beladen, danach nach dasWars
'hier Einsprung von (***) zum abschalten des Startburst für die Pause
LDI R16, 0
Out Ocr1ah , R16
Out Ocr1al , R16                                            'PWM dauerhaft lo


Daswars:                                                    'Einsprungpunkt, auch für (**)

'SREG und Register (R16, XH, XL) wiederherstellen
'Assemblerblockende
$end Asm
Return
 
Aber Du hast in etwa verstanden, wie ich's meinte?
Grml.... eigentlich hab ich gar keine Zeit für sowas ... hmm...
edit: Hab mal den ganzen fehlenden Kram dazugetippt (da, wo die Kommentare waren), außerdem die $asm-Direktiven und die Bascom-Anweiseung "loadadr" - hoffe, das stimmt so. Dann wäre das der Inhalt der Output-Compare-1-A-ISR:
Code:
Oc1a_isr:
$asm
PUSH XH
PUSH XL
PUSH R16
IN R16, SREG
PUSH R16                    ;Register und SREG gesichert
$end ASM
Loadadr Bitzaehler, X       'X enthält Bitzaehler-Speicheradresse
$asm                        'Assemblerblockanfang
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<==>Bitzaehler<33
BREQ pauseEnde              ;=33->pauseEnde
BRSH dasWars                ;>33->dasWars (0,35,33 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:
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, high(8999)
OUT ICR1H, R16
LDI R16, low(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, high(17999)
OUT ICR1H, R16
LDI R16, low(17999)
OUT ICR1L, R16              ;ICR angepaßt
RJMP dasWars                ;Fall 1 erledigt
pauseEnde:
LDI R16, high(4499)
OUT OCR1AH, R16
LDI R16, low(4499)
OUT OCR1AL, R16             ;OCR vieder auf 562,5µs
RJMP dasWars	            ;->dasWars
burstAbschalten:
LDI R16, 0
OUT OCR1AH, R16
OUT OCR1AL, R16             ;OCR auf 0
RJMP dasWars	            ;->dasWars
naechstesVorbereiten:
LDI R16,(3<<WGM12)
OUT TCCR1B, R16             ;Timer steht
LDI R16, high(17999)
OUT OCR1AH, R16
OUT ICR1H, R16
LDI R16, low(17999)
OUT OCR1AL, R16
OUT ICR1L, R16              ;OCR1A und ICR1 für nächsten Start vorbereitet
LDI R16, 39
SUBI XL, 2
ST X,R16                    ;Bitzäehler reinitialisiert (39)
LDI R16, 
OUT TCNT1H, R16
OUT TCNT1L, R16             ;Timer=0
dasWars:                     
POP R16
OUT SREG, R16
POP R16
POP XL
POP XH                      ;SREG und Register (R16, XH, XL) wiederhergestellt
$end ASM                    ;Assemblerblockende
Return
fehlt noch:
-Definition der 3 Bytes (hintereinander im SRAM), Bitzaehler=39
-Initialisierung des Timers als FastPWM mit TOP=ICR1 und dem entsprechenden OutPutCompareMode an OCR1A.
-Freigabe des OCR1A-IRQs, und die Zuweisung der ISR
-globale Interruptfreigabe
-'ne sinnige Prozedur, die "Adress" und "Komando" mit Werten befüllt, und dann den Timer startet (Prescalerbit in TCCR1B).
...
und dann ein Oszilloskop/LogikAnalysator zum Testen...:p
 
mhh bekomme da viele fehler beim compilieren..
z.B.
syntax error
LDI R16,(3<<WGM12)
LDI R16, high(17999)
anscheinend darf man da die zahlen niht so ohne weiteres einsetzen
 
Die Controllerdefinitionsdatei hast Du eingebunden?
Ansonsten zeig mal den Code. Keine nähere Fehlerbeschreibung?
Hmm... Bascom scheint high(word) und low(word) nicht zu kennen - stattdessen wird wohl hbyte(word) und lbyte(word) benutzt...
Bei dem anderen versuch mal vor der Klammer ein Leerzeichen. Ansonsten könnte man das auch aufdröseln:
LDI R16 , (1<<WGM13) | (1<<WGM12)
Wenn das auch nichts bringt, sollte e zu Fuß klappen:
LDI R16 , 24

Aber wie gesagt, das ist nur die ISR selbst...

Für die direkte Adressierung scheint man auch {Variablenname} verwenden zu können - ließe sich am Ende beim reinitialisieren des Bitzählers auf 39 verwenden. Also statt der beiden Zeilen SUBI und ST(ore) könnte man schreiben:
STS {Bitzaehler} , R16

In der Zeile darunter (also vor "OUT TCNT1H...") ist mir übrigens eine "0" abhanden gekommen. Da muß stehen:
LDI R16 , 0

Edit: die Erklärung/Lösung für den ersten Fehler steht schon seit fast 2 Jahren im Forum:
Laplace schrieb:
Dazu bräuchte man eine Shiftoperation (in C “<<“), die im BASCOM "Assemblerteil" jedoch nicht zur Verfügung steht. Es geht aber trotzdem, so dass die symbolischen Konstanten ISC10 (=2, gemeint ist Bit 2) und ISC11 (=3, gemeint ist Bit 3) weiter benutzt werden können. Die Lösung ergibt sich durch Verwendung der Exponentialschreibweise (Operator “^“).

Das folgende Beispiel erzeugt daher den verkürzten, äquivalenten Code von Beispiel 1:
Code:
LDS mReg,MCUCR+&H20
ORI mReg,[B]2^ISC10 + 2^ISC11[/B]
STS MCUCR+&H20,mReg
http://www.avr-praxis.de/forum/showthread.php?1616-Bascom-und-Assembler&p=15958&viewfull=1#post15958
 
hab noch kein komplettes programm, da ich eigentolich erst den asm code ohne fehler compilieren möchte,. das geht jetzt auch, bis auf die "loadadr" die werden mit invalide datatype kommeniert
Code:
On Oc1a Oc1a_isr
Enable Oc1a
Enable Interrupts


Dim Bitzaehler As Byte
Dim Adress As Byte
Dim Kommando As Byte
Dim Variablen As Iram Long
Dim Varr16 As Iram Byte At Variablen + 1 Overlay
Dim Varxh As Iram Byte At Variablen + 1 Overlay
Dim Varxl As Iram Byte At Variablen + 1 Overlay

Adress = &B10011101
Kommando = &B00101000
Bitzaehler = 39

Do
Start Timer1
Loop
End


Oc1a_isr:
      $asm
      .def R17 Xh
      .def R18 Xl

      PUSH XH
      PUSH XL
      PUSH R16
      IN R16, SREG
      PUSH R16                    ;Register und SREG gesichert
      $end Asm

      Loadadr Bitzaehler , X                                'X enthält Bitzaehler-Speicheradresse
      'Loadadr Varr16 , R16
      'Loadadr Varxh , Xh
      'Loadadr Varxl , Xl

      $asm                                                  'Assemblerblockanfang
      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<==>Bitzaehler<33
      BREQ pauseEnde              ;=33->pauseEnde
      BRSH dasWars                ;>33->dasWars (0,35,33 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:
      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)
      Out Ocr1al , R16 ; Ocr Vieder Auf 562 , 5µs
      RJMP dasWars             ;->dasWars

   Burstabschalten:
      LDI R16, 0
      Out Ocr1ah , R16
      Out Ocr1al , R16 ; Ocr Auf 0
      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, 39
      SUBI XL, 2
      ST X,R16                    ;Bitzäehler reinitialisiert (39)
      LDI R16,0
      Out Tcnt1h , R16
      Out Tcnt1l , R16 ; Timer = 0

   Daswars:
      POP R16
      Out Sreg , R16
      POP R16
      POP XL
      POP XH                      ;SREG und Register (R16, XH, XL) wiederhergestellt
$end Asm
Return

mir ist das aber immernoch nich so ganz klar, muss ich jetzt mit DIm XY as byte defienieren und dann loadadr die bytes in die Register laden,
oder muss ih einfach .def RXY machen ?
 
So, mal etwas sortieren:
1. hatte ich in Beitrag 13 ja schon angedeutet, was so noch fehlt.
2.sollten die 4 Zeilen mit dem IRAM unnötig/Quatsch sein.
Bis auf wenige Ausnahmen verfügt jeder 8Bit-AVR über 32 Rechenregister. das sind R0 bis R31 Das sind alles 8-Bit-Register. Eine Sonderstellung nehmen R26 bis R31 ein. R27:R26, R29:R28, R31:R30 können nämlich als 16bit-Register verwendet werden. Insbesondere als Adresspointer, aber eben auch für andere Sachen. Diese 3 Doppelregister haben die Namen X, Y und Z bekommen - R27 IST XH, R26 IST XL - klar?
Code:
Loadadr var, reg
var ist der Bascom-Variablenname
reg ist eines der 16bit-Register, also X, Y oder Z (wir hatte X genommen).
Also
Code:
Loadadr Bitzaehler, X
Bascom macht daraus dann:
Code:
LDI XH, hbyte(adresse(Bitzaehler))
LDI XL, lbyte(adresse(Bitzaehler))
ok?
Das X-Doppelregister anhält also jetzt die Adresse vom Bitzaehler im SRAM - zeigt darauf. Wir können also indirekt (über X) darauf zugreifen, und genau das machen wir mit dem folgenden "LD".
MEIN FEHLER war, Loadadr aus dem ASM-Block auszuklammern... gehört da doch rein. Du kannst also bis auf diese eine Loadadr-Zeile alles von (inklusive) "$asm" bis (inklusive) "$end Asm) entfernen.
3. vermisse ich die Einbindung der Controllerdefinitionsdatei, Vorgaben für die Stackgrößen, Taktgeschwindigkeit (für Bascom) usw. Oder willst Du Dich da auf die Vorgaben verlassen?
4. hatte ich ja bereits angedeutet, daß das .def R17 - R18 da Quatsch ist -> raus damit;)
5. Da wir mit Loadadr im Datenblock also Zugriff auf den Bitzaehler bekommen, muß eigentlich nur sichergestellt werden, daß die Reihenfolge im SRAM stimmt: erst "Bitzaehler", dann "Adress", dann "Kommando" - sollte also so stimmen. das sollte im Code so früh wie möglich erfolgen, also würde ich das direkt nach "On Oc1a..." machen.
6. Ist die Initialisierung des Timers etwas komplexer/spezieller. Sicher wird das auch irgendwie mit irgendwelchen Bascom-Config-Parametern gehen, MIR fällt es leichter, die entsprechenden I/O-Register selbst festzulegen.
Ok, welche Register gehören zum Timer1? Datenblatt ab S.104 !
TCCR1A - enthält:
-2Bits für den Compare Output Mode für Channel A <- Da steckt unser PWM-verhalten drin
-2Bits für den Compare Output Mode für Channel B <- interessiert uns nicht
-2 der WGM-Bits <- müssen wir beachten wir brauchen WGM11=1, WGM10=0
Beim PWM wollten wir, daß der Überlauf den Pin setzt, das CompareMatch ihn löscht. Das wäre CompareOutputMode=2. COM1A1=1, COM1A0=0. Wir wollen also:
TCCR1A=1|0|0|0|0|0|1|0=130dez
TCCR1B - enthält
-2Bits, die mit der InputCapture Hardware zu tun haben <- verwenden wir nicht (als solche)
-2Bits, die den WGM festlegen <-WGM13 und WGM12 müssen beide auf 1 gesetzt werden
-3Bits, die den Prescaler festlegen. CS12..CS10. Wenn die alle=0 sind, wird der Timer gestoppt, mit CS10=1 ist der Prescaler 1, der Timer läuft dann mit dem MCU-Takt. Zum stoppen brauchen wir also:
TCCR1B=0|0|0|1|1|0|0|0=24dez
zum starten:
TCCR1B=0|0|0|1|1|0|0|1=25dez
TCCR1C - enthält
-2Bits, mit denen im non-PWM-Mode Compare Matches erzwungen werden können (auf den beiden Kanälen)<-interessiert uns nicht
TCNTH/L IST der Timer, also der Hardware-Zähler, den müssen wir eigentlich auch nicht manipulieren
OCR1AH/L legt den Vergleichspunkt (PWM etc) beim Channel A fest, den manipulieren wir in der ISR. Wir müssen ihn aber auch (einmal) auf 17999 initialisieren: "OCR1A=17999"
OCR1BH/L - dasselbe für Channel B <- verwenden wir nicht
ICR1H/L - nimmt normalerweise den Timer-Wert auf, bei dem ein InputCaptureEreignis eintrat. Wir verwenden es jedoch zum festlegen des Timerüberlaufes (WGM=14) - folglich manipulieren wir diese Register in der ISR. Auch hier müssen wir initialisieren: "ICR1=17999"
TIMSK - hier werden die (lokalen) Interrupts (, die die Timer betreffen) freigegeben - das erledigst Du bereits mit "enable Oc1a" - kann so bleiben
TIFR - hier befinden sich die Interrupt-Flags der Timer - darum kümmern sich die ISRs bzw die Interrupthardware

Also:
Code:
On Oc1a...
bleibt so, danach initialisieren wir die Variablen und den Timer (erstmal ohne TCCR1B)
Code:
Dim Bitzaehler as Byte
Dim Adress as Byte
Dim Kommando as Byte
Tccr1a=130
Ocr1a=17999
ICR=17999
Enable Oc1a
Enable Interrupts
Bitzaehler=39
Wenn was gesendet werden soll, muß "Adress" mit der Adresse beladen werden, "Kommando" mit dem Kommando, klar. Mit "TCCR1B=25" wird das ganze dann gestartet. das darf natürlich nicht geschehen, während im Hintergrund noch was gesendet wird. Wenn dies der Fall ist, ist TCCR1B=25, könnte man also später pollen - für den ersten Test würde ich jedoch einfach "Adress" und "Kommando" befüllen, mit wait 'ne Pause einbauen (ggf 'ne Led schalten oder sowas), und danach das TCCR1B auf 25 setzen.
Danach kommt dann die leere Endlosschleife (das Start Timer1 muß da raus - erledigen wir mit TCCR1B ja direkt).
Das End ist da auch sinnfrei - soweit ich weiß, baut Bascom da auch nur eine leere Endlosschleife ein, ggf nach vorheriger Deaktivierung der globalen IRQs. Aufgrund der vorherigen Endlosschleife wird dieser Bereich aber nie ausgeführt.
 
also, im geamten dann ca so,.
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
$sim

Radio_out Alias Portb.0

On Oc1a Oc1a_isr
Enable Oc1a
Enable Interrupts


Dim Bitzaehler As Byte
Dim Adress as Byte
Dim Kommando as Byte

Tccr1a=130
Ocr1a=17999
Icr1 = 17999
Enable Oc1a
Enable Interrupts
Bitzaehler=39





Do
  ' If Tccr1b <> 25 Then
      Adress = &B10011101
      Kommando = &B00101000
   '   TCCR1B=25
   'End If
   Waitms 50
Loop
End


Oc1a_isr:
      $asm

      PUSH XH
      PUSH XL
      PUSH R16
      IN R16, SREG
      PUSH R16                                              ';Register und SREG gesichert


      Loadadr Bitzaehler , X                                'X enthält Bitzaehler-Speicheradresse
                                                     'Assemblerblockanfang
      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<==>Bitzaehler<33
      BREQ pauseEnde                                        ';=33->pauseEnde
      BRSH dasWars                                          ';>33->dasWars (0,35,33 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:
      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)
      Out Ocr1al , R16                                      '; Ocr Vieder Auf 562 , 5µs
      RJMP dasWars                                          ';->dasWars

   Burstabschalten:
      LDI R16, 0
      Out Ocr1ah , R16
      Out Ocr1al , R16                                      '; Ocr Auf 0
      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, 39
      SUBI XL, 2
      ST X,R16                                              ';Bitzäehler reinitialisiert (39)
      LDI R16,0
      Out Tcnt1h , R16
      Out Tcnt1l , R16 ; Timer = 0

   Daswars:
      POP R16
      Out Sreg , R16
      POP R16
      POP XL
      POP XH                                                ';SREG und Register (R16, XH, XL) wiederhergestellt
$end Asm
Return
 
Vergessen: im das Registerretten kümmern wir uns ja selbst - mach mal hinter die Festlegung der Interruptserviceroutine ein "nosave"
(also "On Oc1a Oc1a_isr nosave")
den Rest schau ich mir später an...
Bisher noch irgendwelche Fehlermeldungen?
Derzeit würde das Paket ca alle 50ms gesendet werden - wenn es selbst länger dauert knallts (habs grad nicht durchgerechnet, ob 50ms reichen)
soweit klar?

Edit: wenn ich mich jetzt nicht verrechnet habe, braucht der "best case", also nur 0en gesendet, etwas über 50ms - im worst case etwas über 86ms pro Paket. Mit dieser Schleife gehts also so nicht.
Du hast ja eh das eigentliche Starten auskommentiert.

Ich hätte für einen ersten Test erstmal nur ein Paket gesendet. Also VOR dem "Do" die zu sendenden Bytes zuweisen, dann eventuell 'ne kleine Pause und ggf 'n Signal, daß es gleich losgeht (LED), dann das TCCR1B zuweisen, und dann die leere Endlosschleife. Dann sollte nach dem Reset (hoffentlich) genau ein Paket über den OC1A-Pin gesendet werden. Hast Du denn 'ne Möglichkeit, das aufzuzeichnen?
 
mh svheint so zu funkitonieren, nachmessen im eigentlich sinne geht noch nicht, da ich noch kein harware aufbau hab,.
aber im simulator läufts ganz ut durch, vl bisschen schnell zum testen, da muessteman den timer prescaler hochsetzen,.

Die variable adress läuft von 157(dez) auf 35(dez) runter,.
Xl wechselt zwischen 222(dez) und 96(dez)
 

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