LoRa节点开发:5、代码详解LoRaWAN中的几种数据包(发送与接收数据)

LoraWan OTAA OTAA即Over-The-Air Activation(空中激活),是LoRaWAN网络中的一种设备入网方法。 阅读详情
AI摘要

本文深入解析LoRaWAN规范中的数据包类型,包括入网请求、入网回复及上行、下行数据包的确认机制。通过分析LoRaNodeSDKv4.4.2源码,详细阐述了上行数据的准备、发送流程及下行数据的接收、处理过程。

本文来源微信公众号【物联网思考】

本文主要结合LoRaNode SDK v4.4.2和LoRaWAN规范1.0.3来展开。

1、数据包类型

LoRaWAN规范中有不同的数据包,通过MType字段区分,MType是3位的,总共可以表示8种不同类型的数据,其中前六种是不同的数据包,分别是“入网请求”、“入网回复”、“不需要确认上行数据包”、“需要确认上行数据包”、“不需要确认下行数据包”、“需要确认下行数据包”,后面两个一个是预留(RFU),一个开放给用户自定义(Proprietary)。
在这里插入图片描述
其中“入网请求”、“入网回复”,主要是用于OTAA入网的,在前面的LoRa节点开发——代码详解 LoRaWAN节点入网文章已经分析过了。

“不需要确认上行数据包”、“需要确认上行数据包”:主要用于用户上报数据。这里说一下不需要确认和需要确认,“需要确认”:就是发送数据后需要服务器回复一个ack,表明已经收到数据了,如果没有回复ack,那么还会重复发,一般用于紧急重要的数据上报;“不需要确认”:就是不管服务器有没有收到数据,发一次就不管了,一般用于非紧急不重要数据上报。

“不需要确认下行数据包”、“需要确认下行数据包”:主要服务器下发数据。不需要确认和需要确认同上面。服务器发送“需要确认”数据包时,需要节点回复ack给服务器。

2、源码分析

2.1上行数据
/*!
 * \brief   Prepares the payload of the frame
 */
static void PrepareTxFrame( uint8_t port )
{
    switch( port )
    {
    case 2:
        {
            AppDataSizeBackup = AppDataSize = 1;
            AppDataBuffer[0] = AppLedStateOn;
        }
        break;
    case 224:
        if( ComplianceTest.LinkCheck == true )
        {
            ComplianceTest.LinkCheck = false;
            AppDataSize = 3;
            AppDataBuffer[0] = 5;
            AppDataBuffer[1] = ComplianceTest.DemodMargin;
            AppDataBuffer[2] = ComplianceTest.NbGateways;
            ComplianceTest.State = 1;
        }
        else
        {
            switch( ComplianceTest.State )
            {
            case 4:
                ComplianceTest.State = 1;
                break;
            case 1:
                AppDataSize = 2;
                AppDataBuffer[0] = ComplianceTest.DownLinkCounter >> 8;
                AppDataBuffer[1] = ComplianceTest.DownLinkCounter;
                break;
            }
        }
        break;
    default:
        break;
    }
}

可以看到,在PrepareTxFrame这个函数中,应用只需要在AppDataBuffer中填充相应的数据以及设置数据长度AppDataSize即可。

