LoRa SX1278/76驱动原理 附代码

  • 原理解释
    • LoRa 关键参数说明
    • 前导码:
    • 报头:
    • 显式报头模式:
    • 隐式报头模式:
    • LoRa 调制解调:
    • 扩频因子:
    • 编码率:
    • 信号带宽:
  • 代码说明
    • SPI接口引脚的宏定义 初始化
    • LoRa 数据发送流程
    • LoRa 数据接收流程
      • 单一接收模式:
      • 连接接收模式:
    • 信道活动检测(CAD)
    • IO 引脚中断映射
    • LoRa 状态机和接口
    • 主函数 main()分析

LoRa 的名字是远距离无线电(Long Range Radio),作为一种线性调频扩频的调制技术,最早由法国几位年轻人创立的一家创业公司 Cycleo 推出,2012 年 Semtech 收购了这家公司,并将这一调制技术封装到芯片中,基于 LoRa 技术开发出一整套LoRa 通信芯片解决方案,包括用于网关和终端上不同款的LoRa 芯片,开启了 LoRa 芯片产品化之路。
LoRa 是低功耗局域网无线标准,它最大特点就是在同样的功耗条件下比其他无线方式传播的距离更远,实现了低功耗和远距离的统一,它在同样的功耗下比传统的无线射频通信距离扩大 3-5 倍。在实验中使用的 LoRa 模块是安信可的 Ra01,该模组用于超长距离扩频通信,其射频芯片 SX1278主要采用 LoRa™远程调制解调器,用于超长距离扩频通信,抗干扰性强,能够最大限度降低电流消耗。借助 SEMTECH 的 LoRa™专利调制技术,SX1278 具有超过-148dBm 的高灵敏度,+20dBm 的功率输出,传输距离远,可靠性高。

原理解释

SX1278无线串口模块LORA扩频超远距离传输

LoRa 关键参数说明

Lora 数据包由三个部分组成部分:前导码可选报头数据有效负载

前导码:

前导码用于保持接收机与输入的数据流同步。默认情况下,数据包含有12个符号长度的前导码。前导长度是一个可以通过编程来设置的变量,所以前导码的长度可以扩展。可以将前导码寄存器长度设置在6到65536之间来改变发送前导码长度,实际发送前导码的长度范围为6+4至65535+4个符号。接收机会定期执行前导码检测。接收机的前导码长度应与发射机一致。如果前导码长度为未知或可能会发生变化,应将接收机的前导码长度设置为最大值。

报头:

根据所选择的操作模式,可以选用两种报头。在 RegModemConfig1 寄存器上,通过设定ImplicitHeaderModeOn 位选择报头类型。

显式报头模式:

显式报头模式是默认的操作模式。在这种模式下,报头包含有效负载的相关信息,包括:

  1. 以字节数表示的有效负载长度;
  2. 前向纠错码率;
  3. 是否打开可选的 16 位负载 CRC。

报头按照最大纠错码(4/8)发送。另外,报头还包含自己的 CRC,使接收机可以丢弃无效的报头。

隐式报头模式:

在特定情况下,如果有效负载长度、编码率及 CRC 为固定或已知,则比较有效的做法是通过调用隐式报头模式来缩短发送时间。这种情况下,需要手动设置无线链路两端的有效负载长度、错误编码率及CRC。

注意:如果将扩频因子 SF 设定为 6,则只能使用隐式报头模式,下面将详细解释扩频因子。

LoRa 调制解调:

LoRa 调制解调技术(下面简称 LoRa)采用专有的调制和解调程序,将扩频调制与循环纠错编码技术结合起来,与传统的调制技术(FSK 或 OOK)相比,这种技术扩大了无线通讯链路的覆盖范围,提高了链路的鲁棒性。具有更强的抗干扰性。对同信道GMSK 干扰信号的抑制能力达到 20dB,所以 LoRa 用于频谱使用率较高的频段和混合通讯网络,方便在网络中原有的调制方案失败时扩大覆盖范围。开发人员通过调整扩频因子、调制带宽和编码率这三个关键设计参数对 LoRa 进行优化,可在链路预算、抗干扰性、频谱占用度及标称数据速率之间达到平衡。

