LoRa点对点系统8 测试

1 测试环境1.1 测试工具PC机2台;锐米LoRa终端2个;USB转串口套件2个;锐米LoRa终端评估软件;1.2 搭建平台如下图所示,2个LoRa终端,分别通过USB转UART连接2台PC,终端之间通过LoRa无线通信。这样一来,PC#i发送的数据,PC#j能远程接收;反之,亦然。2 集成测试2.1 测试目的将LoRa终端和PC评估软件联合测试,使它们能够正常运行。2.2 测试内容
步骤方法结果
使用PC评估软件,遍历测试LoRa终端的接口协议;
发送RF数据包,Comm2Trm和Network进程正常工作;
接收RF数据包,Comm2Trm和Network进程正常工作;
设置参数,2个进程和SystSettings模块正常工作;
3 功能测试3.1 测试目的功能测试指按产品说明书,逐项测试列举的功能。3.2 测试内容
测试对象测试内容测试结果
读取软件版本使用PC评估软件,读取LoRa终端的软件版本
发送数据发送字节从1到247,都能够正确发送
配置射频参数...
了解详情

LoRa点对点系统7 剖析核心代码

1 引言在LoRa点对点系统中,核心是Network进程的处理代码,它除了响应用户发送无线数据包外,还需要驱动射频和响应多种中断信号。为此,我们列出该进程的逻辑,并且剖析它的代码。2 核心代码逻辑有2个特别注意的地方:1. 如果RF_Rx_Error,需要重新启动RF接收功能,以避免引发宕机错误;2. RF缓冲区中有多个数据包时,给自身发poll消息,让其他进程有机会运行。3 剖析核心代码PROCESS_THREAD(NetworkProcess, ev, data){/*ATTENTION: stack variables can NOT cross any “XX_YIELD()”. */uint8_t    byDataSize;uint16_t    wCalcCRC16;uint16_t    wSrcCRC16;PROCESS_BEGIN();SX1278Receive(0);while(TRUE){PROCESS_YIELD();if (NETWORK_EVENT_TX_RF_PACKAGE == ev)                                                      1{/* Make RF package as well as TX it. */wCalcCRC16= util_CRC16( s_stTxRFPackage.a_byBuf,s_stTxRFPackage.byRFTxSize );*(uint16_t *)&s_stTxRFPackage.a_byBuf[s_stTxRFPackage.byRFTxSize] =wCalcCRC16;SX1278SetSleep();                                                                                                       2SX1278Send( s_stTxRFPackage.a_byBuf,s_stTxRFPackage.byRFTxSize +sizeof(uint16_t));                               3/* Waiting until TX is done. */PROCESS_YIELD_UNTIL( RF_Tx_Done == s_tRFResult ||RF_Tx_Timeout ==s_tRFResult );                                  4/* Enable RF_RX. */SX1278Receive(0);                                                                                                       5}else                                                                                                                                6{if (RF_Rx_Error == s_tRFResult){/*EXPLAIN: Restore the RX of RFif Rx-Error or frame is NOT integrity. */SX1278SetSleep();                                                                                                     7SX1278Receive(0);}/* EXPLAIN: process all received packets for simplicity. */if (!IsRadioBufEmpty()){/* Fetch data from RF buffer, CheckCRC16. */s_stParseRFBuf.bySize = GetRadioBuf(s_stParseRFBuf.a_byBuf,RF_FIFO_SIZE); 8if (sizeof(uint16_t) < s_stParseRFBuf.bySize){byDataSize = s_stParseRFBuf.bySize – sizeof(uint16_t);wSrcCRC16 = *(uint16_t *)&s_stParseRFBuf.a_byBuf[byDataSize];wCalcCRC16 = util_CRC16(s_stParseRFBuf.a_byBuf, byDataSize);if (wSrcCRC16 == wCalcCRC16)                                                                             9{/* Deliver data to Comm2Trm-Process */comm2trm_RxRFPackage(s_stParseRFBuf.a_byBuf, byDataSize);                     10}else{/*EXPLAIN: Restore the RX of RF if Rx-Error orframe is NOT integrity. */SX1278SetSleep();                                                                                                11SX1278Receive(0);}}/*if*//* Check whether some packages still stay in buffer. */if (!IsRadioBufEmpty())                                                                                               12{/* Don’t disturb the scheduling ofother processes. */process_poll(&NetworkProcess);}}/*if (!IsRadioBufEmpty())*/}}/*while(TRUE)*/PROCESS_END();}Line#1:用户需要发送RF数据包;Line#2:将处于持续接收的RF设置休眠状态;Line#3:通过SX1278发送该RF数据包;Line#4:阻塞进程,直到RF发送数据包完毕;Line#5:将RF切换到持续接收模式;Line#6:射频中断服务程序发来消息:接收到数据包,或,接收错误;Line#7:RF接收出错,重新启动RF接收功能,避免宕机错误;Line#8:从RF缓冲区复制数据包到解析工作区;Line#9:检查接收数据包的CRC16是否正确;Line#10:交付接收数据给Comm2Trm进程;Line#11:如果数据包的CRC16错误,重新启动RF接收功能,避免宕机错误;Line#12:如果RF缓冲区还有数据包,给自身发poll消息,允许Contiki调度其他进程运行。了解详情

LoRa点对点系统6 源代码结构