static bool SendFrame( void )
{
    McpsReq_t mcpsReq;
    LoRaMacTxInfo_t txInfo;

    if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
    {
        // Send empty frame in order to flush MAC commands
        mcpsReq.Type = MCPS_UNCONFIRMED;
        mcpsReq.Req.Unconfirmed.fBuffer = NULL;
        mcpsReq.Req.Unconfirmed.fBufferSize = 0;
        mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
    }
    else
    {
        if( IsTxConfirmed == false )
        {
            mcpsReq.Type = MCPS_UNCONFIRMED;
            mcpsReq.Req.Unconfirmed.fPort = AppPort;
            mcpsReq.Req.Unconfirmed.fBuffer = AppDataBuffer;
            mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
        }
        else
        {
            mcpsReq.Type = MCPS_CONFIRMED;
            mcpsReq.Req.Confirmed.fPort = AppPort;
            mcpsReq.Req.Confirmed.fBuffer = AppDataBuffer;
            mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Confirmed.NbTrials = 8;
            mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
        }
    }

    // Update global variable
    AppData.MsgType = ( mcpsReq.Type == MCPS_CONFIRMED ) ? LORAMAC_HANDLER_CONFIRMED_MSG : LORAMAC_HANDLER_UNCONFIRMED_MSG;
    AppData.Port = mcpsReq.Req.Unconfirmed.fPort;
    AppData.Buffer = mcpsReq.Req.Unconfirmed.fBuffer;
    AppData.BufferSize = mcpsReq.Req.Unconfirmed.fBufferSize;

    LoRaMacStatus_t status;
    status = LoRaMacMcpsRequest( &mcpsReq );
    printf( "\r\n###### ===== MCPS-Request ==== ######\r\n" );
    printf( "STATUS      : %s\r\n", MacStatusStrings[status] );

    if( status == LORAMAC_STATUS_OK )
    {
        return false;
    }
    return true;
}

一些紧急重要数据可以发送“需要确认数据包”,从SendFrame这个函数中,可以看出需要发送“需要确认数据包”的时候,只需把IsTxConfirmed这个参数设置true即可。

应用只需设置以上3个参数即可发送,数据准备好之后,就是协议栈组包了,LoRaMacMcpsRequest( &mcpsReq )这个函数正是发送数据组包的函数,组包之后就是加密,最后就是射频发送了。

2.2下行数据

过程刚好和发送数据相反(上行数据),先是射频接收,接收到数据之后解密,用户应用数据处理。

查看static void ProcessRadioRxDone( void )函数,可以看到使用switch case语句,通过macHdr.Bits.MType字段对接收到的数据包进行了区分,FRAME_TYPE_DATA_CONFIRMED_DOWN和FRAME_TYPE_DATA_UNCONFIRMED_DOWN正是服务器的下行数据。

LoRaWAN协议栈在处理的时候,使用了设置标志位,然后回调函数的方法来处理。若有下发数据,则将 MacCtx.MacFlags.Bits.McpsInd 设置为1,如下:

            // Provide always an indication, skip the callback to the user application,
            // in case of a confirmed downlink retransmission.
            MacCtx.MacFlags.Bits.McpsInd = 1;

协议栈中,也给了英文注释,跳转到应用回调函数。

在LoRaWAN协议栈初始化的时候,注册了几个函数,然后在满足条件的时候回调。

int main( void )
{
   …………//代码过长,部分代码未截取
    macPrimitives.MacMcpsConfirm = McpsConfirm;
    macPrimitives.MacMcpsIndication = McpsIndication;
    macPrimitives.MacMlmeConfirm = MlmeConfirm;
    macPrimitives.MacMlmeIndication = MlmeIndication;
    macCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
    macCallbacks.GetTemperatureLevel = NULL;
    macCallbacks.NvmContextChange = NvmCtxMgmtEvent;
    macCallbacks.MacProcessNotify = OnMacProcessNotify;

    LoRaMacInitialization( &macPrimitives, &macCallbacks, ACTIVE_REGION );
    …………//代码过长,部分代码未截取
}

其中,MlmeIndication就是下发回调函数。

查看MlmeIndication函数,如下:

static void McpsIndication( McpsIndication_t *mcpsIndication )
{
    printf( "\r\n###### ===== MCPS-Indication ==== ######\r\n" );
    printf( "STATUS      : %s\r\n", EventInfoStatusStrings[mcpsIndication->Status] );
    if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
    {
        return;
    }

    switch( mcpsIndication->McpsIndication )
    {
        case MCPS_UNCONFIRMED:
        {
            break;
        }
        case MCPS_CONFIRMED:
        {
            break;
        }
        case MCPS_PROPRIETARY:
        {
            break;
        }
        case MCPS_MULTICAST:
        {
            break;
        }
        default:
            break;
    }

    // Check Multicast
    // Check Port
    // Check Datarate
    // Check FramePending
    if( mcpsIndication->FramePending == true )
    {
        // The server signals that it has pending data to be sent.
        // We schedule an uplink as soon as possible to flush the server.
        OnTxNextPacketTimerEvent( NULL );
    }
    // Check Buffer
    // Check BufferSize
    // Check Rssi
    // Check Snr
    // Check RxSlot

    if( ComplianceTest.Running == true )
    {
        ComplianceTest.DownLinkCounter++;
    }

    if( mcpsIndication->RxData == true )
    {
        switch( mcpsIndication->Port )
        {
        case 1: // The application LED can be controlled on port 1 or 2
        case 2:
            if( mcpsIndication->BufferSize == 1 )
            {
                AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
            }
            break;
        case 224:
            if( ComplianceTest.Running == false )
            {
                // Check compliance test enable command (i)
                if( ( mcpsIndication->BufferSize == 4 ) &&
                    ( mcpsIndication->Buffer[0] == 0x01 ) &&
                    ( mcpsIndication->Buffer[1] == 0x01 ) &&
                    ( mcpsIndication->Buffer[2] == 0x01 ) &&
                    ( mcpsIndication->Buffer[3] == 0x01 ) )
                {
                    IsTxConfirmed = false;
                    AppPort = 224;
                    AppDataSizeBackup = AppDataSize;
                    AppDataSize = 2;
                    ComplianceTest.DownLinkCounter = 0;
                    ComplianceTest.LinkCheck = false;
                    ComplianceTest.DemodMargin = 0;
                    ComplianceTest.NbGateways = 0;
                    ComplianceTest.Running = true;
                    ComplianceTest.State = 1;

                    MibRequestConfirm_t mibReq;
                    mibReq.Type = MIB_ADR;
                    mibReq.Param.AdrEnable = true;
                    LoRaMacMibSetRequestConfirm( &mibReq );

#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
                    LoRaMacTestSetDutyCycleOn( false );
#endif
                }
            }
            else
            {
                ComplianceTest.State = mcpsIndication->Buffer[0];
                switch( ComplianceTest.State )
                {
                case 0: // Check compliance test disable command (ii)
                    IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
                    AppPort = LORAWAN_APP_PORT;
                    AppDataSize = AppDataSizeBackup;
                    ComplianceTest.DownLinkCounter = 0;
                    ComplianceTest.Running = false;

                    MibRequestConfirm_t mibReq;
                    mibReq.Type = MIB_ADR;
                    mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                    LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
                    LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
                    break;
                case 1: // (iii, iv)
                    AppDataSize = 2;
                    break;
                case 2: // Enable confirmed messages (v)
                    IsTxConfirmed = true;
                    ComplianceTest.State = 1;
                    break;
                case 3:  // Disable confirmed messages (vi)
                    IsTxConfirmed = false;
                    ComplianceTest.State = 1;
                    break;
                case 4: // (vii)
                    AppDataSize = mcpsIndication->BufferSize;

                    AppDataBuffer[0] = 4;
                    for( uint8_t i = 1; i < MIN( AppDataSize, LORAWAN_APP_DATA_MAX_SIZE ); i++ )
                    {
                        AppDataBuffer[i] = mcpsIndication->Buffer[i] + 1;
                    }
                    break;
                case 5: // (viii)
                    {
                        MlmeReq_t mlmeReq;
                        mlmeReq.Type = MLME_LINK_CHECK;
                        LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
                        printf( "\r\n###### ===== MLME-Request - MLME_LINK_CHECK ==== ######\r\n" );
                        printf( "STATUS      : %s\r\n", MacStatusStrings[status] );
                    }
                    break;
                case 6: // (ix)
                    {
                        // Disable TestMode and revert back to normal operation
                        IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
                        AppPort = LORAWAN_APP_PORT;
                        AppDataSize = AppDataSizeBackup;
                        ComplianceTest.DownLinkCounter = 0;
                        ComplianceTest.Running = false;

                        MibRequestConfirm_t mibReq;
                        mibReq.Type = MIB_ADR;
                        mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                        LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
                        LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif

                        JoinNetwork( );
                    }
                    break;
                case 7: // (x)
                    {
                        if( mcpsIndication->BufferSize == 3 )
                        {
                            MlmeReq_t mlmeReq;
                            mlmeReq.Type = MLME_TXCW;
                            mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
                            LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
                            printf( "\r\n###### ===== MLME-Request - MLME_TXCW ==== ######\r\n" );
                            printf( "STATUS      : %s\r\n", MacStatusStrings[status] );
                        }
                        else if( mcpsIndication->BufferSize == 7 )
                        {
                            MlmeReq_t mlmeReq;
                            mlmeReq.Type = MLME_TXCW_1;
                            mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
                            mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100;
                            mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6];
                            LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
                            printf( "\r\n###### ===== MLME-Request - MLME_TXCW1 ==== ######\r\n" );
                            printf( "STATUS      : %s\r\n", MacStatusStrings[status] );
                        }
                        ComplianceTest.State = 1;
                    }
                    break;
                case 8: // Send DeviceTimeReq
                    {
                        MlmeReq_t mlmeReq;

                        mlmeReq.Type = MLME_DEVICE_TIME;

                        LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
                        printf( "\r\n###### ===== MLME-Request - MLME_DEVICE_TIME ==== ######\r\n" );
                        printf( "STATUS      : %s\r\n", MacStatusStrings[status] );
                    }
                    break;
                default:
                    break;
                }
            }
            break;
        default:
            break;
        }
    }

    // Switch LED 2 ON for each received downlink
    GpioWrite( &Led2, 1 );
    TimerStart( &Led2Timer );

    const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" };

    printf( "\r\n###### ===== DOWNLINK FRAME %lu ==== ######\r\n", mcpsIndication->DownLinkCounter );

    printf( "RX WINDOW   : %s\r\n", slotStrings[mcpsIndication->RxSlot] );
    
    printf( "RX PORT     : %d\r\n", mcpsIndication->Port );

    if( mcpsIndication->BufferSize != 0 )
    {
        printf( "RX DATA     : \r\n" );
        PrintHexBuffer( mcpsIndication->Buffer, mcpsIndication->BufferSize );
    }

    printf( "\r\n" );
    printf( "DATA RATE   : DR_%d\r\n", mcpsIndication->RxDatarate );
    printf( "RX RSSI     : %d\r\n", mcpsIndication->Rssi );
    printf( "RX SNR      : %d\r\n", mcpsIndication->Snr );

    printf( "\r\n" );
}