扩频因子:

LoRa 扩采用多个信息码片来代表有效负载信息的每个位。扩频信息的发送速度称为符号速率(Rs),而码片速率与标称符号速率之间的比值即为扩频因子,其表示每个信息位发送的符号数量。负信噪比条件下信号也能正常接收,提高了的灵敏度、链路预算及覆盖范围。但是不同扩频因子之间为正交关系,因此发送端和接收端的扩频因子必须一致。


由上表可以看出当扩频因子为 12 时在-20dB 还能收到数据包,说明扩频因子越大灵敏度越高,发送速度越慢。

编码率:

LoRa 采用循环纠错编码进行前向错误检测与纠错,但会产生传输开销。每次传输产生的数据开销如下:


编码率越大前向纠错越强,链路抗干扰性越强,但是传输开销将会加大,进而加大传输时间。

信号带宽:

由信号频谱图可以观察到一个信号所包含的频率成分。把一个信号所包含谐波的最高频率与最低频率
之差,即该信号所拥有的频率范围,定义为该信号的带宽。信号的频率变化范围越大,信号的带宽就越宽。


上表可以看出增加信号带宽,发送标称比特率越大,说明增加信号带宽可以有效提高数据速率以缩短传输时间,但会有弊端将会降低接收灵敏度,缩短传输距离。

代码说明

附LoRa SX1278/76驱动源码

SPI接口引脚的宏定义 初始化

源文件叫做 SX1276_hal.c,这个文件里包括了 LoRa 模块的硬件驱动接口,包括 SPI2 和使用到的其他 IO 口,在移植驱动的时候,只需要对这个文件修改即可。这一部分建议对着 LORA 接口电路图来看。

在这个文件的最前面,是接口引脚的宏定义,在做驱动移值的时候,这一部分是主要修改的对象:

#include "sx1276_hal.h"
#include "stm32f10x_it.h"
/** LoRa LoRa sx1278/76驱动*/
#define RESET_IOPORT                                GPIOA
#define RESET_PIN                                   GPIO_Pin_1/*!* SX1276 SPI definitions*/
#define NSS_IOPORT                                  GPIOB
#define NSS_PIN                                     GPIO_Pin_12#define SPI_INTERFACE                               SPI2
#define SPI_CLK                                     RCC_APB1Periph_SPI2#define SPI_PIN_SCK_PORT                            GPIOB
#define SPI_PIN_SCK_PORT_CLK                        RCC_APB2Periph_GPIOB
#define SPI_PIN_SCK                                 GPIO_Pin_13#define SPI_PIN_MISO_PORT                           GPIOB
#define SPI_PIN_MISO_PORT_CLK                       RCC_APB2Periph_GPIOB
#define SPI_PIN_MISO                                GPIO_Pin_14#define SPI_PIN_MOSI_PORT                           GPIOB
#define SPI_PIN_MOSI_PORT_CLK                       RCC_APB2Periph_GPIOB
#define SPI_PIN_MOSI                                GPIO_Pin_15/*!* SX1276 DIO pins  I/O definitions*/
#define DIO0_IOPORT                                 GPIOC
#define DIO0_PIN                                    GPIO_Pin_4#define DIO1_IOPORT                                 GPIOB
#define DIO1_PIN                                    GPIO_Pin_11#define DIO2_IOPORT                                 GPIOB
#define DIO2_PIN                                    GPIO_Pin_3#define DIO3_IOPORT                                 GPIOB
#define DIO3_PIN                                    GPIO_Pin_10#define DIO4_IOPORT                                 GPIOC
#define DIO4_PIN                                    GPIO_Pin_3#define DIO5_IOPORT                                 GPIOB
#define DIO5_PIN                                    GPIO_Pin_4//软件延时函数,ms级别
void Soft_delay_ms(u16 time)
{u16 i=0;while(time--){i=7950;  //自己定义调试时间:20141116while(i--) ;}
}//spi初始化
static void SpiInit( void )
{SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;///* Enable peripheral clocks --------------------------------------------------*//* Enable SPIy clock and GPIO clock for SPIy */RCC_APB2PeriphClockCmd( SPI_PIN_MISO_PORT_CLK | SPI_PIN_MOSI_PORT_CLK |SPI_PIN_SCK_PORT_CLK, ENABLE );RCC_APB1PeriphClockCmd( SPI_CLK, ENABLE );/* GPIO configuration ------------------------------------------------------*/GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = SPI_PIN_SCK;GPIO_Init( SPI_PIN_SCK_PORT, &GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = SPI_PIN_MOSI;GPIO_Init( SPI_PIN_MOSI_PORT, &GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = SPI_PIN_MISO;GPIO_Init( SPI_PIN_MISO_PORT, &GPIO_InitStructure );//禁用JTAGRCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );GPIO_PinRemapConfig( GPIO_Remap_SWJ_JTAGDisable, ENABLE );/* SPI_INTERFACE Config -------------------------------------------------------------*/SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 72/8 MHzSPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init( SPI_INTERFACE, &SPI_InitStructure );SPI_Cmd( SPI_INTERFACE, ENABLE );
}//SX127x相关初始化希要设置如下内容
//SPI片选设置为输出,并初始化SPI口
//复位角初始化为输出高电平
//DI00~5为输入(暂时只用到了DIo0和DIo1,如果不用硬件超时DIo1也可以不接)
void SX1276HALInit( void )
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// Configure SPI-->NSS as outputGPIO_InitStructure.GPIO_Pin = NSS_PIN;GPIO_Init( NSS_IOPORT, &GPIO_InitStructure );GPIO_WriteBit( NSS_IOPORT, NSS_PIN, Bit_SET );SpiInit();//配置复位引脚GPIO_InitStructure.GPIO_Pin = RESET_PIN;GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_SET );// Configure radio DIO as inputsGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;// Configure DIO0GPIO_InitStructure.GPIO_Pin =  DIO0_PIN;GPIO_Init( DIO0_IOPORT, &GPIO_InitStructure );// Configure DIO1GPIO_InitStructure.GPIO_Pin =  DIO1_PIN;GPIO_Init( DIO1_IOPORT, &GPIO_InitStructure );// Configure DIO2GPIO_InitStructure.GPIO_Pin =  DIO2_PIN;GPIO_Init( DIO2_IOPORT, &GPIO_InitStructure );// Configure DIO3GPIO_InitStructure.GPIO_Pin =  DIO3_PIN;GPIO_Init( DIO3_IOPORT, &GPIO_InitStructure );// Configure DIO4GPIO_InitStructure.GPIO_Pin =  DIO4_PIN;GPIO_Init( DIO4_IOPORT, &GPIO_InitStructure );// Configure DIO5GPIO_InitStructure.GPIO_Pin =  DIO5_PIN;GPIO_Init( DIO5_IOPORT, &GPIO_InitStructure );}//spi发送和接收函数
uint8_t SpiInOut( uint8_t outData )
{/* Send SPIy data */SPI_I2S_SendData( SPI_INTERFACE, outData );while( SPI_I2S_GetFlagStatus( SPI_INTERFACE, SPI_I2S_FLAG_RXNE ) == RESET );return SPI_I2S_ReceiveData( SPI_INTERFACE );
}//spi片选,status=0使能(NSs拉低)status=1失能(NSs拉高)
void SpiNSSEnable( uint8_t status )
{GPIO_WriteBit( NSS_IOPORT, NSS_PIN, status );
}void SX1276Write( uint8_t addr, uint8_t data )
{SX1276WriteBuffer( addr, &data, 1 );
}void SX1276Read( uint8_t addr, uint8_t *data )
{SX1276ReadBuffer( addr, data, 1 );
}void SX1276ReadBuffer(uint8_t addr,uint8_t *buffer,uint8_t size)
{uint8_t i;//NSS = 0;SpiNSSEnable(0);  //片选spi1SpiInOut(addr & 0x7F );for( i = 0; i < size; i++ ){buffer[i] = SpiInOut(0x00);//读取数据}//NSS = 1;SpiNSSEnable(1);
}void SX1276WriteBuffer(uint8_t addr,uint8_t *buffer,uint8_t size)
{uint8_t i;//NSS = 0;SpiNSSEnable(0);SpiInOut(addr | 0x80 );for( i = 0; i < size; i++ ){SpiInOut(buffer[i]);//写入数据}//NSS = 1;SpiNSSEnable(1);
}void SX1276WriteFifo( uint8_t *buffer, uint8_t size )
{SX1276WriteBuffer( 0, buffer, size );
}void SX1276ReadFifo( uint8_t *buffer, uint8_t size )
{SX1276ReadBuffer( 0, buffer, size );
}void SX1276SetReset( uint8_t state )
{GPIO_InitTypeDef GPIO_InitStructure;if( state == RADIO_RESET_ON ){// Configure RESET as outputGPIO_InitStructure.GPIO_Pin = RESET_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );// Set RESET pin to 0GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_RESET );}else{GPIO_InitStructure.GPIO_Pin =  RESET_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init( RESET_IOPORT, &GPIO_InitStructure );// Set RESET pin to 1GPIO_WriteBit( RESET_IOPORT, RESET_PIN, Bit_SET );}
}//读取DTo0电平,返回值0低电平,1高电平
uint8_t SX1276ReadDio0(void){return GPIO_ReadInputDataBit( DIO0_IOPORT, DIO0_PIN );
}//读取DTo1电平,返回值0低电平,1高电平
uint8_t SX1276ReadDio1(void){return GPIO_ReadInputDataBit( DIO1_IOPORT, DIO1_PIN );
}uint8_t SX1276ReadDio2(void){return 0;//GPIO_ReadInputDataBit( DIO2_IOPORT, DIO2_PIN );
}uint8_t SX1276ReadDio3(void){return GPIO_ReadInputDataBit( DIO3_IOPORT, DIO3_PIN );
}uint8_t SX1276ReadDio4(void){return GPIO_ReadInputDataBit( DIO4_IOPORT, DIO4_PIN );
}uint8_t SX1276ReadDio5(void){return ;//GPIO_ReadInputDataBit( DIO5_IOPORT, DIO5_PIN );
}

在头文件sx1276-LoRa.h里,定义有这么一个结构体tLoRaSettings,这个结构就是第三部介绍的LoRa的参数缩影,定义如下:

通过这个结构体定义的变量我们就可以初始化LoRa模块,在源文件sx1276-LoRa.c里,是这样初始化的:

也就是模块工作在 450MHz,功率是 20dB,带宽是 500kHz,扩频因子是 128,前导码长度是 10 个字节,CRC 校验是打开的等,在两个通信模块之间,这些参考必须一致,才能保证通信。

LoRa 数据发送流程

从上图可以看出,LoRa 发送前一直处于待机状态,在初始化 Tx 模块后,将待发送数据(Payload)写
入 FIFO,然后切换到发送状态将数据通过 LoRa 调制成信号发送出去,等到发送完成后,会产生 TxDone 中断,同时再次切换为待机状态,完成一个发送流程。

当发送完成后,根据设计要求,可以是发送状态,也可以是新的接收状态。

LoRa 数据接收流程

LoRa 接收有两种模式:单一接收连续接收

单一接收模式:

在这种模式下,调制解调器在给定的时间窗口内搜索前导码。如果在该时间窗口结束时还未找到前导码,则芯片会产生RxTimeout中断信号并切换回待机模式。时间窗口长度(以符号计)由RegSymbTimeout寄存器定义,必须为4(调制解调器获取前导码锁的最短时间)到1023个符号。缺省值为5。如果在时间窗口内未发现前导码,则会产生RxTimeout中断信号,同时芯片切换回待机模式
在有效负载结束时,如果负载CRC无效,则会产生RxDone中断信号及PayloadCrcError中断信号。然而,即使CRC无效,仍然可以在FIFO数据缓存中写入数据,以便后续进行处理。
RxDone中断产生后,芯片切换回待机模式。当RxDoneRxTimeout中断信号产生时,调制解调器也会自动回到待机模式。 因此,只有在数据包到达时间窗口为已知的情况下才会使用RX单一接收模式 。而在其他情况下,应使用X连续模式。

连接接收模式:

在连续接收模式下,调制解调器会持续扫描信道,以搜索前导码。每当检测到前导码时,调制解调器都会在收到数据包前对该前导码进行检测及跟踪,然后继续等待检测下一前导码。如果前导码长度超过寄存器RegPreambleMsbRegPreambleLsb设定的预计值(按照符号周期测量),则前导码会被丢弃,并重新开始前导码搜索。但在这种场景不会产生中断标志。与单一 Rx 模式相反,在连续 Rx 模式下,当产生超时中断时,设备不会进入待机模式。这时,用户必须在设备继续等待有效前导码的同时直接清除中断信号。
在实验里,基本上都是使用连接接收模式。

信道活动检测(CAD)

LoRa 使用信道检测器来检测其他 LoRa 信号,流程如下图:

信道活动检测模式在以尽可能高的功耗效率检测无线信道上的 LoRa 前导码,当检测到前导码的存在,
就进入接收模块。

IO 引脚中断映射

在前面的介绍中 CAD,TX,RX 都有操作完成中断,例如 CadDone 中断,TxDone 中断,RxDone 中断这些中断的配置与 RegDioMapping1RegDioMapping2 这两个寄存器有关,DIO0 到 DIO3 引脚映射RegDioMapping1,DIO4 到 DIO5 引脚映射 RegDioMapping2,具体见下表所示:

LoRa 状态机和接口

在源文件 sx1276-LoRa.h里,有一个处理函数 uint32_t SX1276LoRaProcess( void),在这个函数里根
据当前 LoRa 的状态(发送、接收或者 CAD 检测)决定进行不同的处理。
LoRa 的状态有以下几种:

LoRa 对外接口 API 定义,操作 LoRa 的时候,只需要使用这些 API 即可。定义在 radio.h文件里:

在 radio.c 里,定义了 tRadioDriver RadioDriver 这样的一个变量,应用层就是对这个变量的操作,以下是对它赋值代码

主函数 main()分析

首先看初始化部分,以下是它的代码:

第 49 行:首先取出操作 LoRa 的函数指针保存在 radio 里。
第 50 行:对 LoRa 初始化。

LoRa SX1278/76驱动原理 附代码相关推荐

  1. 内核与驱动_08_键盘驱动原理及代码

    文章目录 技术原理 Windows中从击键到内核 流程 键盘硬件原理 键盘过滤的框架搭建 应用设备扩展 键盘过滤模块的动态卸载 键盘过滤的请求处理 通常的处理 PNP的处理 读的处理 读完成的处理 从 ...

  2. 换发型算法_【AI超级美发师】深度学习算法打造染发特效(附代码)

    原标题:[AI超级美发师]深度学习算法打造染发特效(附代码) 来源:OpenCV学堂 作者:胡耀武 [新智元导读]如今,在类似天天P图.美图秀秀等手机APP中,给指定照片或视频中的人物更换头发颜色已经 ...

  3. LoRa SX1278通信代码开发学习

    前言 最近在学习和摸索LoRa SX1278无线发射模块,其中学到了很多新知识和对SX1278也有了深一点的认识,现在将学习开发中遇到的问题.解决方法.调试完成和低功耗等内容分享出来,也是一种学习记录 ...

  4. 洪水攻击程序c语言,洪水攻击原理及代码实现全攻略(附源代码)

    下载本文示例代码 推荐:应用程序安全的魔道之争 声明:本文所提供的资料仅仅限于技术交流和学习,请不要用于其他非法目的,维护网络安全是我们的共同责任. 下载本文源代码和例程 一. 什么是洪水攻击 洪水之 ...

  5. 辗转相除法求最大公约数原理分析(附代码实现)

    辗转相除法求最大公约数原理分析(附代码实现) 前言 解释 原理分析 代码 结语 前言 辗转相除法用起来很简单,但是其原理却自己想不明白.于是乎看了几篇有关辗转相除法原理的分析,在这里自己写下自己的理解 ...

  6. RTC芯片——DS1302驱动方式讲解(附代码)

    RTC芯片--DS1302驱动方式讲解(附代码) 最近的一个项目中用到了DS1302rtc芯片,中间弯弯绕绕也费了点时间,好在最后还是成功搞定,现做一下总结,希望能让各位少走些弯路. 写代码前所需了解 ...

  7. html放大镜原理,Canvas实现放大镜效果完整案例分析(附代码)

    本文主要记录 canvas 在图像.文字处理.离屏技术和放大镜特效的实现过程中使用到的API.先看下效果吧: 一张模糊的图片: 鼠标点击任意位置,产生放大效果: 哇塞~ 一个帅哥,哈哈哈哈~ 1.放大 ...

  8. AlphaGoZero 原理讲解(附代码)

    AlphaGoZero 原理讲解 前言 一.AlphaGoZero 棋盘编码器 二.AlphaGoZero树搜索算法 1. 树节点及其动作分支 2. 选择要探索的动作分支 3. 扩展搜索树 4. 选择 ...

  9. 基于单片机的压力流量报警器(附代码+仿真+论文)

    基于单片机的压力流量报警器(附代码+仿真+论文) **==完整论文+代码+仿真可关注我在主页私我==** 摘要 关键字 第一章绪论 1.1课题背景及其意义 1.2 国内外的研究状况 1.3本文的主要研 ...

最新文章

  1. 按home退出程序到后台后再打开崩溃的问题
  2. 5种IO模式形象的比喻
  3. ddm模型公式_简单判断目前行情——从股利贴现模型切入
  4. python压缩算法_LZ77压缩算法编码原理详解(结合图片和简单代码)
  5. java升级菜单切换_java 关于系统菜单升级
  6. poj1753 Flip Game(枚举Enum+dfs)
  7. VUE系列-Vue中组件的应用(三)
  8. 交换机 路由器 OSI7层模型
  9. 计算hashCode的常见方法
  10. php限制单设备登录,app限制一个账号只能单设备登陆
  11. 微信朋友圈点赞和评论测试用例
  12. libnet库的安装与使用
  13. 计算机房低压配电系统,机房工程之配电系统
  14. R语言 按照行名称取行
  15. 基础版微信模板消息开发详解,附代码PHP
  16. 嵌入式设备显示屏相关概念汇总
  17. 正则表达式re之模块函数和编译标志
  18. 【C++学习】 设计案例1:设计立方体类
  19. LeetCode T36 Valid Sudoku
  20. 2022最新蚂蚁金服Java岗面试题库(整理版)

热门文章

  1. 免费的网站,堪称神器
  2. 快速云:云计算供应商在合同谈判时可能拒绝的三个事项以及要求
  3. android hook 第三方app_【MiSRC】技术分享-浅谈android hook技术
  4. 伊诺ET-33夹式校(音器吉他/贝司/小提琴/尤克里里 使用
  5. Java Annotation自定义注解详解
  6. 打造成功IT项目经理——光环国际——读感
  7. 【汇总】nltk相关资源包无法下载报错问题
  8. 特殊纪念日Android APP内设置黑灰色背景
  9. 开源MySQL数据仓库解决方案:Infobright
  10. FineUI学习笔记1