1 源代码结构main.c      基于C语言系统的入口函数main.h      系统的全局配置文件Application  应用程序,以Contiki系统的protothread方式组织Contiki      Contiki操作系统Driver       驱动:ST官方驱动库和MCU外设驱动文件Project      IAR环境下所有工程文档RF         SX1278射频芯片驱动代码2 使用源代码在源代码文件main.h中,有如下宏编译语句:#define CUR_PRODUCT    iWL882A#define REL_VER    1 /* 0=debug; 1=release */#define CUR_VER    “LoRaP2PTW V1.0.00 2016-10-20” /*current version */它们代表如下含义:CUR_PRODUCT:当前LoRa终端的硬件版本号,目前出厂为iWL882A;REL_VER:0=debug版本,串口支持shell命令;1=release版本,串口与评估软件通信;CUR_VER:软件版本号,其中“LoRaP2PTW”不能更改,因为评估软件依赖该版本编号来识别产品种类;3  Main入口函数void main(void){/* Initialize hardware */chip_Init();                                                                                                   1SX1278InitPins();                                                                                        2rtimer_init();                                                                                                 3ss_Init();                                                                                                       4cpc_Init();                                                                                                        5#if (!REL_VER)dp_Init();                                                                                                      6#endif/* EXPLAIN: enable INT before initialize process! */HAL_ENABLE_INTERRUPTS();                                                                 7/*Initialize contiki system */process_init();                                                                                              8/* Start process of user */comm2trm_Init();                                                                                          9network_Init();                                                                                            10#if (!REL_VER)monitor_Init();                                                                                             11#endifwhile (1){while (0 < process_run())                                                                       12{null();                                                                                                  13}/* EXPLAIN: Set MCU to low power mode if have nothing to do. */wfi();                                                                                                       14}}Line#1:初始化MCU时钟和引脚等;Line#2:初始化连接SX1278的SPI总线和中断控制线;Line#3:初始化rtimer(高精度实时时钟);Line#4:初始化SystSettings(系统参数)模块;Line#5:初始化通信串口,它连接PC;Line#6:如果是Debug版本,初始化调试串口;Line#7:使能MCU硬件中断;Line#8:初始化Contiki的进程模块;Line#9:初始化comm2trm模块,同时启动comm2trm进程;Line#10:初始化network模块,同时启动network进程;Line#11:如果是Debug版本,初始化monitor模块,同时启动monitor进程;Line#12:Contiki主循环函数,根据post和poll消息,调用对应的进程;Line#13:空语句,为代码可读性而添加;Line#14:节能指令,如果MCU空闲则进入WFI模式,可以被任意中断唤醒。了解详情

LoRa点对点系统5 数据结构与算法

1 Comm2Trm进程1.1处理UART数据帧为节省内存,接收与处理UART数据“复用”了缓冲区,如下图所示:UART驱动:#1:一个接一个将接收的UART数据存储到缓冲区;#2:接收一完整UART帧后,发消息给进程通知处理;Comm2Trm进程:#3:给缓冲区加锁,解析UAR帧;#4:组织UART回应帧;#5:通过UART发送回应帧,给缓冲区解锁。为什么要给缓冲区加锁和解锁呢?如下图的时序逻辑所示:进程“锁定”缓冲区期间UART驱动无法向缓冲区中写数据,因此也不会“竞态打扰”进程处理该数据帧。1.2 发送RF数据包#1:UART一个接一个输入数据到缓冲区COMM_TRM_DATA;#2:当接收一完整帧结束后,UART_ISR给进程poll消息;#3:进程解析和处理该UART数据帧;#4:进程拷贝用户数据到缓冲区TxDataBuf;#5:Network进程从缓冲区TxDataBuf提取数据,通过RF发送。1.3 接收RF数据包#1:Network进程存储接收数据到缓冲区RxDataBuf;#2:Network进程post消息给Comm2Trm进程;#3:Comm2Trm进程组织该数据为UART帧;#4:进程通过UART口发送该数据帧。2 Network进程2.1发送RF数据包#1:从Comm2Trm进程提取发送数据到packetbuf;#2:基于packetbuf组织RF数据包;#3:通过RF发送packetbuf中的RF数据包;2.2接收RF数据包#1:RF接收的数据包存入RadioBuf,并poll进程;#2:进程从RadioBuf拷贝数据包到ParseRFBuf;#3:进程解析该RF数据包;#4:提取用户数据,交付给Comm2Trm进程;2.3 逻辑流程3 SystSettings模块为简化设计,定义了NetSettings_t数据结构,它的“主本”存储在SystSettings模块的EEPROM中,Comm2Trm和Network这2个进程各自拥有一个“副本”。1.上电时,Comm2Trm和Network这2个进程各自从“主本”拷贝“副本”;2.任意一方修改“NetSettings_t”的副本数据,必须:①存储到“主本”之中;②通知“另一方”同步更新副本数据。了解详情

LoRa点对点系统4 进程通信

1 Comm2Trm进程1.1 接收RF数据包,发送给PCt0时刻:Network进程通知Comm2Trm进程(简称进程),接收到RF数据;t1时刻:进程封装数据为UART帧,通过UART端口发送;t2时刻:UART端口启动发送;t3时刻:UART发送完毕,ISR执行扫尾工作(清除硬件中标标识等);1.2 接收PC数据帧,通过RF发送t4时刻:UART接收到来自PC的UART数据帧,poll进程;t5时刻:进程提取UART帧中用户数据,通知Network进程;t6时刻:Network进程通过RF发送该数据帧。2 Network进程2.1 接收PC数据帧,通过RF发送t0时刻:Comm2Trm进程通知Network进程(简称进程),接收到UART数据;t1时刻:进程封装数据为RF包,通过RF端口发送,阻塞自身;t2时刻:RF启动发送;t3时刻:RF发送完毕,ISR执行扫尾工作,通知进程;t4时刻:进程恢复运行,切换RF到RF模式;2.2 接收RF数据包,发送给PC接收RF数据包,发送给PC。t5时刻:RF接收到数据包,poll进程;t6时刻:进程处理该RF数据包,通知Comm2Trm进程;t7时刻:Comm2Trm进程了解详情

LoRa点对点系统3 与PC接口