应用可以在这里获取服务器下发的数据,也可以获取到下发信号的RSSI和SNR等。

至此,如何上报数据,下发接收数据分析完成。

                                    ——————END———————

推荐阅读:
LoRa节点开发——初识SDK
LoRa节点开发——构建keil工程
LoRa节点开发——SDK整体设计思路
LoRa节点开发——SDK整体设计思路

欢迎关注公众号:“物联网思考”,获取更多开发资料、经验。
在这里插入图片描述

LoRa技术-LoRa调制解调技术 目录 1 说明 2 调制参数 2.1 扩频因子SF 2.2 编码速率CR 2.3 调制带宽BW 3 调制链路 3.1 纠错编码机 3.2 交织器 3.3 扩频序列产生器 3.4 坐标转换器和Delta-sigma调制输出 4 解调链路 1 说明 本文主要介绍LoRa扩频技术细节,详细的描述了LoRa信号从数据流变为LoRa扩频信号,再从射频信号通过解调变为数据的全过程。内容主要来自《LoRa物联网通信技术》一书,该书是由现任Semtech LoRa中国区应用技术团队... 阅读详情

相关推荐

LoRa学习<一>:基本参数和数据格式

一、与硬件相关参数 首先打开LoRa计算工具:SX1272CalculatorUI.exe,该工具主要用于分析和计算LoRa传输参数 设定,以此得出所选方案的空中速率、功耗等特征。 1.1 Spreading Factor(SF扩频因子) 根据数据semtech数据手册,SF值越大,SNR值越理想。但同样的数据量情况下,实际有效数据会减小。实际原因是数据每一位都和扩频因子相乘。例如有一个1 bit需要传送,假如扩频因子有8位 10101010, 这样乘出来每一个bit位都由一个8位的数据来表

