avatar

松果工作室

欢迎光临

  • 首页
  • freeRTOS
  • ESP
  • 开发手册
  • 快速笔记
  • 个人收藏
  • 工具
Home Lora
文章

Lora

Posted 2024-10-18 Updated 2024-10- 19
By YCP
69~89 min read

芯片手册

SX1278-data-cn.pdf

代码

SX1278.c

#include "SX1278.h"
#include <string.h>

[SX1278-data-cn.pdf](/upload/SX1278-data-cn.pdf)
uint8_t SX1278_SPIRead(SX1278_t *module, uint8_t addr){
	uint8_t tmp;
	SX1278_hw_SPICommand(module->hw, addr);
	tmp = SX1278_hw_SPIReadByte(module->hw);
	SX1278_hw_SetNSS(module->hw, 1);
	return tmp;
}

void SX1278_SPIWrite(SX1278_t *module, uint8_t addr, uint8_t cmd) {
	SX1278_hw_SetNSS(module->hw, 0);
	SX1278_hw_SPICommand(module->hw, addr | 0x80);
	SX1278_hw_SPICommand(module->hw, cmd);
	SX1278_hw_SetNSS(module->hw, 1);
}

void SX1278_SPIBurstRead(SX1278_t *module, uint8_t addr, uint8_t *rxBuf,
		uint8_t length) {
	uint8_t i;
	if (length <= 1) {
		return;
	} else {
		SX1278_hw_SetNSS(module->hw, 0);
		SX1278_hw_SPICommand(module->hw, addr);
		for (i = 0; i < length; i++) {
			*(rxBuf + i) = SX1278_hw_SPIReadByte(module->hw);
		}
		SX1278_hw_SetNSS(module->hw, 1);
	}
}

void SX1278_SPIBurstWrite(SX1278_t *module, uint8_t addr, uint8_t *txBuf,
		uint8_t length) {
	unsigned char i;
	if (length <= 1) {
		return;
	} else {
		SX1278_hw_SetNSS(module->hw, 0);
		SX1278_hw_SPICommand(module->hw, addr | 0x80);
		for (i = 0; i < length; i++) {
			SX1278_hw_SPICommand(module->hw, *(txBuf + i));
		}
		SX1278_hw_SetNSS(module->hw, 1);
	}
}

void SX1278_config(SX1278_t *module) {
	SX1278_sleep(module); //Change modem mode Must in Sleep mode
	SX1278_hw_DelayMs(15);

	SX1278_entryLoRa(module);
	//SX1278_SPIWrite(module, 0x5904); //?? Change digital regulator form 1.6V to 1.47V: see errata note

	uint64_t freq = ((uint64_t) module->frequency << 19) / 32000000;
	uint8_t freq_reg[3];
	freq_reg[0] = (uint8_t) (freq >> 16);
	freq_reg[1] = (uint8_t) (freq >> 8);
	freq_reg[2] = (uint8_t) (freq >> 0);
	SX1278_SPIBurstWrite(module, LR_RegFrMsb, (uint8_t*) freq_reg, 3); //setting  frequency parameter

	SX1278_SPIWrite(module, RegSyncWord, 0x34);

	//setting base parameter
	SX1278_SPIWrite(module, LR_RegPaConfig, SX1278_Power[module->power]); //Setting output power parameter

	SX1278_SPIWrite(module, LR_RegOcp, 0x0B);			//RegOcp,Close Ocp
	SX1278_SPIWrite(module, LR_RegLna, 0x23);		//RegLNA,High & LNA Enable
	if (SX1278_SpreadFactor[module->LoRa_SF] == 6) {	//SFactor=6
		uint8_t tmp;
		SX1278_SPIWrite(module,
		LR_RegModemConfig1,
				((SX1278_LoRaBandwidth[module->LoRa_BW] << 4)
						+ (SX1278_CodingRate[module->LoRa_CR] << 1) + 0x01)); //Implicit Enable CRC Enable(0x02) & Error Coding rate 4/5(0x01), 4/6(0x02), 4/7(0x03), 4/8(0x04)

		SX1278_SPIWrite(module,
		LR_RegModemConfig2,
				((SX1278_SpreadFactor[module->LoRa_SF] << 4)
						+ (SX1278_CRC_Sum[module->LoRa_CRC_sum] << 2) + 0x03));

		tmp = SX1278_SPIRead(module, 0x31);
		tmp &= 0xF8;
		tmp |= 0x05;
		SX1278_SPIWrite(module, 0x31, tmp);
		SX1278_SPIWrite(module, 0x37, 0x0C);
	} else {
		SX1278_SPIWrite(module,
		LR_RegModemConfig1,
				((SX1278_LoRaBandwidth[module->LoRa_BW] << 4)
						+ (SX1278_CodingRate[module->LoRa_CR] << 1) + 0x00)); //Explicit Enable CRC Enable(0x02) & Error Coding rate 4/5(0x01), 4/6(0x02), 4/7(0x03), 4/8(0x04)

		SX1278_SPIWrite(module,
		LR_RegModemConfig2,
				((SX1278_SpreadFactor[module->LoRa_SF] << 4)
						+ (SX1278_CRC_Sum[module->LoRa_CRC_sum] << 2) + 0x00)); //SFactor &  LNA gain set by the internal AGC loop
	}

	SX1278_SPIWrite(module, LR_RegModemConfig3, 0x04);
	SX1278_SPIWrite(module, LR_RegSymbTimeoutLsb, 0x08); //RegSymbTimeoutLsb Timeout = 0x3FF(Max)
	SX1278_SPIWrite(module, LR_RegPreambleMsb, 0x00); //RegPreambleMsb
	SX1278_SPIWrite(module, LR_RegPreambleLsb, 8); //RegPreambleLsb 8+4=12byte Preamble
	SX1278_SPIWrite(module, REG_LR_DIOMAPPING2, 0x01); //RegDioMapping2 DIO5=00, DIO4=01
	module->readBytes = 0;
	SX1278_standby(module); //Entry standby mode
}

