物联网实战--驱动篇之(三)LoRa(sx1278)

目录

一、LoRa简介

二、sx1278模块

三、硬件抽象层

四、SX1278初始化

五、发送时间计算

六、发送模式

七、接收模式

八、总结


 本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html

一、LoRa简介

        LoRa在物联网传输领域有着举足轻重的地位,平时大家可能比较少听说,因为它主要还是在行业应用,跟后面会讲的NB-Iot差不多,主要特点都是低功耗、广域网。它们的差别在于,NB-Iot是运营商主导的,规则得按他们的来,还得流量费;LoRa是相对自由的,可以用LoRaWAN,也可以自组网,灵活多变。在使用场景上,有交集,但大部分是互补,NB-Iot适合政企项目,比如远程抄表,节点成千上万个;LoRa适合节点几百个的小规模自组网,它的优势在于不用担心有没有运营商的基站信号,到哪里都可以部署,特别是郊区、户外、地下配电房这些容易没有信号的地方,还有一个优势是不用流量费,相对来讲成本有一定优势,再者,数据可以不用经过互联网平台,一定程度上更安全。

        当然了,这不是绝对的,很多时候是要看甲方的选择,比如我家的水表就是LoRa的。

二、sx1278模块

        sx1278是比较经典的LoRa芯片,大部分人也是从这款芯片开始接触LoRa的,正如上面所说的,正因为足够自由开放,所以用起来还是很麻烦的,寄存器一大堆,各种状态切换,参数设置,刚开始学一头雾水,这里是中文资料,自己先过过眼。https://download.csdn.net/download/ypp240124016/89095343

        根据使用经验,我先提炼出一些关键信息,如果只是应用,了解这些信息也就差不多了。

1、sx1278采用SPI通讯,SPI是一种类似于IIC的通讯总线,核心还是初始化+读写数据,STM32配置SPI很简单的,后面代码会体现;

2、sx1278有两类无线调制模式,一种是传统的FSK等模式,类似于NRF24L01,传输距离比较近;另一种就是LoRa模式,通过扩频技术,增加链路的鲁棒性和接收端的灵敏度,达到远距离传输的目的,对于我们来讲,都是用LoRa模式的,不然没必要用这款芯片了,成本比较高;

3、两个sx1278模块之间要通讯的话,它们的这几个参数要一致,频率、带宽、扩频因子和纠错编码率,一般纠错编码率都是固定的,可以忽略,剩下的3个参数是我们在使用中要经常接触的内容;

4、具体地,sx1278的频率(Freq)范围是137~525MHz,但是根据我国的频段使用规范,正常分为433M和475M两个免费段,合计范围是下图中的410~525M,其实核心还是看模块厂家给的参数了,然后结合测试情况和当地法规自己看下这里的频段哪些比较合适。正常这么宽的范围足够使用了。

5、扩频因子(SF)如下图所示,我们主要关注的是最左侧一列,设置参数范围一般是7~12,这里6比较特殊,一般没怎么用,要用的话设置繁琐一点。扩频因子对传输的影响是 数值越高速度越慢,距离越远,即其它条件固定的情况下,扩频因子为12时比7传的远,但是速度慢。

6、带宽(BW)比较好理解了,直接跟速度挂钩的,好比河道宽度跟水流量的关系。如下定义,我们设置的范围一般是4~9,9速度最快,4是极限了,很多厂家的模块用不了4,会收不到,跟模块用料有关系,一般也用不到这么低了,正常6差不多了。

7、SX1278的数据缓冲区最大是256字节,也就是一次最多发送256字节数据,另外它是半双工设备,也就是说同一时刻只能处在发状态或者接收状态或者其他状态。

        模块的基本信息就是这些了,下面结合代码作讲解。

三、硬件抽象层

        因为SPI的读写函数涉及到应用层,我们这里为了可移植性,依然采用回调的方式,结合sx1278的特性,写一个SPI驱动程序,先看下头文件定义。

        结构体内的函数在应用层都要具体定义,这样才能正常驱动,其中的片选是SPI的特征,选中后对应的模块才会回应数据,具体的应用层代码如下所示。


/*		
================================================================================
描述 : 硬件复位
输入 : 
输出 : 
================================================================================
*/
static void app_sx1278_reset(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_15);
	delay_ms(10);
	GPIO_SetBits(GPIOA, GPIO_Pin_15);
	delay_ms(10);	
}