xqw19891201的博客 4857

快速实现Lora通信(一对多)详解

某个Lora节点每隔2秒主动向中心点发送一包5字节的数据(1,2,3,4,5),Lora中心点收到后将收到的数据每个都加1,作为应答内容返回给该节点。所以当该Lora节点收到(2,3,4,5,6)时即可判定正确收到了响应。这里只演示了Lora中心点和一个Lora节点的通信,实际应用中如果中心点需要和多个Lora节点通信,那么每个Lora节点的代码可以都一样,只需将每个节点的地址(addr)改成不一样的即可。--发射功率(范围:11, 14, 17, 20dB),该值越大通信质量越高,但功耗会增加。

vvoennvv的博客 4548

LoRa、LoRaWAN及网关相关技术介绍

LoRa、LoRaWAN及网关技术介绍1. LoRa与LoRaWAN2. LoRaWAN协议定义的终端节点工作模式3. LoRaWan网络架构4. 组网方式5. 终端节点→网关:多对一时6. 终端节点→网关:一对多时7. 网关↔服务器间连接方式8. 数据上下行传输9. 终端节点加网 1. LoRa与LoRaWAN 二者对应关系如下: 1)LoRa LoRa是一种低功耗远程无线通信技术,特点是远距离、低功耗、多节点、低成本、抗扰特性,同时LoRa低速率,小数据传输。LoRa工作频段为433/470/868/

weixin_42970036的博客 6084

LoRaWan协议解析

Join Accept是作为一个普通下行帧进行下发的,唯一的区别是它使用的是JOIN_ACCEPTA_DELAY1或JOIN_ACCEPTA_DELAY2(分别代替RECEIVR_DELAY1和RECEIVR_DELAY2),但是它所使用的两个接收窗口的信道频率和数据速率和LoRaWAN地区参数文件所描述的RX1和RX2接收窗口相同。LoRaWan协议中规定了7种不同的数据包,每种数据包又有不同的字段,除了“入网请求”和“入网回复”,其它的数据包都是AES-128加密的。

weixin_47077788的博客 1506

LoRaWAN数据包分析工具

前言:LoRaWAN的射频数据包是加密的,而且有些字段是某个字节的某几位,看着不是那么直观,因此在某些情况下需要借助工具来分析数据包。 1、安装npm 这个工具是用JavaScript写的,其中用到了一些依赖库,而npm就可以一次性把这些依赖库下载下来,因此我们先要下载安装npm这个工具。 安装:sudo apt install npm 输入y,等待安装完成: 检查是否安装成功:npm -v 说明安装完成。 2、安装LoRa数据包分析工具lora-packet 安装:npm i.

freemote的博客 4629

LoRa开发|LoRaWAN节点(node)代码解析(STM32L051+SX1276/8)安信可RHF76-052

一、前言 嵌入式开发中我们要时刻保持代码的高效与整洁。目前LoRaWAN规范有两个版本V1.0.2和V1.0.3,相应的SDK也有两个:LoRaMac-node v4.0.0和LoRaMac-node v4.4.2。LoRaMac-node v4.4.2增加了classB的通信方式,但是LoRaMac-node v4.4.2的内存占用要比v4.0.0大一些,不过目前市面上买的Lo...

SunnyBit的博客 9931

LoRa及LoRaWAN简介

1、什么是LoRa和LoRaWAN 1.1 LoRa和LoRaWAN的区别 LoRa是低功耗广域网通信技术中的一种,是Semtech公司专有的一种基于扩频技术的超远距离无线传输技术。 LoRaWAN是为LoRa远距离通信网络设计的一套通讯协议和系统架构。它是一种媒体访问控制(MAC)层协议。 LoRa = PHY Layer LoRaWAN ...

倚楼听风雨的博客 4万+

