nRF52832 作为一个低功耗蓝牙芯片,其数据发送发送速率一直都偏低(高就不叫低功耗了^_^),作为初学者在网上找了很多资料,终于找到通过修改ATT_MTU来提升发送速率的方法,最快能达到8.2KB/s,现在就分享出来

首先我用的协议栈是 nRF5_SDK_14.2.0 ,将\examples\ble_peripheral中的 ble_app_template 作为模板,以此进行修改

废话不说,先上代码,首先是定义

#define TIMER_INTERVAL        APP_TIMER_TICKS(29)      //定时器时间间隔

1 BLE_NUS_DEF(m_nus);          //加入串口服务结构(修改)
BLE_CMD_DEF(m_cmd); //加入命令服务结构
APP_TIMER_DEF(m_timer1); //定时器1 uint8_t hr_data[];
uint8_t cmd_data; //接收的命令
bool send_state = false; //发送状态,默认不发送 static uint16_t length = ;

主函数基本没修改,主要初始化了一组数据用来测试发送,加入了调度器,因为使用的定时器定时进行发送,而蓝牙发送不好放在中断里进行,定时器中断就做一个接发送函数放入调度器的操作。定义了一个全局数组,用来存放发送的数据。

 int main(void)
{
bool erase_bonds; // Initialize.
log_init();
timers_init();
buttons_leds_init(&erase_bonds);
ble_stack_init();
gap_params_init();
gatt_init();
advertising_init();
services_init();
conn_params_init();
peer_manager_init(); // Start execution.
NRF_LOG_INFO("Template example started."); advertising_start(erase_bonds); for(uint8_t i=;i<;i++) hr_data[i]=i; //初始化数据包
SEGGER_RTT_printf(, "\n");// 此处打印信息 APP_SCHED_INIT(, ); //初始化调度器 // Enter main loop.
for (;;)
{
app_sched_execute(); //调度 if (NRF_LOG_PROCESS() == false)
{
power_manage();
}
}
}

先看定时器

 static void timers_init(void)
{
// Initialize timer module.
uint32_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code); err_code = app_timer_create(&m_timer1, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
APP_ERROR_CHECK(err_code);
}

定时器中断服务函数

 void timer_timeout_handler(void * p_context)
{
if ( send_state == true )
{
hr_data[]++;
if(hr_data[]>) hr_data[]=; //改变第一个字节
app_sched_event_put(NULL, , ble_nus_send); // 加入调度
}
}

蓝牙发送函数

 void ble_nus_send(void)
{
uint32_t err_code;
do
{
err_code = ble_nus_string_send(&m_nus, hr_data, &length);
if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) )
{
APP_ERROR_CHECK(err_code);
}
} while (err_code == NRF_ERROR_BUSY);
}

接下来是蓝牙服务,这里我使用了两个自定义的服务,因为之前测试发送同一个串口服务进行收发的话,在连续接收数据时候,发送的命令会被堵塞,所以索性改了两个服务,分别用来收发,不知道大家有碰到过这种情况没,有的话欢迎一起交流交流。

 static void services_init(void)
{
uint32_t err_code;
ble_nus_init_t nus_init;
ble_cmd_init_t cmd_init; /* 初始化串口服务 */
memset(&nus_init, , sizeof(nus_init));
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code); /* 初始化自定义命令服务 */
memset(&cmd_init, , sizeof(cmd_init));
cmd_init.data_handler = cmd_data_handler; //命令处理函数
err_code = ble_cmd_init(&m_cmd, &cmd_init);
APP_ERROR_CHECK(err_code);
}

命令数据处理函数,定义了一个全局变量,用来指示发送状态,根据接收的命令修改状态,以及开关定时器。

 static void cmd_data_handler(ble_cmd_evt_t * p_evt)
{
ret_code_t err_code;
SEGGER_RTT_printf(, "Receive a command\n");// 此处打印信息
cmd_data = p_evt->params.rx_data.p_data[]; //接收1个字节作为命令 switch ( cmd_data )
{
case BLE_STOP_CMD :
send_state = false; //停止发送
err_code = app_timer_stop(m_timer1); //停止定时器
APP_ERROR_CHECK(err_code);
break;
case BLE_SEND_CMD :
send_state = true; //允许发送
err_code = app_timer_start(m_timer1, TIMER_INTERVAL, NULL); //启动定时器
APP_ERROR_CHECK(err_code);
break;
default:
SEGGER_RTT_printf(, "Invalid command\n");// 此处打印信息
break;
}
}

整个程序的框架基本上就是这样,通过蓝牙接收的命令打开定时器,定时器中断将发送函数加入调度,主循环轮转到发送时进行数据发送

通过修改 length 改变发送包的大小

通过修改TIMER_INTERVAL  修改定时器时间

两者配合改变数据发送速率。

到了这里,就得修改ATT_MTU了,不然244个字节根本发不了,打开sdk_config.h

 // <h> nRF_SoftDevice 

 //==========================================================
