物联网之LoRa开发与应用四(LoRaPingPang系统设计)

深入了解LoRa技术原理

内容概要

1、LoRa扩频通信原理

2、LoRa关键技术参数

3、LoRa数据收发任务

模拟无线通信

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第1张图片

数字无线通信

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第2张图片

无线通信传播方式:地波传播(低于2MHz)、天波传播(2MHz~30MHz)、直线传播(30MHz以上)

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第3张图片

无线通信传播路径:反射、散射、衍射

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第4张图片

无线通信噪声

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第5张图片

扩频通信技术:从各种类型的噪声和多径失真中获得免疫性

扩频通信算法:C表示信号质量

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第6张图片

扩频通信原理:用户数据和扩频数据异或得到发送数据,增加了信号带宽,提高了信号质量

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第7张图片

信号带宽(BW)

增加BW,可以提高有效数据速率以缩短传输时间,但是 以牺牲部分接受灵敏度为代价。对于LoRa芯片SX127x,LoRa带宽为双边带宽(全信道带宽),而FSK调制方式的BW是指单边带宽。

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第8张图片

扩频因子(SF):原本使用1位来表示的信号变成多位来表示这个信号,提高信号的通讯质量

LoRa采用多个信息码片来代表有效负载信息的每个位,扩频信息的发送速度称为符号速率(Rs),而码片速率与标称的Rs比值即为扩频因子(SF,SpreadingFactor),表示了每个信息位发送的符号数量。

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第9张图片

编码率(CR):提高信号质量的冗余,提高数据的可靠性

编码率(或信息率)是数据流中有用部分(非冗余)的比例。也就是说,如果编码率是k/n,则对每k位有用信息,编码器总共产生n位的数据,其中n-k是多余的。

LoRa采用循环纠错编码进行前向错误检测与纠错。。使用该方式会产生传输开销。

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第10张图片

LoRa关键技术参数

LoRa符号速率Rs计算:Rs=BW/(2^SF)

LoRa数据速率DR计算:DR= SF*( BW/2^SF)*CR

LoRaWAN主要使用了125kHz信号带宽设置,但其他专用协议可以利用其他的信号带宽(BW)设置。改变BW、SF和CR也就改变了链路预算和传输时间,需要在电池寿命和距离上做个权衡。

LoRa参数设置

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第11张图片

LoRa数据发送序列

数据发送流程:(1)LoRa模块标准模式—>(2)发送模式—>(3)将数据写入发送队列—>(4)发送数据—>(5)等待发送完成(判断数据是否发送完成,如果发送完成则再次进入标准模式,如果还有数据需要发送,则进入第三步)

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第12张图片

LoRa数据接收序列

数据接收流程:

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第13张图片

Radio事件任务:(官方固件提供的事件处理的任务)

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第14张图片

LoRa固件相关代码:初始化时的参数设置 和 事件处理函数

​​sx1276-LoRa.c

// Default settings
tLoRaSettings LoRaSettings =       //设置LoRa参数
{
    870000000,        // RFFrequency
    20,               // Power
    9,                // SignalBw [0: 7.8kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,
                      // 5: 41.6 kHz, 6: 62.5 kHz, 7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]
    7,                // SpreadingFactor [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096  chips]
    2,                // ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
    true,             // CrcOn [0: OFF, 1: ON]
    false,            // ImplicitHeaderOn [0: OFF, 1: ON]
    1,                // RxSingleOn [0: Continuous, 1 Single]
    0,                // FreqHopOn [0: OFF, 1: ON]
    4,                // HopPeriod Hops every frequency hopping period symbols
    100,              // TxPacketTimeout
    100,              // RxPacketTimeout
    128,              // PayloadLength (used for implicit header mode)
};





/*!
 * \brief Process the LoRa modem Rx and Tx state machines depending on the
 *        SX1276 operating mode.
 *
 * \retval rfState Current RF state [RF_IDLE, RF_BUSY, 
 *                                   RF_RX_DONE, RF_RX_TIMEOUT,
 *                                   RF_TX_DONE, RF_TX_TIMEOUT]
 */