void SX1278_standby(SX1278_t *module) {
	SX1278_SPIWrite(module, LR_RegOpMode, 0x09);
	module->status = STANDBY;
}

void SX1278_sleep(SX1278_t *module) {
	SX1278_SPIWrite(module, LR_RegOpMode, 0x08);
	module->status = SLEEP;
}

void SX1278_entryLoRa(SX1278_t *module) {
	SX1278_SPIWrite(module, LR_RegOpMode, 0x88);
}

void SX1278_clearLoRaIrq(SX1278_t *module) {
	SX1278_SPIWrite(module, LR_RegIrqFlags, 0xFF);
}

int SX1278_LoRaEntryRx(SX1278_t *module, uint8_t length, uint32_t timeout) {
	uint8_t addr;

	module->packetLength = length;

	SX1278_config(module);		//Setting base parameter
	SX1278_SPIWrite(module, REG_LR_PADAC, 0x84);	//Normal and RX
	SX1278_SPIWrite(module, LR_RegHopPeriod, 0xFF);	//No FHSS
	SX1278_SPIWrite(module, REG_LR_DIOMAPPING1, 0x01);//DIO=00,DIO1=00,DIO2=00, DIO3=01
	SX1278_SPIWrite(module, LR_RegIrqFlagsMask, 0x3F);//Open RxDone interrupt & Timeout
	SX1278_clearLoRaIrq(module);
	SX1278_SPIWrite(module, LR_RegPayloadLength, length);//Payload Length 21byte(this register must difine when the data long of one byte in SF is 6)
	addr = SX1278_SPIRead(module, LR_RegFifoRxBaseAddr); //Read RxBaseAddr
	SX1278_SPIWrite(module, LR_RegFifoAddrPtr, addr); //RxBaseAddr->FiFoAddrPtr
	SX1278_SPIWrite(module, LR_RegOpMode, 0x8d);	//Mode//Low Frequency Mode
	//SX1278_SPIWrite(module, LR_RegOpMode,0x05);	//Continuous Rx Mode //High Frequency Mode
	module->readBytes = 0;

	while (1) {
		if ((SX1278_SPIRead(module, LR_RegModemStat) & 0x04) == 0x04) {	//Rx-on going RegModemStat
			module->status = RX;
			return 1;
		}
		if (--timeout == 0) {
			SX1278_hw_Reset(module->hw);
			SX1278_config(module);
			return 0;
		}
		SX1278_hw_DelayMs(1);
	}
}

uint8_t SX1278_LoRaRxPacket(SX1278_t *module) {
	unsigned char addr;
	unsigned char packet_size;

	if (SX1278_hw_GetDIO0(module->hw)) {
		memset(module->rxBuffer, 0x00, SX1278_MAX_PACKET);

		addr = SX1278_SPIRead(module, LR_RegFifoRxCurrentaddr); //last packet addr
		SX1278_SPIWrite(module, LR_RegFifoAddrPtr, addr); //RxBaseAddr -> FiFoAddrPtr

		if (module->LoRa_SF == SX1278_LORA_SF_6) { //When SpreadFactor is six,will used Implicit Header mode(Excluding internal packet length)
			packet_size = module->packetLength;
		} else {
			packet_size = SX1278_SPIRead(module, LR_RegRxNbBytes); //Number for received bytes
		}

		SX1278_SPIBurstRead(module, 0x00, module->rxBuffer, packet_size);
		module->readBytes = packet_size;
		SX1278_clearLoRaIrq(module);
	}
	return module->readBytes;
}

int SX1278_LoRaEntryTx(SX1278_t *module, uint8_t length, uint32_t timeout) {
	uint8_t addr;
	uint8_t temp;

	module->packetLength = length;

	SX1278_config(module); //setting base parameter
	SX1278_SPIWrite(module, REG_LR_PADAC, 0x87);	//Tx for 20dBm
	SX1278_SPIWrite(module, LR_RegHopPeriod, 0x00); //RegHopPeriod NO FHSS
	SX1278_SPIWrite(module, REG_LR_DIOMAPPING1, 0x41); //DIO0=01, DIO1=00,DIO2=00, DIO3=01
	SX1278_clearLoRaIrq(module);
	SX1278_SPIWrite(module, LR_RegIrqFlagsMask, 0xF7); //Open TxDone interrupt
	SX1278_SPIWrite(module, LR_RegPayloadLength, length); //RegPayloadLength 21byte
	addr = SX1278_SPIRead(module, LR_RegFifoTxBaseAddr); //RegFiFoTxBaseAddr
	SX1278_SPIWrite(module, LR_RegFifoAddrPtr, addr); //RegFifoAddrPtr

	while (1) {
		temp = SX1278_SPIRead(module, LR_RegPayloadLength);
		if (temp == length) {
			module->status = TX;
			return 1;
		}

		if (--timeout == 0) {
			SX1278_hw_Reset(module->hw);
			SX1278_config(module);
			return 0;
		}
	}
}

int SX1278_LoRaTxPacket(SX1278_t *module, uint8_t *txBuffer, uint8_t length,
		uint32_t timeout) {
	SX1278_SPIBurstWrite(module, 0x00, txBuffer, length);
	SX1278_SPIWrite(module, LR_RegOpMode, 0x8b);	//Tx Mode
	while (1) {
		if (SX1278_hw_GetDIO0(module->hw)) { //if(Get_NIRQ()) //Packet send over
			SX1278_SPIRead(module, LR_RegIrqFlags);
			SX1278_clearLoRaIrq(module); //Clear irq
			SX1278_standby(module); //Entry Standby mode
			return 1;
		}

		if (--timeout == 0) {
			SX1278_hw_Reset(module->hw);
			SX1278_config(module);
			return 0;
		}
		SX1278_hw_DelayMs(1);
	}
}