/*		
================================================================================
描述 : 片选0
输入 : 
输出 : 
================================================================================
*/
static void app_sx1278_cs0(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

/*		
================================================================================
描述 : 片选1
输入 : 
输出 : 
================================================================================
*/
static void app_sx1278_cs1(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

/*		
================================================================================
描述 : 字节读写
输入 : 
输出 : 
================================================================================
*/
static u8 app_sx1278_spi_rw_byte(u8 byte)
{
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)==RESET);
	SPI_I2S_SendData(SPI2,byte);
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET);
	return SPI_I2S_ReceiveData(SPI2);  
}

/*		
================================================================================
描述 :应用层sx1278初始化,注册
输入 : 
输出 : 
================================================================================
*/
static void app_sx1278_hal_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
	

	//复位引脚初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//SPI初始化	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//SPI
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB,&GPIO_InitStructure);		//CS

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB,&GPIO_InitStructure);   //CLK   MOSI

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB,&GPIO_InitStructure);  //MISO

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI2,&SPI_InitStructure);

	SPI_Cmd(SPI2,ENABLE);
	
	g_sDrvSx1278.tag_hal_sx1278.sx1278_reset = app_sx1278_reset;
	g_sDrvSx1278.tag_hal_sx1278.sx1278_cs_0 = app_sx1278_cs0;
	g_sDrvSx1278.tag_hal_sx1278.sx1278_cs_1 = app_sx1278_cs1;
	g_sDrvSx1278.tag_hal_sx1278.sx1278_spi_rw_byte = app_sx1278_spi_rw_byte;
	drv_sx1278_init(&g_sDrvSx1278);//初始化

	printf("app_sx1278_hal_init ok!\n");
}

        这里使用的是硬件SPI2,最后将具体函数赋值注册到结构体内,这样底层驱动就能调用了。硬件抽象层的函数具体定义如下:

#include "hal_sx1278.h"
 
 
/*		
================================================================================
描述 :复位LORA设备
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_rst(HalSx1278Struct *psx1278) 
{
	psx1278->sx1278_reset();      
}


/*		
================================================================================
描述 : SPI字节读写
输入 : 
输出 : 
================================================================================
*/
u8 hal_sx1278_spi_rw_byte(HalSx1278Struct *psx1278, u8 byte)
{
	uint32_t dat;
	
	dat=psx1278->sx1278_spi_rw_byte(byte);
	return dat;  
}


/*		  
================================================================================
描述 : SPI写数据流
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_write_buffer(HalSx1278Struct *psx1278, u8 addr, u8 *buff, u8 size)
{
	u8 i;

	psx1278->sx1278_cs_0();//选中	  
	addr |= 0x80;
	hal_sx1278_spi_rw_byte(psx1278, addr);
	for(i=0;i<size;i++)
	{
		hal_sx1278_spi_rw_byte(psx1278, buff[i]);
	}		
	psx1278->sx1278_cs_1();//取消选择	
}

/*		
================================================================================
描述 : SPI读数据流
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_read_buffer(HalSx1278Struct *psx1278, u8 addr, u8 *buff, u8 size)
{
	u8 i;
	psx1278->sx1278_cs_0();//选中
	
	addr &= 0x7F;
	hal_sx1278_spi_rw_byte(psx1278, addr);
	for(i=0;i<size;i++)
	{
		buff[i]=hal_sx1278_spi_rw_byte(psx1278, 0);
	}	
	
	psx1278->sx1278_cs_1();//取消选择
}


/*		
================================================================================
描述 :往指定寄存器地址写入数据
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_write_addr(HalSx1278Struct *psx1278, u8 addr, u8 data)
{
	hal_sx1278_write_buffer(psx1278, addr, &data, 1);
}


/*		
================================================================================
描述 :读取指定寄存器地址的数据
输入 : 
输出 : 
================================================================================
*/
u8 hal_sx1278_read_addr(HalSx1278Struct *psx1278, u8 addr)
{
	u8 data=0;
	hal_sx1278_read_buffer(psx1278, addr, &data, 1);
	return data;  	
}

/*		
================================================================================
描述 :往LORA芯片FIFO写入数据
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_write_fifo(HalSx1278Struct *psx1278, u8 *buff, u8 size)
{
	hal_sx1278_write_buffer(psx1278, 0, buff, size);
}

/*		
================================================================================
描述 :读取LORA芯片FIFO的数据
输入 : 
输出 : 
================================================================================
*/
void hal_sx1278_read_fifo(HalSx1278Struct *psx1278, u8 *buff, u8 size)
{
	hal_sx1278_read_buffer(psx1278, 0, buff, size);
}

        这里面函数都有具体描述,SX1278驱动层要用的就是最后四个函数了,驱动SX1278本质上就是读写其寄存器的过程。

