DW1000开发笔记(五)DW1000使用轮询方式接收数据
发布日期:2021-07-01 02:35:25 浏览次数:2 分类:技术文章

本文共 5479 字,大约阅读时间需要 18 分钟。

系列文章

〇、准备工作

之前的STM32L4小熊派开发板用于发送数据,这里我们使用一个STM32G070RB的板子连接DW1000官方评估板,作为数据接收端,硬件连接方式和STM32CubeMX工程配置生成请参考第二篇文章。

这里DW1000评估板和STM32G0开发板的连接情况如下表:

DW1000评估板引脚名 STM32G0引脚
RST PB3(输出)(评估板没有,预留出来这个引脚)
WAKEUP PB2(输出)
IRQ PB3(EXTI输入)
SPI_MISO PC2(SPI2_MISO)
SPI_MOSI PC3(SPI2_MOSI)
SPI_SCK PB13(SPI2_SCK)
SPI_CSn PB12(SPI2_NSS)

实物如下图:

接下来参考第二篇文章,使用STM32CubeMX配置SPI2、USART1、以及额外的两个GPIO,并测试是否可以正确读取DeviceID。

测试无误后,参考第三篇文章,将之前移植的HAL库通用驱动复制过来,复制过来之后,如图将驱动添加到MDK工程中,将头文件路径添加到MDK中:
接着需要在dw1000.h中配置控制引脚号,并根据板子实际的时钟主频来修改SPI配置高速率和低速率的函数,这里STM32G0T0RB的主频为64Mhz,SPI低速率最大3Mhz,所以低速率分频系数应该为32分频,SPI高速率最大20Mhz,所以高速率分频系数为4,综上所述,改为如下配置:

#ifndef _DW1000_H_#define _DW1000_H_#include "stm32g0xx_hal.h"/*	CS <-------------  PB12	RST <------------- PB4	WAKEUP <---------- PB2*/#define DW1000_CS_PORT			GPIOB#define DW1000_CS_PIN			GPIO_PIN_12#define DW1000_RST_PORT			GPIOB#define DW1000_RST_PIN			GPIO_PIN_4#define DW1000_WAKEUP_PORT	    GPIOB#define DW10000_WAKEUP_PIN	    GPIO_PIN_2/*	IRQ --------------> PB3*/#define DW1000_IRQn_TYPE		EXTI2_3_IRQn#define DW1000_IRQ_PORT		    GPIOB#define DW1000_IRQ_PIN			GPIO_PIN_3/*	SPI Interface <---> SPI2	SPI_CS <----------> PB12	SPI_CLK <---------> PB13	SPI_MISO <--------> PC2	SPI_MOSI <--------> PC3*/extern SPI_HandleTypeDef hspi2;#define DW1000_SPI_Handle hspi2/*    SPI rate = HCLK / SPI_BAUDRATEPRESCALE    SPI low rate must less than 3Mhz    SPI High rate must less than 20Mhz*/#define SPI_LOW_RATE    SPI_BAUDRATEPRESCALER_32#define SPI_HIGH_RATE   SPI_BAUDRATEPRESCALER_4void reset_DW1000(void);void spi_set_rate_low(void);void spi_set_rate_high(void);#endif /* _DW1000_H_ */

之后参考第三篇文章,测试使用驱动初始化DW1000,测试结果如下:

一、移植官方示例

1. 复制官方示例文件

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

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

将其添加到MDK工程中:

2. 修改官方示例文件

① 修改替换头文件:

② 修改函数名,修改打印和延时函数:

添加打印信息:

/* hex dump */printf("Recv Frame, frame_len is %d, frame data:\r\n", frame_len);for (i = 0; i < frame_len; i++){
printf("%02x ", rx_buffer[i]);}printf("\r\n");

修改完成。

3. 调用示例代码

修改main.c,移除我们之前自己添加的所有测试代码。

接着先引入外部定义:

/* USER CODE BEGIN PFP */extern int example_application_entry(void);/* USER CODE END PFP */

然后在main函数中调用:

/* USER CODE BEGIN 2 */printf("DW1000 UWB ic port on STM32G0 board By Mculover666\r\n");example_application_entry(); /* USER CODE END 2 */

需要注意:

此函数需要在GPIO、USART、SPI外设初始化完成之后调用

此函数中已经包含while(1)循环,所以此函数之后的代码无效

4. 移植结果

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

此时在等待接收数据,将第四节中完成的数据发送板上电,即可接收到发送板发送的数据:
示例程序移植成功。