void SX1278_init(SX1278_t *module, uint64_t frequency, uint8_t power,
		uint8_t LoRa_SF, uint8_t LoRa_BW, uint8_t LoRa_CR,
		uint8_t LoRa_CRC_sum, uint8_t packetLength) {
	SX1278_hw_init(module->hw);
	module->frequency = frequency;
	module->power = power;
	module->LoRa_SF = LoRa_SF;
	module->LoRa_BW = LoRa_BW;
	module->LoRa_CR = LoRa_CR;
	module->LoRa_CRC_sum = LoRa_CRC_sum;
	module->packetLength = packetLength;
	SX1278_config(module);
}

int SX1278_transmit(SX1278_t *module, uint8_t *txBuf, uint8_t length,
		uint32_t timeout) {
	if (SX1278_LoRaEntryTx(module, length, timeout)) {
		return SX1278_LoRaTxPacket(module, txBuf, length, timeout);
	}
	return 0;
}

int SX1278_receive(SX1278_t *module, uint8_t length, uint32_t timeout) {
	return SX1278_LoRaEntryRx(module, length, timeout);
}

uint8_t SX1278_available(SX1278_t *module) {
	return SX1278_LoRaRxPacket(module);
}

uint8_t SX1278_read(SX1278_t *module, uint8_t *rxBuf, uint8_t length) {
	if (length != module->readBytes)
		length = module->readBytes;
	memcpy(rxBuf, module->rxBuffer, length);
	rxBuf[length] = '\0';
	module->readBytes = 0;
	return length;
}

uint8_t SX1278_RSSI_LoRa(SX1278_t *module) {
	uint32_t temp = 10;
	temp = SX1278_SPIRead(module, LR_RegRssiValue); //Read RegRssiValue, Rssi value
	temp = temp + 127 - 137; //127:Max RSSI, 137:RSSI offset
	return (uint8_t) temp;
}

uint8_t SX1278_RSSI(SX1278_t *module) {
	uint8_t temp = 0xff;
	temp = SX1278_SPIRead(module, RegRssiValue);
	temp = 127 - (temp >> 1);	//127:Max RSSI
	return temp;
}

SX1278.h

#ifndef __SX1278_H__
#define __SX1278_H__

#include <stdint.h>
#include <stdbool.h>

#include "SX1278_hw.h"

#define SX1278_MAX_PACKET	256
#define SX1278_DEFAULT_TIMEOUT		3000

//RFM98 Internal registers Address
/********************LoRa mode***************************/
#define LR_RegFifo                                  0x00
// Common settings
#define LR_RegOpMode                                0x01
#define LR_RegFrMsb                                 0x06
#define LR_RegFrMid                                 0x07
#define LR_RegFrLsb                                 0x08
// Tx settings
#define LR_RegPaConfig                              0x09
#define LR_RegPaRamp                                0x0A
#define LR_RegOcp                                   0x0B
// Rx settings
#define LR_RegLna                                   0x0C
// LoRa registers
#define LR_RegFifoAddrPtr                           0x0D
#define LR_RegFifoTxBaseAddr                        0x0E
#define LR_RegFifoRxBaseAddr                        0x0F
#define LR_RegFifoRxCurrentaddr                     0x10
#define LR_RegIrqFlagsMask                          0x11
#define LR_RegIrqFlags                              0x12
#define LR_RegRxNbBytes                             0x13
#define LR_RegRxHeaderCntValueMsb                   0x14
#define LR_RegRxHeaderCntValueLsb                   0x15
#define LR_RegRxPacketCntValueMsb                   0x16
#define LR_RegRxPacketCntValueLsb                   0x17
#define LR_RegModemStat                             0x18
#define LR_RegPktSnrValue                           0x19
#define LR_RegPktRssiValue                          0x1A
#define LR_RegRssiValue                             0x1B
#define LR_RegHopChannel                            0x1C
#define LR_RegModemConfig1                          0x1D
#define LR_RegModemConfig2                          0x1E
#define LR_RegSymbTimeoutLsb                        0x1F
#define LR_RegPreambleMsb                           0x20
#define LR_RegPreambleLsb                           0x21
#define LR_RegPayloadLength                         0x22
#define LR_RegMaxPayloadLength                      0x23
#define LR_RegHopPeriod                             0x24
#define LR_RegFifoRxByteAddr                        0x25
#define LR_RegModemConfig3                          0x26
// I/O settings
#define REG_LR_DIOMAPPING1                          0x40
#define REG_LR_DIOMAPPING2                          0x41
// Version
#define REG_LR_VERSION                              0x42
// Additional settings
#define REG_LR_PLLHOP                               0x44
#define REG_LR_TCXO                                 0x4B
#define REG_LR_PADAC                                0x4D
#define REG_LR_FORMERTEMP                           0x5B
#define REG_LR_AGCREF                               0x61
#define REG_LR_AGCTHRESH1                           0x62
#define REG_LR_AGCTHRESH2                           0x63
#define REG_LR_AGCTHRESH3                           0x64