【LoRaWAN_End_Node】基于LoRaWAN模组代码解析

基于lorawan模组的节点代码解析可实现lorawan节点接入标准lorawan网关。

欢迎私信、留言交流 2542

LoRaWAN介绍 - LoRa从业者读这篇就够了

这篇介绍文章是用于团队内部培训使用,对部分内容做了删减后公开发出。 本文是一篇LoRaWAN的科普介绍,你已经在朋友圈看过无数蜻蜓点水的LoRaWAN文章,是时候来一篇真正的技术干货了。

IoT小能手 11万+

LoRa实验练习2——Lorawan 基础通信实验+传感器采集和控制

对Lorawan 基础通信实验和传感器采集和控制实验的介绍

江苏学蠡信息科技有限公司是一家国家高新技术企业,与众多高校深入开展产学研合作,有一支以硕博士为主导的研发和服务团队,获得自主知识产权十余项。围绕中国高等教育人工智能及物联网专业发展规划,创新性的推出人工智能类、物联网类、嵌入式类三大学科教学产品与培训服务。 5123

将pytorch的权值矩阵量化为定点数补码并导入FPGA中

Xilinx FPGA实现LSTM算法时对ROM的初始化 将pytorch框架的权重矩阵以定点数补码的形式导入到FPGA中 文章目录Xilinx FPGA实现LSTM算法时对ROM的初始化1. pytorch框架中的LSTM2. 初始化一个RNN模型 3. 初始化ROM的coe文件格式 4. 将参数转换为补码,并且输出到coe文件 5. 配置一个ROM 6. 结论7. 代码 1. pytorch框架中的LSTM pytorch框架将LSTM算法中的八个权值矩阵连接成两个矩阵,假设要导入的LSTM网络的输

随缘分享 4527

【通信模块】LoRa与LoRaWAN简介

LoRa基本原理、LoRa网关的部署和配置、LoRa终端与LoRa网关、 LoRa上云

Thmos_vader的嵌入式学习笔记 3591

STM32驱动HC-SR04超声波模块:两种精准测距方案详解

本文详解STM32驱动HC-SR04超声波模块的两种精准测距方案:定时器中断计数法和外部中断边沿检测法。涵盖硬件连接、代码实现与优化技巧,帮助开发者根据精度和复杂度需求选择合适方案,提升超声波测距在嵌入式项目中的稳定性和准确性。

g5h6i的博客 682

资料分享 | 整理一下自己积攒的 LoRa和LoRaWan 资料

1. LoRa和LoRaWan 很多人在接触LoRa时经常会问一个问题:LoRa是什么?LoRaWAN是什么?对这两个概念迟迟不能理解。 LoRa是Long Range(长距离)的简称,是一种长距离、低功耗无线通信技术,2009年法国公司Cycleo设计出一种优异的扩频通信算法,后来,该公司被美国semtech公司收购,后者于2013年推出LoRa芯片,目前,semtech公司是LoRa芯片唯一供...

Mculover666的博客(嵌入式) 8424

半导体AMHS天车振动控制:从0.5G到超低振动的技术演进与工程实战

在先进晶圆厂中,自动化物料搬运系统(AMHS)的天车如同空中出租车,承担着晶圆盒(FOUP)在洁净室各工艺区间的转运任务。然而,当天车加减速、过弯或抓取时产生的机械振动通过轨道梁和建筑结构传递至光刻机等敏感设备,便可能直接威胁套刻精度与良率。传统被动减振方案依靠橡胶垫和弹簧,在0.5G指标时代曾行之有效,但在EUV光刻和先进制程面前已力不从心。主动振动控制技术通过传感器、控制器与作动器构成的闭环系统,在轨道吊点和机械手端实时输出反向力抵消振动,配合磁悬浮走行、轻量化结构及调度系统的路径优化,将振动从0.5G

weixin_29188043的博客 341

SVG绘制圆环进度条

