【物联网无线通信技术】LoRa从理论到实现(SX1268)

这篇具有很好参考价值的文章主要介绍了【物联网无线通信技术】LoRa从理论到实现(SX1268)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章先从LoRa的物联网通信技术前辈们讲起,慢慢引出了这种功耗又低,距离又远的无线通信技术,然后又似庖丁解牛一般,从物理层到链路层,详细的介绍了LoRa这种技术的组成,最后以一种实际的原理与嵌入式软件实现,让读者近距离接触到基于LoRa这种无线通信技术产品的开发过程。总而言之,博主在这一篇文章中集中的介绍了物联网无线通信技术-LoRa的前世今生,帮助各位对这门“新”的无线通信技术有一个全面且直观的了解。

文章目录

LoRa技术前序 

LoRa技术简介

LoRa应用

LoRa系统架构

LoRaWAN 

LoRa通信物理层

LoRa调制与解调

LoRa 编码与解码

STM32+SX1268实现LoRa

实现原理

嵌入式程序

参考文献


LoRa技术前序 

LoRa之前的主要无线通信协议分为一下三种:

  1. 第一类是远距离高速率的传输协议,典型协议包括蜂窝网络通信技术,如3G、4G、5G相关技术等,这是我们目前移动通信使用的典型技术。
  2. 第二类是近距离高速率传输技术,如WiFi、蓝牙等,这些技术传输距离在几十到几百米级别,主要用在家庭环境和日常应用中,使用非常广泛,前面两类可能是一般用户最常使用到的网络协议了,也符合传统网络应用的主要特点和需求。
  3. 第三类是近距离低功耗传输技术,如传统物联网中ZigBee、RFID、低功耗蓝牙等。

上面三类技术大都要求较高的信噪比,并且对障碍的穿透性较小,无法在复杂环境中实现远距离低功耗传输。低功耗广域网有效的弥补了现有物联网连接方法的不足,成为支持物联网连接的重要基础,得到了国内外的广泛关注,并成为了国内外的研究和应用前沿。

LPWAN (Low Power Wide Area Network)指的是低功耗广域网,其特点在于极低功耗,长距离以及海量连接,适用于物联网万物互联的场景。LPWAN不只是一种技术,而是代表了一族有着各种形式的低功耗广域网技术,如下图所示。其中LoRa使用的是一种扩频技术,NB-IoT使用的是窄带技术,这是两种有代表性的低功耗广域网技术。

【物联网无线通信技术】LoRa从理论到实现(SX1268)


LoRa技术简介

LoRa 是 Long Range Communication的简称,我们可以从三个不同的角度来理解LoRa这门技术。从而获得对LoRa这么技术完整的理解。

  • LoRa本质上指的是一种物理层的信号调制方式,是 Semtech 公司定义的一种基于Chirp扩频技术的物理层调制方式,可达到-148 dBm的接收灵敏度,以偏小的数据速率(0.3-50kbps)换取更高的通讯距离(市内3km,郊区15km)和低功耗(电池供电在特定条件下可以工作长达10年)。
  •  从系统角度看,LoRa也指由终端节点、网关、网络服务器、应用服务器所组成的一种网络系统架构:LoRa定义了不同设备在系统中的分工与作用,规定了数据在系统中流动与汇聚的方式。
  • 从应用角度看,LoRa为物联网应用提供了一种低成本、低功耗、远距离的数据传输服务:LoRa在使用10mW射频输出功率的情况下,可以提供超过25km视线传输距离,从而支持大量广域低功耗物联网应用。

LoRa应用

LoRa作为目前广泛使用的低功耗广域网技术(LPWAN),为低功耗物联网设备提供了可靠的连接方案。 如下图所示,相比于Wi-Fi、蓝牙、ZigBee等传统无线局域网,LoRa可以实现更远距离的通信,有效扩展了网络的覆盖范围; 而相比于移动蜂窝网络,LoRa具有更低的硬件部署成本和更长的节点使用寿命,单个LoRa节点可以在电池供电的情况下连续工作数年。 LoRa具有低数据率、远距离和低功耗的性质,因此非常适合与室外的传感器及其他物联网设备进行通信或数据交互。

【物联网无线通信技术】LoRa从理论到实现(SX1268)

考虑到LoRa在覆盖距离、部署成本等方面的巨大优势,近年来LoRa在全球范围内进行了大量的应用部署,在智能仪表(如智能水表、智能电表)、智慧城市、智能交通数据采集、野生动物监控等众多物联网场景中都可以看到LoRa的应用。例如LoRa通信模块与传统的水质传感器进行连接,从而使用户可以数十公里外远程监控饮用水在输送过程中的水质变化情况。而在荷兰的KPN项目中,工程人员通过广泛部署LoRa网关,实现LoRa网络全覆盖,为智慧运输、智能农业、智慧路灯等具体应用提供了通信支持。


LoRa系统架构

现在常用的LoRa架构由节点、网关及服务器所组成,各部分的关系如下图所示。 LoRa节点与网关之间采用单跳直接连接,这一阶段的物理层使用线性扩频调制(Chirp Spreading Spectrum, CSS),MAC层(Media Access Control,媒体访问控制)通常使用LoRaWAN协议。

网关收到数据包后,对数据包信号进行解码,并将解码结果通过蜂窝或有线网络传输给网络服务器,这一阶段使用传统的TCP/IP进行传输,同时网络服务器与网关之间的交互仍然遵守LoRaWAN协议。 网络服务器汇总多个网关的数据,过滤重复的数据包,执行安全检查,并根据内容将数据发送至不同的应用服务器,供用户读取和使用,这一阶段也使用TCP/IP和SSL进行传输和加密。