/********************FSK/ook mode***************************/
#define  RegFIFO                0x00
#define  RegOpMode              0x01
#define  RegBitRateMsb      	0x02
#define  RegBitRateLsb      	0x03
#define  RegFdevMsb             0x04
#define  RegFdevLsb             0x05
#define  RegFreqMsb             0x06
#define  RegFreqMid             0x07
#define  RegFreqLsb         	0x08
#define  RegPaConfig            0x09
#define  RegPaRamp              0x0a
#define  RegOcp                 0x0b
#define  RegLna                 0x0c
#define  RegRxConfig            0x0d
#define  RegRssiConfig      	0x0e
#define  RegRssiCollision 		0x0f
#define  RegRssiThresh      	0x10
#define  RegRssiValue           0x11
#define  RegRxBw                0x12
#define  RegAfcBw               0x13
#define  RegOokPeak             0x14
#define  RegOokFix              0x15
#define  RegOokAvg              0x16
#define  RegAfcFei              0x1a
#define  RegAfcMsb              0x1b
#define  RegAfcLsb              0x1c
#define  RegFeiMsb              0x1d
#define  RegFeiLsb              0x1e
#define  RegPreambleDetect  	0x1f
#define  RegRxTimeout1      	0x20
#define  RegRxTimeout2      	0x21
#define  RegRxTimeout3      	0x22
#define  RegRxDelay             0x23
#define  RegOsc                 0x24
#define  RegPreambleMsb     	0x25
#define  RegPreambleLsb     	0x26
#define  RegSyncConfig      	0x27
#define  RegSyncValue1      	0x28
#define  RegSyncValue2      	0x29
#define  RegSyncValue3      	0x2a
#define  RegSyncValue4      	0x2b
#define  RegSyncValue5      	0x2c
#define  RegSyncValue6      	0x2d
#define  RegSyncValue7      	0x2e
#define  RegSyncValue8      	0x2f
#define  RegPacketConfig1       0x30
#define  RegPacketConfig2       0x31
#define  RegPayloadLength       0x32
#define  RegNodeAdrs            0x33
#define  RegBroadcastAdrs       0x34
#define  RegFifoThresh      	0x35
#define  RegSeqConfig1      	0x36
#define  RegSeqConfig2      	0x37
#define  RegTimerResol      	0x38
#define  RegTimer1Coef      	0x39
#define  RegSyncWord			0x39
#define  RegTimer2Coef      	0x3a
#define  RegImageCal            0x3b
#define  RegTemp                0x3c
#define  RegLowBat              0x3d
#define  RegIrqFlags1           0x3e
#define  RegIrqFlags2           0x3f
#define  RegDioMapping1			0x40
#define  RegDioMapping2			0x41
#define  RegVersion				0x42
#define  RegPllHop				0x44
#define  RegPaDac				0x4d
#define  RegBitRateFrac			0x5d

/**********************************************************
 **Parameter table define
 **********************************************************/

#define SX1278_POWER_20DBM		0
#define SX1278_POWER_17DBM		1
#define SX1278_POWER_14DBM		2
#define SX1278_POWER_11DBM		3

static const uint8_t SX1278_Power[4] = { 0xFF, //20dbm
		0xFC, //17dbm
		0xF9, //14dbm
		0xF6, //11dbm
		};

#define SX1278_LORA_SF_6		0
#define SX1278_LORA_SF_7		1
#define SX1278_LORA_SF_8		2
#define SX1278_LORA_SF_9		3
#define SX1278_LORA_SF_10		4
#define SX1278_LORA_SF_11		5
#define SX1278_LORA_SF_12		6

static const uint8_t SX1278_SpreadFactor[7] = { 6, 7, 8, 9, 10, 11, 12 };

#define	SX1278_LORA_BW_7_8KHZ		0
#define	SX1278_LORA_BW_10_4KHZ		1
#define	SX1278_LORA_BW_15_6KHZ		2
#define	SX1278_LORA_BW_20_8KHZ		3
#define	SX1278_LORA_BW_31_2KHZ		4
#define	SX1278_LORA_BW_41_7KHZ		5
#define	SX1278_LORA_BW_62_5KHZ		6
#define	SX1278_LORA_BW_125KHZ		7
#define	SX1278_LORA_BW_250KHZ		8
#define	SX1278_LORA_BW_500KHZ		9

static const uint8_t SX1278_LoRaBandwidth[10] = { 0, //   7.8KHz,
		1, //  10.4KHz,
		2, //  15.6KHz,
		3, //  20.8KHz,
		4, //  31.2KHz,
		5, //  41.7KHz,
		6, //  62.5KHz,
		7, // 125.0KHz,
		8, // 250.0KHz,
		9  // 500.0KHz
		};

//Coding rate
#define SX1278_LORA_CR_4_5    0
#define SX1278_LORA_CR_4_6    1
#define SX1278_LORA_CR_4_7    2
#define SX1278_LORA_CR_4_8    3

static const uint8_t SX1278_CodingRate[4] = { 0x01, 0x02, 0x03, 0x04 };

//CRC Enable
#define SX1278_LORA_CRC_EN              0
#define SX1278_LORA_CRC_DIS             1

static const uint8_t SX1278_CRC_Sum[2] = { 0x01, 0x00 };

typedef enum _SX1278_STATUS {
	SLEEP, STANDBY, TX, RX
} SX1278_Status_t;

typedef struct {
	SX1278_hw_t *hw;

	uint64_t frequency;
	uint8_t power;
	uint8_t LoRa_SF;
	uint8_t LoRa_BW;
	uint8_t LoRa_CR;
	uint8_t LoRa_CRC_sum;
	uint8_t packetLength;

	SX1278_Status_t status;

	uint8_t rxBuffer[SX1278_MAX_PACKET];
	uint8_t readBytes;
} SX1278_t;

uint8_t SX1278_SPIRead(SX1278_t *module, uint8_t addr);
void SX1278_SPIWrite(SX1278_t *module, uint8_t addr, uint8_t cmd);
void SX1278_SPIBurstRead(SX1278_t *module, uint8_t addr, uint8_t *rxBuf,
		uint8_t length);