// <e> NRF_SDH_BLE_ENABLED - nrf_sdh_ble - SoftDevice BLE event handler
//==========================================================
#ifndef NRF_SDH_BLE_ENABLED
#define NRF_SDH_BLE_ENABLED 1
#endif
// <h> BLE Stack configuration - Stack configuration parameters // <i> These values are not used directly by the SoftDevice handler but the application or other libraries might depend on them.
// <i> Keep them up-to-date with the desired configuration.
//==========================================================
// <o> NRF_SDH_BLE_PERIPHERAL_LINK_COUNT - Maximum number of peripheral links.
#ifndef NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1
#endif // <o> NRF_SDH_BLE_CENTRAL_LINK_COUNT - Maximum number of central links.
#ifndef NRF_SDH_BLE_CENTRAL_LINK_COUNT
#define NRF_SDH_BLE_CENTRAL_LINK_COUNT 0
#endif // <o> NRF_SDH_BLE_TOTAL_LINK_COUNT - Maximum number of total concurrent connections using the default configuration.
#ifndef NRF_SDH_BLE_TOTAL_LINK_COUNT
#define NRF_SDH_BLE_TOTAL_LINK_COUNT 1
#endif // <o> NRF_SDH_BLE_GAP_EVENT_LENGTH - The time set aside for this connection on every connection interval in 1.25 ms units.
#ifndef NRF_SDH_BLE_GAP_EVENT_LENGTH
#define NRF_SDH_BLE_GAP_EVENT_LENGTH 8 //默认值3
#endif // <o> NRF_SDH_BLE_GATT_MAX_MTU_SIZE - Static maximum MTU size.
#ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE
#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247 //默认值23
#endif // <o> NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE - Attribute Table size in bytes. The size must be a multiple of 4.
#ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE
#define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1408
#endif // <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs.
#ifndef NRF_SDH_BLE_VS_UUID_COUNT
#define NRF_SDH_BLE_VS_UUID_COUNT 1 //默认为0
#endif

这里修改了3个地方,

NRF_SDH_BLE_GAP_EVENT_LENGTH    这个是每个间隔预留给连接的时间

NRF_SDH_BLE_GATT_MAX_MTU_SIZE   这个就是最大MTU了

NRF_SDH_BLE_VS_UUID_COUNT   这个因为我加了两个自定义服务,所以也要改成1

接下来通过修改 length 和  TIMER_INTERVAL   编译下载后来测试速率了

注意的是,因为修改过NRF_SDH_BLE_GATT_MAX_MTU_SIZE,所以RAM的地址会发生改变,打开sdk_config.h,修改

 //==========================================================
// <e> NRF_LOG_ENABLED - Logging module for nRF5 SDK
//==========================================================
#ifndef NRF_LOG_ENABLED
#define NRF_LOG_ENABLED 1
#endif
 //==========================================================
// <e> NRF_LOG_BACKEND_RTT_ENABLED - nrf_log_backend_rtt - Log RTT backend
//==========================================================
#ifndef NRF_LOG_BACKEND_RTT_ENABLED
#define NRF_LOG_BACKEND_RTT_ENABLED 1
#endif

这样就可以通过RTT打印的信息来调整RAM的地址和大小了

再次编译,下载,没问题后,在andorid手机上使用 ‘nRF Connect’ 进行调试

附上我的测试图片

数据显示

这里使用的就是每29ms发送一次,每次发送244字节,通过计算,(1000/29)*244 = 8413byte  约  8.2KB/s  ,这是我目前测出的最大传输速率,但是不停稳定,超出一米的距离基本就会失去连接,另外连接间隔我也有修改

 #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(8, UNIT_1_25_MS)
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_1_25_MS)
#define SLAVE_LATENCY 0
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)

因为初次接触蓝牙,这方面不是太懂,可能写的不是太好,欢迎指正,或者有测出更高速率的朋友也可以一起交流下

对于改变MTU为什么会提高发送速率,我抓包分析了一下

从机接收到命令开始发数据

第一个包,可以看出数据只发送到0x13,也就是20个字节

第二个包,从0x14 发送到了0x2e, 也就是27个字节

第三个包,从0x2f 到0x49, 也是27个字节

也就是说,通过修改MTU后,每次发送从第二个包开始都可以达到每个包27个字节,这样一来自然就会比之前限定的每次只能发20个字节要快一点了。

先写到这里吧,如果有什么写的不对的,欢迎大家指正,后面还需要测试稳定性,距离,功耗,还好实际上也不需要用到8K的传输速率,还需要深入的学习BLE,加油!