四、SX1278初始化

        先看驱动文件的头文件,RSSI_OFFSET_LF和RSSI_OFFSET_HF是计算接收强度用的,这样就能大概知道两个模块的信号质量了,从而优化通讯参数,这在组网时候很有用。接下来的版本号是固定的,如果读出来不是等于0x12就说明硬件模块有故障。剩下的频率、扩频因子、带宽和纠错编码率之前说过了,这里定义的默认值。发射功率也是可调的,在低功耗设备里有用。硬件的CRC校验一般是打开的,显式报头和隐式报头文档我截图出来了,如下所示。

具体初始化代码如下所示:

/*		
================================================================================
描述 :
输入 : 
输出 : 
================================================================================
*/
void drv_sx1278_init(DrvSx1278Struct *psx1278)
{
	hal_sx1278_rst(&psx1278->tag_hal_sx1278);//复位 
	drv_sx1278_set_on(psx1278);
	drv_sx1278_set_default_param(psx1278);
	printf("drv_sx1278b version=0x%02X\n", drv_sx1278_get_version(psx1278));
}


/*		
================================================================================
描述 :设置lora的默认参数
输入 : 
输出 : 
================================================================================
*/
void drv_sx1278_set_default_param(DrvSx1278Struct *psx1278 )
{
    hal_sx1278_write_addr( &psx1278->tag_hal_sx1278, REG_LR_LNA, RFLR_LNA_GAIN_G1);

    drv_sx1278_set_rf_freq( psx1278, LR_SET_RF_FREQ );     // 设置载波频率
    drv_sx1278_set_sf( psx1278, LR_SET_SF );      // 设置扩频因子 SF6 only operates in implicit header mode.
    drv_sx1278_set_error_coding( psx1278, LR_SET_CR );          // 设置纠错编码率
    drv_sx1278_set_packet_crc_on( psx1278, LR_SET_CRC_ON );      // CRC开关
    drv_sx1278_set_bw( psx1278, LR_SET_RF_BW );    // 设置带宽
    drv_sx1278_set_implicit_header_on( psx1278, LR_SET_IM_ON);    // 设置显式/隐式报头模式
	
    drv_sx1278_set_symb_timeout( psx1278, 0x3FF );//设置RX超时
    drv_sx1278_set_payload_length(psx1278, LR_SET_PAY_LEN);//负载字节长度
    drv_sx1278_set_lowdatarateoptimize( psx1278, true );       // 低速率优化模式,符号长度超过 16ms时必须打开

    drv_sx1278_set_pa_output( psx1278, RFLR_PACONFIG_PASELECT_PABOOST );//选择PA输出引脚
    drv_sx1278_set_rf_power( psx1278, LR_SET_RF_PWR ); 
    
		hal_sx1278_write_addr( &psx1278->tag_hal_sx1278, REG_LR_OCP, (hal_sx1278_read_addr(&psx1278->tag_hal_sx1278, REG_LR_OCP)& RFLR_OCP_TRIM_MASK) | RFLR_OCP_TRIM_180_MA );//为PA开启过流保护 180mA        

    drv_sx1278_set_op_mode( psx1278, RFLR_OPMODE_STANDBY );//进入待机模式
} 

        下面对初始化细节做介绍。

1、硬件复位,这是常规操作,必要时复位一下,可以避免模块死机。

2、drv_sx1278_set_on开启LoRa模式。

3、默认参数初始化,首先设置AGC阈值,无线领域的专业了;然后依次设置频率等参数,这里面有个设置接收超时的drv_sx1278_set_symb_timeout,函数内容挺长,核心就是设置下图红框的寄存器内容为0x3FF。

4、低速率优化和PA输出都打开,这样才能发挥出LoRa的效果,PA类似于放大器,可以增加发射功率。

5、初始化接收后就进入待机模式,其他的应用层就能操作了。

五、发送时间计算

        如果SF和BW等参数知道后,就可以计算发送某个数据包所需要的时间了,具体公式如下:

        是不是看得有点懵,懵就对了,直接上代码:


/*		
================================================================================
描述 : 
输入 : 
输出 : 
================================================================================
*/ 
static u32 bsp_pow2(u8 n)
{
    u8 i;
    u16 sum=1;
    for(i=0;i<n;i++)
        sum=sum*2;
    return sum;
}


/*		
================================================================================
描述 : 根据射频参数计算发送时间
输入 : 
输出 : 发送时间,返回0表示无效,单位:ms
================================================================================
*/ 
u32 drv_sx1278_calcu_air_time(u8 sf, u8 bw, u16 data_len)
{
	float bw_value=0.f, t_s;
	u32 tx_time=0;
	
	switch(bw)
	{
		case 0:
			bw_value=7.8;
			break;
		case 1:
			bw_value=10.4;
			break;
		case 2:
			bw_value=15.6;
			break;
		case 3:
			bw_value=20.8;
			break;
		case 4:
			bw_value=31.25;
			break;
		case 5:
			bw_value=41.6;
			break;
		case 6:
			bw_value=62.5;
			break;
		case 7:
			bw_value=125;
			break;
		case 8:
			bw_value=250;
			break;
		case 9:
			bw_value=500;
			break;
		default: return 0;	
	}
	
	if(sf<7 || sf>12)
	{
		return 0;
	}
	t_s=1.f*bsp_pow2(sf)/bw_value;
	
	int payload_nb=0;
	int k1=8*data_len-4*sf+24;
	int k2=4*(sf-2);
	
	payload_nb=k1/k2;
	if(payload_nb<0)
	{
		payload_nb=0;
	}
	else if(k1%k2>0)
	{
		payload_nb++;
	}
	
	payload_nb=payload_nb*5+8;
		
	tx_time=(u32)(payload_nb+12.5)*t_s;
	if(tx_time==0)
	{
		tx_time=1;
	}
	return tx_time;
}

        实际验证这个时间基本准确,这有什么用呢?因为发送的时候要等待,这期间我们可以先去干别的事,等差不多时间再回来检测是否发送成功,就不会浪费时间和系统资源了。

六、发送模式

        发送数据前要进行一系列操作,首先模式切换前都要先进入待机模式,然后依次是屏蔽中断、设置数据长度、设置缓冲区起始地址为0(这样256字节都能用来发送了,默认是一半发送一半接收)、写入数据、配置中断引脚,最后切换到发送模式。这里中断引脚一般没用,我们是直接查询寄存器状态的,算是保留功能吧。具体代码如下:

/*		
================================================================================
描述 :用户层Lora数据发送 
输入 : 
输出 : 
================================================================================
*/
void drv_sx1278_send(DrvSx1278Struct *psx1278, u8 *buff, u16 len)
{
	u8 RegIrqFlagsMask=0,RegFifoTxBaseAddr=0,RegDioMapping1=0,RegDioMapping2=0;
	drv_sx1278_set_op_mode( psx1278, RFLR_OPMODE_STANDBY );//待机模式
	
	printf("send start!\n");
	RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
								RFLR_IRQFLAGS_RXDONE |
								RFLR_IRQFLAGS_PAYLOADCRCERROR |
								RFLR_IRQFLAGS_VALIDHEADER |
								//RFLR_IRQFLAGS_TXDONE |
								RFLR_IRQFLAGS_CADDONE |
								RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
								RFLR_IRQFLAGS_CADDETECTED;//置位表示该位中断屏蔽

	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGSMASK, RegIrqFlagsMask );

	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_PAYLOADLENGTH, len);//设置数据长度
	
	RegFifoTxBaseAddr = 0x00; // Full buffer used for Tx
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFOTXBASEADDR, RegFifoTxBaseAddr );//设置待发送数据 写入的RAM起始地址,芯片内部有256字节RAM,要跟FIFO区别
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFOADDRPTR, RegFifoTxBaseAddr);
		   
	hal_sx1278_write_fifo(&psx1278->tag_hal_sx1278, (uint8_t*)buff, len);//向FIFO写入数据
		
									// TxDone               RxTimeout                   FhssChangeChannel          ValidHeader         
	RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_01 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_01;//将DIO_0配置成发送完成中断
									// PllLock              Mode Ready
	RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_01 | RFLR_DIOMAPPING2_DIO5_00;
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_DIOMAPPING1, RegDioMapping1 );//写入配置
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_DIOMAPPING2, RegDioMapping2 );

	drv_sx1278_set_op_mode( psx1278, RFLR_OPMODE_TRANSMITTER );//设置成发送模式
	
}