二、示例程序分析

1. DW1000初始化API

和第四篇文章相同。

2. DW1000配置API(重点)

和第四篇文章相同。

3. DW1000使用轮询方式接收数据流程

3.1. 轮询接收流程

3.2. 接收使能API

该API的定义在deca_device_api.h中,实现在deca_device.c中,其原型如下:

int dwt_rxenable(int mode);

该函数使能DW1000接收数据

入参只有一个,表示接收数据模式,意义如下表:

意义
0 立即使能接收
1 设置延迟接收
3
4

这些值都有对应的宏定义:

#define DWT_START_RX_IMMEDIATE  0#define DWT_START_RX_DELAYED    1    // Set up delayed RX, if "late" error triggers, then the RX will be enabled immediately#define DWT_IDLE_ON_DLY_ERR     2    // If delayed RX failed due to "late" error then if this                                     // flag is set the RX will not be re-enabled immediately, and device will be in IDLE when function exits#define DWT_NO_SYNC_PTRS        4    // Do not try to sync IC side and Host side buffer pointers when enabling RX. This is used to perform manual RX                                     // re-enabling when receiving a frame in double buffer mode.

返回值也有两个:

返回值 意义
DWT_SUCCESS 使能成功
DWT_ERROR 使能错误(如果延迟时间已过,则延迟接收失败)

3.3. 查询中断标志寄存器

while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))  {
};

dwt_read32bitreg用来读取DW1000中一个32位的寄存器,SYS_STATUS_ID表示系统状态寄存器(System event Status Register)的ID:

#define SYS_STATUS_ID           0x0F            /* System event Status Register */

SYS_STATUS_RXFCG表示该寄存器中的RXFCG位,该位在接收到一帧数据成功后会被设置为1:

#define SYS_STATUS_RXFCG        0x00004000UL    /* Receiver FCS Good */

SYS_STATUS_RXFCE表示该寄存器中的RXFCE,该位在接收一帧数据错误后会被设置为1:

#define SYS_STATUS_RXFCE        0x00008000UL    /* Receiver FCS Error */

查询到这两位被设置之后,意味着接收到数据,但成功还是失败未知,进一步进行判断,使用完毕后,向对应的位写1,清空该位:

if (status_reg & SYS_STATUS_RXFCG) {
//接收成功 /* Clear good RX frame event in the DW1000 status register. */ dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);} else {
//接收失败 /* Clear RX error events in the DW1000 status register. */ dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);}

3.4. 读取接收的帧长度

判断到接收成功后,读取接收帧信息寄存器( RX_FINFO 寄存器),获取帧的信息:

这两个数据域的作用如下:
这里读取的时候有三种读取模式:

  • 只读取帧长度
  • 只读取帧长度扩展
  • 同时读取帧长度和帧长度扩展
#define RX_FINFO_RXFLEN_MASK    0x0000007FUL    /* Receive Frame Length (0 to 127) */#define RX_FINFO_RXFLE_MASK     0x00000380UL    /* Receive Frame Length Extension (0 to 7)<<7 */#define RX_FINFO_RXFL_MASK_1023 0x000003FFUL    /* Receive Frame Length Extension (0 to 1023) */

3.5. 读取接收的帧内容API

该API的定义在deca_device_api.h中,实现在deca_device.c中,其原型如下:

/*! ------------------------------------------------------------------------------------------------------------------ * @fn dwt_readrxdata() * * @brief This is used to read the data from the RX buffer, from an offset location give by offset parameter * * input parameters * @param buffer - the buffer into which the data will be read * @param length - the length of data to read (in bytes) * @param rxBufferOffset - the offset in the rx buffer from which to read the data * * output parameters * * no return value */void dwt_readrxdata(uint8 *buffer, uint16 length, uint16 rxBufferOffset);

该函数从DW1000接收缓冲区中读取接收的帧的内容

入参有三个,意义如下表:

意义
buffer 用于存储读取的内容
length 读取的数据的长度(一般为上一步获取到的帧长度)
rxBufferOffset 读取开始时在接收缓冲区中的偏移量

至此,DW1000接收示例代码移植、学习完成。

转载地址:https://mculover666.blog.csdn.net/article/details/115023448 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:DW1000开发笔记(六)DW1000发送数据并等待另一个DW1000回应
下一篇:DW1000开发笔记(四)DW1000使用轮询方式发送数据

发表评论

最新留言

很好
[***.229.124.182]2024年04月27日 05时23分19秒