nRF52832 改变ATT_MTU提高蓝牙数据发送速率(nRF5_SDK_14.2.0)的更多相关文章

  1. nrf51822-提高nordic ble数据发送速率

    讲解2点: 为什么 nordic的4.0协议栈中ble只能发送20字节的应用负载数据. 大量数据发送时如何提高发送速率 1:为何上层应用负载每次最多20字节 首先了解 4.0中链路层的包格式如下: P ...

  2. 第一章:1-20、试计算以下两种情况的发送时延和传播时延: (1) 数据长度为107bit,数据发送速率为100kbit/s,传播距离为1000km,信号在媒体上 的传播速率为2×108m/s。 (2) 数据长度为103bit,数据发送速率为1Gbit/s,传输距离和信号在媒体上的传播速率同 上。

    <计算机网络>谢希仁著第四版课后习题答案答: 1):发送延迟=107/(100×1000)=100s         传播延迟=1000×1000/(2×108)=5×10-3s=5ms ...

  3. 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计

    基于都志辉老师<MPI并行程序设计模式>第14章内容. 前面接触到的MPI发送的数据类型都是连续型的数据.非连续类型的数据,MPI也可以发送,但是需要预先处理,大概有两类方法: (1)用户 ...

  4. python网络编程-socket“粘包”(小数据发送问题)

    一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ...

  5. 如何使用Arduino和SIM900A GPRS / GSM模块将数据发送到Web服务器

    今天我们在这里介绍一个非常有趣的项目,我们将使用Arduino开发板和GPRS将数据发送到SparkFun服务器.这是一个基于IoT的项目,我们将使用GSM模块SIM900A将一些数据发送到互联网上的 ...

  6. [转帖]Linux TCP/IP协议栈,数据发送接收流程,TCP协议特点

    Linux TCP/IP协议栈,数据发送接收流程,TCP协议特点 http://network.51cto.com/art/201909/603780.htm 可以毫不夸张的说现如今的互联网是基于TC ...

  7. 【笔记】nrf52832广播使用--厂商自定义数据应用

    需求: 1)使用蓝牙不停发送ble广播,发送自定义的数据,并每一秒更新自定义数据. 2)设置不同的发射功率.广播间隔.广播名称 1.初始化 使用nordic官方sdk17版本,打开一个ble串口用例. ...

  8. QT串口助手(四):数据发送

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 开发环境:Qt5.12.10 + MinGW 实现的功能 串口数据的发送 ascii字符与hex字符的相互转换 自 ...

  9. ASP.NET POST XML JSON数据,发送与接收

    接收端通过Request.InputStream读取:byte[] byts = new byte[Request.InputStream.Length];Request.InputStream.Re ...

随机推荐

  1. 使用Spring操作Redis的key-value数据

    前言 最近工作一直忙的不可开交,小Alan已经很久没有和大家分享知识了,在深圳待了两年多,依然感觉自己还是个小菜鸟,工作中还是会遇到很多自己在短期内无法搞定的事情,每当这个时候总是会感觉到很沮丧,就会 ...

  2. WCF3.5 SP1 参考源码索引

    http://www.projky.com/dotnet/WCF3.5SP1/Microsoft/InfoCards/AccessibilityApplicationManager.cs.htmlht ...

  3. kvm 启动libvirtd时出现错误

    kvm 启动libvirtd市出现错误: /etc/init.d/libvirtd start启动 libvirtd 守护进程:libvirtd: relocation error: libvirtd ...

  4. MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    MySQL InnoDB支持三种行锁定方式: l   行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. l   间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙 ...

  5. 使用Github的高级搜索功能

    使用Github的高级搜索功能 1. 首先,提供Github高级搜索帮助页面 https://help.github.com/categories/search/ 2. 搜索语法 https://he ...

  6. [翻译] TransitionKit

    TransitionKit https://github.com/blakewatters/TransitionKit A simple, elegantly designed block based ...

  7. [转]SQL Server 数据库定时自动备份

    前提:在使用下面的备份方式之前需要确保你的Sqlserver Agent服务启动,切设置为自动启动.否则当你服务器重启了但是Agent服务没有启动,那么自动备份任务就不会执行 (一)使用TSql代码自 ...

  8. QuickBI助你成为分析师-数据建模(二)

    摘要: 数据集编辑功能界面介绍以及常见问题总结. 在数据集编辑界面可以进行数据建模来更好的展示数据,创建数据集默认将数值类型字段作为度量,日期.字符串等类型作为维度,度量可以根据维度分组展示.下面来介 ...

  9. CSS学习摘要-定位实例

    CSS学习摘要-定位实例 注:全文摘自MDN-CSS定位实例 列表消息盒子 我们研究的第一个例子是一个经典的选项卡消息框,你想用一块小区域包括大量信息时,一个非常常用的特征.这包括含有大信息量的应用, ...

  10. 阿里八八Alapa事后诸葛亮

    设想和目标 1.我们的软件要解决什么问题?是否定义的很清楚?是否对典型用户和典型场景有清晰的描述? 我们的项目希望解决用户对于时间.日程管理上不够方便.直观.易丢失的问题,因为并不是新颖高端的概念,因 ...