小熊派-物联网+LoRa——实现LoRa组网(2.数据接收、发送、CAD检测)
LoRa作为低功耗广域网的一员,同NB-IoT一样在物联网的地位崇高;理论上通信距离最远可达15km,在城市中达3Km。但因为工作在非工业授权频段(而NB-IoT工作于授权频段,三大移动运营商嘛),因此为保证稳定、合理的应用,使用起来就相对复杂。本贴,将使用小熊派作为嵌入式平台,采用安信可Ra01(其内核为SX127x芯片),以SPI方式对其相应的寄存器进行读写,完成基本环境搭建。
前面我们已经完成了lora的初始化操作,已经设置了载波频率、扩频因子、带宽等信息。我们调用初始化函数,完成初始化。但是,我们还需自己设计其为接收还是发送模式。同时还需要考虑阻塞。
首先,我们要明白,LoRa中数据都存放在fifo中,需要从lora的fifo中读取数据。
从lora的fifo中读取数据
函数如下:
//写sx1278 fifo
void SX127xWriteFifo(uint8_t *buffer,uint8_t size)
{
SX1278WriteBuffer(0,buffer,size);
}
//读sx1278 fifo
void SX127xReadFifo(uint8_t *buffer,uint8_t size)
{
SX1278ReadBuffer(0,buffer,size);
}
再做适当封装
//读取fifo中接收到的数据
static void Sx127xReadRxPackage( void *buffer, uint16_t *size ){
//读取数据
uint16_t tmpReciveLength;
tmpReciveLength=Read127xReg(REG_LR_NBRXBYTES);
if(tmpReciveLength > *size){
tmpReciveLength=*size;
}else{
*size=tmpReciveLength;
}
SX127xReadFifo(buffer,tmpReciveLength);
}
普通的发送数据
发送数据我们要传入需要发送的数据、数据的长度以及数据发送超时
- 我们将lora设置为待机模式,因为睡眠模式下不能读写fifo(即不能获取发送数据)
- 打开对应的中断,这里我们至留下RFLR_IRQFLAGS_TXDONE 中断,将其余的中断屏蔽。设置为发送模式后任意读写一个寄存器就会触发发送
- 设置为发送模式
具体实现如下
uint8_t sx127xSend(uint8_t *data,uint8_t len,uint32_t tomeoutMs)
{
uint32_t systickBak = HAL_GetTick() ,currTick;
Write127xReg(REG_LR_PAYLOADLENGTH ,len); //设置负载长度
Write127xReg(REG_LR_FIFOTXBASEADDR,0);//发送buf的基地址指向0x00,此时整个fifo都可以用来发送数据
SX127xSetOpMode(LORA_OPMODE_STANDBY); //睡眠模式下不能读写fifo
SX127xWriteFifo(data,len); //需要发送的数据写入fifo
//开启中断屏蔽位(只留下了 RFLR_IRQFLAGS_TXDONE 中断没有屏蔽掉),设置为发送模式后任意读写一个寄存器就会触发发送,这里写入这个开中断正好触发
Write127xReg(REG_LR_IRQFLAGSMASK,RFLR_IRQFLAGS_RXTIMEOUT |
RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
RFLR_IRQFLAGS_CADDETECTED );
Write127xReg( REG_LR_DIOMAPPING1, ( Read127xReg( REG_LR_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_01 );//DIO0设置为TXdone中断
SX127xSetOpMode(LORA_OPMODE_TRANSMITTER); //设置为发送模式
Read127xReg(REG_LR_IRQFLAGS);//设置发送后读写任意寄存器可以开始发送
while(1){
if(1 == LoRaReadDio0())
{
Write127xReg(REG_LR_IRQFLAGS,RFLR_IRQFLAGS_TXDONE);//清除中断标志位
return 0;
}
currTick = HAL_GetTick();
//判断超时
if(currTick >= systickBak)
{
if(currTick - systickBak > tomeoutMs)
{
return 1;
}
}
else
{
if (currTick + (~systickBak) > tomeoutMs)
return 1;
}
}
}
普通的接收数据
接收数据其实和发送数据的实现大同小异。我们需要传入参数接收数据、接收数据的长度以及接收数据超时时间。
- 设置LoRa为LORA_OPMODE_STANDBY(睡眠模式下不能读写fifo)
- 我们只打开接收中断RFLR_IRQFLAGS_RXDONE,其余中断屏蔽
- 设置为连续接收模式
- 根据DIO0 DIO1的电平判断LoRa状态(空闲、发送中、发送完成...)
具体实现如下:
uint8_t sx127xRx(uint8_t *buf,uint8_t *len,uint32_t timeoutMs){
uint32_t systickBak=HAL_GetTick(),currTick;
uint8_t u8_reciveLength;
SX127xSetOpMode(LORA_OPMODE_STANDBY);
Write127xReg( REG_LR_FIFORXBASEADDR, 0 );//将接收buf的基地址指向0x00,此时整个fifo都可以用来接收数据
Write127xReg( REG_LR_FIFOADDRPTR, 0 );//将fifi读写指针执行0x00,此时向寄存器0x00读写数据指针会自增的从fifo中读取数据
Write127xReg( REG_LR_SYMBTIMEOUTLSB, 0xFF );//配置 0x1f rx超时
//配置中断
Write127xReg( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT |
//RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
RFLR_IRQFLAGS_TXDONE |
RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
RFLR_IRQFLAGS_CADDETECTED );
Write127xReg( REG_LR_DIOMAPPING1, ( Read127xReg( REG_LR_DIOMAPPING1) & RFLR_DIOMAPPING1_DIO0_MASK) | RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00);
SX127xSetOpMode(LORA_OPMODE_RECEIVER);//连续接收
Read127xReg(REG_LR_IRQFLAGS);//设置接收后读写任意寄存器可以开始接收
while(1){
if(1==LoRaReadDio0()){
Write127xReg(REG_LR_IRQFLAGS,RFLR_IRQFLAGS_RXDONE);//清除中断标志位
u8_reciveLength=Read127xReg(REG_LR_NBRXBYTES);
if(u8_reciveLength > *len){
u8_reciveLength=*len;
}else{
*len=u8_reciveLength;
}
SX127xReadFifo(buf,u8_reciveLength);
return 0;
}
if(1==LoRaReadDio0()){
Write127xReg(REG_LR_IRQFLAGS,RFLR_IRQFLAGS_RXTIMEOUT);//清除中断标志位
return 1;
}
currTick=HAL_GetTick();
if(currTick>=systickBak){
if(currTick-systickBak>timeoutMs){
return 1;
}
}else{
//currTick溢出了
if(currTick+(~systickBak)>timeoutMs){
return 1;
}
}
}
}
综上,我们调用相应的函数可以实现LoRa数据发送、数据接收。但还需考虑到,上面实现为阻塞实现。SX127x官方给出的示例代码是添加一个状态轮询函数,使用类似于使用CAD检测状态机思想,根据返回状态执行各个操作,并打开CAD检测。
但是呢,我们在前期学习的时候,只需要进行数据接收、发送验证即可,理解也简单。在附件中,各个代码均已给出,包括非阻塞接收、发送。
注意:
附件中主函数如上,其他加入了NBIoT模组(串口1)连接互联网,如果你没有NB-IoT,其注释掉NB_Task()函数哦
- 点赞
- 收藏
- 关注作者
评论(0)