void SX1278_SPIBurstWrite(SX1278_t *module, uint8_t addr, uint8_t *txBuf,
		uint8_t length);
void SX1278_config(SX1278_t *module);
void SX1278_entryLoRa(SX1278_t *module);
void SX1278_clearLoRaIrq(SX1278_t *module);
int SX1278_LoRaEntryRx(SX1278_t *module, uint8_t length, uint32_t timeout);
uint8_t SX1278_LoRaRxPacket(SX1278_t *module);
int SX1278_LoRaEntryTx(SX1278_t *module, uint8_t length, uint32_t timeout);
int SX1278_LoRaTxPacket(SX1278_t *module, uint8_t *txBuf, uint8_t length,
		uint32_t timeout);
void SX1278_init(SX1278_t *module, uint64_t frequency, uint8_t power,
		uint8_t LoRa_SF, uint8_t LoRa_BW, uint8_t LoRa_CR,
		uint8_t LoRa_CRC_sum, uint8_t packetLength);
int SX1278_transmit(SX1278_t *module, uint8_t *txBuf, uint8_t length,
		uint32_t timeout);
int SX1278_receive(SX1278_t *module, uint8_t length, uint32_t timeout);
uint8_t SX1278_available(SX1278_t *module);
uint8_t SX1278_read(SX1278_t *module, uint8_t *rxBuf, uint8_t length);
uint8_t SX1278_RSSI_LoRa(SX1278_t *module);
uint8_t SX1278_RSSI(SX1278_t *module);
void SX1278_standby(SX1278_t *module);
void SX1278_sleep(SX1278_t *module);

#endif

SX1278_HW.c

#include "SX1278_hw.h"
#include <string.h>

#include "gpio.h"
#include "spi.h"

__weak void SX1278_hw_init(SX1278_hw_t *hw) {
	SX1278_hw_SetNSS(hw, 1);
	HAL_GPIO_WritePin(hw->reset.port, hw->reset.pin, GPIO_PIN_SET);
}