【物联网无线通信技术】LoRa从理论到实现(SX1268)


LoRaWAN 

在LoRa网络中,会有很多LoRa节点向同一网关发送数据,这就需要MAC协议来协调不同节点间的数据传输,在LoRa中比较典型的MAC协议就是开源的LoRaWAN。 LoRaWAN是由LoRa联盟在LoRa物理层编码技术的基础上提出的MAC层协议,由LoRa联盟负责维护。LoRaWAN规范1.0版本于2015年6月发布。LoRaWAN协议主要规定了节点与网关、网关与服务器之间的连接规范,确定了LoRa网络的星型拓扑结构。受LoRa节点成本和能耗的限制,现有的LoRaWAN协议基本采用纯ALOHA机制,即节点在发送数据前不进行载波侦听,也就是没有使用CSMA/CA,而是随机选择时间进行发送。

LoRaWAN定义了网络的通信协议和系统架构,还负责管理所有设备的通信频率,数据速率和功率。 在LoRaWAN的控制下,网络中的所有设备可以是异步的,并在只有可用数据时进行传输。 针对不同的应用场景,LoRaWAN定义了三种节点运行模式,分别是Class A(ALL)、Class B(Beacon)、Class C(Continuously Listening):

  • Class A模式主要提供低功耗上行连接,处于Class A模式的节点可以在任意时间发起上行传输,并只在传输结束时打开两个下行接收窗口,此时接收来自网关ACK。Class A模式下,网关无法主动连接到节点,当无数据传输时,节点处于休眠状态,因此该模式下节点能耗最低。
  • Class B模式提供节点与网关的周期性连接,该模式下网关节点周期性向节点广播信标帧,保持节点与网关的时间同步。
  • Class C模式提供节点与网关的持续性连接,该模式下节点始终处于唤醒状态,因此能耗最高。

三种网络模式中,Class A是所有LoRa网络都必须支持的模式,也是最常用的网络模式。这三个模式设计并不复杂,其实就是在网络灵活性、可用性和节能之间的一个平衡。Class A最节能,但是灵活性相对较低,例如下行数据只能依赖于上行数据的时间。Class C最耗电,但是也是上行和下行数据发送最灵活的。

【物联网无线通信技术】LoRa从理论到实现(SX1268)


LoRa通信物理层

我们来介绍LoRa通信的基本原理,包括调制、解调、编码和解码,着重于物理层协议的分析,关于上层协议(如LoRaWAN),有很多其他的资料和开源实现供读者学习[1][2],这里就不详述了。

需要说明的是,LoRa物理层是一个商用的私有协议,并没有完整公开的协议说明,因而已有的一些LoRa实现[3][4][5][6][7]都是依照Semtech公司的相关专利和文件猜出来的。[6]MATLAB版本用于原型验证和离线操作,[7]基于GNURadio平台的C++版本则是一个实时的高性能LoRa实现。很多对LoRa的说法只是基于大家的观察和理解,同时很多LoRa代码实现的性能是很差的,包括不少研究论文中使用的LoRa代码,实际性能也存在着很大的问题。

相关论文的介绍见[8]: Zhenqiang Xu, Pengjin Xie, Jiliang Wang. "Pyramid: Real-Time LoRa Collision Decoding withPeak Tracking", IEEE INFOCOM 2021. [PDF]


LoRa调制与解调

在这节我们介绍LoRa的调制与解调,也即如何在物理波形和比特数据之间进行转换。

LoRa 使用 CSS (Chirp Spread Spectrum)线性扩频调制,频率线性扫过整个带宽,因此抗干扰极强,对多径和多普勒效应的抵抗也很强。LoRa的基本通信单元是linear chirp,也即频率随时间线性增加(或减小)的信号。我们将频率随着时间线性增加的chirp符号叫做upchirp,将频率随着时间线性减小的chirp符号叫做downchirp。如下图分别从时域波形和时频域展示了一个upchirp的图像:

【物联网无线通信技术】LoRa从理论到实现(SX1268)

 一个chirp怎么编码数据呢?LoRa的做法是通过在频域循环平移chirp进行数据的编码,不同的起始频率代表不同的数据。如下图所示,在带宽B内四等分标定四个起始频率,我们可以得到4种类型的符号,分别表示00,01,10,11。所以在接收端,只需要将这个起始频率计算出来,就可以计算出每一个chirp对应的比特数据。我们将下图(a)所示从最低频率扫频到最高频率的chirp符号称为basic upchirp。

【物联网无线通信技术】LoRa从理论到实现(SX1268)

LoRa规定了一个参数SF(Spreading Factor,扩频因子),如上图所示,在带宽一定的情况下,扩频因子的增加意味着采样时长的增加(扫频速度减低)。可以看出,提高SF,虽然在相同时间减少了可以传输的实际数据,但是这样扩频后传输可以降低误码率,灵敏度越高,可以得到更远的传输距离。

LoRa解调过程,实质就是求出chirp符号的起始频率,其做法通常是这样的:首先将收到的基带upchirp信号与downchirp点乘,化为单频信号,这一操作叫做dechirp(解扩频)。这个过程可以简单理解为两个收到的upchirp信号与basic upchirp进行混频,就可以得到upchirp的启始频率。如下图所示。

【物联网无线通信技术】LoRa从理论到实现(SX1268)

Dechirp之后,对得到的信号进一步做FFT(快速傅里叶变换),即可在频域获得一个峰值,这个峰值位置对应的频率即是接收到upchirp的起始频率,我们因此得到对应SF个比特的数据。如下图所示。

【物联网无线通信技术】LoRa从理论到实现(SX1268)