在我们的大屏可视化项目中,经常会用到各种各样的图表。与传统的表格展示、枯燥的文字阐述相比,图表展示则使用户看起来更加直观、数据的展示则更加一目了然。本文基于svg绘图技术结合前端技术栈vue,以工作中常用的环形进度条为例,简单阐述一下绘制进度条的一些思路。............

qq_40289557的博客 8358

LoRaWAN协议

本篇文章详细讲解了LoRaWAN的协议栈,文章有点长,仔细看完,详细一定会对LoRaWAN有了深刻的了解!

m0_65292176的博客 6307

W5500+STM32F103C8T6进行TCP通信(modbus)

一路生花一、w5500资料二、modbus通信三、从机代码四、总结五、参考 一、w5500资料 w5500的资料就放在下面了,单纯的客户端和其他模式上面有教程 https://www.aliyundrive.com/s/enPnnZgNtpE 二、modbus通信 Modbus RTU通信时使用的数据帧结构如下图,而Moubus TCP通信的数据帧和这个稍微不一样,没有crc检验,因为tcp本就是一种可靠传输协议 这里是Modbus TCP数据帧 公共功能码定义 三、从机代码

junseven164的博客 5777

打造自己的LoRaWAN网关,进阶1:构建软件

2 步构建 LoRaWAN 网关软件系统:安装 Linux -> 编译软件

jiangjunjie_2005的专栏 1万+

Autodesk全家桶:从AutoCAD到Maya,设计师必备的7款神器全解析

本文全面解析Autodesk全家桶中的7款设计师必备软件,包括AutoCAD、Revit、Inventor、Fusion 360、Maya和3ds Max等。从二维制图到三维建模,从建筑信息模型(BIM)到影视动画制作,这些工具在工程设计、建筑可视化和数字创意领域展现出强大的协同效应。通过实战案例展示如何整合工作流,显著提升设计效率与项目质量。

weixin_29237635的博客 460

麒麟 ARMv10 SP3 安装 Oracle 19c 官方文档 或 教程

在麒麟ARMv10 SP3系统上安装Oracle 19c需要特别注意架构兼容性。

qq_43032338的博客 2936

学习笔记--浅谈LoRa与LoRaWAN

浅谈LoRa与LoRaWAN,以及LoRaWAN的网络架构。

emmmmhhg的博客 5992

django drf 框架知识点(一)——serializer序列化器_用法全解

【django drf】序列化器:别名设置,全部参数序列化,自定义字段,只读只写,部分更新

qq_59344127的博客 1338

认识LoRa以及LoRaWAN

文章目录1, 了解物联网 1, 了解物联网 话不多说,直接上图,就知道整个物联网的架构,下面的图是网上搜索来的图。 服务层:其实服务层其实是属于应用层,服务层就是用来处理从传输层传来的海量数据的。 应用层:就是交互界面,我们可以从交互界面直观的看到数据,并且可以下感知层传送控制命令。 传输层:就是用来传输数据的,我们下面的LORA 技术就是一种传输数据的射频技术。 感知层: 就是各种由各种传感器构成的,用于将环境的变量转换成二进制数据。 ...

桦桦的博客 1624

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

物联网LoRa系列-25:LoRa终端--LoRaWAN协议简介与LoRa WAN终端软件选择

前言: 从本篇文章开始: 从通信角度看,将着眼于LoRa终端与LoRa网关的通信、LoRa终端与LoRa云服务器的通信; 从协议栈上看,将从物理层上升到LoRa的MAC层, 即LoRaWAN; 从软件工程项项目来看,主要是Class A和 Class C的软件工程。 1. 软件工程文件的转型 PingPong软件工程已经不使用,必须转到Class A和 Class C的软件工程。 2. LoRa与LoRaWAN LoRa:低功耗无线通信技术 是一种低功耗远程无线通信技术, 它是由法国.

文火冰糖(王文兵)的博客 8182

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: 树莓派使用wiringPi库驱动i2c设备
下一篇: LoRa节点开发:4、代码详解 LoRaWAN节点入网
freemote
博客等级 码龄10年 1万+粉丝 196原创
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

freemote

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

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

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

打赏作者

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

抵扣说明:

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

余额充值