小熊派-物联网+LoRa——实现LoRa组网(2.数据接收、发送、CAD检测)

举报
ttking 发表于 2020/12/30 20:39:41 2020/12/30
【摘要】 前面我们已经完成了lora的初始化操作,已经设置了载波频率、扩频因子、带宽等信息。我们调用初始化函数,完成初始化。但是,我们还需自己设计其为接收还是发送模式。同时还需要考虑阻塞。

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检测。

但是呢,我们在前期学习的时候,只需要进行数据接收、发送验证即可,理解也简单。在附件中,各个代码均已给出,包括非阻塞接收、发送。
注意:
image.png
附件中主函数如上,其他加入了NBIoT模组(串口1)连接互联网,如果你没有NB-IoT,其注释掉NB_Task()函数哦

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。