一个完整的LoRa数据包结构包含三个部分:前导码(Preamble)、SFD(Start Frame Delimiter)和数据部分(Data)。 前导码包含6~65535个basic upchirp和两个标识网络号的其他chirp符号。接着是2.25个basic downchirp,作为SFD标识数据段的开始。后面的数据段则包含着若干编码了数据的data chirp。

当我们使用软件无线电设备(Software-defined radio, SDR)接收一段LoRa设备发出的信号,并用inspectrum这个软件(其他可画时频图的软件或代码也可以)把信号的时频图画出来,那么它大概会是如下样子:

【物联网无线通信技术】LoRa从理论到实现(SX1268)


LoRa 编码与解码

LoRa物理层编码过程如下:

  • 包头共2.5个有效bytes,包尾循环纠错编码。
  • Hamming 编码
  • Interleaving将每字节的位转化到物理层对应的多chirp频率(8 bits/byte => SF bits/symbol),从下图可以看到实际的口空发射与数据之间的关系。

    【物联网无线通信技术】LoRa从理论到实现(SX1268)

  • Gray 解码(Gray code => Binary code)

LoRa采用循环纠错编码(CRC)进行前向错误检测与纠错,但会产生传输开销。编码率越大前向纠错越强,链路抗干扰性越强,但是传输开销将会加大,进而加大传输时间。

LoRa物理层解码过程与编码相反,如下:

  • 格雷码编码(Gray coding)
  • 对角交织(Interleaving)
  • 海明解码(Hamming decoding)
  • 包头解析(Header Decoding)与CRC(校验CRC checksum)

补充说明一下:在仅仅增加带宽的情况下,能有效的提高传输速率。下图是带宽与SF对接收数据dbm底线以及传输速率的对应数据。

【物联网无线通信技术】LoRa从理论到实现(SX1268)


STM32+SX1268实现LoRa

实现原理

MCU选择STM81L101F3P6S实现超低功耗,其与LoRa射频芯片SX1268之间采用SPI通信接口。

【物联网无线通信技术】LoRa从理论到实现(SX1268)


嵌入式程序

下面的嵌入式程序为main函数,主要实现了三个部分功能的调用实现。

  • SX126x芯片初始化。
  • 将LoRa接收的数据通过串口打印的功能。
  • 通过摁键触发LoRa发送数据。
oid main(void)
{
    u8 ExtiDelay = 0;
    u8 Txbuffer[5] = {0x11,0x22,0x33,0x44,0x99};
    
	CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);	//1分频,16MHz

    //串口初始化
    USART1_Init();
    
    //SX126x初始化
	Sx1276M_GpioInt();
	CS_LOW;
	delayxms(5);
	CS_HIGH;
	RESET_HIGH;
	reset_sx1262();//reset RF
	sx1262_Config();//频率431.5M
	Rx_Init();//接收模式 
    
    //按键初始化
	GPIO_Init(GPIOB, GPIO_Pin_1, GPIO_Mode_In_FL_No_IT);//PB1按键
    
  	while(1)
  	{
    	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1))
    	{
            ExtiDelay++;
            delayxms(1);
            if(ExtiDelay > 10)
            {//消抖
            	ExtiDelay = 0;
            	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1))
            	{
    				KeyTrigger_Flag = 0;
    				LORA_TxData(Txbuffer, 5);//LORA发送数据
    				delayxms(30);//等待一会再接收,发射和接收不能同时进行
        			sx1262_Config();
        			Rx_Init();//切回接收模式
            	}
            }
    	}
        hal_Sx1268_RxHandle();//等待接收
	}
}

void USART1_Init(void)
{
	GPIO_Init(GPIOC, GPIO_Pin_3, GPIO_Mode_Out_PP_High_Fast);
	GPIO_Init(GPIOC, GPIO_Pin_2, GPIO_Mode_In_PU_No_IT);
	CLK_PeripheralClockConfig(CLK_Peripheral_USART,ENABLE);//使能串口外设时钟
	USART_Init(115200,                      //波特率115200
			   USART_WordLength_8D,         //数据位8
               USART_StopBits_1,            //停止位1
			   USART_Parity_No,             //无奇偶校验
			   USART_Mode_Tx|USART_Mode_Rx);//USART初始化		 
	USART_ITConfig(USART_IT_RXNE,ENABLE);//使能接收中断
	USART_Cmd(ENABLE);//使能USART
	//USART1_SendStr("usart_tx is ok");
}

void hal_Sx1268_RxHandle(void)
{
  	if(IRQ_DATABIT)//Wait for the IRQ RxDone or Timeout
	{
		Irq_Status = GetIrqStatus();//0x02
		if((Irq_Status&0x02) == RxDone_IRQ)
		{
			GetRxBufferStatus(&packet_size, &buf_offset);	//read rx packet_size
			if(packet_size>0)
			{//接收长度大于0
				ReadBuffer(buf_offset, &rxbuf[0], packet_size); 	//read rx data
           
				USART1_SendString(&rxbuf[0], packet_size);//串口打印接收数据
				ClearIrqStatus(RxDone_IRQ);//清除中断 
			}
			else
			{
				ClearIrqStatus(RxDone_IRQ); 		
			} 
			Rx_Init();
		}
	}
} 

下面是SX1628芯片的驱动代码,包括初始化,发送模式接收配置,数据发送等具体的接口实现。

/*
 * THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND 
 * (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
 * CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
 * CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
 * CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 * 
 * Copyright (C) SEMTECH S.A.
 */

#include "stm8l10x.h"
#include "sx1268-LoRa.h"
#include "string.h"

void Sx1276M_GpioInt();
   
u8 gb_SF;
u8  gb_BW;
u8  CR;	//LR_RegModemConfig1 
  
#define CRC   0x01  //CRC Enable

