赞
踩
LoRa 的名字是远距离无线电(Long Range Radio),作为一种线性调频扩频的调制技术,最早由法国几位年轻人创立的一家创业公司 Cycleo 推出,2012 年 Semtech 收购了这家公司,并将这一调制技术封装到芯片中,基于 LoRa 技术开发出一整套LoRa 通信芯片解决方案,包括用于网关和终端上不同款的LoRa 芯片,开启了 LoRa 芯片产品化之路。
LoRa 是低功耗局域网无线标准,它最大特点就是在同样的功耗条件下比其他无线方式传播的距离更远,实现了低功耗和远距离的统一,它在同样的功耗下比传统的无线射频通信距离扩大 3-5 倍。在实验中使用的 LoRa 模块是安信可的 Ra01,该模组用于超长距离扩频通信,其射频芯片 SX1278主要采用 LoRa™远程调制解调器,用于超长距离扩频通信,抗干扰性强,能够最大限度降低电流消耗。借助 SEMTECH 的 LoRa™专利调制技术,SX1278 具有超过-148dBm 的高灵敏度,+20dBm 的功率输出,传输距离远,可靠性高。
Lora 数据包由三个部分组成部分:前导码、可选报头、数据有效负载:
前导码用于保持接收机与输入的数据流同步。默认情况下,数据包含有12个符号长度的前导码。前导长度是一个可以通过编程来设置的变量,所以前导码的长度可以扩展。可以将前导码寄存器长度设置在6到65536之间来改变发送前导码长度,实际发送前导码的长度范围为6+4至65535+4个符号。接收机会定期执行前导码检测。接收机的前导码长度应与发射机一致。如果前导码长度为未知或可能会发生变化,应将接收机的前导码长度设置为最大值。
根据所选择的操作模式,可以选用两种报头。在 RegModemConfig1 寄存器上,通过设定ImplicitHeaderModeOn 位选择报头类型。
显式报头模式是默认的操作模式。在这种模式下,报头包含有效负载的相关信息,包括:
报头按照最大纠错码(4/8)发送。另外,报头还包含自己的 CRC,使接收机可以丢弃无效的报头。
在特定情况下,如果有效负载长度、编码率及 CRC 为固定或已知,则比较有效的做法是通过调用隐式报头模式来缩短发送时间。这种情况下,需要手动设置无线链路两端的有效负载长度、错误编码率及CRC。
注意:如果将扩频因子 SF 设定为 6,则只能使用隐式报头模式,下面将详细解释扩频因子。
LoRa 调制解调技术(下面简称 LoRa)采用专有的调制和解调程序,将扩频调制与循环纠错编码技术结合起来,与传统的调制技术(FSK 或 OOK)相比,这种技术扩大了无线通讯链路的覆盖范围,提高了链路的鲁棒性。具有更强的抗干扰性。对同信道GMSK 干扰信号的抑制能力达到 20dB,所以 LoRa 用于频谱使用率较高的频段和混合通讯网络,方便在网络中原有的调制方案失败时扩大覆盖范围。开发人员通过调整扩频因子、调制带宽和编码率这三个关键设计参数对 LoRa 进行优化,可在链路预算、抗干扰性、频谱占用度及标称数据速率之间达到平衡。
LoRa 扩采用多个信息码片来代表有效负载信息的每个位。扩频信息的发送速度称为符号速率(Rs),而码片速率与标称符号速率之间的比值即为扩频因子,其表示每个信息位发送的符号数量。负信噪比条件下信号也能正常接收,提高了的灵敏度、链路预算及覆盖范围。但是不同扩频因子之间为正交关系,因此发送端和接收端的扩频因子必须一致。
由上表可以看出当扩频因子为 12 时在-20dB 还能收到数据包,说明扩频因子越大灵敏度越高,发送速度越慢。
LoRa 采用循环纠错编码进行前向错误检测与纠错,但会产生传输开销。每次传输产生的数据开销如下:
编码率越大前向纠错越强,链路抗干扰性越强,但是传输开销将会加大,进而加大传输时间。
由信号频谱图可以观察到一个信号所包含的频率成分。把一个信号所包含谐波的最高频率与最低频率
之差,即该信号所拥有的频率范围,定义为该信号的带宽。信号的频率变化范围越大,信号的带宽就越宽。
上表可以看出增加信号带宽,发送标称比特率越大,说明增加信号带宽可以有效提高数据速率以缩短传输时间,但会有弊端将会降低接收灵敏度,缩短传输距离。
源文件叫做 SX1276_hal.c,这个文件里包括了 LoRa 模块的硬件驱动接口,包括 SPI2 和使用到的其他 IO 口,在移植驱动的时候,只需要对这个文件修改即可。这一部分建议对着 LORA 接口电路图来看。
在这个文件的最前面,是接口引脚的宏定义,在做驱动移值的时候,这一部分是主要修改的对象:
#include "sx1276_hal.h"
#include "stm32f10x_it.h"
/*
* LoRa LoRa sx1278/76驱动
*/
#define RESET_IOPORT GPIOA
#define RESET_PIN GPIO_Pin_1
/*!
* SX1276 SPI definitions
*/
#define NSS_IOPORT GPIOB
#define NSS_PIN GPIO_Pin_12
#define SPI_INTERFACE SPI2
#define SPI_CLK RCC_APB1Periph_SPI2
#define SPI_PIN_SCK_PORT GPIOB
#define SPI_PIN_SCK_PORT_CLK RCC_APB2Periph_GPIOB
#define SPI_PIN_SCK GPIO_Pin_13
#define SPI_PIN_MISO_PORT GPIOB
#define SPI_PIN_MISO_PORT_CLK RCC_APB2Periph_GPIOB
#define SPI_PIN_MISO GPIO_Pin_14
#define SPI_PIN_MOSI_PORT GPIOB
#define SPI_PIN_MOSI_PORT_CLK RCC_APB2Periph_GPIOB
#define SPI_PIN_MOSI GPIO_Pin_15
/*!
* SX1276 DIO pins I/O definitions
*/
#define DIO0_IOPORT GPIOC
#define DIO0_PIN GPIO_Pin_4
#define DIO1_IOPORT GPIOB
#define DIO1_PIN GPIO_Pin_11
#define DIO2_IOPORT GPIOB
#define DIO2_PIN GPIO_Pin_3
#define DIO3_IOPORT GPIOB
#define DIO3_PIN GPIO_Pin_10
#define DIO4_IOPORT GPIOC
#define DIO4_PIN GPIO_Pin_3
#define DIO5_IOPORT GPIOB
#define DIO5_PIN GPIO_Pin_4
//软件延时函数,ms级别
void Soft_delay_ms(u16 time)
{
u16 i=0;
while(time--)
{
i=7950; //自己定义调试时间:20141116
while(i--) ;
}
}
//spi初始化
static void SpiInit( void )
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//
/* Enable peripheral clocks --------------------------------------------------*/
/* Enable SPIy clock and GPIO clock for SPIy */
RCC_APB2PeriphClockCmd( SPI_PIN_MISO_PORT_CLK | SPI_PIN_MOSI_PORT_CLK |
SPI_PIN_SCK_PORT_CLK, ENABLE );
RCC_APB1PeriphClockCmd( SPI_CLK, ENABLE );
/* GPIO configuration ------------------------------------------------------*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = SPI_PIN_SCK;
GPIO_Init( SPI_PIN_SCK_PORT, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = SPI_PIN_MOSI;
GPIO_Init( SPI_PIN_MOSI_PORT, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = SPI_PIN_MISO;
GPIO_Init( SPI_PIN_MISO_PORT, &GPIO_InitStructure );
//禁用JTAG
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
GPIO_PinRemapConfig( GPIO_Remap_SWJ_JTAGDisable, ENABLE );
/* SPI_INTERFACE Config -------------------------------------------------------------*/
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_8; // 72/8 MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init( SPI_INTERFACE, &SPI_InitStructure );
SPI_Cmd( SPI_INTERFACE, ENABLE );
}
//SX127x相关初始化希要设置如下内容
//SPI片选设置为输出,并初始化SPI口
//复位角初始化为输出高电平
//DI00~5为输入(暂时只用到了DIo0和DIo1,如果不用硬件超时DIo1也可以不接)
void SX1276HALInit( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// Configure SPI-->NSS as output
GPIO_InitStructure.GPIO_Pin = NSS_PIN;
GPIO_Init( NSS_IOPORT, &GPIO_InitStructure );
GPIO_WriteBit( NSS_IOPORT, NSS_PIN, Bit_SET );
SpiInit();
//配置复位引脚
GPIO_InitStructure.GPIO_Pin = RESET_PIN;
GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );
GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_SET );
// Configure radio DIO as inputs
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
// Configure DIO0
GPIO_InitStructure.GPIO_Pin = DIO0_PIN;
GPIO_Init( DIO0_IOPORT, &GPIO_InitStructure );
// Configure DIO1
GPIO_InitStructure.GPIO_Pin = DIO1_PIN;
GPIO_Init( DIO1_IOPORT, &GPIO_InitStructure );
// Configure DIO2
GPIO_InitStructure.GPIO_Pin = DIO2_PIN;
GPIO_Init( DIO2_IOPORT, &GPIO_InitStructure );
// Configure DIO3
GPIO_InitStructure.GPIO_Pin = DIO3_PIN;
GPIO_Init( DIO3_IOPORT, &GPIO_InitStructure );
// Configure DIO4
GPIO_InitStructure.GPIO_Pin = DIO4_PIN;
GPIO_Init( DIO4_IOPORT, &GPIO_InitStructure );
// Configure DIO5
GPIO_InitStructure.GPIO_Pin = DIO5_PIN;
GPIO_Init( DIO5_IOPORT, &GPIO_InitStructure );
}
//spi发送和接收函数
uint8_t SpiInOut( uint8_t outData )
{
/* Send SPIy data */
SPI_I2S_SendData( SPI_INTERFACE, outData );
while( SPI_I2S_GetFlagStatus( SPI_INTERFACE, SPI_I2S_FLAG_RXNE ) == RESET );
return SPI_I2S_ReceiveData( SPI_INTERFACE );
}
//spi片选,status=0使能(NSs拉低)status=1失能(NSs拉高)
void SpiNSSEnable( uint8_t status )
{
GPIO_WriteBit( NSS_IOPORT, NSS_PIN, status );
}
void SX1276Write( uint8_t addr, uint8_t data )
{
SX1276WriteBuffer( addr, &data, 1 );
}
void SX1276Read( uint8_t addr, uint8_t *data )
{
SX1276ReadBuffer( addr, data, 1 );
}
void SX1276ReadBuffer(uint8_t addr,uint8_t *buffer,uint8_t size)
{
uint8_t i;
//NSS = 0;
SpiNSSEnable(0); //片选spi1
SpiInOut(addr & 0x7F );
for( i = 0; i < size; i++ )
{
buffer[i] = SpiInOut(0x00);//读取数据
}
//NSS = 1;
SpiNSSEnable(1);
}
void SX1276WriteBuffer(uint8_t addr,uint8_t *buffer,uint8_t size)
{
uint8_t i;
//NSS = 0;
SpiNSSEnable(0);
SpiInOut(addr | 0x80 );
for( i = 0; i < size; i++ )
{
SpiInOut(buffer[i]);//写入数据
}
//NSS = 1;
SpiNSSEnable(1);
}
void SX1276WriteFifo( uint8_t *buffer, uint8_t size )
{
SX1276WriteBuffer( 0, buffer, size );
}
void SX1276ReadFifo( uint8_t *buffer, uint8_t size )
{
SX1276ReadBuffer( 0, buffer, size );
}
void SX1276SetReset( uint8_t state )
{
GPIO_InitTypeDef GPIO_InitStructure;
if( state == RADIO_RESET_ON )
{
// Configure RESET as output
GPIO_InitStructure.GPIO_Pin = RESET_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );
// Set RESET pin to 0
GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_RESET );
}
else
{
GPIO_InitStructure.GPIO_Pin = RESET_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );
// Set RESET pin to 1
GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_SET );
}
}
//读取DTo0电平,返回值0低电平,1高电平
uint8_t SX1276ReadDio0(void){
return GPIO_ReadInputDataBit( DIO0_IOPORT, DIO0_PIN );
}
//读取DTo1电平,返回值0低电平,1高电平
uint8_t SX1276ReadDio1(void){
return GPIO_ReadInputDataBit( DIO1_IOPORT, DIO1_PIN );
}
uint8_t SX1276ReadDio2(void){
return 0;//GPIO_ReadInputDataBit( DIO2_IOPORT, DIO2_PIN );
}
uint8_t SX1276ReadDio3(void){
return GPIO_ReadInputDataBit( DIO3_IOPORT, DIO3_PIN );
}
uint8_t SX1276ReadDio4(void){
return GPIO_ReadInputDataBit( DIO4_IOPORT, DIO4_PIN );
}
uint8_t SX1276ReadDio5(void){
return ;//GPIO_ReadInputDataBit( DIO5_IOPORT, DIO5_PIN );
}
在头文件sx1276-LoRa.h里,定义有这么一个结构体tLoRaSettings,这个结构就是第三部介绍的LoRa的参数缩影,定义如下:
通过这个结构体定义的变量我们就可以初始化LoRa模块,在源文件sx1276-LoRa.c里,是这样初始化的:
也就是模块工作在 450MHz,功率是 20dB,带宽是 500kHz,扩频因子是 128,前导码长度是 10 个字节,CRC 校验是打开的等,在两个通信模块之间,这些参考必须一致,才能保证通信。
从上图可以看出,LoRa 发送前一直处于待机状态,在初始化 Tx 模块后,将待发送数据(Payload)写
入 FIFO,然后切换到发送状态将数据通过 LoRa 调制成信号发送出去,等到发送完成后,会产生 TxDone 中断,同时再次切换为待机状态,完成一个发送流程。
当发送完成后,根据设计要求,可以是发送状态,也可以是新的接收状态。
LoRa 接收有两种模式:单一接收和连续接收:
在这种模式下,调制解调器在给定的时间窗口内搜索前导码。如果在该时间窗口结束时还未找到前导码,则芯片会产生RxTimeout中断信号并切换回待机模式。时间窗口长度(以符号计)由RegSymbTimeout寄存器定义,必须为4(调制解调器获取前导码锁的最短时间)到1023个符号。缺省值为5。如果在时间窗口内未发现前导码,则会产生RxTimeout中断信号,同时芯片切换回待机模式。
在有效负载结束时,如果负载CRC无效,则会产生RxDone中断信号及PayloadCrcError中断信号。然而,即使CRC无效,仍然可以在FIFO数据缓存中写入数据,以便后续进行处理。
RxDone中断产生后,芯片切换回待机模式。当RxDone或RxTimeout中断信号产生时,调制解调器也会自动回到待机模式。 因此,只有在数据包到达时间窗口为已知的情况下才会使用RX单一接收模式 。而在其他情况下,应使用X连续模式。
在连续接收模式下,调制解调器会持续扫描信道,以搜索前导码。每当检测到前导码时,调制解调器都会在收到数据包前对该前导码进行检测及跟踪,然后继续等待检测下一前导码。如果前导码长度超过寄存器RegPreambleMsb和RegPreambleLsb设定的预计值(按照符号周期测量),则前导码会被丢弃,并重新开始前导码搜索。但在这种场景不会产生中断标志。与单一 Rx 模式相反,在连续 Rx 模式下,当产生超时中断时,设备不会进入待机模式。这时,用户必须在设备继续等待有效前导码的同时直接清除中断信号。
在实验里,基本上都是使用连接接收模式。
LoRa 使用信道检测器来检测其他 LoRa 信号,流程如下图:
信道活动检测模式在以尽可能高的功耗效率检测无线信道上的 LoRa 前导码,当检测到前导码的存在,
就进入接收模块。
在前面的介绍中 CAD,TX,RX 都有操作完成中断,例如 CadDone 中断,TxDone 中断,RxDone 中断这些中断的配置与 RegDioMapping1 和 RegDioMapping2 这两个寄存器有关,DIO0 到 DIO3 引脚映射RegDioMapping1,DIO4 到 DIO5 引脚映射 RegDioMapping2,具体见下表所示:
在源文件 sx1276-LoRa.h里,有一个处理函数 uint32_t SX1276LoRaProcess( void),在这个函数里根
据当前 LoRa 的状态(发送、接收或者 CAD 检测)决定进行不同的处理。
LoRa 的状态有以下几种:
LoRa 对外接口 API 定义,操作 LoRa 的时候,只需要使用这些 API 即可。定义在 radio.h文件里:
在 radio.c 里,定义了 tRadioDriver RadioDriver 这样的一个变量,应用层就是对这个变量的操作,以下是对它赋值代码
首先看初始化部分,以下是它的代码:
第 49 行:首先取出操作 LoRa 的函数指针保存在 radio 里。
第 50 行:对 LoRa 初始化。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。