uint32_t SX1276LoRaProcess( void )   //事件任务处理函数,里面有多种工作模式:接收、发送等。。。
{
    uint32_t result = RF_BUSY;
    
    switch( RFLRState )
    {
    case RFLR_STATE_IDLE:
        break;
    case RFLR_STATE_RX_INIT:
        
        SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );

        SX1276LR->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;
        SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );

        if( LoRaSettings.FreqHopOn == true )
        {
            SX1276LR->RegHopPeriod = LoRaSettings.HopPeriod;

            SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
            SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
        }
        else
        {
            SX1276LR->RegHopPeriod = 255;
        }
        
        SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
                
                                    // RxDone                    RxTimeout                   FhssChangeChannel           CadDone
        SX1276LR->RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_00;
                                    // CadDetected               ModeReady
        SX1276LR->RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_00 | RFLR_DIOMAPPING2_DIO5_00;
        SX1276WriteBuffer( REG_LR_DIOMAPPING1, &SX1276LR->RegDioMapping1, 2 );
    
        if( LoRaSettings.RxSingleOn == true ) // Rx single mode
        {

            SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER_SINGLE );
        }
        else // Rx continuous mode
        {
            SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxBaseAddr;
            SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
            
            SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER );
        }
        
        memset( RFBuffer, 0, ( size_t )RF_BUFFER_SIZE );

        PacketTimeout = LoRaSettings.RxPacketTimeout;
        RxTimeoutTimer = GET_TICK_COUNT( );
        RFLRState = RFLR_STATE_RX_RUNNING;
        break;
    case RFLR_STATE_RX_RUNNING:
        
        if( DIO0 == 1 ) // RxDone
        {
            RxTimeoutTimer = GET_TICK_COUNT( );
            if( LoRaSettings.FreqHopOn == true )
            {
                SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
                SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
            }
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE  );
            RFLRState = RFLR_STATE_RX_DONE;
        }
        if( DIO2 == 1 ) // FHSS Changed Channel
        {
            RxTimeoutTimer = GET_TICK_COUNT( );
            if( LoRaSettings.FreqHopOn == true )
            {
                SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
                SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
            }
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
            // Debug
            RxGain = SX1276LoRaReadRxGain( );
        }

        if( LoRaSettings.RxSingleOn == true ) // Rx single mode
        {
            if( ( GET_TICK_COUNT( ) - RxTimeoutTimer ) > PacketTimeout )
            {
                RFLRState = RFLR_STATE_RX_TIMEOUT;
            }
        }
        break;
    case RFLR_STATE_RX_DONE:
        SX1276Read( REG_LR_IRQFLAGS, &SX1276LR->RegIrqFlags );
        if( ( SX1276LR->RegIrqFlags & RFLR_IRQFLAGS_PAYLOADCRCERROR ) == RFLR_IRQFLAGS_PAYLOADCRCERROR )
        {
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_PAYLOADCRCERROR  );
            
            if( LoRaSettings.RxSingleOn == true ) // Rx single mode
            {
                RFLRState = RFLR_STATE_RX_INIT;
            }
            else
            {
                RFLRState = RFLR_STATE_RX_RUNNING;
            }
            break;
        }
        
        {
            uint8_t rxSnrEstimate;
            SX1276Read( REG_LR_PKTSNRVALUE, &rxSnrEstimate );
            if( rxSnrEstimate & 0x80 ) // The SNR sign bit is 1
            {
                // Invert and divide by 4
                RxPacketSnrEstimate = ( ( ~rxSnrEstimate + 1 ) & 0xFF ) >> 2;
                RxPacketSnrEstimate = -RxPacketSnrEstimate;
            }
            else
            {
                // Divide by 4
                RxPacketSnrEstimate = ( rxSnrEstimate & 0xFF ) >> 2;
            }
        }
        
        SX1276Read( REG_LR_PKTRSSIVALUE, &SX1276LR->RegPktRssiValue );
    
        if( LoRaSettings.RFFrequency < 860000000 )  // LF
        {    
            if( RxPacketSnrEstimate < 0 )
            {
                RxPacketRssiValue = RSSI_OFFSET_LF + ( ( double )SX1276LR->RegPktRssiValue ) + RxPacketSnrEstimate;
            }
            else
            {
                RxPacketRssiValue = RSSI_OFFSET_LF + ( 1.0666 * ( ( double )SX1276LR->RegPktRssiValue ) );
            }
        }
        else                                        // HF
        {    
            if( RxPacketSnrEstimate < 0 )
            {
                RxPacketRssiValue = RSSI_OFFSET_HF + ( ( double )SX1276LR->RegPktRssiValue ) + RxPacketSnrEstimate;
            }
            else
            {    
                RxPacketRssiValue = RSSI_OFFSET_HF + ( 1.0666 * ( ( double )SX1276LR->RegPktRssiValue ) );
            }
        }

        if( LoRaSettings.RxSingleOn == true ) // Rx single mode
        {
            SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxBaseAddr;
            SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );

            if( LoRaSettings.ImplicitHeaderOn == true )
            {
                RxPacketSize = SX1276LR->RegPayloadLength;
                SX1276ReadFifo( RFBuffer, SX1276LR->RegPayloadLength );
            }
            else
            {
                SX1276Read( REG_LR_NBRXBYTES, &SX1276LR->RegNbRxBytes );
                RxPacketSize = SX1276LR->RegNbRxBytes;
                SX1276ReadFifo( RFBuffer, SX1276LR->RegNbRxBytes );
            }
        }
        else // Rx continuous mode
        {
            SX1276Read( REG_LR_FIFORXCURRENTADDR, &SX1276LR->RegFifoRxCurrentAddr );

            if( LoRaSettings.ImplicitHeaderOn == true )
            {
                RxPacketSize = SX1276LR->RegPayloadLength;
                SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxCurrentAddr;
                SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
                SX1276ReadFifo( RFBuffer, SX1276LR->RegPayloadLength );
            }
            else
            {
                SX1276Read( REG_LR_NBRXBYTES, &SX1276LR->RegNbRxBytes );
                RxPacketSize = SX1276LR->RegNbRxBytes;
                SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxCurrentAddr;
                SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
                SX1276ReadFifo( RFBuffer, SX1276LR->RegNbRxBytes );
            }
        }
        
        if( LoRaSettings.RxSingleOn == true ) // Rx single mode
        {
            RFLRState = RFLR_STATE_RX_INIT;
        }
        else // Rx continuous mode
        {
            RFLRState = RFLR_STATE_RX_RUNNING;
        }
        result = RF_RX_DONE;
        break;
    case RFLR_STATE_RX_TIMEOUT:
        RFLRState = RFLR_STATE_RX_INIT;
        result = RF_RX_TIMEOUT;
        break;
    case RFLR_STATE_TX_INIT:

        SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );

        if( LoRaSettings.FreqHopOn == true )
        {
            SX1276LR->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;
            SX1276LR->RegHopPeriod = LoRaSettings.HopPeriod;

            SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
            SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
        }
        else
        {
            SX1276LR->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;
            SX1276LR->RegHopPeriod = 0;
        }
        SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
        SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );

        // Initializes the payload size
        SX1276LR->RegPayloadLength = TxPacketSize;
        SX1276Write( REG_LR_PAYLOADLENGTH, SX1276LR->RegPayloadLength );
        
        SX1276LR->RegFifoTxBaseAddr = 0x00; // Full buffer used for Tx
        SX1276Write( REG_LR_FIFOTXBASEADDR, SX1276LR->RegFifoTxBaseAddr );

        SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoTxBaseAddr;
        SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
        
        // Write payload buffer to LORA modem
        SX1276WriteFifo( RFBuffer, SX1276LR->RegPayloadLength );
                                        // TxDone               RxTimeout                   FhssChangeChannel          ValidHeader         
        SX1276LR->RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_01 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_01;
                                        // PllLock              Mode Ready
        SX1276LR->RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_01 | RFLR_DIOMAPPING2_DIO5_00;
        SX1276WriteBuffer( REG_LR_DIOMAPPING1, &SX1276LR->RegDioMapping1, 2 );

        SX1276LoRaSetOpMode( RFLR_OPMODE_TRANSMITTER );

        RFLRState = RFLR_STATE_TX_RUNNING;
        break;
    case RFLR_STATE_TX_RUNNING:
        if( DIO0 == 1 ) // TxDone
        {
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE  );
            RFLRState = RFLR_STATE_TX_DONE;   
        }
        if( DIO2 == 1 ) // FHSS Changed Channel
        {
            if( LoRaSettings.FreqHopOn == true )
            {
                SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
                SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
            }
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
        }
        break;
    case RFLR_STATE_TX_DONE:
        // optimize the power consumption by switching off the transmitter as soon as the packet has been sent
        SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );

        RFLRState = RFLR_STATE_IDLE;
        result = RF_TX_DONE;
        break;
    case RFLR_STATE_CAD_INIT:    
        SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
    
        SX1276LR->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;
        SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
           
                                    // RxDone                   RxTimeout                   FhssChangeChannel           CadDone
        SX1276LR->RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_00;
                                    // CAD Detected              ModeReady
        SX1276LR->RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_00 | RFLR_DIOMAPPING2_DIO5_00;
        SX1276WriteBuffer( REG_LR_DIOMAPPING1, &SX1276LR->RegDioMapping1, 2 );
            
        SX1276LoRaSetOpMode( RFLR_OPMODE_CAD );
        RFLRState = RFLR_STATE_CAD_RUNNING;
        break;
    case RFLR_STATE_CAD_RUNNING:
        if( DIO3 == 1 ) //CAD Done interrupt
        { 
            // Clear Irq
            SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE  );
            if( DIO4 == 1 ) // CAD Detected interrupt
            {
                // Clear Irq
                SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED  );
                // CAD detected, we have a LoRa preamble
                RFLRState = RFLR_STATE_RX_INIT;
                result = RF_CHANNEL_ACTIVITY_DETECTED;
            } 
            else
            {    
                // The device goes in Standby Mode automatically    
                RFLRState = RFLR_STATE_IDLE;
                result = RF_CHANNEL_EMPTY;
            }
        }   
        break;
    
    default:
        break;
    } 
    return result;
}

 LoRaPingPong系统设计