#define DATA_LEN        (13)

/**********************************************************
**Parameter table define
**********************************************************/
//__root const u16 SX1276FreqTbl[3] = {0x066C, 0x0780, 0x0800}; //434MHz
__root const u16 SX1276FreqTbl[3] = {0x06D9, 0x0700, 0x0800}; //868MHz @ 26m

 
__root const u16 SX1276PowerTbl[4] =

{ 
  0x09FF,                   //20dbm  
  0x09FC,                   //17dbm
  0x09F9,                   //14dbm
  0x09F6,                   //11dbm 
};


__root const u8 SX1276LoRaBwTbl[10] =
{// 0        1     2       3      4       5         6      7       8      9
//7.8KHz,10.4KHz,15.6KHz,20.8KHz,31.2KHz,41.7KHz,62.5KHz,125KHz,250KHz,500KHz
  0,1,2,3,4,5,6,7,8,9
};

__root const u8 SX1276SpreadFactorTbl[7] =
{
  6,7,8,9,10,11,12
};


u8  SX1276Data[11];

u8  gb_RxData[256];                                         //Receive data buffer

#if 1  //sx1268  Aloma
#define payload_length    13
#define payload_length1    11

#if 0
u8  txbuf[payload_length] = {'s','e','n','d','_','t','e','s','t'};
#else
u8  txbuf[payload_length];
#endif
u8  txbuf_1[payload_length1] = {'r','e','t','u','r','n','_','t','e','s','t'};
u8 rxbuf[200];

u8 packet_size;
u8 buf_offset;

	
u8 Irq_Status;
u8 tx_buff_flag;
extern u16 Lux_Data;
extern u8 STM8S_ID[12];
extern u8 FrameID;
#endif

void delayms(unsigned int t)
{
	unsigned int i;
	unsigned char j; 
	for(i=0;i<t;i++)
	for(j=0;j<120;j++);
}
 
void delayxms(unsigned int t)//8M内部晶振下,已测试
{
	unsigned int i;
	unsigned int j; 
	for(i=0;i<t;i++)
	//for(j=0;j<1600;j++);//8M主频
	for(j=0;j<3200;j++);//16M主频
}
	
void Sx1276M_GpioInt()
{
    //***** RF_SCK         PC_ODR_ODR4
    GPIO_Init(SCK_PORT,SCK_PIN , GPIO_Mode_Out_PP_Low_Slow);
    //*****RF_MISO       PC_IDR_IDR5 //INPUT
    GPIO_Init(MISO_PORT,MISO_PIN , GPIO_Mode_In_PU_No_IT);//上拉输入
    //*****RF_MOSI       PC_ODR_ODR6
    GPIO_Init(MOSI_PORT,MOSI_PIN , GPIO_Mode_Out_PP_Low_Slow); 
    //*****RF_NSEL_PIN  
    GPIO_Init(CS_PORT,CS_PIN , GPIO_Mode_Out_PP_Low_Slow);
    RF SWT
    //BUSY
    GPIO_Init(BUSY_PORT,BUSY_PIN , GPIO_Mode_In_PU_No_IT);
    //IRQ
    GPIO_Init(LORA_RCV_IRQ_PORT,LORA_RCV_IRQ_PIN, GPIO_Mode_In_FL_No_IT);
    //RESET
    GPIO_Init(RESET_PORT,RESET_PIN , GPIO_Mode_Out_PP_Low_Slow); 
}

#if 1//Aloma  sx1268
u8 spi_rw(u8 data) 
{
	u8 i;
	
	for (i = 0; i < 8; i++)//高位先传	
	{				
		if (data & 0x80)
			MOSI_HIGH;
		else
			MOSI_LOW;
			
		data <<= 1;
		SCK_HIGH;
 		if (MISO_DATABIT)//高位先收
			data |= 0x01;
		else
			data &= 0xfe;
			
		SCK_LOW;
	}	
	MOSI_LOW;
	return (data);	
}

/***************sx1262*****************/
void reset_sx1262(void)
{
	RESET_LOW;
	delayxms(1);		//more thena 100us, delay 10ms
	RESET_HIGH;
	delayxms(1);	//delay 10ms
} 

void check_busy(void)//发送时,busy拉低
{
	unsigned char busy_timecnt = 0;			
	while(BUSY_DATABIT)
	{
		delayxms(1);
		busy_timecnt++;
		if(busy_timecnt>5)		//超时120ms复位	
		{
			busy_timecnt=0;
			//SetStandby(0);		//0:STDBY_RC; 1:STDBY_XOSC
			reset_sx1262();		//reset RF
			//sx1262_Config();
			//Rx_Init();
			break;		
		}
	}
}

void SetSleep(void)
{
	u8 Opcode,sleepConfig;
	
	check_busy();
	Opcode = SET_SLEEP;	//0x84
	sleepConfig = 0x00;	//bit2: 1:warm start; bit0: 0: RTC timeout disable
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(sleepConfig);
	CS_HIGH;
}

//0:STDBY_RC; 1:STDBY_XOSC
void SetStandby(u8 StdbyConfig)
{
	u8 Opcode;
	
	check_busy();
	Opcode = SET_STANDBY;	//0x80	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(StdbyConfig);
	CS_HIGH;
}

void SetTx(u32 timeout)
{
	u8 Opcode;
	u8 time_out[3];
	
	check_busy();
	Opcode = SET_TX;	//0x83
	time_out[0] = (timeout>>16)&0xFF;//MSB
	time_out[1] = (timeout>>8)&0xFF;
	time_out[2] = timeout&0xFF;//LSB
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(time_out[0]);
	spi_rw(time_out[1]);
	spi_rw(time_out[2]);
	CS_HIGH;
}

