1、DW1000简介
DWM1000 芯片是 Decawave 公司设计的超宽带收发模组,其自成收发系统,通过SPI接口与外界系统通信。用于TDOA定位系统中,测距精度可达10cm,最高6.8Mbps的数据传输率。其具有如下参数:
2、DW1000测距帧
测距过程:模块A发起poll帧,模块B回复resp帧,最后模块A发送final帧。最后距离计算在模块B中。
static uint8 rx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x21, 0, 0};
static uint8 tx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0x10, 0x02, 0, 0, 0, 0};
static uint8 rx_final_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1、DW1000传输数据
DW1000芯片定义了规范的通信数据帧格式,不是用户想怎么定义就怎么定义的。如果没有按照规范进行数据发送,就会出现传输数据不是自己期望的情况。数据帧格式如下:
因此,如果想要正确传输数据,需要按照上表定义通信报文数组。
首先是2个字节的Frame Control帧——用于帧过滤、通信组网、地址设置;
接下来1个字节的Sequence Number帧——帧序列号,每帧数据DW1000会自动增加1;
接下来2个字节的PAN ID帧——用于通信组网;
接下来2个字节的Destination Address帧——用于帧过滤,目的地址;
接下来2个字节的Source Address帧——用于帧过滤,源地址;
接下来多个字节的Ranging Message帧——这里才是我们用户可以自行添加和定义的数据位置;
最后的2个字节的FCS帧——用于数据校验,DW1000芯片会自动添加校验值,所以我们留空即可,设为0,0;
1.1 发送帧过滤的数据
假如节点A(0x0)需要发送数据:0x01,0x02,0x03,0x04,0x05,0x06给节点B(0x1)。
可以这样定义数据:0x88,0x41,0x0,0x59,0x68,0x01,0x0,0x01,0x02,0x03,0x04,0x05,0x06,0x0,0x0
1、DW1000需要配置的参数
typedef struct
{
uint8 chan ; //!< channel number {1, 2, 3, 4, 5, 7 }
uint8 prf ; //!< Pulse Repetition Frequency {DWT_PRF_16M or DWT_PRF_64M}
uint8 txPreambLength ; //!< DWT_PLEN_64..DWT_PLEN_4096
uint8 rxPAC ; //!< Acquisition Chunk Size (Relates to RX preamble length)
uint8 txCode ; //!< TX preamble code
uint8 rxCode ; //!< RX preamble code
uint8 nsSFD ; //!< Boolean should we use non-standard SFD for better performance
uint8 dataRate ; //!< Data Rate {DWT_BR_110K, DWT_BR_850K or DWT_BR_6M8}
uint8 phrMode ; //!< PHR mode {0x0 - standard DWT_PHRMODE_STD, 0x3 - extended frames DWT_PHRMODE_EXT}
uint16 sfdTO ; //!< SFD timeout value (in symbols)
} dwt_config_t ;
2、帧过滤模式
1.发送消息
//发送消息数组
static uint8 tx_msg[] = {0xC5, 0, 'D', 'E', 'C', 'A', 'W', 'A', 'V', 'E', 0, 0};
#define BLINK_FRAME_SN_IDX 1//帧数索引
#define TX_DELAY_MS 1000//休眠时间,单位ms
//main函数内
//第一步:传入数据,开始发送
dwt_writetxdata(sizeof(tx_msg), tx_msg, 0);//将需要发送的数据写入dwm1000芯片的内存,从偏移位置0开始
dwt_writetxfctrl(sizeof(tx_msg), 0);//确认发送数据参数
dwt_starttx(DWT_START_TX_IMMEDIATE);//开启发送(立即发送)
//第二步:等待发送完成
while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
{ };
//第三步:清空发送标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);
//第四步:下次发送前休眠
deca_sleep(TX_DELAY_MS);
//第五步:帧数自增
tx_msg[BLINK_FRAME_SN_IDX]++;
//函数功能:向外发送数据
void SendData(uint8_t data[])
{
//print_Message("in SendData!!!\r\n");
tx_status = TX_WAIT;
//第一步:传入数据,开始发送
dwt_writetxdata(sizeof(data), data, 0); //将需要发送的数据写入dwm1000芯片的内存,从偏移位置0开始
dwt_writetxfctrl(sizeof(data), 0, 1); //确认发送数据参数
int ret = dwt_starttx(DWT_START_TX_IMMEDIATE); //开启发送(立即发送)
HAL_IWDG_Refresh(&hiwdg); //喂狗。不要自动重启,告警后让人工重启
if (ret == DWT_ERROR)
{
//发送失败,打印失败信息
print_Message("send data error!\r\n");
//第三步:清空发送标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS);
//灯光示警
while (1)
{
HAL_IWDG_Refresh(&hiwdg); //喂狗。不要自动重启,告警后让人工重启
print_Message("please reboot device!!!\r\n");
led_on(LED_ALL);
HAL_Delay(200); //ms延时
led_off(LED_ALL);
}
}
//第二步:等待发送完成
while (!tx_status)
{
HAL_IWDG_Refresh(&hiwdg); //喂狗
};
print_Message("send data success!\r\n");
HAL_IWDG_Refresh(&hiwdg); //喂狗
//第三步:清空发送标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS);
}
2.芯片手动休眠
#define DUMMY_BUFFER_LEN 600
static uint8 dummy_buffer[DUMMY_BUFFER_LEN];
main函数:
//先唤醒DWM1000芯片,防止芯片在休眠
dwt_spicswakeup(dummy_buffer, DUMMY_BUFFER_LEN);
//配置休眠和唤醒参数
dwt_configuresleep(DWT_PRESRV_SLEEP | DWT_CONFIG, DWT_WAKE_CS | DWT_SLP_EN);
//芯片进入休眠
dwt_entersleep();
//唤醒DWM1000芯片
dwt_spicswakeup(dummy_buffer, DUMMY_BUFFER_LEN);
3.芯片自动休眠
#define DUMMY_BUFFER_LEN 600
static uint8 dummy_buffer[DUMMY_BUFFER_LEN];
main函数:
//先唤醒DWM1000芯片,防止芯片在休眠
dwt_spicswakeup(dummy_buffer, DUMMY_BUFFER_LEN);
//配置休眠和唤醒参数
dwt_configuresleep(DWT_PRESRV_SLEEP | DWT_CONFIG, DWT_WAKE_CS | DWT_SLP_EN);
//发送一帧数据后自动进入休眠
dwt_entersleepaftertx(1);
//单片机延时等待下一次发送
deca_sleep(TX_DELAY_MS);
//唤醒DWM1000芯片
dwt_spicswakeup(dummy_buffer, DUMMY_BUFFER_LEN);
4.接收消息
#define FRAME_LEN_MAX 127
static uint8 rx_buffer[FRAME_LEN_MAX];
main函数:
//步骤1:初始化接收数组
int i;
for (i = 0 ; i < FRAME_LEN_MAX; i++ )
{
rx_buffer[i] = 0;
}
//开启芯片接收
dwt_rxenable(0);
//等待接收到数据或者错误、超时发生
while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
{ };
//如果接收到数据成功
if (status_reg & SYS_STATUS_RXFCG)
{
//将接收到的数据拷贝到单片机中
frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
if (frame_len <= FRAME_LEN_MAX)
{
dwt_readrxdata(rx_buffer, frame_len, 0);//从芯片读取接收数据,从偏移地址0开始
}
//清空芯片寄存器的接收数据标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
}
else
{
//清空芯片寄存器的接收错误标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}
//函数功能:转为监听状态
void ListenData(void)
{
//步骤1:初始化接收数组
int i, status_reg, frame_len;
for (i = 0; i < FRAME_LEN_MAX; i++)
{
rx_buffer[i] = 0;
}
HAL_IWDG_Refresh(&hiwdg); //喂狗
dwt_setrxtimeout(inst_resp_rx_timeout); //设置接收超时时间,不设置一直在接收状态,都发送不了数据
int ret = dwt_rxenable(DWT_START_RX_IMMEDIATE); //开启接收机接收
if (ret == DWT_ERROR)
{
print_Message("recv 001\r\n"); //打印系统参数信息
//接收机开启失败,打印失败信息
print_Message("Recv Open error!\r\n");
//清空芯片寄存器的接收数据标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS);
//清空芯片寄存器的接收错误标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}
HAL_IWDG_Refresh(&hiwdg); //喂狗
}
5.发送后延迟一段时间开启接收
//延迟开启时间,单位:1 uus is 512/499.2 ms
#define TX_TO_RX_DELAY_UUS 60
//超时时间,单位:1 uus is 512/499.2 ms
#define RX_RESP_TO_UUS 5000
main函数:
//在帧输出完成后延迟一段时间开启接收
dwt_setrxaftertxdelay(TX_TO_RX_DELAY_UUS);
//设置回复帧超时
dwt_setrxtimeout(RX_RESP_TO_UUS);
6.接收数据后回复
#define FRAME_LEN_MAX 127
static uint8 rx_buffer[FRAME_LEN_MAX];
static uint8 tx_msg[] = {0x41, 0x8C, 0, 0x9A, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 'D', 'W', 0x10, 0x00, 0, 0, 0, 0};
#define DATA_FRAME_SN_IDX 2
#define DATA_FRAME_DEST_IDX 5
#define BLINK_FRAME_SRC_IDX 2
//延迟开启时间,单位:1 uus is 512/499.2 ms
#define TX_TO_RX_DELAY_UUS 60
//超时时间,单位:1 uus is 512/499.2 ms
#define RX_RESP_TO_UUS 5000
main函数:
//条件符合情况,回复数据
if ((frame_len == 14) && (rx_buffer[0] == 0xC5) && (rx_buffer[10] == 0x43) && (rx_buffer[11] == 0x2))
{
int i;
//发送数据初始化,把收到的数据链接到发送数据中
for (i = 0; i < 8; i++)
{
tx_msg[DATA_FRAME_DEST_IDX + i] = rx_buffer[BLINK_FRAME_SRC_IDX + i];
}
//发送数据
dwt_writetxdata(sizeof(tx_msg), tx_msg, 0);
dwt_writetxfctrl(sizeof(tx_msg), 0);
dwt_starttx(DWT_START_TX_IMMEDIATE);
//等待发送完成
while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
{ };
//清空发送标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);
tx_msg[DATA_FRAME_SN_IDX]++;
}
7.发送连续波
static dwt_txconfig_t txconfig = {
0xC0, /* PG delay. */
0x25456585, /* TX power. */
};
main函数:
dwt_configuretxrf(&txconfig);
//启动连续波模式
dwt_configcwmode(config.chan);
//延时一段时间
deca_sleep(CONT_WAVE_DURATION_MS);
//软件重启
dwt_softreset();
8.连续帧发送
//帧与帧之间的时延,单位8ns
#define CONT_FRAME_PERIOD 124800
static dwt_txconfig_t txconfig = {
0xC0, /* PG delay. */
0x25456585, /* TX power. */
};
main函数:
//设置发射模式
dwt_configuretxrf(&txconfig);
//启动连续帧模式
dwt_configcontinuousframemode(CONT_FRAME_PERIOD);
//发送数据,然后延迟一段时间
//软件重启
dwt_softreset();
9.twr标签:测距
#define POLL_TX_TO_RESP_RX_DLY_UUS 150
#define RESP_RX_TIMEOUT_UUS 2700
static uint8 tx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x21, 0, 0};
static uint8 rx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0x10, 0x02, 0, 0, 0, 0};
static uint8 tx_final_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#define ALL_MSG_SN_IDX 2
static uint8 frame_seq_nb = 0;
typedef unsigned long long uint64;
static uint64 poll_tx_ts;
static uint64 resp_rx_ts;
static uint64 final_tx_ts;
#define FINAL_MSG_POLL_TX_TS_IDX 10
#define FINAL_MSG_RESP_RX_TS_IDX 14
#define FINAL_MSG_FINAL_TX_TS_IDX 18
main函数:
//设置发送和接收后的天线到事件的延迟
dwt_setrxantennadelay(RX_ANT_DLY);
dwt_settxantennadelay(TX_ANT_DLY);
//设置发送后延迟一段时间开启接收
dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS);
//设置接收超时时间
dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);
tx_poll_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
//发送数据tx_poll_msg
//发送后期待回复
dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);
//等待接收数据
while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
{ };
//帧自增
frame_seq_nb++;
//如果数据正常接收
if (status_reg & SYS_STATUS_RXFCG)
{
uint32 frame_len;
//清空接收标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS);
//获取接收帧长度,读取接收数据
frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_MASK;
if (frame_len <= RX_BUF_LEN)
{
dwt_readrxdata(rx_buffer, frame_len, 0);
}
//对接收数据进行解析
rx_buffer[ALL_MSG_SN_IDX] = 0;
//如果接收数据是回复消息
if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0)
{
uint32 final_tx_time;
//提取时间戳
poll_tx_ts = get_tx_timestamp_u64();
resp_rx_ts = get_rx_timestamp_u64();
//计算最终消息的传输时间
final_tx_time = (resp_rx_ts + (RESP_RX_TO_FINAL_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8;
dwt_setdelayedtrxtime(final_tx_time);
//最终发送帧时间戳是传输时间+天线延迟
final_tx_ts = (((uint64)(final_tx_time & 0xFFFFFFFE)) << 8) + TX_ANT_DLY;
//在最终发送帧中写入所有时间戳
final_msg_set_ts(&tx_final_msg[FINAL_MSG_POLL_TX_TS_IDX], poll_tx_ts);
final_msg_set_ts(&tx_final_msg[FINAL_MSG_RESP_RX_TS_IDX], resp_rx_ts);
final_msg_set_ts(&tx_final_msg[FINAL_MSG_FINAL_TX_TS_IDX], final_tx_ts);
//发送数据
tx_final_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
dwt_writetxdata(sizeof(tx_final_msg), tx_final_msg, 0);
dwt_writetxfctrl(sizeof(tx_final_msg), 0);
dwt_starttx(DWT_START_TX_DELAYED);
//等待发送完成
while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS))
{ };
//清空发送标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);
//帧自增
frame_seq_nb++;
}
}
else
{
//清除接收错误数据标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}
10.twr基站:测距
#define TX_ANT_DLY 16436
#define RX_ANT_DLY 16436
static uint8 rx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x21, 0, 0};
static uint8 tx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0x10, 0x02, 0, 0, 0, 0};
static uint8 rx_final_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#define ALL_MSG_COMMON_LEN 10
/* Index to access some of the fields in the frames involved in the process. */
#define ALL_MSG_SN_IDX 2
#define FINAL_MSG_POLL_TX_TS_IDX 10
#define FINAL_MSG_RESP_RX_TS_IDX 14
#define FINAL_MSG_FINAL_TX_TS_IDX 18
#define FINAL_MSG_TS_LEN 4
#define RX_BUF_LEN 24
static uint8 rx_buffer[RX_BUF_LEN];
#define UUS_TO_DWT_TIME 65536
#define POLL_RX_TO_RESP_TX_DLY_UUS 2600
#define RESP_TX_TO_FINAL_RX_DLY_UUS 500
#define FINAL_RX_TIMEOUT_UUS 3300
main函数:
//设置发送和接收后的天线到事件的延迟
dwt_setrxantennadelay(RX_ANT_DLY);
dwt_settxantennadelay(TX_ANT_DLY);
//设置接收超时时间
dwt_setrxtimeout(0);
//开启接收
dwt_rxenable(0);
//等待接收完成
while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
{ };
//如果接收数据正常,进入
if (status_reg & SYS_STATUS_RXFCG)
{
uint32 frame_len;
//清除接收标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
//读取数据到单片机
frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
if (frame_len <= RX_BUFFER_LEN)
{
dwt_readrxdata(rx_buffer, frame_len, 0);
}
//如果是poll消息,发送回复消息
rx_buffer[ALL_MSG_SN_IDX] = 0;
if (memcmp(rx_buffer, rx_poll_msg, ALL_MSG_COMMON_LEN) == 0)
{
uint32 resp_tx_time;
//提取poll的时间戳
poll_rx_ts = get_rx_timestamp_u64();
//发送回复消息
resp_tx_time = (poll_rx_ts + (POLL_RX_TO_RESP_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8;
//设置发送延迟时间
dwt_setdelayedtrxtime(resp_tx_time);
//设置发送后延时开启接收
dwt_setrxaftertxdelay(RESP_TX_TO_FINAL_RX_DLY_UUS);
//设置接收超时时间
dwt_setrxtimeout(FINAL_RX_TIMEOUT_UUS);
//发送消息
tx_resp_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
dwt_writetxdata(sizeof(tx_resp_msg), tx_resp_msg, 0);
dwt_writetxfctrl(sizeof(tx_resp_msg), 0);
dwt_starttx(DWT_START_TX_DELAYED | DWT_RESPONSE_EXPECTED);
//等待接收完成,接收的是最终消息
while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
{ };
//帧数自增
frame_seq_nb++;
//如果接收的数据正常
if (status_reg & SYS_STATUS_RXFCG)
{
//清除接收数据标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS);
//将数据读取到单片机
frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_MASK;
if (frame_len <= RX_BUF_LEN)
{
dwt_readrxdata(rx_buffer, frame_len, 0);
}
//确认接收的是不是最终消息
rx_buffer[ALL_MSG_SN_IDX] = 0;
if (memcmp(rx_buffer, rx_final_msg, ALL_MSG_COMMON_LEN) == 0)
{
uint32 poll_tx_ts, resp_rx_ts, final_tx_ts;
uint32 poll_rx_ts_32, resp_tx_ts_32, final_rx_ts_32;
double Ra, Rb, Da, Db;
int64 tof_dtu;
//提取回复时间戳和最终消息时间戳
resp_tx_ts = get_tx_timestamp_u64();
final_rx_ts = get_rx_timestamp_u64();
final_msg_get_ts(&rx_buffer[FINAL_MSG_POLL_TX_TS_IDX], &poll_tx_ts);
final_msg_get_ts(&rx_buffer[FINAL_MSG_RESP_RX_TS_IDX], &resp_rx_ts);
final_msg_get_ts(&rx_buffer[FINAL_MSG_FINAL_TX_TS_IDX], &final_tx_ts);
//计算飞行时间
poll_rx_ts_32 = (uint32)poll_rx_ts;
resp_tx_ts_32 = (uint32)resp_tx_ts;
final_rx_ts_32 = (uint32)final_rx_ts;
Ra = (double)(resp_rx_ts - poll_tx_ts);
Rb = (double)(final_rx_ts_32 - resp_tx_ts_32);
Da = (double)(final_tx_ts - resp_rx_ts);
Db = (double)(resp_tx_ts_32 - poll_rx_ts_32);
tof_dtu = (int64)((Ra * Rb - Da * Db) / (Ra + Rb + Da + Db));
tof = tof_dtu * DWT_TIME_UNITS;
distance = tof * SPEED_OF_LIGHT;
//显示
sprintf(dist_str, "DIST: %3.2f m", distance);
lcd_display_str(dist_str);
}
}
else
{
//清除接收错误标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}
}
}
else
{
//清除接收错误标志
dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}