内容概要

1、PingPong系统设计需求

2、PingPong系统通信机制

3、PingPong系统业务流程

PingPong系统设计需求

将LoRa终端定义成两种角色:Master(主机)和Slave(从机)

Master主动发送PING数据,接收PANG数据

Slave如果接收到PING数据,回应PANG数据

终端在LCD屏幕上显示终端类型及收发数据包个数

PingPong通信机制

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第15张图片

//sx1276-LoRa.c

void SX1276LoRaGetRxPacket( void *buffer, uint16_t *size )//LoRa无线数据接收
{
    *size = RxPacketSize;
    RxPacketSize = 0;
    memcpy( ( void * )buffer, ( void * )RFBuffer, ( size_t )*size );
}

void SX1276LoRaSetTxPacket( const void *buffer, uint16_t size )//LoRa无线数据发送
{
    TxPacketSize = size;
    memcpy( ( void * )RFBuffer, buffer, ( size_t )TxPacketSize ); 

    RFLRState = RFLR_STATE_TX_INIT;//状态设置为发送初始化
}
sx1276-LoRa.h

typedef enum  //LoRa的所有状态。监听和设置这些状态来实现数据的收发
{
    RFLR_STATE_IDLE,           //空闲模式
    RFLR_STATE_RX_INIT,        //接收初始化
    RFLR_STATE_RX_RUNNING,     //接收进行
    RFLR_STATE_RX_DONE,        //接收完成
    RFLR_STATE_RX_TIMEOUT,     //接收超时
    RFLR_STATE_TX_INIT,        //发送初始化
    RFLR_STATE_TX_RUNNING,     //发送进行
    RFLR_STATE_TX_DONE,        //发送完成
    RFLR_STATE_TX_TIMEOUT,     //发送超时
    RFLR_STATE_CAD_INIT,       //
    RFLR_STATE_CAD_RUNNING,
}tRFLRStates;

 PingPong业务流程-初始化

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第16张图片