void SetRx(u32 timeout)
{
	u8 Opcode;
	u8 time_out[3];
	
	check_busy();
	
	Opcode = SET_RX;	//0x82
	time_out[0] = (timeout>>16)&0xFF;//MSB
	time_out[1] = (timeout>>8)&0xFF;
	time_out[2] = timeout&0xFF;//LSB
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(time_out[0]);
	spi_rw(time_out[1]);
	spi_rw(time_out[2]);
	CS_HIGH;
}

//0:GFSK; 1:LORA
void SetPacketType(u8 PacketType)
{
	u8 Opcode;
	
	check_busy();
	Opcode = SET_PACKET_TYPE;	//0x8A	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(PacketType);
	CS_HIGH;
}

u8 GetPacketType(void)
{
	u8 Opcode;
	u8 Status;
	u8 packetType;
	
	check_busy();
	Opcode = 0x11;	
	
	CS_LOW;
	spi_rw(Opcode);
	Status = spi_rw(0xFF);
	packetType = spi_rw(0xFF);
	CS_HIGH;
	
	return packetType;
}

//RF_Freq = freq_value * 32M / (2^25)  ----->  freq_value = (RF_Freq * (2^25)) / 32M
//431.5M : freq_value = (431.5M * (2^25)) / 32M = 452460544 = 0x1AF80000
//868M : freq_value = (868M * (2^25)) / 32M = 910163968 = 0x36400000
void SetRfFrequency(void)
{
	u8 Opcode;
	u8 Rf_Freq[4];
	u32 RfFreq = 0;
	
	//RfFreq = 0x1B200096;//434M
	RfFreq = 0x1AF80000;//431.5M : freq_value = (431.5M * (2^25)) / 32M = 452460544 = 0x1AF80000
	check_busy();
	
	Opcode = SET_RF_FREQUENCY;	//0x86
	
	Rf_Freq[0] = (RfFreq>>24)&0xFF;//MSB
	Rf_Freq[1] = (RfFreq>>16)&0xFF;
	Rf_Freq[2] = (RfFreq>>8)&0xFF;
	Rf_Freq[3] = RfFreq&0xFF;//LSB
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(Rf_Freq[0]);
	spi_rw(Rf_Freq[1]);
	spi_rw(Rf_Freq[2]);
	spi_rw(Rf_Freq[3]);
	CS_HIGH;
}

void SetPaConfig(void)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x95;	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(0x04);	//paDutyCycle//22dbm
	spi_rw(0x07);	//hpMax:0x00~0x07; 7:22dbm
	spi_rw(0x00);	//deviceSel: 0: SX1262; 1: SX1261
	spi_rw(0x01);
	CS_HIGH;
}

void SetRegulatorMode(void)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x96;	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(0x01);//regModeParam
	CS_HIGH;
}

void WriteRegister(u16 address, u8 *data, u8 length)
{
	u8 Opcode;
	u8 addr_l,addr_h;
	u8 i;
	
	if(length<1)			
		return;
	
	check_busy();
	addr_h = address>>8;
	addr_l = address&0xff;
	
	Opcode = 0x0D;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(addr_h);//MSB
	spi_rw(addr_l);//LSB
	for(i=0;i<length;i++)
	{
		spi_rw(data[i]);
	}
	CS_HIGH;
}

void ReadRegister(u16 address, u8 *data, u8 length)
{
	u8 Opcode;
	u8 addr_l,addr_h;
	u8 i;
	
	if(length<1)			
		return;
	check_busy();
	
	addr_l = address&0xff;
	addr_h = address>>8;
	
	Opcode = 0x1D;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(addr_h);//MSB
	spi_rw(addr_l);//LSB
	spi_rw(0x00);	//20190809 fix
	for(i=0;i<length;i++)
	{
		data[i]=spi_rw(0xFF);
	}
	CS_HIGH;
}

/*
@para 
power:
-17(0xEF) to +14(0x0E) dBm by step of 1 dB if low power PA is selected
-9(0xF7) to +22(0x16) dBm by step of 1 dB if high power PA is selected

RampTime:
-------------------------------------
RampTime 	  | Value | RampTime(μs)
-------------------------------------
SET_RAMP_10U    0x00    10
SET_RAMP_20U    0x01    20
SET_RAMP_40U 	0x02	40
SET_RAMP_80U 	0x03	80
SET_RAMP_200U 	0x04	200
SET_RAMP_800U 	0x05	800
SET_RAMP_1700U 	0x06	1700
SET_RAMP_3400U 	0x07	3400
*/

void SetTxParams(int power,u8 RampTime)
{
	u8 Opcode;
	u8 data_buf[2];
	
	// WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
    // RegTxClampConfig = @address 0x08D8
	ReadRegister(0x08D8,data_buf,1); 
	data_buf[0] = data_buf[0]|(0x0F << 1);
        WriteRegister(0x08D8,data_buf,1);
    // WORKAROUND END
	
	check_busy();
	Opcode = SET_TX_PARAMS;	//0x8E	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(power);
	spi_rw(RampTime);
	CS_HIGH;
}


void SetBufferBaseAddress(u8 TX_base_addr,u8 RX_base_addr)
{
	u8 Opcode;
	
	check_busy();
	Opcode = SET_BUF_BASE_ADDR;	//0x8F	
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(TX_base_addr);
	spi_rw(RX_base_addr);
	CS_HIGH;
}

void WriteBuffer(u8 offset, u8 *data, u8 length)
{
	u8 Opcode;
	u8 i;
	
	if(length<1)			
		return;
	
	check_busy();
	Opcode = 0x0E;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(offset);
	for(i=0;i<length;i++)
	{
		spi_rw(data[i]);
	}
	CS_HIGH;
}