__weak void SX1278_hw_SetNSS(SX1278_hw_t *hw, int value) {
	HAL_GPIO_WritePin(hw->nss.port, hw->nss.pin,
			(value == 1) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

__weak void SX1278_hw_Reset(SX1278_hw_t *hw) {
	SX1278_hw_SetNSS(hw, 1);
	HAL_GPIO_WritePin(hw->reset.port, hw->reset.pin, GPIO_PIN_RESET);

	SX1278_hw_DelayMs(1);

	HAL_GPIO_WritePin(hw->reset.port, hw->reset.pin, GPIO_PIN_SET);

	SX1278_hw_DelayMs(100);
}

__weak void SX1278_hw_SPICommand(SX1278_hw_t *hw, uint8_t cmd) {
	SX1278_hw_SetNSS(hw, 0);
	HAL_SPI_Transmit(hw->spi, &cmd, 1, 1000);
	while (HAL_SPI_GetState(hw->spi) != HAL_SPI_STATE_READY)
		;
}

__weak uint8_t SX1278_hw_SPIReadByte(SX1278_hw_t *hw) {
	uint8_t txByte = 0x00;
	uint8_t rxByte = 0x00;

	SX1278_hw_SetNSS(hw, 0);
	HAL_SPI_TransmitReceive(hw->spi, &txByte, &rxByte, 1, 1000);
	while (HAL_SPI_GetState(hw->spi) != HAL_SPI_STATE_READY)
		;
	return rxByte;
}

__weak void SX1278_hw_DelayMs(uint32_t msec) {
	HAL_Delay(msec);
}

__weak int SX1278_hw_GetDIO0(SX1278_hw_t *hw) {
	return (HAL_GPIO_ReadPin(hw->dio0.port, hw->dio0.pin) == GPIO_PIN_SET);
}


SX1278_HW.h

#ifndef __SX1278_HW_HEADER
#define __SX1278_HW_HEADER

#include <stdint.h>

typedef struct {
	int pin;
	void *port;
} SX1278_hw_dio_t;

typedef struct {
	SX1278_hw_dio_t reset;
	SX1278_hw_dio_t dio0;
	SX1278_hw_dio_t nss;
	void *spi;
} SX1278_hw_t;

void SX1278_hw_init(SX1278_hw_t *hw);
void SX1278_hw_SetNSS(SX1278_hw_t *hw, int value);
void SX1278_hw_Reset(SX1278_hw_t *hw);
void SX1278_hw_SPICommand(SX1278_hw_t *hw, uint8_t cmd);
uint8_t SX1278_hw_SPIReadByte(SX1278_hw_t *hw);
void SX1278_hw_DelayMs(uint32_t msec);
int SX1278_hw_GetDIO0(SX1278_hw_t *hw);

#endif

几个注意事项

  • CS 引脚拉低选中,发送指令,结束后拉高取消选中。
  • HAL_SPI_TransmitReceive(&spi1, &txByte, &rxByte, 1, 1000);发送空字节即可得到返回值。
  • 发送完之后调用while (HAL_SPI_GetState(hw->spi) != HAL_SPI_STATE_READY);再 return 返回值,不知道为什么这样写。我觉得在HAL_SPI_TransmitReceive(hw->spi, &txByte, &rxByte, 1, 1000);这一句已经等待 1000ms 了。如果不通信再尝试这个库的写法吧。
  • 在这里可以看到 SPI 函数如何层层递进:
    __weak void SX1278_hw_SPICommand(SX1278_hw_t *hw, uint8_t cmd) {
      SX1278_hw_SetNSS(hw, 0);
      HAL_SPI_Transmit(hw->spi, &cmd, 1, 1000);
      while (HAL_SPI_GetState(hw->spi) != HAL_SPI_STATE_READY);
      }
      
    __weak uint8_t SX1278_hw_SPIReadByte(SX1278_hw_t *hw) {
      uint8_t txByte = 0x00;
      uint8_t rxByte = 0x00;
    
      SX1278_hw_SetNSS(hw, 0);
      HAL_SPI_TransmitReceive(hw->spi, &txByte, &rxByte, 1, 1000);
      while (HAL_SPI_GetState(hw->spi) != HAL_SPI_STATE_READY);
      return rxByte;
      }
      
    uint8_t SX1278_SPIRead(SX1278_t *module, uint8_t addr) {
      uint8_t tmp;
      SX1278_hw_SPICommand(module->hw, addr);
      tmp = SX1278_hw_SPIReadByte(module->hw);
      SX1278_hw_SetNSS(module->hw, 1);
      return tmp;
      }
    
    void SX1278_SPIWrite(SX1278_t *module, uint8_t addr, uint8_t cmd) {
      SX1278_hw_SetNSS(module->hw, 0);
      SX1278_hw_SPICommand(module->hw, addr | 0x80);
      SX1278_hw_SPICommand(module->hw, cmd);
      SX1278_hw_SetNSS(module->hw, 1);
      }
    
    void SX1278_SPIBurstRead(SX1278_t *module, uint8_t addr, uint8_t *rxBuf,
      	uint8_t length) {
      uint8_t i;
      if (length <= 1) {
      	return;
      } else {
      	SX1278_hw_SetNSS(module->hw, 0);
      	SX1278_hw_SPICommand(module->hw, addr);
      	for (i = 0; i < length; i++) {
      		*(rxBuf + i) = SX1278_hw_SPIReadByte(module->hw);
      	}
      	SX1278_hw_SetNSS(module->hw, 1);
      }
      }
    
    void SX1278_SPIBurstWrite(SX1278_t *module, uint8_t addr, uint8_t *txBuf,
      	uint8_t length) {
      unsigned char i;
      if (length <= 1) {
      	return;
      } else {
      	SX1278_hw_SetNSS(module->hw, 0);
      	SX1278_hw_SPICommand(module->hw, addr | 0x80);
      	for (i = 0; i < length; i++) {
      		SX1278_hw_SPICommand(module->hw, *(txBuf + i));
      	}
      	SX1278_hw_SetNSS(module->hw, 1);
      }
      }
    
    只需要记住我们最终要得到的几个函数:
    • SPI 往某个地址发送单字节函数
    • SPI 往某个地址获取单字节函数
    • SPI 往某个地址发送几个字节函数
    • SPI 往某个地址获取几个字节函数
    • 期间记得这个addr | 0x80

如何使用

#include <sys.h>
#include "SX1278.h"

SX1278_hw_t SX1278_hw;
SX1278_t SX1278;

int master;
int ret;
char buffer[512];
int message;
int message_length;

int main(void) {
	init_sys();
	master = HAL_GPIO_ReadPin(MODE_GPIO_Port, MODE_Pin);
	if (master == 1) {
		printf("Mode: Master\r\n");
		HAL_GPIO_WritePin(MODE_GPIO_Port, MODE_Pin, GPIO_PIN_RESET);
	} else {
		printf("Mode: Slave\r\n");
		HAL_GPIO_WritePin(MODE_GPIO_Port, MODE_Pin, GPIO_PIN_SET);
	}

	SX1278_hw.dio0.port = DIO0_GPIO_Port;
	SX1278_hw.dio0.pin = DIO0_Pin;
	SX1278_hw.nss.port = NSS_GPIO_Port;
	SX1278_hw.nss.pin = NSS_Pin;
	SX1278_hw.reset.port = RESET_GPIO_Port;
	SX1278_hw.reset.pin = RESET_Pin;
	SX1278_hw.spi = &hspi2;

	SX1278.hw = &SX1278_hw;

	printf("Configuring LoRa module\r\n");
	SX1278_init(&SX1278, 434000000, SX1278_POWER_17DBM, SX1278_LORA_SF_7,
	SX1278_LORA_BW_125KHZ, SX1278_LORA_CR_4_5, SX1278_LORA_CRC_EN, 10);
	printf("Done configuring LoRaModule\r\n");

	if (master == 1) {
		ret = SX1278_LoRaEntryTx(&SX1278, 16, 2000);
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
	} else {
		ret = SX1278_LoRaEntryRx(&SX1278, 16, 2000);
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
	}
	while (1) {
		if (master == 1) {
			printf("Master ...\r\n");
			HAL_Delay(1000);
			printf("Sending package...\r\n");
			message_length = sprintf(buffer, "Hello %d", message);
			ret = SX1278_LoRaEntryTx(&SX1278, message_length, 2000);
			printf("Entry: %d\r\n", ret);
			printf("Sending %s\r\n", buffer);
			ret = SX1278_LoRaTxPacket(&SX1278, (uint8_t*) buffer,
					message_length, 2000);
			message += 1;
			printf("Transmission: %d\r\n", ret);
			printf("Package sent...\r\n");
		} else {
			printf("Slave ...\r\n");
			HAL_Delay(800);
			printf("Receiving package...\r\n");

			ret = SX1278_LoRaRxPacket(&SX1278);
			printf("Received: %d\r\n", ret);
			if (ret > 0) {
				SX1278_read(&SX1278, (uint8_t*) buffer, ret);
				printf("Content (%d): %s\r\n", ret, buffer);
			}
			printf("Package received ...\r\n");
		}

		//change mode
		if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(MODE_GPIO_Port, MODE_Pin)) {
			printf("Changing mode\r\n");
			master = ~master & 0x01;
			if (master == 1) {
				ret = SX1278_LoRaEntryTx(&SX1278, 16, 2000);
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
			} else {
				ret = SX1278_LoRaEntryRx(&SX1278, 16, 2000);
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
			}
			HAL_Delay(1000);
			while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(MODE_GPIO_Port, MODE_Pin));
		}
	}
}
  • Lora 接收函数
    ret = SX1278_LoRaRxPacket(&SX1278);
    if (ret > 0) {
    			SX1278_read(&SX1278, (uint8_t*) buffer, ret);
    			printf("Content (%d): %s\r\n", ret, buffer);
    }
    
  • Lora 发送函数
    ret = SX1278_LoRaTxPacket(&SX1278, (uint8_t*) buffer,message_length, 2000);
    

