RF-link
RF-link modulet er baseret på to billige moduler der kan købes sammen i Kina f.x. ved denne nethandel[1]
Modulet er udviklet uden at kigge på databladet, men blot ved at gætte sig frem omkring de betegnelser der er på printet, hvor man kan se hvor den skal have stel og +5V, og hvor data skal ind/ud.
Det er ikke så let at finde egentlige data på enhederne, men der ligger lidt på sendermodulet [2], godt nok i en 315 MHz version, men der er ikke den store forskel.
Modtagermodulet er fundet på en lidt sjov side [3], men man kan læse hvilke data den burde overholde.
Er man interesseret i kommunikationen til Arduino, så er der et eksempel på den her[4].
Teori for RF-link modulet
Der er ikke så meget teori for RF-link modulet, da det princip der udnyttes blot er at transmittermodulet kan styres til at lave en frekvens på 433 MHz som den sender, eller der kan slukkes for den, så den ikke sender noget. Modtagermodulet giver så et højt signal ud når den modtager 433 MHz og et lavt når den ikke modtager noget.
For at teste om der er "hul igennem" på det helt simple plan, så er der lavet et lille program, der ligger i send1.jal, og som består af følgende kode
forever loop
tx = ! tx
if kontakt then
delay_10us(10) -- giver en puls/pauselængde på ca. 127 us
else
delay_10us(2) -- giver en puls/pauselængde på ca. 47 us
end if
end loop
Ved at sætte forsyning på modtageren kan man måle med et oscilloscop hvordan modtageren reagerer.
Med et en frekvens på ca. 10 kHz (47 us puls og 47 us pause) vil det svare til en bitrate på 20.000 bit/sekund, her kan man se at puls og pause ikke modtages ens, som vist her:
Måling med 47 us puls-tid og 47 us pausetid
Denne forskel kan blive problematisk, hvis man ønsker at kommunikere så hurtigt. I den videre udvikling nedsættes hastigheden for at lette transmissionen.
Hvis man i stedet sender med 127 us puls og pause, så bliver det modtagne signal noget tættere på en 50% duty-cycle, som det kan ses her:
Måling med 127 us puls-tid og 127 us pausetid
Princip for RF-link
Opbygningen af RF-link består af to hardware-moduler: et sendermodul med en tilhørende software og et modtagermodul med en tilhørende software. De to moduler skal være indstillet til samme frekvens, hvor de viste moduler arbejder på 433 MHz.
Sender-modul
Opbygningen af sendermodulet er en færdig opbygget oscillator, der arbejder på 433 MHz, hvor man ved hjælp af en transistor styrer om oscillatoren skal være tændt eller slukket ved hjælp af en transistor på modulet. Styringen sker ved hjælp af databenet, hvor det skal have 5V for at sende og 0V for at være slukket.
Ben | Navn | Betydning | PIC-ben |
---|---|---|---|
1 | GND | Stel | 10 |
2 | Vcc | +5V forsyning | 9 |
3 | Data | Sende signal - når den er høj, sendes 433 MHz | Valgfrit 1-8 |
Modtager-modul
Modtagermodulet består af en diskret opbygget modtager omkring to transistorer og en svingningskreds hvor der indgår en trimmekondensator som er afstemt til den ønskede frekvens. Herefter bliver signalet ensrettet og sammenlignet med et niveau, så modulet giver høj ud når det modtager noget på den ønskede frekvens, og det giver lavt niveau ud når der ikke modtages noget.
Sammenligningen foretages med en LM358 comperator inde i modulet.
Ben | Navn | Betydning | PIC-ben |
---|---|---|---|
1 | GND | Stel | 10 |
2 | Data | Det modtagne signal - høj, når der modtages 433 MHz | Valgfrit 1-8 kant-interrupt |
3 | Data | Samme signal | Valgfrit 1-8 kant-interrupt |
4 | Vcc | +5V forsyning | 9 |
Specifikationer for RF-link
Specifikationerne er sakset fra de hjemmesider det har været muligt at finde, som dokumenterer funktionen.
Parameter | Data |
---|---|
Forsynings spænding | 2.5V - 12V DC (nom. 5V) |
Krævet forsynings-strøm | 4mA @ 5V, 15mA @ 9V |
Hvile-strømforbrug | 10 uA |
Modulationsform | ASK |
Temperatur område | -10 til 60 grader C |
Maks datarate | 9600 k Baud |
Data input | TTL niveau (0/5V) |
Output effekt | 20 mW @ 5V |
Parameter | Data |
---|---|
Forsynings spænding | 3V - 8V DC (nom. 5V) |
Krævet forsynings-strøm | < 3mA @ 5V |
Modtage frekvens | 315 / 433 MHz (433 MHz i vores version) |
Frekvens område | 260 - 440 MHz justerbart (undlad dette) |
Modulationsform | ASK / OOK |
RF følsomhed | -105 dBm (50 Ω) |
Data rate | < 5 kbps (315 MHz, -95 dBm) |
Temperatur område | -20 til 70 grader C |
Data output | TTL niveau (0/5V) |
Antenne længde | 24 cm (315 MHz), 18 cm (433,92 MHz) |
Målinger på RF-link sending
For at udvikle en transmission, der kan overføre en byte korrekt, så opbygges der en datapakke ud fra følgende principper:
- Pakken starter med en marker på 1 ms sending og en kort pause.
- Der sendes en adresse, for at kunne sende til flere modtagere
- Efter adressen sendes det inverterede, for sikre at pakken går godt
- Den ønskede byte sendes
- Der sendes det inverterede, igen for at sikre at data kommer korrekt over
- Der sendes med mindst betydende bit først
- En lav bit (0) sendes som 120 us lavt efterfulgt af 70 us højt
- En høj bit (1) sendes som 120 us lavt efterfulgt af 170 us højt
Sendingen efter disse principper, som også går igen i den endelige version er implementeret i send2.jal og en samlet sending ser ud som følger:
Sending af en samlet pakke med marker og 4 bytes
Pakken tager totalt ca. 9 ms at sende som vist.
De 4 bytes består af byte med en adresse efterfulgt af den inverterede for at sikre at det modtages korrekt, derefter en byte med data og igen den inverterede for sikkerhed i modtagelsen.
Adressen sendes for at kunne identificere hvilken enhed man sender til, og data er for at kunne sende noget konkret indhold – de to bytes kan ikke forveksles, da de altid kommer i den rækkefølge efter en marker på 1 ms.
Byten sendes med mindstbetydende bit først, og et 0 er kodet som ca. 120 us lav og 70 us høj, mens et 1 er kodet som ca. 120 us lav og 170 us høj, så det er let at se forskel på dem i modtagelsen. Ved at der først sendes en byte og derefter den inverterede vil der altid sendes 8 lav og 8 høj, så pakketiden er konstant.
Herunder ses en måling hvor man kan se slutningen af markeren efterfulgt af 9 bit. Første bit er høj, de næste 4 bit er lave, næste igen er høj og de to sidste bit der hører til byten er lave, og da mindst betydende bit sendes først, så er adressen udtrykt binært 0010_0001, hvilket svarer til 33, som det også kan ses i send2.jal.
Slutningen af marker og den første byte (adressen)
Målinger på RF-link modtagelse
For at teste modtagelsen er der opbygget en relativ simpel modtagelse modtag1.jal, hvor man venter aktivt på at modtage de enkelte bit.
På modtagersiden ser det ud som følger, hvor man kan se at de lave pauser er noget kortere end målingerne på sendersiden (selvom det er en anden timebase det er målt i) :
Modtagelse af den første del af en pakke.
Her kan man se at den første byte består af en lang, fire korte en lang og to korte, hvilket svarer til det binære tal 0010_0001 (laveste bit kommer først), så tallet er 33, som er den faste sendeadresse i send2.jal
Den røde kurve er bare et signal for at scopet kan trigge ved modtagelse.
Praktiske problemer ved transmission
Ved modtagelsen er man nødt til at tage højde for at der kan være en del støj ved modtageren. Det viste sig ved test at det hjalp en hel del at anvende ekstern forsyning, for at fjerne noget af støjen.
Hvis man ikke opbygger softwaren robust, så kan man kan miste enkelte pakker, fordi man misforstår noget af støjen som en del af en pakke.
Måling på modtager-siden mellem pakkerne, der viser støjpulser
For at teste robustheden af softwaren er en del af testen foretaget ved at bruge forsyning via PICkit 2, hvor man så får væsentligt mere støj.
I den endelige version er modtagelsen er alligevel så robust at over halvdelen af pakkerne kommer uskadt igennem.
Måling på modtagersiden mellem pakkerne, når man bruger PICkit 2 som forsyning
Simpel test af rækkevidde
For at teste hvordan rækkevidden er, så er senderen blevet placeret to etager over modtageren, så der skal transmitteres gennem to etageadskillelser, hvilket normalt ville dæmpe signalerne væsentligt. For at optimere er der monteret ca 18 cm antenne på både sender og modtager. Både sender og modtager forsynes med ekstern forsyning, for ikke at bidrage med ekstra støj.
I denne konfiguration gik alle pakker igennem ved en test over 256 pakker.
Hvis det kun er senderen der har monteret antenne, så går ca. 220 ud af 256 pakker igennem.
Hvis modtageren forsynes med PICkit 2, så reduceres antallet af pakker der kommer igennem til ca. 6 ud af 256 uden antenne på modtageren, og dette kan igen forbedres ved hjælpe af en antenne på modtageren, så der kommer ca. 16 igennem ud af 256.
Andre versioner af RF-link
Man kunne bygge sit eget modul, men det er normalt ikke tilrådeligt, da det kan være svært at sikre sig at man ikke sender noget på uønskede frekvenser, hvilket kan forstyrre anden kommunikation, som kan være kritisk (f.x. flykommunikation).
Simpel anvendelse af RF-link
For at kunne foretage en transmission med forskellige værdier kan man opbygge et sender-program med f.x 3 taster, hvor man lader den sende de 3 funktioner afhængigt af tasterne. Det kunne gøres med følgende kode,laver ud fra send2.jal:
forever loop
if kontakt1 then
send(33, 1)
delay_1ms(500)
end if
if kontakt2 then
send(33, 2)
delay_1ms(500)
end if
if kontakt3 then
send(33, 3)
delay_1ms(500)
end if
delay_1ms(10)
end loop
Koden er lavet så den fanger tasten, og sender pakken en gang, og det skal modtageren så opfange for at det kan bruges som tænd/sluk af 3 udgange.
For at modtage dette kan der laves en modificeret version af modtag2.jal, hvor der reageres på det der modtages:
var byte modtaget
forever loop
if rf_get_byte(modtaget) then
if modtaget == 1 then
udgang1 = ! udgang1
end if
if modtaget == 2 then
udgang2 = ! udgang2
end if
if modtaget == 3 then
udgang3 = ! udgang3
end if
end if
end loop
Dette forudsætter at alle pakker modtages korrekt, hvilket det ikke kan garanteres at de gør, men dette er blot et simpelt eksempel på en anvendelse, hvor man godt kunne leve med at man evt. skulle trykke på knappen igen.
Softwaren med send2.jal og modtag2.jal kan hentes i denne ZIP-fil.
Software modulet RF-link.jal
Modulet indeholder både sender-software og modtager-software, hvilket man vælger ud fra to bit-constanter, som kan gøres som følger inden man includer RF-link modulet:
const bit receiver = false
const bit transmitter = true
include RF-link
Interface-fil til RF-link
I interface-filen ligger definitioner til både sende-modulet og modtager-modulet. Begge dele skal ligge der for at modulet kan fungere, men det er kun den ene del der oversættes, afhængigt af hvilken del man vælger.
const byte rf_my_address = 33
const byte rf_bytes_send = 4
alias rf_rx is pin_a2
alias rf_rx_dir is pin_a2_direction
alias rf_tx is pin_a2
alias rf_tx_dir is pin_a2_direction
Der er defineret hvilken adresse modulet har, og det skal være den samme for sending og modtagelse.
Antallet af bytes der sendes er defineret som det totale antal der reelt sendes, selvom det kun er en byte der reelt kan anvendes, så sendes der 4 byte. Dette kan lette en udvidelse til at sende flere bytes, hvis man har det behov.
Der skal selvfølgelig også defineres et ben til sende-bittet og et til modtage-bittet. Der er her valgt samme ben, hvilket ikke betyder noget, da det alligevel skal fungere i hvert sit program.
Der er også definitioner som går på interruptet:
if target_chip == PIC_16F690 then
alias rf_rx_int is IOCA_IOCA2 -- Skal rettes med pin_a2
alias rf_intcon_ie is intcon_rabie
alias rf_intcon_if is intcon_rabif
elsif target_chip == PIC_16F684 then
alias rf_rx_int is IOCA_IOCA2 -- Skal rettes med pin_a2
alias rf_intcon_ie is intcon_raie
alias rf_intcon_if is intcon_raif
end if
Der anvendes et kanttrigget interrupt, som er navngivet forskelligt på de forskellige procesorer. Derfor oversættes interruptets navn til samme alias, så man kan aktivere interruptet i softwaren og man kan arbejde med interrupt-flaget inde i intrerruptrutinen.
Enedelig skal interruptet for det aktuelle ben slås til ved at man aktiverer det, derfor skal der defineres hvilket interruptben det er man anvender.
Demo-eksempler til RF-link
Der er lavet 2 demo-eksempler som illustrerer hvordan modulet RF-link.jal fungerer. Der er koderne send_demo.jal og modt_demo.jal, der kan det samme som send2.jal og modtag2.jal, men med den forskel, at de anvender modulet RF-link.jal
Koden i send_demo.jal ser ud som følger:
const bit receiver = false
const bit transmitter = true
include RF-link
var byte tael = 1
forever loop
rf_send(33, tael)
delay_100ms(10)
tael = tael + 1
end loop
koden i modt_demo.jal ser ud som følger:
const bit receiver = true
const bit transmitter = false
include RF-link
var byte modtaget
forever loop
if rf_get_byte(modtaget) then
ALCD_cursor_position(0,0) -- start of first line
-- Skriv det aflæste direkte
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_arr[0])
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_arr[1])
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_arr[2])
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_arr[3])
ALCD_cursor_position(1,0)
ALCD_write_char(" ")
ALCD_Dec_3(modtaget)
else
ALCD_cursor_position(1,4)
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_error)
ALCD_write_char(" ")
ALCD_Dec_3(rf_rx_tid)
end if
delay_1ms(10)
end loop
Modtage-demoen fungerer ved at den forsøger at modtage en pakke, og hvis det lykkes, så skrives der i første linje de 4 bytes der er modtaget, og i starten af anden linje skrives den byte som funktionen returnerer i parameteren. Hvis pakken ikke modtages korrekt bliver der i næste linje udskrevet to interne variabler, der indeholder en fejlstatus og en den tæller der anvendes til at bestemme tiderne på det modtagne.
Modtage-demoen viser følgende skærmbillede:
Opbygningen af sendingen
Princippet i at sende en byte er relativt simpelt, da det er baseret på aktivt venten i koden, så de 9 ms det tager at sende en marker og de 4 byte sker aktivt i sende-rutinen, og der returneres ikke før hele byten er sendt.
Sendingen er opbygget ud fra følgende pseudokode:
Send en marker Send adressen Send det inverterede af adressen Send data Send det inverterede af data
Dette er implementeret ved hjælp af følgende kode:
Procedure rf_send(byte in adr, byte in data) is
rf_tx = high
delay_10us(100) -- 1 ms marker til start
rf_tx = low
delay_10us(10)
rf_send_byte(adr) -- send adresse
rf_send_byte(! adr) -- inverteret adresse for sikkerhed
rf_send_byte(data) -- send data
rf_send_byte(! data) -- inverteret data for sikkerhed
end procedure
Det at sende en byte er implementeret ved hjælp af følgende pseudokode:
Løb gennem alle 8 bit send lav i 100 us hvis aktuel bit er 0 send høj i 50 us ellers send høj i 150 us skift til næste bit
Dette er implementeret ved hjælp af følgende kode:
Procedure rf_send_byte(byte in data) is
for 8 loop
delay_10us(10)
rf_tx = high
if (data & 1) == 0 then
delay_10us(5)
else
delay_10us(15)
end if
rf_tx= low
data = data / 2
end loop
end procedure
Opbygningen af modtagelsen
Hele modtagedelen er opbygget omkring et interrupt, hvor man anvender det kanttriggede interrupt af port A hvis det er PIC16F684 eller hvis det er PIC16F690, så kan det være både port A og port B. Desuden anvendes timer 0 og interruptet til den, ved håndtering af fejl.
Selve det at modtage pakken og få den godkendt sker i en servicefunktion, der kan beskrives ud fra følgende pseudokode:
Hvis der er en pakke klar Hvis der ikke er opstået en fejltilstand Hvis adressen er til mig og der ikke er fejl i adressen Hvis der ikke er fejl i data Returner data Registrer at pakker en modtaget ellers Returner fejl
Dette er implementeret ved hjælp af følgende kode:
function rf_get_byte (byte out data) return bit is
var bit retval = true
if rf_data_ready then
if rf_rx_error == 0 then
if rf_rx_arr[0] != (! rf_rx_arr[1]) then
retval = false
elsif rf_rx_arr[2] != (! rf_rx_arr[3]) then
retval = false
elsif rf_rx_arr[0] != rf_my_address then
retval = false
else
data = rf_rx_arr[2]
end if
end if
rf_data_ready = false
else
retval = false
end if
return retval
end function
Selve tidsregistreringen sker i interruptet, men ikke ved hjælp af timer-interruptet, men derimod at timer 0's register (TMR0) sættes til at tælle med en takt på 8 us, så man kan måle tiden ved at se på indholdet af registeret TMR0.
Kommunikationen er indrettet så det udelukkende er de høje pulser der er interessante tidsmæssigt, så hvis man beskriver interruptet der kommer på alle kanter, så kan det gøres ud fra følgende pseudokode:
hvis input et højt så nulstil TMR0 (tiden i den lave periode måles ikke) ellers husk TMR0 hvis der er modtagelse i gang aflæs en bit ellers hvis tiden er ca. 1 ms og sidste pakke er aflæst sæt op til modtagelse af en ny pakke nulstil fejltilstand marker at kant-interruptet er afviklet
Dette er implementeret med følgende kode:
if rf_intcon_if then
if rf_rx then
TMR0 = 0
else
rf_rx_tid = TMR0
if rf_receiving then
-- Aflæs en bit
--
else
if (rf_rx_tid > 124) & (rf_rx_tid < 132) & (! rf_data_ready) then
rf_receiving = true
rf_rx_error = 0
rf_rx_ptr = 0
rf_rx_bit_nr = 0
end if
end if
end if
rf_intcon_if = false
end if
Selve det at aflæse en bit tester på mange forskellige ting, og der kan komme forskellige fejl-tilstande ud af det, da dette gerne skulle ske mens vi er i gang med at modtage en pakke, men man kan have misforstået en marker, eller man kan have mistet nogle bits i en pakke, eller der kan komme støj inde i pakken som kan forstyrre modtagelsen.
Alle disse ting skal der tages højde for i modtagelsen af bits, og hvis ellers alt går godt, så skal der modtages 32 bit, der lagres i 4 byte. Dette kan illustrares med følgende pseudokode:
Hvis der modtages i pakken så skift bit hvis tiden for høj < 48 us så Marker fejl 1 (for kort en høj puls) hvis tiden for høj < 144 us så Modtag 0-bit hvis tiden for høj < 240 us så Modtag 1-bit ellers Marker fejl 2 (for lang en høj puls) gå til næste bit hvis antallet af bit = 8 så Gem modtaget byte Gå til næste byte hvis antallet af bytes = 4 så Afslut modtagelse og marker at der er en pakke klar
Denne del er implementeret inde i den foregående kode som:
if rf_rx_ptr < rf_bytes_send then
rf_rx_byte = rf_rx_byte / 2
if rf_rx_tid < 6 then
rf_rx_error = 1
rf_receiving = false
elsif rf_rx_tid < 18 then
elsif rf_rx_tid < 30 then
rf_rx_byte = rf_rx_byte + 128
else
rf_rx_error = 2
rf_receiving = false
end if
rf_rx_bit_nr = rf_rx_bit_nr + 1
if rf_rx_bit_nr == 8 then
rf_rx_bit_nr = 0
rf_rx_arr[rf_rx_ptr] = rf_rx_byte
rf_rx_ptr = rf_rx_ptr + 1
if rf_rx_ptr == rf_bytes_send then
rf_data_ready = true
rf_receiving = false
end if
end if
end if
Som nævnt er det TMR0 registeret der håndterer tids-målingen. Til dette register er der et interrupt tilknyttet når den tæller over fra 255 til 0 (svarende til godt 2 ms). Da der i en gyldig pakke ikke kan være hverken høje eller lave impulser der er mere end 1 ms, så vil det enten være mellem to pakker, eller en fejl i modtagelsen, hvis den stadig er i gang med at modtage en pakke når timer 0 interrupter (den nulstiller altid i starten af en lav puls).
Timer 0 interruptet kan udtrykkes med følgende pseudokode:
afstil timer 0 interruptet hvis der modtages så Marker fejl 3 (mere end 2 ms pause i modtagelse) Sæt modtagelsen passiv
Dette er implementeret ved følgende kode:
if intcon_tmr0if then
intcon_tmr0if = False
if rf_receiving then
rf_rx_error = 3
rf_receiving = false
end if
end if
Anvendelse af RF-link
Man skal include modulet som vist:
const bit receiver = false
const bit transmitter = true
include RF-link
Herefter kan den valgte af de to funktioner rf_send eller rf_get_byte anvendes som vist.
Alle kodeeksempler ligger samlet i en ZIP-fil
Moduler på Holstebro HTX | |||||||
---|---|---|---|---|---|---|---|
Tastaturer | Displays | AD-konvertering | I/O-ekspander | Serielt | Interface | Færdige | Andre |
RC-tast - AD-tast - M_tast | ALCD - LCD | ADC_holst - ADC mcp3201 - mcp3208 |
input - output | Seriel_holst - Serial hardware Serial hw int cts - Serial software |
Stepmotor - RFID RGB - RF-link - Afstand |
Humidity - Analog temp - Dig temp Accelerometer |
Rotary Encoder |
Oversigt over Hardware Moduler på Holstebro HTX