单片机
返回首页

DW1000开发笔记(六)DW1000发送数据并等待另一个DW1000回应

2021-07-30 来源:eefocus

一、移植发送数据并等待响应的代码

本文中使用基于STM32F103ZET6开发板+DW1000评估板作为发送数据并等待回应端。


1. 复制官方示例文件

将官方驱动库中example下的第三个示例 a 移植过来:

复制到之前移植的STM32CubeMX生成的工程文件中,并重命名文件为tx_wait_resp_example.c:

将其添加到MDK工程中:

将之前移植的发送demo取消工程构建(防止冲突):

2. 修改官方示例文件

① 修改替换头文件:

② 修改函数名

③ 修改打印和延时函数:

添加调试打印信息:

printf('send okrn');


printf('send data:rn[');

/* hex dump */

for (int i = 0; i < sizeof(tx_msg); i++)

{

    printf('%02x ', tx_msg[i]);

}

printf(']rn');


printf('recv okrn');


printf('recv resp data:rn[');

/* hex dump */

for (int i = 0; i < frame_len; i++)

{

    printf('%02x ', rx_buffer[i]);

}

printf(']rn');



修改延时函数:

修改完成。


3. 调用示例代码

main.c保持原来第三节中的测试代码不变。


4. 移植结果

编译、下载程序,在串口助手中查看打印日志:

可以看到DW1000一直在循环发送,但没有收到应答。


三、移植接收数据并发送响应的代码

本文中使用基于STM32L431RCT6开发板+DW1000 E53扩展板作为接收数据并发送响应的一侧设备。


1. 复制官方示例文件

将官方驱动库中example下的第三个示例 b 移植过来:

复制到之前移植的STM32CubeMX生成的工程文件中,并重命名文件为rx_send_resp_example.c:

将其添加到MDK工程中:

将之前移植的接收demo取消工程构建(防止冲突):

2. 修改官方示例文件

① 修改替换头文件:

② 修改函数名

③ 修改打印函数:

再添加一些额外的调试信息:

printf('recv okrn');

/* hex dump */

printf('recv data:rn[');

for (int i = 0; i < frame_len; i++)

{

    printf('%02x ', rx_buffer[i]);

}

printf(']rn');


printf('send resp okrn');


/* hex dump */

printf('send data:rn[');

for (int i = 0; i < sizeof(tx_msg); i++)

{

    printf('%02x ', tx_msg[i]);

}

printf(']rn');


在这里插入图片描述
修改完成。


3. 调用示例代码

main.c保持原来第四节中的测试代码不变。


4. 移植结果

编译、下载程序,在串口助手中查看打印日志:

可以看到这一侧没有问题 ,接收到数据之后并发送响应数据回去。

此时再看等待响应的一侧:

发送成功但是接收数据超时,移植失败。接下来我们对照API手册,研究一下本实验中的API,之后再对此问题进行定位、分析、解决。


四、发送之后等待接收响应API分析

1. 发送并等待响应的流程

2. 发送并等待响应流程中需要设置的延时时间

在发生并等待响应端,延时时间有两个,设置API分别如下。

第一个是从发送完成开始,到自动打开接收模式的延时时间。使用下面的API进行设置:

void dwt_setrxaftertxdelay(uint32 rxDelayTime);


它的入参只有一个,表示设置的时间大小。

这个时间值的大小宽度为20bit,也就是最大为 2 20 − 1 = 1048575 2^{20}-1=1048575 220−1=1048575。这个时间值的单位是UWB ms,该单位与正常的时间关系为 1 U W B m s = 512 / 499.2 M h z u s = 1.0256 u s 1 UWB ms = 512/499.2Mhz us = 1.0256 us 1UWBms=512/499.2Mhzus=1.0256us。


这个值最小可以设置为0,设置为0的时候,则DW1000会在发送完成后立即打开接收模式,这个操作大概需要花费6.2us的时间。而且如果设置的值小于7us,则花费的时间依然会是6.2us。


第二个是设置接收数据超时时间,即接收端在RX启用命令之后保持开着多久,其API原型如下:

void dwt_setrxtimeout(uint16 time);


该函数的入参也有一个,是一个16位的值(最大65535),单位依然是UWB ms,也就是1.0256us。