初始化参数

void SX1278_init(
SX1278_t *module,
uint64_t frequency,//工作频率
uint8_t power,//发射功率
uint8_t LoRa_SF,//扩频因子 SF
uint8_t LoRa_BW,//带宽 BW
uint8_t LoRa_CR,//编码率 CR,控制数据的冗余度和纠错能力
uint8_t LoRa_CRC_sum,//是否启用 CRC
uint8_t packetLength//数据包长度
) {
	SX1278_hw_init(module->hw);
	module->frequency = frequency;
	module->power = power;
	module->LoRa_SF = LoRa_SF;
	module->LoRa_BW = LoRa_BW;
	module->LoRa_CR = LoRa_CR;
	module->LoRa_CRC_sum = LoRa_CRC_sum;
	module->packetLength = packetLength;
	SX1278_config(module);
}

扩频因子 SF

  • 数字越大传的越远,但容量小
  • 定义
    在采用扩频技术的通信系统中,扩频因子是指每个信息比特被扩展成的码片数量。例如,扩频因子为 8 意味着每个信息比特被扩展成 8 个码片进行传输。
  • 作用
    • 增加通信距离
      较高的扩频因子可以使信号在传输过程中具有更强的抗干扰能力。因为信号被扩展到更宽的频带上,对于相同的干扰功率,干扰在每个码片上的能量就会降低,从而提高了信号的信噪比。这使得接收端能够更准确地恢复出原始信号,尤其在长距离通信中,能够有效地增加通信距离。
      例如,在一些远距离的无线传感器网络应用中,选择较高的扩频因子可以确保传感器节点与基站之间的可靠通信,即使在信号传播路径上存在各种干扰源。
    • 降低数据传输速率
      扩频因子与数据传输速率成反比关系。当扩频因子增大时,每个信息比特需要更多的码片来传输,这就导致了数据传输速率的降低。
      虽然降低了数据传输速率,但在一些对数据实时性要求不高的应用场景中,如环境监测、智能农业等,为了保证通信的可靠性,可以接受较低的数据传输速率以换取更远的通信距离和更好的抗干扰性能。
    • 提高系统容量
      在多用户通信系统中,不同的用户可以使用不同的扩频因子进行区分。由于扩频因子的多样性,系统可以同时支持更多的用户进行通信,从而提高了系统的容量。
      例如,在 LoRa(Long Range)无线通信技术中,通过调整扩频因子,可以实现不同用户之间的异步通信,减少了用户之间的干扰,提高了整个系统的容量和性能。
    • 增强抗干扰能力
      扩频通信将信号扩展到更宽的频带上,使得信号的功率谱密度降低。这使得信号在频域上更加难以被检测和干扰,增强了系统的抗干扰能力。
      对于在复杂电磁环境中工作的通信系统,如工业自动化、智能交通等领域,扩频因子的选择可以有效地提高系统的抗干扰性能,确保通信的可靠性。

带宽 BW

  • 数字越小传的越远,但容量小
  • 定义
    LoRa 带宽指的是信号所占的频率范围。通常以赫兹(Hz)为单位,常见的 LoRa 带宽有 125kHz、250kHz 和 500kHz 等。
  • 作用
    • 影响数据传输速率
      较大的带宽可以在单位时间内传输更多的数据,从而提高数据传输速率。例如,使用 500kHz 的带宽通常比使用 125kHz 的带宽具有更高的数据传输速率。
      但是,数据传输速率的提高也会带来一些负面影响,如增加了信号的噪声和干扰,降低了通信的可靠性。
      相反,较小的带宽虽然数据传输速率较低,但可以提供更好的抗干扰性能和更远的通信距离。
    • 抗干扰能力
      较窄的带宽可以更好地抵抗窄带干扰。如果在通信环境中存在特定频率的窄带干扰源,选择较窄的带宽可以减少干扰对信号的影响。
      例如,在一些工业环境中,可能存在其他无线设备或电气设备产生的窄带干扰,此时选择合适的 LoRa 带宽可以提高通信的稳定性。
      然而,过窄的带宽也可能导致信号的频谱效率降低,需要在抗干扰能力和频谱效率之间进行权衡。
    • 通信距离
      一般来说,较小的带宽可以提供更远的通信距离。这是因为在相同的发射功率下,较窄的带宽信号的功率谱密度更低,更容易在接收端被检测到。
      例如,在远距离的物联网应用中,为了实现更远的通信距离,可以选择较小的 LoRa 带宽。
      但是,通信距离还受到其他因素的影响,如发射功率、扩频因子、天线高度等。
    • 频谱资源利用
      不同的带宽选择会影响对频谱资源的利用效率。较宽的带宽可以在更短的时间内传输大量数据,但可能会占用更多的频谱资源。
      在频谱资源紧张的情况下,需要合理选择 LoRa 带宽,以充分利用有限的频谱资源,同时满足通信需求。
      总之,在 LoRa 通信中,带宽的选择需要根据具体的应用场景和需求来进行权衡。需要考虑数据传输速率、抗干扰能力、通信距离和频谱资源利用等因素,以选择最合适的带宽参数。