void ReadBuffer(u8 offset, u8 *data, u8 length)
{
	u8 Opcode;
	u8 i;
	
	if(length<1)			
	return;
	check_busy();
	
	Opcode = 0x1E;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(offset);
	spi_rw(0xFF);
	for(i=0;i<length;i++)
	{
		data[i]=spi_rw(0xFF);
	}
	CS_HIGH;
}

void GetRxBufferStatus(u8 *payload_len, u8 *buf_pointer)
{
	u8 Opcode;
	u8 Status;
	
	check_busy();
	
	Opcode = 0x13;
	CS_LOW;
	spi_rw(Opcode);

	Status = spi_rw(0xFF);
	*payload_len = spi_rw(0xFF);
	*buf_pointer = spi_rw(0xFF);
	CS_HIGH;
}

void SetModulationParams(u8 sf, u8 bw, u8 cr, u8 ldro)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x8B;
	
	CS_LOW;
	spi_rw(Opcode);
	
	spi_rw(sf);//SF=5~12
	spi_rw(bw);//BW
	spi_rw(cr);//CR
	spi_rw(ldro);//LDRO LowDataRateOptimize 0:OFF; 1:ON;
	
	spi_rw(0XFF);//
	spi_rw(0XFF);//
	spi_rw(0XFF);//
	spi_rw(0XFF);//
	
	CS_HIGH;
}

void SetPacketParams(uint8_t payload_len)
{
	u8 Opcode;
	u16 prea_len;
	u8 prea_len_h,prea_len_l;
	u8 data_buf[2];
	u8 invertIQ;
	
	check_busy();
	
	Opcode = 0x8C;
	
	prea_len = 16;//前导码长度
	prea_len_h = prea_len>>8;
	prea_len_l = prea_len&0xFF;
	
	invertIQ = LORA_IQ_NORMAL;
	
	CS_LOW;
	spi_rw(Opcode);
	
	spi_rw(prea_len_h);//PreambleLength MSB
	spi_rw(prea_len_l);//PreambleLength LSB
	spi_rw(0x00);//HeaderType 0:Variable,explicit 1:Fixed,implicit
	//spi_rw(0x01);
	spi_rw(payload_len);//PayloadLength: 0x00 to 0xFF
	
	spi_rw(0X01);//CRCType 0:OFF 1:ON
	spi_rw(invertIQ);//InvertIQ 0:Standard 1:Inverted
	spi_rw(0XFF);//
	spi_rw(0XFF);//
	spi_rw(0XFF);//
	
	CS_HIGH;	
	
	// WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4
	if( invertIQ == LORA_IQ_INVERTED )
	{
		// RegIqPolaritySetup = @address 0x0736		
		ReadRegister(0x0736,data_buf,1);
		data_buf[0] = data_buf[0] & ~( 1 << 2 );
		WriteRegister( 0x0736,data_buf,1);
	}
	else
	{
		// RegIqPolaritySetup @address 0x0736
		ReadRegister(0x0736,data_buf,1);//0x0D
		data_buf[0] = data_buf[0] | ( 1 << 2 );
		WriteRegister(0x0736,data_buf,1);
	}
	// WORKAROUND END
}

void SetDioIrqParams(u16 irq)
{
	u8 Opcode;
	u16 Irq_Mask;
	u8 Irq_Mask_h,Irq_Mask_l;
	u16 DIO1Mask;
	u8 DIO1Mask_h,DIO1Mask_l;
	u16 DIO2Mask;
	u8 DIO2Mask_h,DIO2Mask_l;
	u16 DIO3Mask;
	u8 DIO3Mask_h,DIO3Mask_l;
	
	Irq_Mask = irq;
	DIO1Mask = irq;
	DIO2Mask = 0;
	DIO3Mask = 0;
	
	Irq_Mask_h = Irq_Mask>>8;
	Irq_Mask_l = Irq_Mask&0xFF;
	DIO1Mask_h = DIO1Mask>>8;
	DIO1Mask_l = DIO1Mask&0xFF;
	DIO2Mask_h = DIO2Mask>>8;
	DIO2Mask_l = DIO2Mask&0xFF;
	DIO3Mask_h = DIO3Mask>>8;
	DIO3Mask_l = DIO3Mask&0xFF;
	Opcode = 0x08;
	
	check_busy();
	
	CS_LOW;
	spi_rw(Opcode);
	
	spi_rw(Irq_Mask_h);//Irq_Mask MSB
	spi_rw(Irq_Mask_l);//Irq_Mask LSB
	spi_rw(DIO1Mask_h);//
	spi_rw(DIO1Mask_l);//
	
	spi_rw(DIO2Mask_h);//
	spi_rw(DIO2Mask_l);//
	spi_rw(DIO3Mask_h);//
	spi_rw(DIO3Mask_l);//
	
	CS_HIGH;
}

u16 GetIrqStatus(void)
{
	u8 Opcode;
	u8 Status;
	u16 IrqStatus;
	u8 temp;
	
	check_busy();
	
	Opcode = 0x12;
	
	CS_LOW;
	spi_rw(Opcode);
	Status = spi_rw(0xFF);
	temp = spi_rw(0xFF);
	IrqStatus = temp;
	IrqStatus = IrqStatus<<8;
	temp = spi_rw(0xFF);
	IrqStatus = IrqStatus|temp;
	CS_HIGH;	
	
	return IrqStatus;
}
void ClearIrqStatus(u16 irq)
{
	u8 Opcode;
	u16 irq_h,irq_l;
	check_busy();
	
	irq_h = irq>>8;
	irq_l = irq&0xFF;
	
	Opcode = 0x02;
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(irq_h);
	spi_rw(irq_l);
	CS_HIGH;
}