1 通信介质UART口:115200波特率、8位数据位、1位停止位、无校验。2 通信模式设置和读取参数遵循主从方式,PC为主,Node为从。通信由PC发起,Node根据相应的命令进行响应,如下图所示。当Node接收唤醒通信数据帧时,它以“异步方式”发送给PC,如下图所示。3 通信帧格式PC与Node通信帧采用变长格式,如下图所示。大部分设备可以很好地处理以“回车符”结尾的数据帧,因此协议中的Tail等于0x0D(换行符)。4 通信帧种类没有额外说明,数据格式均为“大端”,即:4字节整数0x12345678在内存中(自低向高)存储顺序为:0x12、0x34、0x56、0x78。
帧含义Typ数据域实例
字节数据解释
读取软件版本(PC->No0x0
回应软件版本(Node->0x8软件版本号(字符串,以’\0’结尾2“LoRaP2P V1.0.0 16-10-20”
发送数据(PC->No0x0实际发送数据,最大字节=24数据帧(十六进制):12 34发送2字节数据:...
了解详情

LoRa点对点系统2 软件模块划分

1 任务逻辑图如下图所示,软件系统包括2个进程:Network和Comm2Trm,它们分别控制LoRa射频和UART口,数据模块SystemSettings用于保存系统参数。2 数据流图2.1 发送数据#1:PC将用户数据帧通过UART交付给LoRa终端;#2:Comm2Trm进程接收该UART数据帧;#3:Comm2Trm进程抽取用户数据,通知Network进程发送;#4:Network进程封装用户数据为RF数据包,通过LoRa射频发送。2.2 接收数据#1:LoRa射频接收RF数据包,通知Network进程处理;#2:Network进程提取用户数据,通知Comm2Trm进程;#3:Comm2Trm进程将用户数据封装成UART帧,并通过UART发送;#4:PC接收UART帧,打印用户数据。2.3 设置参数#1:PC将参数帧通过UART交付给LoRa终端;#2:Comm2Trm进程接收该UART参数帧;#3:Comm2Trm进程提取参数,写入SystemSettings;#4:Comm2Trm进程通知Network进程更新参数。了解详情

LoRa点对点系统1 需求分析

1 引入为更进一步了解LoRa终端和Contiki系统,我们设计一个P2P(Point to Point)系统。虽然该系统简单,我们还是采用软件工程的方法来实现,借此展示一个嵌入式产品的开发过程。2 连接设备如下图所示,2个LoRa终端,分别通过USB转UART连接2台PC,终端之间通过LoRa无线通信。这样一来,PC#i发送的数据,PC#j能远程接收;反之,亦然。当然,这2个终端也可以连接到同一台PC,只是不能体现LoRa远距离通信的功能。3 通信时序这4个设备的一次通信时序如下图所示:#1:PC#i接收用户数据;#2:PC#i将用户数据封装成UART帧#i,并交付给LoRa终端#i;#3:LoRa终端#i抽取用户数据,封装成RF数据包#i,通过LoRa射频发送;#4:LoRa终端#j接收到RF数据包#i,抽取用户数据,封装成UART帧#i;#5:LoRa终端#j将UART帧#i交付给PC#j。#6:PC#j打印用户数据。了解详情

LoRa开发8: 下载源代码

1 源代码下载地址源代码可以从以下链接下载http://download.csdn.net/detail/jiangjunjie_2005/96571612 开发环境与工具硬件平台:锐米LoRa终端http://www.rimelink.com/pd.jsp?id=2测试套件:USB转串口 + LoRa终端转接板https://shop140974727.taobao.com/?spm=2013.1.1000126.d21.DL6hVR仿真器:  ST LINK V2https://item.taobao.com/item.htm?spm=2013.1.20141002.4.Sj743Y&scm=1007.10009.31621.100200300000004&id=540446816750&pvid=8a31520e-d2bd-4a21-b940-aa421c82d92dIDE环境:IAR for STM8  http://www.rimelink.com/nd.jsp?id=33&_np=105_3153 编译对应的进程void main(void){//   process_start(&TxRandData, NULL);//   process_start(&RxPrintSNRRSSI, NULL);process_start(&PingPong, NULL);}在源代码main.c中,屏蔽不需要的进程,仅允许编译一个进程,即可将LoRa终端设置成对应的系统。如上例所示,编译了PingPong进程。4 源代码结构main.c        基于C语言系统的入口函数main.h        系统的全局配置文件Application  应用程序,以Contiki系统的protothread方式组织Contiki        Contiki操作系统Driver         驱动:ST官方驱动库和MCU外设驱动文件Project        IAR环境下所有工程文档RF              SX1278射频芯片驱动代码了解详情

LoRa开发7:PingPong系统

1 引言前2章介绍了SX1278的发送和接收,在此基础上,我们设计一个有趣的PingPong系统,更好地理解LoRa终端的收发逻辑。该系统将LoRa终端自动定义成2种角色:master和slave。master主动发送ping数据帧,接收pong数据帧;slave如果接收到ping数据帧,回应pong数据帧。2 整体逻辑流程如上图所示,当LoRa终端上电后,在(2 * PingPongPeriod)周期内没有接收到ping数据帧,它就认为自己是master。Master节点每隔(1 * PingPongPeriod)周期主动发送ping数据帧,然后启动RF接收,可能接收到pong回应帧(正常通信),也可能接收超时(slave没有上电或通信失败)。同理,当LoRa终端上电后,在(2 * PingPongPeriod)周期内接收到ping数据帧,它就认为自己是slave。Slave节点启动RF接收,如果接收到ping数据帧,它将发送pong回应帧。一个节点从上电,判断自身角色,根据角色处理逻辑,如下流程图所示。3 代码剖析PROCESS_THREAD(PingPong, ev, data){#definePING    “ping, this is MASTER ofrime node.”#definePONG    “pong, this is SLAVE of rimenode.”#definePING_SIZE    34#definePONG_SIZE    33staticbool    s_bIsMaster;staticuint16_t    s_wPingPongPeriod;staticint32_t    s_lTxCnt = 0;staticint32_t    s_lRxCnt = 0;PROCESS_BEGIN();InitSetLoRa();s_wPingPongPeriod =SX1278GetTimeOnAir(4) + SX1278GetTimeOnAir(4) + 15;                   1/*Determine MASTER or SLAVE by RX “ping”. */SX1278Receive(2 * s_wPingPongPeriod);                                              2PROCESS_YIELD(); /* Yield until receive or timeout. */                          3SX1278SetSleep(); /* MUST stop RxContinuous mode manually. */       4if(GetCompareRxFrame(PING, PING_SIZE))                                           5{s_bIsMaster = FALSE;}else{s_bIsMaster = TRUE;}if(s_bIsMaster) /* Is MASTER */{while (1){/* TX “ping” */++s_lTxCnt;SX1278Send(PING, PING_SIZE);                                                          6PROCESS_YIELD_UNTIL( (RF_Tx_Done == s_tRFResult) ||(RF_Tx_Timeout ==s_tRFResult) );          7/* RX “pong” */SX1278Receive(s_wPingPongPeriod);                                                  8PROCESS_YIELD(); /* Yield until receive a frame or timeout. */SX1278SetSleep(); /* MUST stop RxContinuous mode manually. */if (GetCompareRxFrame(PONG, PONG_SIZE))                                    9{++s_lRxCnt;RIME_DBG( RIME_DBG_ON,“TxCnt=%ld, Rx Cnt=%ld, SNR=%d, RSSI=%d.\r\n”,s_lTxCnt, s_lRxCnt, s_chPacketSnr,s_nPacketRssi );   10}}}else /* Is SLAVE */{while (1){/* RX “ping” */SX1278Receive(0);                                                                                  11PROCESS_YIELD(); /* Yield until receive a frame or rx error. */SX1278SetSleep(); /* MUST stop RxContinuous mode manually. */if (GetCompareRxFrame(PING, PING_SIZE))                                          12{/* TX “pong” */++s_lTxCnt;SX1278Send(PONG, PONG_SIZE);                                                      13PROCESS_YIELD_UNTIL( (RF_Tx_Done ==s_tRFResult) ||(RF_Tx_Timeout == s_tRFResult) );         14++s_lRxCnt;RIME_DBG( RIME_DBG_ON,“Tx Cnt=%ld, RxCnt=%ld, SNR=%d, RSSI=%d.\r\n”,s_lTxCnt, s_lRxCnt,s_chPacketSnr, s_nPacketRssi );}}}PROCESS_END();}Line#1:计算PingPong通信空中时间,添加15ms做为收发准备时间;Line#2:启动接收功能,超时时长为2倍PingPong通信空中时间;Line#3:阻塞进程,直到接收数据帧或超时;Line#4:设置SX1278为休眠,否则它将处于持续接收状态(那怕超时亦如此);Line#5:GetCompareRxFrame()复制数据帧到解析工作区,比较是否为ping帧;Master节点逻辑Line#6:master节点发送ping数据帧;Line#7:阻塞进程,直到发送ping数据帧完毕;Line#8:启动接收功能,超时时长为PingPong通信空中时间;Line#9:比较是否为pong回应帧;Line#10:打印发送和接收数据帧个数,SNR和RSSI值;Slave节点逻辑Line#11:启动持续接收功能,为0表明关闭超时功能;Line#12:比较是否为ping数据帧;Line#13:slave节点发送pong回应帧;Line#14:阻塞进程,直到发送pong回应帧完毕;了解详情

LoRa开发6:接收数据帧

1 引言接收LoRa数据帧比发送稍复杂一些,接收是一个异步动作—-不知道下一帧什么时候到来;因为干扰或信号微弱等,接收可能会出错;甚至,当多次接收错误后,RF可能会宕机—-再也无法接收任何数据帧。本章,我们继续基于Contiki和SX1278,开发接收数据帧的代码。2 整体逻辑流程接收数据帧的整体逻辑流程如下所示,特别注意的是,添加了处理异常的代码:如果RF接收错误(硬件自检payloadcrc16失败)或数据帧错误(用户CRC16失败),进程会重启动RF的接收,以防止陷入宕机(根据我们多年的经验,这种缺陷是可能发生的)。3 进程时序t0时刻:进程启动RF接收;t1时刻:SX1278接收到数据帧,中断服务程序poll进程;t2时刻:进程检验数据帧的CRC16,闪烁LED,打印计数、SNR和RSSI;4 代码剖析PROCESS_THREAD(RxPrintSNRRSSI, ev, data){/*ATTENTION: stack variables can NOT cross any “XX_YIELD()”. */bool    bFrameOK;                                                                                                            1RF_FRAME_RAND_DATA    *p_stFrameData;staticint32_t    s_lRxRandCnt = 0;PROCESS_BEGIN();                                                                                                       2InitSetLoRa();                                                                                                                   3SX1278Receive(0);/* Explain: 0 means RX forever */                                                      4while(1){PROCESS_YIELD(); /* Yield until receive aframe. */                                                     5bFrameOK = FALSE;if (RF_Rx_Done == s_tRFResult)                                                                                   6{/* Check CRC16 of this received frame. */s_stParseRFBuf.bySize = GetRadioBuf(s_stParseRFBuf.a_byBuf,RF_FIFO_SIZE);  7p_stFrameData = (RF_FRAME_RAND_DATA *)s_stParseRFBuf.a_byBuf;if ( p_stFrameData->wCRC16 ==util_CRC16( p_stFrameData,GET_ST_FLD_OFFSET(RF_FRAME_RAND_DATA, wCRC16)) )                         8{bFrameOK = TRUE;chip_LEDToogle();++s_lRxRandCnt;RIME_DBG( RIME_DBG_ON,“Rx Rand Cnt=%ld, SNR=%d,RSSI=%d.\r\n”,s_lRxRandCnt, s_chPacketSnr, s_nPacketRssi );                         9}}/*EXPLAIN: Restore the RX of RF if Rx-Error or frame is NOT integrity.*/if(!bFrameOK)                                                                                                              10{SX1278SetSleep();SX1278Receive(0);}}PROCESS_END();                                                                                                         11}Line#1:小心!在Contiki系统自动变量不能跨越阻塞语句,详细原因请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44725997Line#2:Contiki进程的第一条语句,详解请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44600365Line#3:初始化SX1278,详解请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/52824184Line#4:启动RF接收,参数为0代表关闭超时定时器,即持续接收;Line#5:阻塞进程,等待RF中断唤醒;Line#6:判断RF是否接收一帧数据;Line#7:从RF缓冲区复制数据帧到解析工作区;Line#8:检测数据帧的CRC16是否正确;Line#9:打印接收次数、SNR和RSSI,RIME_DBG()的原理和使用,请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/51869953Line#10:如果接收错误或数据帧CRC16错误,重启动RF接收,防止宕机;Line#11:Contiki进程的最后一条语句,详解请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44600365了解详情

LoRa开发5:发送随机数据

1 引言学习需要循序渐进,做开发也不例外。在LoRa终端开发中,最简单的代码是通过SX1278发送数据帧。因此,我们先从发送开始,了解初始化SX1278和建立Contiki进程的入门知识。2 整体逻辑流程发送数据帧的整体逻辑流程如下所示,很明显,进程是一个无限循环:生成随机数据帧-> 发送 -> 生成随机数据帧 ->…3 初始化SX1278初始化SX1278的代码清单如下,它主要完成射频参数的配置。static void InitSetLoRa(void){SX1278Init(&s_stRFEvents);                                                   1SX1278SetFreq(RADIO_FREQ);                                             2SX1278SetPAOutput(PA_OUTPUT_PIN_BOOST);                3SX1278SetTxPower(20);                                                          4SX1278SetPreambleLen(6);                                                     5SX1278SetLowDatarateOptimize(FALSE);                               6SX1278SetFixLen(FALSE);                                                       7SX1278SetCrcOn(TRUE);                                                         8SX1278SetRxContinuous(TRUE);                                             9SX1278SetBandwidth(RF_BW_500000);                                10SX1278SetSpreadingFactor(RF_SF_7);                                  11SX1278SetCodingRate(RF_FEC_4_5);                                   12SX1278SetLoRaSettings();                                                      13SX1278SetTxTimeout(SX1278GetTimeOnAir(255) + 10);       14return;}Line#1:传递一个回调函数指针数组给SX1278驱动,这样一来,当射频中断发生时,可以让调用者执行必需的动作 (一般用于给进程发消息)。该原理的解释,请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/52798757Line#2:设置频率为470MHz;Line#3:使用PA(Power Amplifier,功率放大器)引脚输出;Line#4:设置发射功率为最大值20dBm;Line#5:设置preamble(前导码,用于接收同步)长度为6,根据我们多年的测试经验,6是最小值,低于该值将会导致接收误码率上升;Line#6:关闭低速率优化功能:当symbol驻空时间超过16ms时,打开此选项可以提高LoRa链路健壮性。注意:发送和接收双方必须设置一致!Line#7:允许发射数据帧长度可变;Line#8:使能SX1278对接收数据帧payload进行CRC16校验;Line#9:使能持续接收;Line#10:设置BW为500kHz;Line#11:设置扩频因子为7,即1symbol(每bit用户payload),LoRa扩频到2^7=128 chip(实际发射信号);Line#12:设置前向纠错码,每发送4symbol,添加1symbol纠错码;Line#13:将设置参数写入SX1278寄存器(批量操作提高效率);Line#14:设置发送超时为最大值(使用MCU定时器避免SX1278发送宕机);4 进程时序t0时刻:进程生成随机数据帧,并发送;t1时刻:SX1278启动发送;t2时刻:SX1278发送完毕,中断服务程序poll进程;t3时刻:进程打印发送次数,再次生成随机数据帧和发送;5 代码剖析PROCESS_THREAD(TxRandData, ev, data){/*ATTENTION: stack variables can NOT cross any “XX_YIELD()”. */RF_FRAME_RAND_DATA    *p_stFrameData;                                                            1staticint32_t    s_lTxRandCnt = 0;PROCESS_BEGIN();                                                                                                    2InitSetLoRa();                                                                                                                3while(1)                                                                                                                         4{/* Makethe frame of random data, TX it. */p_stFrameData= (RF_FRAME_RAND_DATA *)s_abyTxRFBuf;MakeRandData(p_stFrameData->a_byBuf, sizeof(p_stFrameData->a_byBuf));        5p_stFrameData->wCRC16= util_CRC16( p_stFrameData,GET_ST_FLD_OFFSET(RF_FRAME_RAND_DATA, wCRC16));                         6SX1278Send(s_abyTxRFBuf, sizeof(RF_FRAME_RAND_DATA));                            7/* Block process until Tx Done or timeout. */PROCESS_YIELD_UNTIL( (RF_Tx_Done == s_tRFResult) ||(RF_Tx_Timeout == s_tRFResult) );                              8++s_lTxRandCnt;RIME_DBG(RIME_DBG_ON, “Tx Rand Cnt=%ld\r\n”, s_lTxRandCnt);                      9}PROCESS_END();                                                                                                        10}Line#1:小心!在Contiki系统自动变量不能跨越阻塞语句,详细原因请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44725997Line#2:Contiki进程的第一条语句,详解请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44600365Line#3:初始化SX1278;Line#4:一般而言,进程都是无限循环;Line#5:生成随机数据;Line#6:计算CRC16,宏GET_ST_FLD_OFFSET()用于取结构体中域的偏移;Line#7:发送随机数据帧;Line#8:阻塞进程,直到发送数据帧结束或超时;Line#9:打印总发送次数,RIME_DBG()的原理和使用,请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/51869953Line#10:Contiki进程的最后一条语句,详解请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/44600365了解详情

LoRa开发4:移植Contiki

1  LoRa终端需要OS吗?尽管工程师有很多理由拒绝在LoRa终端上使用OS(Operating System操作系统):“它很复杂”,“没必要”,“内存太小”,“有学习成本”,“要改变编程思维”,“可能不稳定”……然而,基于以下理由,我们强烈推荐移植一个小型OS:降低复杂度LoRa终端的复杂度其实比我们想象的要高:它需要驱动SX1278,这需要处理很多事件,如接收数据超时,接收数据错误等;它需要实现网络算法,申请入网,主动上报,低功耗唤醒,断网续连等;它需要管理本地设备,采集传感器数据,控制阀门等。使用OS,可以将上述任务分解成多个进程,开发者专注于每个进程的实现,可以有效降低复杂度。复用组件LoRa终端一定有这样的需求:射频CAD侦听到唤醒信号后,快速通知进程接收数据帧;需要一个软定时器来灵活地延时和唤醒……这些系统组件,OS都提供,要知道,这些丰富的组件可是经过严格测试的。复用成熟稳定的组件是提高软件生产力的有效手段,这方面,操作系统功不可没。提高CPU效率当LoRa终端“等待射频发送数据包完成”前,它无事可干;而其他进程希望得到CPU运行权,不用担心,操作系统会完成调度,它会将“因等待而无事可干”的进程阻塞,而将CPU分配给“具备运行条件”的进程享用。移植性更好有一天,因为某种原因(需要更强大的计算能力,需要更低成本等)需要更换LoRa终端的MCU,有操作系统支撑的系统就轻松多了,因为应用软件调用的是操作系统的API,它很少与硬件层直接打交道;基本上,只要将操作系统移植到“新MCU平台”,软件系统就OK了。2  Contiki是一个怎样的OS?Contiki是少有能同时实现2个目标的操作系统:对内存要求极低,同时支持进程阻塞机制。8位单片机的RAM极为宝贵,几KB都是很大了,一般的RTOS(FreeRTOS或uc/os-ii等)无法运行,而Contikil可运行良好;有些操作系统,如OSAL也在极少的RAM上可以运行,但是这种基于“状态机”开发的机制,让代码很难理解,程序执行流在状态中来回判断和切换,让逻辑更复杂。节能内存Contiki有一个巧妙的机制来实现进程的调度:当进程被阻塞时,OS记录该进程的下一C语言行号;当进程继续运行时,从记录的C语言行号继续运行。这种机制从2个方面极大节省内存:所有的进程共享一个栈,没有上下文机切换。甚至在小于1KB内存的MCU上,Contiki都可以良好地运行。进程可以阻塞在Contiki系统中可以实现如下语句,进程发送无线电数据包,然后阻塞自己,直到发送完毕。这种“优雅”的机制,非常符合程序员思维,同时降低了开发的复杂度。SX1278Send(packetbuf_dataptr(),packetbuf_datalen());PROCESS_YIELD_UNTIL(RF_Tx_Done ==s_tRFResult);移植简单如果仅使用Contiki的内核,只需要移植clock.c,即从MCU中找一个定时器来给etimer进程提供时钟源。如果使用Contiki的网络协议栈,需要按radio.c实现无线收发函数。丰富的网络协议栈针对无线通信,Contiki提供3种MAC协议,还有RIME通信原语和RPL路由协议;针对TCP/IP,Contiki提供uIP协议栈,它支持IPv4和IPv6。3 怎样移植Contiki?移植一个操作系统是指将它运行在给定的硬件平台。因为Contiki是非可剥夺的OS,不用实现上下文切换(CPU的寄存器保存与恢复),因此它的内核移植特别容易,一般是实现2个定时器:etimer和rtimer。如果站在3万英尺的高度,一个基于Contiki嵌入式系统的层次结构如下所示。考虑2种情况,首先需要升级Contiki更高版本的软件,其次需要将Contiki移植到不同的硬件平台。为了尽可能地减少升级和移植的工作量,增加了ports文件夹,ports目录中文件与core目录中文件低耦合。3.1 移植Contiki内核如果仅仅只移植Contiki的内核,那么还是比较容易的,一般说来只需要修改2个文件:clock.c和contiki-conf.h。clock.c有2个函数需要适配对应硬件平台:void clock_init(void); 设置一定时器,每秒产生CLOCK_SECOND个tick;void SysTick_handler(void); tick中断时递增时间,检测是否有超时事件;contiki-conf.h:设置contiki系统的一些参数,如:CLOCK_CONF_SECOND=100;3.2 移植rtimer3.2.1 rtimer用途Contiki系统引入rtimer可以满足精准定时的需要,一些对时间极为敏感的模块(如MAC协议)依赖于rtimer。和etimer的粗粒度(常见为100Hz)不同,rtimer是细粒度(常见为1kHz)定时器。3.2.2 rtimer移植移植rtimer比较容易,基于MCU实现rtimer-arch.c和rtimer-arch.h。需要特别注意,大多数定时器(尤其是8位MCU)位宽为16位,即MAX=65535, rtimer的频率定为1kHz比较合理,它既可以保证比较好的精度(1ms),又具备65秒的满量程,这可以适应大多数的应用需要。另外,大多数应用需要随机撤销和重启动rtimer,它可以通过添加2个函数来实现:rtimer_arch_disable_irq()和rtimer_arch_enable_irq()。关于rtimer更多的原理与应用介绍,请链接:http://blog.csdn.net/jiangjunjie_2005/article/details/449478994 怎样应用Contiki?Contiki是标准ANSI C语言开发,调用API函数和系统组件和一般的OS无异。在进程函数中开发,以下三点需要注意:1.       自动变量不能跨越阻塞语句2.       不能使用switch语句3.       执行语句位于PROCESS_BEGIN()和PROCESS_END()之间详细了解该规则,请参考《Contiki开发要点》:http://blog.csdn.net/jiangjunjie_2005/article/details/44725997从一个入门级的Contiki进行代码,请参考《Contiki开发5:Hello, Contiki》:http://blog.csdn.net/jiangjunjie_2005/article/details/51921568了解详情

LoRa开发3:终端驱动设计

1 引言从表面看,终端驱动就是MCU通过读写SX1278的寄存器,实现射频收发功能。然而,一个优秀的驱动设计,至少满足以下设计目标;最具喜挑战的是,有些目标是相互抵触的。提供机制:区分策略和机制,驱动仅提供机制,由用户进程实现策略;接口简单:接口越简单,驱动越好使用,另外,更好实现“高内聚、低耦合”;提高效率:最大化硬件设备性能,是驱动的重要使命;节能内存:内存复用和指针传递等方法可以节省MCU宝贵的内存;...了解详情

LoRa开发2:终端硬件平台

1 硬件基本框图一般而言,LoRa终端主要部件包括:MCU,SX1278,TCXO,RF_SWITCH,它们的功能如下表
部件功能
MC驱动SX1278,实现无线网络协议,与用户系统交互等
SX127完成LoRa无线信号的接收与发送
TCX为SX1278高频电路提供精确时钟
RF_SWITC为半双工的SX1278切换输入或输出状态
一个LoRa终端硬件框图如下所示在实际工程应用中,为更好地移植射频...了解详情

LoRa开发1:LoRa设计10问

引言近2年来,LoRa技术在国内受重视,从高校到企业,再到自主创业者,都在了解和研究。作为从事LoRa研发3年,推出2代LoRa网关的锐米通信,接触许多问询LoRa技术的客户。为此,我们解释一些LoRa技术的常见问题。1问:LoRa是什么?答:LoRa是Long Range(长距离)的简称,是一种长距离、低功耗无线通信技术。2009年法国公司Cycleo设计出一种优异的扩频通信算法,后来,该公司被美国semtech公司收购,后者于2013年推出LoRa芯片。目前,semtech公司是LoRa芯片唯一供应商。2问:LoRaWAN是什么?答:LoRaWAN是LoRa Wide Area Network(LoRa广域网)的简称,是基于LoRa技术的一种通信协议。它主要包括三个层次的通信实体:LoRa终端、LoRa网关和LoRa服务器。LoRaWAN是一个较庞大的体系结构,支持CLASS A / B / C三种终端,使用LoRa MAC协议为网关和终端提供防冲突通信和同步机制,有4种服务器角色,分别担任:网络连接、应用管理、接入控制和用户数据。它的层次关系如下:3问:LoRa有什么优点?答:最大的优点是长距离传输,采用扩频增益,它的传输距离约FSK的3倍;其次是低功耗,尽管它通信距离空旷能达到5km,仍保持良好的节能特性;再次,它工作在免费ISM频段,这为普通民众使用该无线网络打开了一道便捷之门,极大降低网络铺设成本。4问:LoRa有哪些缺点?答:第一个缺点,传输速率低,因为扩频调制后的通信带宽窄,一般只适合传感器网络;第二个缺点,硬件价格高,推出市场的时间不长,没有大规模应用,成本没有被摊薄;第三个缺点,LoRaWAN核心技术(通信协议和算法)需要缴纳会费才能获取,这提高了研发成本和难度。5问:LoRa与常见无线技术的区别?答:确实,我们身边的无线技术已经很多了:3G/4G、WiFi、蓝牙和ZigBee,为什么还需要LoRa这种无线技术呢?其实,每种无线技术都只能适应特定通信场景,需要配合使用才能构建高效率、低成本的网络。打个比方,现代化的军事组织,单兵武器都是配合使用,才能达到最佳火力配制。
无线技术类比武器距离...
了解详情

四个案例告诉你“定制树莓派”在企业级市场大有所为

树莓派自2012年推出以来,经过4年技术积淀以及社区运营,它在创客中间已经具备相当的名气了,去年仅英蓓特出货量就达到200多万片,这个对非消费类电路板块来说,是一个很不错的成绩了。近年来智能硬件概念的兴起,再加上国家层面大力推动“互联网+”、“智慧城市”,越来越多的传统企业参与其中,由此也诞生了很多新的创业公司以及新的业务,涌现出一批批刷新三观的应用。在这个讲究速度与激情的商业时代,比竞争对手先一...了解详情

无线通讯LoRa—SX1278芯片开发笔记

1、资源搜集Datasheet 和驱动源码从Semtech官网下载最新驱动代码http://www.semtech.com/apps/filedown/down.php?file=sx12xxDrivers-V2.1.0.zipDatasheet我上传了资源,中文版和英文版都有,还带了笔记的http://download.csdn.net/detail/csdn_logo/95607682、过一遍Datasheet,过之前必须对一些英文缩写有些了解,不然会要到处翻专业术语及其缩写:FHSS 跳频扩频技术 FIFO 先进先出队列,这里代表队列寄存器PA 功率放大器 LNA 低噪声放大器SNR 信噪比 SF 扩频因子PLL 锁相环 CAD 信道活动检测CR 编码率 BW 带宽RS符号速率 Preamble 序头。。。重要参数:扩频因子 RegModulationCfg因为不同扩频因子(SpreadingFactor)之间为正交关系,因此必须提前获知链路发送端和接收端的扩频因子。另外,还必须获知接收机输入端的信噪比。在负信噪比条件下信号也能正常接收,这改善了LoRa接收机的灵敏度、链路预算及覆盖范围。注:SF=6 时必须用ImplicitHeader 模式循环纠错编码cyclic error coding信号带宽Bandwidth较低频段(169 MHz)不支持250kHz和500kHz的带宽数据包结构序头preamble 报头 header (可配) 数据段 payload 校验码CRC对于希望前导码是固定开销的情况,可以将前导码寄存器长度设置在6到65536之间来改变发送前导码长度,实际发送前导码的长度范围为6+4至65535+4个符号。这样几乎就可以发送任意长的前导码序列。接收机会定期执行前导码检测。因此,接收机的前导码长度应与发射机一致。如果前导码长度为未知或可能会发生变化,应将接收机的前导码长度设置为最大值。报头分显示报头模式和隐式报头模式低数据速率优化LowDataRateOptimize当单个符号传输时间超过16毫秒时,必须使用LowDataRateOptimize位。注意:发射机和接收机的LowDataRateOptimize位设置必须一致。有效负载 payload其实就是数据段,即你要发或者要收的数据数字寄存器和 数字I/O寄存器113个,数字I/O也有6个,太多了,具体见Datasheet操作模式 OpMode3、分析驱动源码解压后打开doc下的README.txt找到关于sx1276的相关说明如下:2.1.3 SX1276 driver version V2.1.0——————————————————————————-The SX1276 driver is split in 4 parts (驱动源码包含如下四个部分)1. Generic SX1276 driver. 驱动调用接口( src\radio\SX1276.c )2. SX1272 FSK modem driver. FSK调制模式用( src\radio\SX1276-Fsk.c andsrc\radio\SX1276-FskMisc.c )3. SX1272 LoRa modem driver. LoRa调制模式用( src\radio\SX1276-LoRa.cand src\radio\SX1276-LoRaMisc.c )4. SX1276 HAL ( Hardware Abstraction Layer ). 硬件抽象层(src\platform\sx12xxEiger\SX1276-Hal.c )1. The generic SX1276 driver implements atleast the functions required bythe RadioDriver structure defined in src\radio\radio.h file. It offersalsothe same interface for the FSK or the LoRa modem.Inorder to choose which modem to use one must modify the src\radio\radio.hfile as follows:-For FSK modem#define LORA 0-For LoRa modem#define LORA 12. FSK调制的可以跳过不看3. The LoRa modem driver handles the SX1276as a LoRa modemInorder to change generic LoRa modem settings one must modify the followingparameters in file src\radio\SX1276-LoRa.c (LoRa模式初始化参数配置的结构体)tLoRaSettings LoRaSettings ={870000000, // RFFrequency 收发频率20, // Power 发射功率8, // 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 CRC校验false, // ImplicitHeaderOn 序头模式1, // RxSingleOn 接收模式中的single模式开关 0代表continue模式0, // FreqHopOn 跳频开关4, // HopPeriod 跳频周期100, // TxPacketTimeout 发送超时时间100, // RxPacketTimeout 接收超时时间4 // PayloadLength 负载数据长度};4. The HAL makes the SX1276 driver platformindependent.One must modify each function inside this file(src\platform\sx12xxEiger\SX1272-Hal.c ) according to the platform used.(根据硬件平台修改硬件抽象层)3. How to use the driver:——————————————————————————-This driver has been tested for high speedtransmission (up to 100kbps in FSK)and long payloads (up to 255 bytes in FSK or LoRa). To set a transmission /reception, it is necessary to:-Change the payload lengthThe payload length for the system isdefined with the parameter BUFFER_SIZElocated in main.c#define BUFFER_SIZE 128 // Definethe payload // size hereThe payload length can be configured from 1up to 2554、用例自己定义一个函数用来动态的初始化芯片view plaincopystaticvoidRFInit(){Radio->LoRaSetOpMode(RFLR_OPMODE_STANDBY);//settheRFsettingsRadio->LoRaSetPa20dBm(false);Radio->LoRaSetRFPower(5);Radio->LoRaSetSpreadingFactor(7);//SF6onlyoperatesinimplicitheadermode.Radio->LoRaSetErrorCoding(1);Radio->LoRaSetPacketCrcOn(0);Radio->LoRaSetSignalBandwidth(7);Radio->LoRaSetImplicitHeaderOn(0);Radio->LoRaSetSymbTimeout(0x3FF);Radio->LoRaSetPayloadLength(128);Radio->LoRaSetLowDatarateOptimize(true);Radio->LoRaSetFreqHopOn(false);Radio->LoRaSetRxSingleOn(true);Radio->LoRaSetPreambleLength(6);Radio->LoRaSetOpMode(RFLR_OPMODE_STANDBY);}通过RF发送数据的发送函数,主要用于收发异频,收发异频能减少干扰view plaincopyINT8URFWrite(INT8U*buff,INT8Usize,INT32Ufreq){Radio->LoRaSetRFFrequency(freq);//478750000DownChannel[10]Radio->SetTxPacket(buff,size);while(Radio->Process()!=RF_TX_DONE);returnsize;}通过RF接收数据的接收函数view plaincopyINT8URFRead(INT8U*buff,INT32Ufreq,INT8Utimeout){uint32_tresult;INT16URxLen;Radio->LoRaSetRFFrequency(freq);Radio->LoRaSetRxPacketTimeout(timeout*1500);//1s=1500Radio->StartRx();while(1){result=Radio->Process();///SX1276LoRaProcessif((result==RF_RX_DONE)||(result==RF_RX_TIMEOUT)){break;}}if(result==RF_RX_DONE)//RFBuffer{Radio->GetRxPacket(buff,&RxLen);returnRxLen;}else{return0;}}了解详情