编码率 CR

  • 范围(0~1),数字越小传输越可靠,但容量小
  • 一、定义
    编码率是指在数据编码过程中,有效数据位数与总编码位数的比值。例如,编码率为 4/5 表示在每 5 个编码位中,有 4 个是有效数据位,1 个是冗余校验位。
  • 二、作用
    • 提高数据可靠性
      增加冗余校验位可以提高数据在传输过程中的可靠性。当接收端接收到信号后,可以通过这些冗余校验位来检测和纠正传输过程中可能出现的错误。
      例如,如果编码率为 4/5,那么即使在传输过程中有一些位出现错误,接收端也有一定的概率能够通过冗余校验位来恢复出正确的原始数据。较高的编码率意味着更多的冗余校验位,从而提高了数据的可靠性。
      对于一些对数据准确性要求较高的应用,如工业自动化控制、医疗设备数据传输等,较高的编码率可以确保数据的完整性和正确性。
    • 平衡数据传输速率和可靠性
      编码率的选择需要在数据传输速率和可靠性之间进行权衡。较高的编码率虽然可以提高数据可靠性,但同时也会降低数据传输速率,因为更多的位被用于冗余校验而不是有效数据传输。
      相反,较低的编码率可以提高数据传输速率,但可能会降低数据的可靠性。在实际应用中,需要根据具体的需求来选择合适的编码率。
      例如,对于一些实时性要求较高但对数据准确性要求相对较低的应用,如视频监控等,可以选择较低的编码率以提高数据传输速率。而对于一些对数据准确性要求极高的应用,即使牺牲一定的数据传输速率,也应选择较高的编码率。
    • 适应不同的通信环境
      不同的通信环境可能对编码率有不同的要求。在噪声较大、干扰较强的环境中,较高的编码率可以提供更好的抗干扰能力,确保数据的可靠传输。
      而在通信质量较好的环境中,可以选择较低的编码率以提高数据传输速率。
      例如,在城市中的无线通信环境中,由于存在各种电磁干扰,可能需要选择较高的编码率。而在农村或偏远地区,通信环境相对较好,可以选择较低的编码率。
      总之,编码率在 LoRa 通信中是一个重要的参数,它可以通过增加冗余校验位来提高数据的可靠性,同时需要在数据传输速率和可靠性之间进行权衡,并根据不同的通信环境进行选择。

我的问题

  • 如果带宽小了,扩频因子大了,那数据不能分布在更广泛的频段之内,通信的可靠性是否也会降低
    • 如果带宽小了且扩频因子大了,通信的可靠性并不一定会降低,反而在某些情况下可能会提高,具体如下:
      • 一、数据分布与频段范围的关系影响
        数据并非严格依赖广泛频段分布保证可靠性
        虽然直观上看,数据分布在更广泛的频段内似乎能增加通信的多样性和抗干扰能力,但实际上通信的可靠性并不完全取决于数据在频段上的广泛分布程度。
        扩频因子大意味着每个信息比特被扩展成更多的码片,这样即使在较窄的带宽内,也可以通过增加码片的数量和特定的编码方式来提高抗干扰能力。
      • 二、小带宽和大扩频因子对通信可靠性的积极影响
        抗干扰能力增强
        小带宽使得信号的功率谱密度更低,对于窄带干扰具有更好的抵抗能力。在通信环境中,如果存在特定频率的干扰源,较窄的带宽可以减少干扰对信号的影响。
        大扩频因子将信号扩展到更宽的时间域上,降低了单位时间内的功率,使得信号更难被干扰。即使在窄带干扰存在的情况下,接收端也可以通过相关接收技术,从被干扰的信号中恢复出原始数据。
        例如,在工业环境中,可能存在各种电气设备产生的窄带干扰,选择小带宽和大扩频因子的组合可以提高通信的可靠性。
        远距离通信能力提升
        小带宽和大扩频因子的组合通常可以提供更远的通信距离。这是因为小带宽使得信号更容易被接收端检测到,而大扩频因子提高了抗干扰能力,保证了信号在远距离传输过程中的可靠性。
        对于一些需要远距离通信的物联网应用,如智能农业、环境监测等,这种组合可以确保传感器节点与基站之间的稳定通信。
      • 三、可能存在的局限性
        数据传输速率降低
        小带宽和大扩频因子的组合会导致数据传输速率降低。这是因为在窄带内传输更多的码片需要更长的时间,从而降低了单位时间内传输的数据量。
        如果应用对数据传输速率有较高要求,这种组合可能不适合。但对于一些对数据实时性要求不高的应用,如定期上报传感器数据的场景,较低的数据传输速率是可以接受的。
        综上所述,带宽小了且扩频因子大了的情况下,通信的可靠性不一定会降低,在抗干扰和远距离通信方面可能会有更好的表现,但需要根据具体的应用需求来权衡数据传输速率和通信可靠性之间的关系。

SX1278 的寄存器

DIO 可编程引脚

screenshot_2024-10-19_08-53-20.png

Others
License:  CC BY 4.0
Share

Further Reading

OLDER

BLE MESH (二)

NEWER

CURL 的 POST/GET/PUT 方法

Recently Updated

  • ESP32(八) 简单的webserver
  • ESP32(七) NVS
  • ESP32(四) STA & AP
  • 多级菜单
  • ESP32(五) ESP32 OTA

Trending Tags

WCH Linux Elec freeRTOS STM ESP Flutter Others SwiftUI

Contents

©2025 松果工作室. Some rights reserved.

Using the Halo theme Chirpy