void SetDIO2AsRfSwitchCtrl(void)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x9D;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(0x01);   //DIO2 is selected to be used to control an RF switch; DIO2 = 1 in TX mode
	CS_HIGH;
}

#define  DIO3_1_6V  0x00
#define  DIO3_1_7V  0x01
#define  DIO3_1_8V  0x02
#define  DIO3_2_2V  0x03
#define  DIO3_2_4V  0x04
#define  DIO3_2_7V  0x05
#define  DIO3_3_0V  0x06
#define  DIO3_3_3V  0x07

void SetDIO3AsTCXOCtrl(uint8_t tcxoVoltage)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x97;
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(tcxoVoltage);   //
	spi_rw(0x00);		   //Timeout MSB ; Timeout duration = Timeout *15.625 μs
	spi_rw(0x00);
	spi_rw(0x64);          //Timeout LSB
	
	CS_HIGH;
	}

void ClearDeviceErrors(void)
{
	u8 Opcode;
	
	check_busy();
	Opcode = 0x07;
	
	CS_LOW;
	spi_rw(Opcode);
	spi_rw(0x00);   
	spi_rw(0x00);  
	CS_HIGH;
	}

void sx1262_Config(void)
{
	u8 bw_temp;
	u8 data_buf[2];
	
	SetStandby(0);//0:STDBY_RC; 1:STDBY_XOSC
	SetRegulatorMode();
	SetPaConfig();
	
	/*************************************
	** Uncomment below two lines if you **
	** used the SX1262 module of nicerf,**
	** keep comment if SX1268 used.     **
	**************************************/
	/*SetDIO3AsTCXOCtrl(DIO3_1_8V);*/
	/*ClearDeviceErrors();*/
	
	SetDIO2AsRfSwitchCtrl();
	
	SetPacketType(1);	//0:GFSK; 1:LORA
	SetRfFrequency();		//设置频率
	SetTxParams(22,SET_RAMP_10U);	//set power and ramp_time
	
	bw_temp = LORA_BW_500;//9501
	//bw_temp = LORA_BW_125;//4338: SF7, LORA_BW_125  9501: SF8, LORA_BW_500
	SetModulationParams(SF8, bw_temp, LORA_CR_4_5, LDRO_ON);//9501速率

	// WORKAROUND - Modulation Quality with 500 kHz LoRa mode Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1
    if(bw_temp == LORA_BW_500)
    {
        // RegTxModulation = @address 0x0889
		ReadRegister(0x0889,data_buf,1);//0x04
		data_buf[0] = data_buf[0] & ~( 1 << 2 );		 
        WriteRegister(0x0889,data_buf,1);
    }
    else
    {
        // RegTxModulation = @address 0x0889		
		ReadRegister(0x0889,data_buf,1);
		data_buf[0] = data_buf[0] | ( 1 << 2 ); 
        WriteRegister(0x0889,data_buf,1);
    }
    // WORKAROUND END
	
	SetPacketParams(payload_length);//PreambleLength;HeaderType;PayloadLength;CRCType;InvertIQ
}

void LORA_TxData(unsigned char *data, unsigned char len)
{
	//unsigned char busy_timecnt;
	//u8 i;
	u8 busy_timecnt = 0;
	SetStandby(0);//0:STDBY_RC; 1:STDBY_XOSC
	//SetBufferBaseAddress(0,0);//(TX_base_addr,RX_base_addr)
	
	//if(tx_buff_flag==0)

	WriteBuffer(0,data,len);//(offset,*data,length)
	SetPacketParams(len);//PreambleLength;HeaderType;PayloadLength;CRCType;InvertIQ
	
	//else
	//{
		//WriteBuffer(0,txbuf_1,payload_length1);//(offset,*data,length)
		//SetPacketParams(payload_length1);//PreambleLength;HeaderType;PayloadLength;CRCType;InvertIQ
	//}
	
	SetDioIrqParams(TxDone_IRQ);//TxDone IRQ

	//Define Sync Word value
	SetTx(0);//timeout = 0
	

	//Wait for the IRQ TxDone or Timeout
	#if 1
	while(!IRQ_DATABIT)
	{
		delayxms(1);//if time out, reset the module//超时120ms复位//复位时间与发送数据的长度有关
		busy_timecnt++;
		if(busy_timecnt>60)
		{	
			busy_timecnt=0;	
			ClearIrqStatus(TxDone_IRQ);	//Clear the IRQ TxDone flag
        	SetStandby(0);				//0:STDBY_RC; 1:STDBY_XOSC
        	reset_sx1262();				//reset RF
        	sx1262_Config();
			break;		
		}
	}
	busy_timecnt=0;	
	ClearIrqStatus(TxDone_IRQ);	//Clear the IRQ TxDone flag
	SetStandby(0);				//0:STDBY_RC; 1:STDBY_XOSC
	reset_sx1262();				//reset RF
	sx1262_Config();
	#else
	delayxms(30);//发送数据的长度越长,延时时间越长。发送速率越低,延时时间越长。
	if(!IRQ_DATABIT)
	{
		ClearIrqStatus(TxDone_IRQ);	//Clear the IRQ TxDone flag
		SetStandby(0);				//0:STDBY_RC; 1:STDBY_XOSC
		reset_sx1262();				//reset RF
		sx1262_Config();
	}
	#endif
	Irq_Status = GetIrqStatus();//0x8C
	ClearIrqStatus(TxDone_IRQ);//Clear the IRQ TxDone flag
	//UART1_printf("Irq_Status=%d\r\n",Irq_Status);
	//Irq_Status = GetIrqStatus();
}