如果设置最大,则大约是 1.0256 ∗ 65535 / 1000 = 65 m s 1.0256*65535/1000=65ms 1.0256∗65535/1000=65ms。


如果设置为0,则表示禁止该超时检测功能。


该函数没有返回值,但需要注意,该功能设置的是DW1000内部硬件定时器,如果发生超时,则直接置位SY_STAT_RFTO事件标志。


3. 发送数据并等待回应

写入数据到发送缓冲区和控制发送寄存器的操作和之前普通发送相同,无需赘述。

在启动发送的时候,除了设置立即发送模式(DWT_START_TX_IMMEDIATE),还要设置等待响应模式(DWT_RESPONSE_EXPECTED),如下:

/* Start transmission, indicating that a response is expected so that reception is enabled immediately after the frame is sent. */

dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);


4. 轮询是否接收到响应数据

如果设置了接收超时时间,还应该在轮询的时间检测是否超时(SYS_STATUS_ALL_RX_TO),如下:

/* We assume that the transmission is achieved normally, now poll for reception of a frame or error/timeout. See NOTE 8 below. */

while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR)))

{ };


其余的是成功接收到数据之后的操作,与普通数据接收没有区别。


五、接收超时问题分析(重点)

1. 问题分析

在第二块板没有上电时,第一块板在发送等待接收回应超时,因为响应数据并没有发送,所以这是正常的。


但在第二块板上电后,第二块板的日志显示确实发送响应数据成功,所以问题就出在第一块板的接收上面。


根据上一节对API的分析,接收并等待回应API有两个超时值,可能会出现以下两种情况:

① 从发送完成开始,到自动打开接收模式的延时时间(dwt_setrxaftertxdelay)设置太长,还没有来得及打开接收,对方(第二块板)已发送完毕;

② 接收数据超时时间(dwt_setrxtimeout)设置太短,对方还没来得及发送,本机已经接收超时。


接下来我们分别验证这两种情况,定位问题所在。


2. 问题定位

2.1. 定位是否为情况1

将从发送完成开始,到自动打开接收模式的延时时间设置为最低,也就是0,根据API手册,设置为0之后也要花费6.7us,这时最短时间:

再次编译、下载,查看串口日志:

依然接收超时,证明问题不在这儿,将该值改回原来的60(UWB ms)。


2.2. 定位是否为情况2

将接收数据超时时间设置为最长,也就是0,表示禁止接收超时:

编译、下载,查看串口日志:

接收响应数据成功,定位出问题所在,就是默认的接收超时时间5000(UWB ms)设置太短了,对方还未来的及发送回应数据,本机已接收超时。


那么,接收超时时间到底该设置为多少呢?接下来我们使用STM32 Systick生成的时间戳来测量一下。


3. 测量接收时间

接收数据超时时间是接收端在RX启用命令之后保持开着多久,但是RX又是在发送完成之后自动开启的,所以我们从发送之后开始测量,到接收数据结束。


测量工具利用STM32 Systick,在HAL库中默认为1ms一次。


添加以下测试代码:

uint32_t rx_start_time = 0, rx_end_time = 0;

uint32_t rx_spend_time = 0;


在发送完成之后设置的延时使能时间大约是60us,相对与ms级别来说差了一个量级,可以忽略不计,所以在发送完成之后记录接收开始时间戳:

/* get start timestamp */

rx_start_time = HAL_GetTick();


注意:一定要在发送完成之后立即获取开始时间戳。

然后在接收到数据之后立即获取结束时间戳:

/* get end timestamp */

rx_end_time = HAL_GetTick();


最后在本次数据发送和接收完成之后,打印计算出的响应数据接收花费时间:

/* log rx spend time */

rx_spend_time = rx_end_time - rx_start_time;

printf('rx spend time is %d msrn', rx_spend_time);


编译,运行,查看实际响应数据接收花费的时间:

可以看到,数据实际接收的时间为12ms左右,所以要设置为12000(UWB ms),一个UWB ms几乎可以按1us来算,为了保险起见,设置为15000:

再次编译、下载,查看串口助手结果:

可以看到,发送之后成功接收到响应数据。

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章