PingPong业务流程-Master

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第17张图片

PingPong业务流程-Slave

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第18张图片

LoRa参数设置

// Default settings
tLoRaSettings LoRaSettings =       //设置LoRa参数
{
    870000000,        // RFFrequency
    20,               // Power
    9,                // SignalBw [0: 7.8kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,
                      // 5: 41.6 kHz, 6: 62.5 kHz, 7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]
    7,                // SpreadingFactor [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096  chips]
    2,                // ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
    true,             // CrcOn [0: OFF, 1: ON]
    false,            // ImplicitHeaderOn [0: OFF, 1: ON]
    1,                // RxSingleOn [0: Continuous, 1 Single]
    0,                // FreqHopOn [0: OFF, 1: ON]
    4,                // HopPeriod Hops every frequency hopping period symbols
    100,              // TxPacketTimeout
    100,              // RxPacketTimeout
    128,              // PayloadLength (used for implicit header mode)
};

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第19张图片

数据包结构:

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第20张图片

LoRaPingPang系统功能开发

内容概要

1、IAR工程配置

2、搭建框架

3、编码

IAR工程配置:配置两个工程:Master 和 Slave(两个工程公用一个代码,修改一个工程下的代码,所有工程代码一起改变

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第21张图片

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第22张图片

建立功能函数:建立四个函数(LCD菜单显示信息、无线收发任务处理)

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第23张图片

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第24张图片

//**********************************//
//
//函数名称:  MLCD_Show 
//
//函数描述:   主机显示任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void MLCD_Show(void)
{
  uint8_t str[20] = {0};
  //LCDgpio重新初始化
  LCD_GPIO_Init();

  sprintf((char*)str,"%d",Master_RxNumber);
  show_rx(str);////将RX数据显示到屏幕上
  memset((char*)str,0,strlen((const char*)str));


  sprintf((char*)str,"%d",Master_TxNumber);
  show_tx(str);////将TX数据显示到屏幕上

  //SPI重新初始化
  HAL_SPI_DeInit(&hspi1);
  MX_SPI1_Init();
}


//**********************************//
//
//函数名称:  SLCD_Show 
//
//函数描述:   从机显示任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:    
//*******************************//

void SLCD_Show(void)
{
  uint8_t str[20] = {0};
  //LCDgpio重新初始化
  LCD_GPIO_Init();

  sprintf((char*)str,"%d",Slave_RxNumber);
  show_rx(str);////将RX数据显示到屏幕上
  memset((char*)str,0,strlen((const char*)str));


  sprintf((char*)str,"%d",Slave_TxNumber);
  show_tx(str);////将TX数据显示到屏幕上

  //SPI重新初始化
  HAL_SPI_DeInit(&hspi1);
  MX_SPI1_Init();
}

//**********************************//
//
//函数名称:   Master_Task
//
//函数描述:   主机无线任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void Master_Task(void)//无线任务处理函数会在下面补齐,这里只是搭建了一个框架
{
  
}


//**********************************//
//
//函数名称:   Slave_Task
//
//函数描述:   从机无线任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void Slave_Task(void)//无线任务处理函数会在下面补齐,这里只是搭建了一个框架
{

}

建立数据结构:声明全部变量、进行赋值初始化

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第25张图片

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第26张图片

#define BUFFERSIZE 4

uint8_t PingMsg[] = "PING";//PING数据
uint8_t PongMsg[] = "PONG";//PONG数据

uint16_t BufferSize = BUFFERSIZE;
uint8_t Buffer[BUFFERSIZE];//接收数据缓存

#ifdef MASTER
uint8_t EnbleMaster = true;
#else
uint8_t EnbleMaster = false;
#endif

uint32_t Master_TxNumber = 0;//发送数据计数
uint32_t Master_RxNumber = 0;//接收数据计数

uint32_t Slave_TxNumber = 0;//发送数据计数
uint32_t Slave_RxNumber = 0;//接收数据计数

tRadioDriver *Radio = NULL;/*如果需要收发任务,则要获取无线收发的数据结构:
                            在main函数中调用无线收发任务函数RadioDriverInit
                           进行初始化,返回一个初始化的结构体指针*/

无线收发任务初始化函数RadioDriverInit:

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第27张图片

tRadioDriver RadioDriver;

tRadioDriver* RadioDriverInit( void )//如果需要使用无线收发任务,则需要在main函数中调用该函数进行初始化,返回一个初始化的指针
{
#if defined( USE_SX1232_RADIO )
    RadioDriver.Init = SX1232Init;
    RadioDriver.Reset = SX1232Reset;
    RadioDriver.StartRx = SX1232StartRx;
    RadioDriver.GetRxPacket = SX1232GetRxPacket;
    RadioDriver.SetTxPacket = SX1232SetTxPacket;
    RadioDriver.Process = SX1232Process;
#elif defined( USE_SX1272_RADIO )
    RadioDriver.Init = SX1272Init;
    RadioDriver.Reset = SX1272Reset;
    RadioDriver.StartRx = SX1272StartRx;
    RadioDriver.GetRxPacket = SX1272GetRxPacket;
    RadioDriver.SetTxPacket = SX1272SetTxPacket;
    RadioDriver.Process = SX1272Process;
#elif defined( USE_SX1276_RADIO )
    RadioDriver.Init = SX1276Init;
    RadioDriver.Reset = SX1276Reset;
    RadioDriver.StartRx = SX1276StartRx;
    RadioDriver.GetRxPacket = SX1276GetRxPacket;
    RadioDriver.SetTxPacket = SX1276SetTxPacket;
    RadioDriver.Process = SX1276Process;
#else
    #error "Missing define: USE_XXXXXX_RADIO (ie. USE_SX1272_RADIO)"
#endif    

    return &RadioDriver;
}

编码

功能函数编码

//上面已经对功能函数搭建好框架,现将实现代码填充进去

//**********************************//
//
//函数名称:  MLCD_Show 
//
//函数描述:   主机显示任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void MLCD_Show(void)
{
  uint8_t str[20] = {0};
  //LCDgpio重新初始化
  LCD_GPIO_Init();

  sprintf((char*)str,"%d",Master_RxNumber);
  show_rx(str);////将RX数据显示到屏幕上
  memset((char*)str,0,strlen((const char*)str));


  sprintf((char*)str,"%d",Master_TxNumber);
  show_tx(str);////将TX数据显示到屏幕上

  //SPI重新初始化
  HAL_SPI_DeInit(&hspi1);
  MX_SPI1_Init();
}


//**********************************//
//
//函数名称:  SLCD_Show 
//
//函数描述:   从机显示任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:    
//*******************************//

void SLCD_Show(void)
{
  uint8_t str[20] = {0};
  //LCDgpio重新初始化
  LCD_GPIO_Init();

  sprintf((char*)str,"%d",Slave_RxNumber);
  show_rx(str);////将RX数据显示到屏幕上
  memset((char*)str,0,strlen((const char*)str));


  sprintf((char*)str,"%d",Slave_TxNumber);
  show_tx(str);////将TX数据显示到屏幕上

  //SPI重新初始化
  HAL_SPI_DeInit(&hspi1);
  MX_SPI1_Init();
}

//**********************************//
//
//函数名称:   Master_Task
//
//函数描述:   主机无线任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void Master_Task(void)//无线任务处理函数
{
  switch(Radio->Process())//执行无线功能任务处理函数SX1276LoRaProcess,返回一个无线功能状态值,然后根据状态值做相应的处理
  {
    
    case RF_RX_DONE:
         Radio->GetRxPacket(Buffer,&BufferSize);//接收数据
         printf("Master_Task:RX_____%s\n",Buffer);//串口打印接收的数据
         if(strncmp((const char*)Buffer,(const char*)PongMsg,strlen((const char*)PongMsg)) == 0)//判断接收的是否为PONG数据
         {
          LedToggle(LED_RX);//发送指示灯翻转
          Master_RxNumber++;//发送计数
          Radio->SetTxPacket(PingMsg,strlen((const char*)PingMsg));//打开发送模式
          HAL_Delay(200);
         }
    break;
    case RF_TX_DONE:
          LedToggle(LED_TX);//接收指示灯翻转
          Master_TxNumber++;//接收计数
          Radio->StartRx();//打开接收模式
    break;
    default :
    break;
  }
}


//**********************************//
//
//函数名称:   Slave_Task
//
//函数描述:   从机无线任务
//
//函数参数:   无
//
//返回值:     无
//
//创建者:     
//*******************************//

void Slave_Task(void)//无线任务处理函数
{

  switch(Radio->Process())
  {
    
    case RF_RX_DONE:
         Radio->GetRxPacket(Buffer,&BufferSize);
         printf("Slave_Task:RX_____%s\n",Buffer);
         if(strncmp((const char*)Buffer,(const char*)PingMsg,strlen((const char*)PingMsg)) == 0)
         {
          LedToggle(LED_RX);
          Slave_RxNumber++;
          Radio->SetTxPacket(PongMsg,strlen((const char*)PongMsg));
          HAL_Delay(200);
         }
    break;
    case RF_TX_DONE:
          LedToggle(LED_TX);
          Slave_TxNumber++;
          Radio->StartRx();
    break;
    default :
    break;
  }
}

Main函数编码

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第28张图片

  Lcd_Init();//LCD初始化函数
  
  
  Lcd_Clear_xy(0,0,GREEN);
  Lcd_Clear_xy(0,45,YELLOW);
 
  Gui_DrawFont_GBK16(12, 10, RED, GREEN, "LoRa Topology");
#ifdef MASTER
  Gui_DrawFont_GBK16(40, 26, RED, GREEN, "Master");
#else
  Gui_DrawFont_GBK16(40, 30, RED, GREEN, "SLAVE");
#endif
  Gui_DrawFont_GBK16(12, 50, BLACK, YELLOW, "SSID:");
  Gui_DrawFont_GBK16(12, 77, BLACK, YELLOW, "RX:");
  Gui_DrawFont_GBK16(12, 104, BLACK, YELLOW, "TX:");
  
  show_ssid("ERROR");
  show_rx("ERROR");
  show_tx("ERROR");
  
  Lcd_WriteIndex(0x29);//Display on  打开LCD屏幕显示
  
  Radio = RadioDriverInit();//如果需要使用无线收发任务,则需要在main函数中调用该函数进行初始化,返回一个初始化的指针
  Radio->Init();//调用Radio初始化函数之后才能正确调用Radio中的其他函数
  
  #ifdef MASTER
  Radio->SetTxPacket(PingMsg,strlen((const char*)PingMsg));//如果是主机,则发送PING数据
  printf("I am Master!\n");
#else
  Radio->StartRx();//如果是从机,则设置为接收状态
  printf("I am Slave!\n");
#endif

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
    
    if(EnbleMaster == true)
    {
      MLCD_Show();
      Master_Task();
    }
    else
    {
      SLCD_Show();
      Slave_Task();
    }

  }

LoRa驱动源码修改

    1、注释掉不用的代码:

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第29张图片

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第30张图片

    2、设置LoRa参数

物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第31张图片

    3、因为LoRa无线相关函数涉及到FSK的判断,所以需要添加FSK的相关函数,否则编译不通过:

 物联网之LoRa开发与应用四(LoRaPingPang系统设计)_第32张图片

LoRaPingPong系统功能调试

内容概要

1、硬件准备

2、程序烧写

3、调试信息

硬件准备

LoRa设备X2

STlinkX1

USBmini线X2

程序烧写

选择不同的工程进行分别烧录

调试信息

串口调试信息

屏幕调试信息

 

你可能感兴趣的:(物联网之LoRa开发)