Dragino Lora Module (Semtech SX1278) for Arduino can demodulate FSK, GFSK, MSK and GMSK.
SX1278 datasheet: https://cdn-shop.adafruit.com/product-files/3179/sx1276_77_78_79.pdfhttps://cdn-shop.adafruit.com/product-files/3179/sx1276_77_78_79.pdf
Dragino Lora Module: http://wiki.dragino.com/index.php?title=Lora_Shield
#define SYNC_VALUE 0xCC
// Bits 7-6: AutoRestartRxMode, 01 On, without waiting for the PLL to re-lock
// Bit 4: Enables the Sync word generation and detection: 0 => Off, 1 => On
// Bit 5: Sets the polarity of the Preamble. 0 0xAA, 1 0x55
// Bits 2-0: Size of the Sync word (SyncSize + 1)
b = readSPI(RegSyncConfig);
bitClear(b, 7);
bitSet(b, 6);
bitSet(b, 4);
bitClear(b, 5);
bitClear(b, 2);
bitClear(b, 1);
bitSet(b, 0);
writeSPI(RegSyncConfig, b);
writeSPI(RegSyncValue1, SYNC_VALUE);
writeSPI(RegSyncValue2, SYNC_VALUE);
writeSPI(RegSyncValue3, SYNC_VALUE);
------------------------------------------------------------------------------------------------------------------------------------------------
#include <SPI.h>
#define SERIAL_SPEED 19200
#define BPS 1200
#define FREQ 462.325303
#define STATE_SLEEP 0
#define STATE_STANDBY 1
#define STATE_FSRX 4
#define STATE_RX 5
#define S_DELAY 10
#define L_DELAY 100
#define RX_BUFFER_LEN 255
#define SX_BITRATE "BPS "
#define SX_FREQ "Frequency "
#define SX_IRQ1_TXT "RegIrqFlags1_value "
#define SX_IRQ2_TXT "RegIrqFlags2_value "
#define SX_VERSION "Version code of the chip "
#define RSSI_THRESHOLD 180 // -rssi/2
#define CH_FILTER_BW B00000101 // 25 kHz 00100 31.3 kHz 10100 20.8 kHz 00101 15.6 kHz
#define SYNC_VALUE 0xCC
#define PRINT_IRQ_CHG 1
#define RegFifo 0x00
#define RegOpMode 0x01
#define RegBitrateMsb 0x02
#define RegBitrateLsb 0x03
#define RegFrfMsb 0x06
#define RegFrfMid 0x07
#define RegFrfLsb 0x08
#define RegPaRamp 0x0a
#define RegRssiConfig 0x0e
#define RegRssiThresh 0x10
#define RegRxBw 0x12
#define RegOokPeak 0x14
#define RegPreambleDetect 0x1f
#define RegSyncConfig 0x27
#define RegSyncValue1 0x28
#define RegSyncValue2 0x29
#define RegSyncValue3 0x2a
#define RegPacketConfig1 0x30
#define RegPacketConfig2 0x31
#define RegPayloadLength 0x32
#define RegIrqFlags1 0x3e
#define RegIrqFlags2 0x3f
#define RegVersion 0x42
#define SX_OSC_FREQ 32000000
#define SX_RESET 9
#define SX_RESET_DELAY_H 5
#define SX_RESET_DELAY_L 100
#define SPI_SS 10
#define SPI_RW_DELAY 50
uint8_t RegIrqFlags1_value;
uint8_t RegIrqFlags2_value;
uint8_t rxBuffer[RX_BUFFER_LEN];
void setup() {
Serial.begin(SERIAL_SPEED);
if (initSX()) {
Serial.print(F(SX_VERSION));
Serial.print(readSPI(RegVersion));
Serial.println();
delay(S_DELAY);
startFSK();
uint8_t b = readSPI(RegOpMode);
bitClear(b, 6);
bitClear(b, 5);
writeSPI(RegOpMode, b);
// Channel filter bandwidth control
writeSPI(RegRxBw, CH_FILTER_BW);
setFreq(FREQ);
Serial.print(F(SX_FREQ));
Serial.println(FREQ, DEC);
setBps(BPS);
Serial.print(F(SX_BITRATE));
Serial.println(BPS);
// Bits 7-6: AutoRestartRxMode, 01 On, without waiting for the PLL to re-lock
// Bit 4: Enables the Sync word generation and detection: 0 => Off, 1 => On
// Bit 5: Sets the polarity of the Preamble. 0 0xAA, 1 0x55
// Bits 2-0: Size of the Sync word (SyncSize + 1)
b = readSPI(RegSyncConfig);
bitClear(b, 7);
bitSet(b, 6);
bitSet(b, 4);
bitClear(b, 5);
bitClear(b, 2);
bitClear(b, 1);
bitSet(b, 0);
writeSPI(RegSyncConfig, b);
writeSPI(RegSyncValue1, SYNC_VALUE);
writeSPI(RegSyncValue2, SYNC_VALUE);
writeSPI(RegSyncValue3, SYNC_VALUE);
// Bits 6-5: Defines DC-free encoding/decoding performed: 00->none, 01->manchester, 10->whitening
// Bit 7: packet format, 0 = fixed length, 1 = variable length
// Bit 4: crc calc/check, 0 = off, 1 = on
// Bits 2-1: Defines address based filtering in Rx: 00 ïƒ None (Off)
// Bit 3: Defines the behavior of the packet handler when CRC check fails:
// 0 => Clear FIFO and restart new packet reception. No PayloadReady interrupt issued.
// 1 => Do not clear FIFO. PayloadReady interrupt issued.
// Bit 0: Selects the CRC and whitening algorithms:
// 0 CCITT CRC implementation with standard whitening
// 1 IBM CRC implementation with alternate whitening
b = 0;
bitSet(b, 7);
writeSPI(RegPacketConfig1, b);
// Bits 6-5: FSK data shaping:
// 00 -> no shaping, 01 -> Gaussian filter BT = 1.0
// 10 -> Gaussian filter BT = 0.5, 11 -> Gaussian filter BT = 0.3
// Bits 3-0: Rise/Fall time of ramp up/down in FSK:
// 1001 40 us
b = readSPI(RegPaRamp);
bitClear(b, 6);
bitClear(b, 5);
bitSet(b, 3);
bitClear(b, 2);
bitClear(b, 1);
bitSet(b, 0);
writeSPI(RegPaRamp, b);
writeSPI(RegPayloadLength, RX_BUFFER_LEN);
// Data processing mode: 0 => Continuous mode, 1 => Packet mode
b = readSPI(RegPacketConfig2);
bitSet(b, 6);
writeSPI(RegPacketConfig2, b);
// RSSI smoothing.
// Defines the number of samples taken to average the RSSI result. 010 -> 8 samples
b = readSPI(RegRssiConfig);
bitClear(b, 2);
bitSet(b, 1);
bitClear(b, 0);
writeSPI(RegRssiConfig, b);
writeSPI(RegRssiThresh, RSSI_THRESHOLD);
// Bit 5: enables the Bit Synchronizer:
// 0 -> bit sync disabled (not possible in packet mode), 1 -> bit sync enabled
b = readSPI(RegOokPeak);
bitSet(b, 5);
writeSPI(RegOokPeak, b);
// RegPreambleDetect (0x1f). Enables Preamble detector when set to 1.
// The AGC settings supersede this bit during the startup / AGC phase.
// Bit 7: 0 -> turned off, 1 -> turned on
// Bits 6-5: Number of Preamble bytes to detect to trigger an interrupt.
// 00 1 byte, 10 3 bytes, 01 2 bytes
b = readSPI(RegPreambleDetect);
bitClear(b, 7);
bitClear(b, 6);
bitClear(b, 5);
writeSPI(RegPreambleDetect, b);
clearFifoAndFlags();
setState(STATE_FSRX);
delay(L_DELAY);
setState(STATE_RX);
delay(S_DELAY);
#if (PRINT_IRQ_CHG == 1)
RegIrqFlags1_value = readSPI(RegIrqFlags1);
RegIrqFlags2_value = readSPI(RegIrqFlags2);
Serial.print(F(SX_IRQ1_TXT));
Serial.println(RegIrqFlags1_value, BIN);
Serial.print(F(SX_IRQ2_TXT));
Serial.println(RegIrqFlags2_value, BIN);
#endif
}
}
void loop() {
uint8_t r2;
r2 = readSPI(RegIrqFlags2);
#if (PRINT_IRQ_CHG == 1)
uint8_t r1 = readSPI(RegIrqFlags1);
if (r1 != RegIrqFlags1_value) {
RegIrqFlags1_value = r1;
Serial.print(F(SX_IRQ1_TXT));
Serial.println(RegIrqFlags1_value, BIN);
}
if (r2 != RegIrqFlags2_value) {
RegIrqFlags2_value = r2;
Serial.print(F(SX_IRQ2_TXT));
Serial.println(RegIrqFlags2_value, BIN);
}
#endif
if (bitRead(r2, 2) == 1) {
uint8_t b = readSPI(RegPayloadLength);
if (b > 0) {
b = fetchData(rxBuffer, b);
if (b > 0) {
uint8_t n;
for (n = 0; n < b; n++) {
Serial.print(rxBuffer[n], HEX);
Serial.print(";");
}
Serial.print(b);
Serial.println();
}
}
}
}
void clearFifoAndFlags() {
// Flag(s) and FIFO are cleared when this bit is set
uint8_t b = readSPI(RegIrqFlags2);
bitSet(b, 4);
writeSPI(RegIrqFlags2, b);
delay(S_DELAY);
}
void setBps(uint16_t bps) {
uint16_t baudRate = SX_OSC_FREQ / bps;
writeSPI(RegBitrateMsb, baudRate >> 8);
writeSPI(RegBitrateLsb, baudRate & 0xff);
}
void setFreq(float f)
{
uint32_t lf = (f * 1000000) / 61.035;
writeSPI(RegFrfMsb, (lf >> 16) & 0xff);
writeSPI(RegFrfMid, (lf >> 8) & 0xff);
writeSPI(RegFrfLsb, lf & 0xff);
}
void setState(uint8_t s) {
uint8_t b = readSPI(RegOpMode);
b = b | s;
writeSPI(RegOpMode, b);
}
void startFSK()
{
setState(STATE_SLEEP);
delay(S_DELAY);
uint8_t b = readSPI(RegOpMode);
bitClear(b, 7);
writeSPI(RegOpMode, b);
}
uint8_t fetchData(uint8_t data[], uint8_t len)
{
for (uint8_t n = 0; n < len; n++) {
data[n] = readSPI(RegFifo);
if (bitRead(readSPI(RegIrqFlags2), 6) == 1) {
return n;
}
}
return 0;
}
bool initSX() {
pinMode(SX_RESET, OUTPUT);
resetSX();
initSPI();
if (readSPI(RegVersion) == 0) {
return false;
}
setState(STATE_STANDBY);
return true;
}
void resetSX() {
digitalWrite(SX_RESET, LOW);
delayMicroseconds(SX_RESET_DELAY_L);
digitalWrite(SX_RESET, HIGH);
delay(SX_RESET_DELAY_H);
}
uint8_t readSPI(uint8_t addr) {
digitalWrite(SPI_SS, LOW);
SPI.transfer(addr);
delayMicroseconds(SPI_RW_DELAY);
uint8_t v = SPI.transfer(0x00);
digitalWrite(SPI_SS, HIGH);
return v;
}
void writeSPI(uint8_t addr, uint8_t v) {
digitalWrite(SPI_SS, LOW);
SPI.transfer(addr | 0x80);
delayMicroseconds(SPI_RW_DELAY);
SPI.transfer(v);
digitalWrite(SPI_SS, HIGH);
}
void initSPI()
{
digitalWrite(SPI_SS, HIGH);
pinMode(SPI_SS, OUTPUT);
SPI.begin();
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
}
Kommentit
Tämän blogin kommentit tarkistetaan ennen julkaisua.