/*		
================================================================================
描述 : 发送完成检测
输入 : 
输出 : 
================================================================================
*/ 
u8 drv_sx1278_send_check(DrvSx1278Struct *psx1278)
{

	if(( hal_sx1278_read_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGS) & RFLR_IRQFLAGS_TXDONE ) == RFLR_IRQFLAGS_TXDONE)		
	{
		hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE );//一次写操作清除 IRQ	
		return true;
	}
	return false;
}

        结合发送时间计算函数,应用层的发送函数如下:

七、接收模式

        下面是接收模式的代码,流程差不多,进入待机模式、设置中断、设置缓冲区地址,最后进入连续接收模式。

/*		
================================================================================
描述 : 接收模式初始化
输入 : 
输出 : 
================================================================================
*/ 
void drv_sx1278_recv_init(DrvSx1278Struct *psx1278) 
{
	u8 RegIrqFlagsMask,RegDioMapping1,RegDioMapping2;
	
	drv_sx1278_set_op_mode( psx1278, RFLR_OPMODE_STANDBY );
	RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
								//RFLR_IRQFLAGS_RXDONE |
								//RFLR_IRQFLAGS_PAYLOADCRCERROR |
								RFLR_IRQFLAGS_VALIDHEADER |
								RFLR_IRQFLAGS_TXDONE |
								RFLR_IRQFLAGS_CADDONE |
								//RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
								RFLR_IRQFLAGS_CADDETECTED;
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGSMASK, RegIrqFlagsMask );

	RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_00;
								// CadDetected               ModeReady
	RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_00 | RFLR_DIOMAPPING2_DIO5_00;
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_DIOMAPPING1, RegDioMapping1);
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_DIOMAPPING2, RegDioMapping2);
	
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFORXBASEADDR, 0x00 );
	hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFOADDRPTR, 0x00 );   //指定接收基地址         
	drv_sx1278_set_op_mode( psx1278, RFLR_OPMODE_RECEIVER );//连续接收	
}


/*		
================================================================================
描述 : 
输入 : 
输出 : 
================================================================================
*/ 
u8 drv_sx1278_recv_check(DrvSx1278Struct *psx1278, u8 *buff)
{
	u8 RegFifoRxCurrentAddr;
	u8 RxPacketSize=0; 

	if(( hal_sx1278_read_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGS) & RFLR_IRQFLAGS_RXDONE ) == RFLR_IRQFLAGS_RXDONE)		
	{
		hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE );//一次写操作清除 IRQ	
		RegFifoRxCurrentAddr = hal_sx1278_read_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFORXCURRENTADDR );//接收到最后一个数据包的起始地址(256B的数据缓冲区中)		
		RxPacketSize = hal_sx1278_read_addr(&psx1278->tag_hal_sx1278, REG_LR_NBRXBYTES);//读取 接收到的数据字节数
		hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFOADDRPTR, RegFifoRxCurrentAddr);//设置要读取的起始地址
		hal_sx1278_read_fifo( &psx1278->tag_hal_sx1278, buff, RxPacketSize );//读取数据
		hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFORXBASEADDR, 0x00 );
		hal_sx1278_write_addr(&psx1278->tag_hal_sx1278, REG_LR_FIFOADDRPTR, 0x00 );   //指定接收基地址 
	}
	return RxPacketSize;
}

        正常来讲,模块就是在接收和发送两种模式下切换的,大部分时间是在接收检测,如果是低功耗设备的话,那大部分时间是在休眠。

        

八、总结

        SX1278的驱动层差不多就这样了,内容比较多,对于LoRa而言,这只是开始,因为更复杂的是应用层的组网协议,比如LoRaWAN,但是那个对服务器有要求,网关也是比较昂贵的,小规模组网不合适。现在也有一些公司是做LoRa自组网协议,把协议封装在带MCU的LoRa模块里,用户用AT指令或者二次开发的模式集成到自己的应用,方便用户开发LoRa产品。那我们初学者暂时不要搞那么复杂,下一篇就结合之前的modbus协议,做个简单的应用层轮询协议,带大家看看LoRa具体是怎么应用的。

        对于驱动程序,由于文件比较多,单独建立了个文件夹,所以Keil要做相应设置,头文件才能正常包含,具体如下。

代码链接:https://download.csdn.net/download/ypp240124016/89096542

本项目的交流QQ群:701889554

  • 14
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瓦力农场

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值