void Rx_Init(void)
{
	//SetBufferBaseAddress(0,0);			//(TX_base_addr,RX_base_addr)
	//SetPacketParams(payload_length);	//PreambleLength;HeaderType;PayloadLength;CRCType;InvertIQ
	
	SetDioIrqParams(RxDone_IRQ);		//RxDone IRQ
	SetRx(0);//timeout = 0
}
#endif

参考文献

  1. https://github.com/Lora-net/LoRaMac-node
  2. GitHub - brocaar/chirpstack-network-server: ChirpStack Network Server is an open-source LoRaWAN network-server.
  3. https://github.com/rpp0/gr-lora
  4. GitHub - BastilleResearch/gr-lora: GNU Radio OOT module implementing the LoRa PHY, based on https://github.com/matt-knight/research/tree/master/2016_05_20_jailbreak
  5. LoRa PHY based on GNU Radio ‒ TCL ‐ EPFL
  6. GitHub - jkadbear/LoRaPHY: Complete LoRa physical layer (LoRa PHY) implementation in MATLAB.
  7. GitHub - jkadbear/gr-lora: LoRa physical layer collision decoding based on GNU Radio
  8. Zhenqiang Xu, Pengjin Xie, Jiliang Wang. "Pyramid: Real-Time LoRa Collision Decoding withPeak Tracking", IEEE INFOCOM 2021. [PDF code]

十六宿舍 原创作品,转载必须标注原文链接。

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。文章来源地址https://www.toymoban.com/news/detail-498473.html

到了这里,关于【物联网无线通信技术】LoRa从理论到实现(SX1268)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【物联网无线通信技术】802.11无线安全认证

    本文由简入繁介绍了IEEE802.11i无线局域网安全技术的前世今生,帮助路由器开发者对WLAN的加密安全策略有一个概念上的认知,能够更好地分析STA掉线以及漫游等问题。 目录 WEP WPA WPA/WPA2-PSK认证过程 802.11i WEP是Wired Equivalent Privacy的简称,有线等效保密(WEP)协议对在两台设备间

    2024年02月11日
    浏览(44)
  • MIMO-OFDM无线通信技术(Matlab代码实现)

        目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 本代码为MIMO-OFDM无线通信技术及MATLAB实现。分为十章,供大家学习。 主函数部分代码: [1]黄丘林. MIMO无线通信技术研究[D].西安电子科技大学,2007. 部分理论引用网络文献,若有侵权联系博主删除。

    2023年04月16日
    浏览(36)
  • 无线网络通信技术详细介绍

    以下是对各类网络各自常见和常用的通信技术进行简单介绍。 一、无线广域网(WWAN) 无线广域网WWAN(Wireless Wide Area Networks)主要是为了满足超出一个城市范围的信息交流和网际接入需求,让用户可以和在遥远地方的公众或私人网络建立无线连接。在无线广域网的通信中一般要用

    2024年02月08日
    浏览(40)
  • 元宇宙挑战现实世界无线通信技术

    导 言 事 件 2021年10月28日,在名为Facebook Connect的年度大会上,Facebook宣布,公司名称将更改为“Meta”,这是元宇宙Metaverse的前缀,意思是包含万物无所不连。标志着这一世界级的科技巨头从传统的社交媒体公司,all in元宇宙的战略决心。这一信息也将酝酿多年的元宇宙概念研

    2024年02月05日
    浏览(40)
  • 物联网通信技术

    UWB:超宽带无线通信技术(UWB)是一种无载波通信技术,UWB不使用载波,而是使用短的能量脉冲序列,并通过正交频分调制或直接排序将脉冲扩展到一个频率范围内。 NFC:全称是Near Field  Communication,即“近场通信”,也叫“近距离无线通信”。 ARQ:自动重传请求(Automati

    2024年02月09日
    浏览(29)
  • 了解无线通信技术WiFi,Sub 1G,Zigbee

    本文主要记录一些无线通信技术的常识,用处不大但是至少能让你在别人谈论通信的时候能够听得懂。 通信技术是移动互联网中至关重要的一环,从2G到今天的5G,都显示了移动互联网通信技术的进步。5G通信技术,即第五代移动通信技术,是最新一代的蜂窝移动通信技术,也

    2024年02月11日
    浏览(58)
  • 物联网中的通信技术

    阅读引言: 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术              物联网的通信层担负着极其重

    2024年01月18日
    浏览(30)
  • 物联网通信技术复习题整理

    1【单选题】三层结构类型的物联网不包括( )。 A、感知层 B、网络层 C、应用层 D、会话层 答案:D 2【单选题】物联网的核心是( )。 A、应用 B、产业 C、技术 D、标准 答案:A 3【单选题】属于感知控制层通信技术的是( ). A、ZigBee技术 B、3G网络 C、4G网络 D、局域网 答案:

    2024年02月09日
    浏览(42)
  • 车联网V2X通信技术及应用介绍

    摘要: V2X技术影响用户体验的主要系统指标有延时时间、可靠性、数据速率、通信覆盖范围移动性、用户密度、安全性等。 车联网是物联网在交通这个特殊行业的典型应用。在车联网体系参考模型中主要包括三层:数据感知层、网络传输层和应用层。 1. 数据感知层 数据感知

    2024年02月06日
    浏览(26)
  • 物联网Lora模块从入门到精通(八)Lora无线通信

            在某些环境下,无法通过有线传输数据,这时候我们需要使用Lora无线通信传输数据,Lora无线数据传输具有低功耗、距离长的特点,常用于工厂内等,需要Lora基站。         我曾做过距离测试:Lora模块距离测试-物联网Lora开发         本次的任务目标为将光照数据

    2024年02月14日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包