dannyboy1994
13.12.2016, 17:51
Hallo community. Ich bin derzeit dabei mir eine kleine Wetterstation zu bauen, bei welcher mir ein tiny44 die außentemperatur und Luftfeuchtigkeit über ein RFM12 Modul senden soll. Ein Tiny2313 soll das Ganze dann auf einem LCD und über den USART ausgeben. Nun stehe ich gerade am Anfang des ganzen und versuche mir funktionstüchtige routinen zu schreiben. Einmal eine für den tiny(reiner empfänger) und einen für den tiny44(reiner sender)
Das Ganze soll der USI realisiert werden.
Hier einmal mein aktueller stand beim tiny2313 Empfänger. Das drum herum ist erst einmal nebensächlich sondern eher die vorgehensweise beim empfang.
Könnte ein ambitioniertes Midglied des Forums einmal drüber schaun und mir evtl unter die arme greifen. Auch habe ich das gefühl das ich die ansteuerung des Moduls noch nicht so ganz verstanden habe.
;;;Kleines Testprogramm
;;Tiny2313 als empfänger
;;Empfängt ein Byte und gibt dieses via usart aus
;;USI als SPI Master
.list
.include "tn2313def.inc"
.nolist
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000
.def temp1=r16
.def temp2=r17
.def temp3=r18
.def data=r19
.def lsb=r21
.def msb=r22
.def datain=r23
.org 0x0000
.equ spiddr=ddrb
.equ spiport=portb
.equ nsel=0
rjmp start
.org 0x020
loop:
mov data, lsb
rcall read_byte ;befindet sich anschließend in LSB
cp data, lsb
breq loop
mov temp1, lsb
rcall seroutdez
rcall delay1s
rjmp loop
start:
ldi temp1, low(ramend)
out spl, temp1 ;Stackpointer init
sbi spiddr, nsel
rcall rfninit ;RFM12 inittialisiert und bereit("hoffentlich")
rcall initrs232
rcall loop
;;Nsel auf low einen momment warten dann bit an SDI vom modul(mit dem höchsten bit starten)
; high low an sclk(serial clock) nächstes bit.....dann Nsel wieder auf high
rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7 868mhz, RX fifo TX buffer 12pf
;0x8280 enable receiver
;0xA640 868mhz center freq
;0xC647 19,2kbaud
;0x9582 Max empfangsstärke 200khz pin als VDI pin
;0xC2AC digitaler fehlerbehebung
;0xCA81
;0xC483
;0x9850 TX controll
;0xE000
;0xC800
;0xC040
;KOmmando 0xB000 read 8 bits from fifoRX
;kommando 0xB8xx send 8 bits of data
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command
ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command
ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command
ldi msb, 0x95
ldi lsb, 0x82
rcall send_command
ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command
ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command
ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command
ldi msb, 0x98
ldi lsb, 0x50
rcall send_command
ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command
ret
usi_init:
;;USIWM1 und 0 für SPI
;; 0 1
ret
send_byte:
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
rcall send_command
ret
read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret
send_command:
mov temp1, msb
cbi spiport,nsel
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel
ret
SPITransfer:
out USIDR,temp1
ldi r16,(1<<USIOIF)
out USISR,r16
ldi r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)
SPITransfer_loop:
out USICR,r17
in r16, USISR
sbrs r16, USIOIF
rjmp SPITransfer_loop
in temp1,USIDR
ret
ret
initrs232:
.equ takt = 1000000 ; 16/8 MHz Systemtakt
.equ baud =2400 ; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1) ; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1))) ; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000) ; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10)) ; max +/- 10 Promill Fehler
.error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
.message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
rcall serinit
rcall hallo
ret
seroutdez:
push temp1 ; die Funktion verändert temp1 und temp2,
push temp2 ; also sichern wir den Inhalt, um ihn am Ende
; wieder herstellen zu können
mov temp2, temp1 ; das Register temp1 frei machen
; abzählen wieviele Hunderter
; in der Zahl enthalten sind
;** Hunderter **
ldi temp1, '0'-1 ; temp1 mit ASCII '0'-1 vorladen
number_1:
inc temp1 ; ASCII erhöhen (somit ist nach dem ersten
; Durchlauf eine '0' in temp1)
subi temp2, 100 ; 100 abziehen
brcc number_1 ; ist dadurch kein Unterlauf entstanden?
; nein, dann zurück zu lcd_number_1
subi temp2, -100 ; 100 wieder dazuzählen, da die
; vorherhgehende Schleife 100 zuviel
; abgezogen hat
cpi temp1, 0 ;Führende null weg
breq number_2
rcall serout ; die Hunderterstelle ausgeben
;** Zehner **
ldi temp1, '0'-1 ; temp1 mit ASCII '0'-1 vorladen
number_2:
inc temp1 ; ASCII erhöhen (somit ist nach dem ersten
; Durchlauf eine '0' in temp1)
subi temp2, 10 ; 10 abziehen
brcc number_2 ; ist dadurch kein Unterlauf enstanden?
; nein, dann zurück zu lcd_number_2
subi temp2, -10 ; 10 wieder dazuzählen, da die
; vorherhgehende Schleife 10 zuviel
; abgezogen hat
cpi temp1, 0 ;Führende null weg
breq number_3
rcall serout ; die Zehnerstelle ausgeben
;** Einer **
number_3:
ldi temp1, '0' ; die Zahl in temp2 ist jetzt im Bereich
add temp1, temp2 ; 0 bis 9. Einfach nur den ASCII Code für
rcall serout ; '0' dazu addieren und wir erhalten dierekt
; den ASCII Code für die Ziffer
pop temp2 ; den gesicherten Inhalt von temp2 und temp1
pop temp1 ; wieder herstellen
ret ; und zurück
hallo:
ldi temp1, 'O'
rcall serout
ldi temp1, 'K'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, 'R'
rcall serout
ldi temp1, 'S'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, '2'
rcall serout
ldi temp1, '3'
rcall serout
ldi temp1, '2'
rcall serout
ret
serout:
sbis ucsra,udre ; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
; UART Data Register Empty
rjmp serout
out udr, temp1 ; Zeichen senden
ret ; zurück aus der Subroutine
; Zeichen über RS232 einlesen
; temp1: gibt das Zeichen zurück
serin:
sbis ucsra, rxc
rjmp serin ; wir warten bis ein Byte angekommen ist
in temp1, udr ; Zeichen einlesen
;rcall serout ; und zurücksenden
ret
serinit:
; Baudrate für RS232 einstellen
ldi temp1, high(ubrr_val)
out ubrrh, temp1
ldi temp1, low(ubrr_val)
out ubrrl, temp1
ldi temp1, (1<<ucsz1) | (1<<ucsz0) ; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
out ucsrc, temp1
sbi ucsrb, txen ; TXE-Bit (3) setzen
sbi ucsrb, rxen ; RXE-Bit (4) setzen
;sbi ucsrb, rxcie ; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
ret
Nun ja das ganze sieht aus wie kraut und rüben. Ich bin gerade in der "hauptsache es funktioniert mal irgendwas "-Phase
mfg Daniel
PS: Was mir gerade noch einfällt
wenn ich 8 bits per SPI an das RFM übertrage mit vorhergehendem msb 0x82
werden diese 8 bits dann sofort vom modul übertragen?
kann ich diese 8 bits beim empfänger mit dem senden von 0xB000 direkt auslesen und sie aus dem USIDR entnehmen?
kann ich das Modul einmal konfigurieren und dann durchgehend warten lassen bis etwas kommt, oder fängt es dann nur müll ein?
wie ist das mit dem VDI pin bzw nINT. Muss ich diese nutzen? oder kann ich auch softwareseitig sicher stellen wann neue daten vorhanden sein müssten.
Wenn ich den FIFO lese während das MOdul etwas empfängt, bekomme ich dann bitsalat oder bleiben die daten im FIFO so lange bestehen bis alle 8 bits empfangen sind und werden dann in den FIFO verschoben. Ich möchte möglichst mit einer minimalen beschaltung auskommen. Das nutzen eines externen intterupts wäre evtl noch eine nette sache. z.B intterupt wenn daten empfangen wurden...Dann auslesen und den MC in den sleep mode
Fragen über fragen...ich hoffe jemand kann für erleuchtung sorgen
PPS: Die Senderoutine wurde wie folgt geändert
send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command
ret
Grund dafür isT:
-Energiesparen durch deaktivieren des senders
- Ich habe gelsen das man erst eine Präambel senden soll dann das Synchronbyte und der receiver auf der gegenseite erst das Byte nach dem Synchronbyte in seinen FIFO übernimmt
Das Ganze soll der USI realisiert werden.
Hier einmal mein aktueller stand beim tiny2313 Empfänger. Das drum herum ist erst einmal nebensächlich sondern eher die vorgehensweise beim empfang.
Könnte ein ambitioniertes Midglied des Forums einmal drüber schaun und mir evtl unter die arme greifen. Auch habe ich das gefühl das ich die ansteuerung des Moduls noch nicht so ganz verstanden habe.
;;;Kleines Testprogramm
;;Tiny2313 als empfänger
;;Empfängt ein Byte und gibt dieses via usart aus
;;USI als SPI Master
.list
.include "tn2313def.inc"
.nolist
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000
.def temp1=r16
.def temp2=r17
.def temp3=r18
.def data=r19
.def lsb=r21
.def msb=r22
.def datain=r23
.org 0x0000
.equ spiddr=ddrb
.equ spiport=portb
.equ nsel=0
rjmp start
.org 0x020
loop:
mov data, lsb
rcall read_byte ;befindet sich anschließend in LSB
cp data, lsb
breq loop
mov temp1, lsb
rcall seroutdez
rcall delay1s
rjmp loop
start:
ldi temp1, low(ramend)
out spl, temp1 ;Stackpointer init
sbi spiddr, nsel
rcall rfninit ;RFM12 inittialisiert und bereit("hoffentlich")
rcall initrs232
rcall loop
;;Nsel auf low einen momment warten dann bit an SDI vom modul(mit dem höchsten bit starten)
; high low an sclk(serial clock) nächstes bit.....dann Nsel wieder auf high
rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7 868mhz, RX fifo TX buffer 12pf
;0x8280 enable receiver
;0xA640 868mhz center freq
;0xC647 19,2kbaud
;0x9582 Max empfangsstärke 200khz pin als VDI pin
;0xC2AC digitaler fehlerbehebung
;0xCA81
;0xC483
;0x9850 TX controll
;0xE000
;0xC800
;0xC040
;KOmmando 0xB000 read 8 bits from fifoRX
;kommando 0xB8xx send 8 bits of data
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command
ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command
ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command
ldi msb, 0x95
ldi lsb, 0x82
rcall send_command
ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command
ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command
ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command
ldi msb, 0x98
ldi lsb, 0x50
rcall send_command
ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command
ret
usi_init:
;;USIWM1 und 0 für SPI
;; 0 1
ret
send_byte:
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
rcall send_command
ret
read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret
send_command:
mov temp1, msb
cbi spiport,nsel
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel
ret
SPITransfer:
out USIDR,temp1
ldi r16,(1<<USIOIF)
out USISR,r16
ldi r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)
SPITransfer_loop:
out USICR,r17
in r16, USISR
sbrs r16, USIOIF
rjmp SPITransfer_loop
in temp1,USIDR
ret
ret
initrs232:
.equ takt = 1000000 ; 16/8 MHz Systemtakt
.equ baud =2400 ; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1) ; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1))) ; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000) ; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10)) ; max +/- 10 Promill Fehler
.error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
.message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
rcall serinit
rcall hallo
ret
seroutdez:
push temp1 ; die Funktion verändert temp1 und temp2,
push temp2 ; also sichern wir den Inhalt, um ihn am Ende
; wieder herstellen zu können
mov temp2, temp1 ; das Register temp1 frei machen
; abzählen wieviele Hunderter
; in der Zahl enthalten sind
;** Hunderter **
ldi temp1, '0'-1 ; temp1 mit ASCII '0'-1 vorladen
number_1:
inc temp1 ; ASCII erhöhen (somit ist nach dem ersten
; Durchlauf eine '0' in temp1)
subi temp2, 100 ; 100 abziehen
brcc number_1 ; ist dadurch kein Unterlauf entstanden?
; nein, dann zurück zu lcd_number_1
subi temp2, -100 ; 100 wieder dazuzählen, da die
; vorherhgehende Schleife 100 zuviel
; abgezogen hat
cpi temp1, 0 ;Führende null weg
breq number_2
rcall serout ; die Hunderterstelle ausgeben
;** Zehner **
ldi temp1, '0'-1 ; temp1 mit ASCII '0'-1 vorladen
number_2:
inc temp1 ; ASCII erhöhen (somit ist nach dem ersten
; Durchlauf eine '0' in temp1)
subi temp2, 10 ; 10 abziehen
brcc number_2 ; ist dadurch kein Unterlauf enstanden?
; nein, dann zurück zu lcd_number_2
subi temp2, -10 ; 10 wieder dazuzählen, da die
; vorherhgehende Schleife 10 zuviel
; abgezogen hat
cpi temp1, 0 ;Führende null weg
breq number_3
rcall serout ; die Zehnerstelle ausgeben
;** Einer **
number_3:
ldi temp1, '0' ; die Zahl in temp2 ist jetzt im Bereich
add temp1, temp2 ; 0 bis 9. Einfach nur den ASCII Code für
rcall serout ; '0' dazu addieren und wir erhalten dierekt
; den ASCII Code für die Ziffer
pop temp2 ; den gesicherten Inhalt von temp2 und temp1
pop temp1 ; wieder herstellen
ret ; und zurück
hallo:
ldi temp1, 'O'
rcall serout
ldi temp1, 'K'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, 'R'
rcall serout
ldi temp1, 'S'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, '2'
rcall serout
ldi temp1, '3'
rcall serout
ldi temp1, '2'
rcall serout
ret
serout:
sbis ucsra,udre ; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
; UART Data Register Empty
rjmp serout
out udr, temp1 ; Zeichen senden
ret ; zurück aus der Subroutine
; Zeichen über RS232 einlesen
; temp1: gibt das Zeichen zurück
serin:
sbis ucsra, rxc
rjmp serin ; wir warten bis ein Byte angekommen ist
in temp1, udr ; Zeichen einlesen
;rcall serout ; und zurücksenden
ret
serinit:
; Baudrate für RS232 einstellen
ldi temp1, high(ubrr_val)
out ubrrh, temp1
ldi temp1, low(ubrr_val)
out ubrrl, temp1
ldi temp1, (1<<ucsz1) | (1<<ucsz0) ; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
out ucsrc, temp1
sbi ucsrb, txen ; TXE-Bit (3) setzen
sbi ucsrb, rxen ; RXE-Bit (4) setzen
;sbi ucsrb, rxcie ; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
ret
Nun ja das ganze sieht aus wie kraut und rüben. Ich bin gerade in der "hauptsache es funktioniert mal irgendwas "-Phase
mfg Daniel
PS: Was mir gerade noch einfällt
wenn ich 8 bits per SPI an das RFM übertrage mit vorhergehendem msb 0x82
werden diese 8 bits dann sofort vom modul übertragen?
kann ich diese 8 bits beim empfänger mit dem senden von 0xB000 direkt auslesen und sie aus dem USIDR entnehmen?
kann ich das Modul einmal konfigurieren und dann durchgehend warten lassen bis etwas kommt, oder fängt es dann nur müll ein?
wie ist das mit dem VDI pin bzw nINT. Muss ich diese nutzen? oder kann ich auch softwareseitig sicher stellen wann neue daten vorhanden sein müssten.
Wenn ich den FIFO lese während das MOdul etwas empfängt, bekomme ich dann bitsalat oder bleiben die daten im FIFO so lange bestehen bis alle 8 bits empfangen sind und werden dann in den FIFO verschoben. Ich möchte möglichst mit einer minimalen beschaltung auskommen. Das nutzen eines externen intterupts wäre evtl noch eine nette sache. z.B intterupt wenn daten empfangen wurden...Dann auslesen und den MC in den sleep mode
Fragen über fragen...ich hoffe jemand kann für erleuchtung sorgen
PPS: Die Senderoutine wurde wie folgt geändert
send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command
ret
Grund dafür isT:
-Energiesparen durch deaktivieren des senders
- Ich habe gelsen das man erst eine Präambel senden soll dann das Synchronbyte und der receiver auf der gegenseite erst das Byte nach dem Synchronbyte in seinen FIFO übernimmt