DWM1000 中断与STM32外部中断

DWM1000 中断与STM32外部中断

概述

  • DWM1000 本身有很多中断控制,例如发送完成中断,接收完成中断等等, 可以通过IRQ(GPIO8) 送到外部控制器。

  • DWM1000 IRQ pin可以挂到STM32 的外部中断上。 例如当接收到数据帧后,DWM1000 拉IRQ,STM32 实时处理接收到的数据帧。之前代码没有用到中断部分,这里补上一些相关内容。

原理图

  • 从原理图上看,IRQ 连到的PB0上

在这里插入图片描述

中断

中断事件

//DW1000中断事件定义
#define DWT_INT_TFRS            0x00000080          // 帧发送完成,数据帧成功发送后触发
#define DWT_INT_LDED            0x00000400          // 微码执行完毕,DWM1000内部处理结束后触发
#define DWT_INT_RFCG            0x00004000          // 帧接收且CRC校验正确,表示接收到完整无误的数据帧
#define DWT_INT_RPHE            0x00001000          // 接收器PHY头部错误,物理层接收到的帧头部有误
#define DWT_INT_RFCE            0x00008000          // 接收器CRC错误,接收到的数据帧CRC校验失败,数据可能已损坏
#define DWT_INT_RFSL            0x00010000          // 接收器同步丢失错误,接收过程中丢失同步
#define DWT_INT_RFTO            0x00020000          // 帧等待超时,预定时间内没有接收到完整的帧
#define DWT_INT_RXOVRR          0x00100000          // 接收器溢出,数据超过接收缓冲区容量
#define DWT_INT_RXPTO           0x00200000          // 前导码检测超时,设定时间内未检测到前导码,表示无帧传输
#define DWT_INT_SFDT            0x04000000          // SFD超时,指定时间内未检测到帧起始界定符
#define DWT_INT_ARFE            0x20000000          // 帧被拒绝,由于帧过滤配置,接收到的帧不被接受

这段代码定义了一系列宏,它们代表了DWM1000(一款用于超宽带通信的集成电路)的不同中断事件标志。当DWM1000的某个特定事件发生时,相应的位在设备的状态寄存器中会被设置。这些宏定义了每个事件对应的位掩码,使得软件可以检查(通过读取状态寄存器)哪个事件已经发生。下面是每个宏定义的事件详细解释:

  • DWT_INT_TFRS (0x00000080):帧发送完成。当一帧数据成功发送之后,这个中断事件会被触发。

  • DWT_INT_LDED (0x00000400):微代码执行完毕。在DWM1000执行特定的内部处理完毕后,会触发这个事件。

  • DWT_INT_RFCG (0x00004000):帧接收并且CRC校验正确。当接收到的帧的CRC(循环冗余检查)校验是正确的,表明这是一个完整且无误的数据帧。

  • DWT_INT_RPHE (0x00001000):接收器PHY头错误。指示在物理层接收到的帧头部存在错误。

  • DWT_INT_RFCE (0x00008000):接收器CRC错误。如果接收到的帧CRC校验失败,表明数据在传输中可能已损坏。

  • DWT_INT_RFSL (0x00010000):接收器同步丢失错误。如果在接收过程中丢失了同步,这个事件会被触发。

  • DWT_INT_RFTO (0x00020000):帧等待超时。如果在预定的时间内没有接收到完整的帧,这个事件就会发生。

  • DWT_INT_RXOVRR (0x00100000):接收器溢出。如果接收缓存区溢出,即数据超过了接收缓存区的容量,就会发生这个错误。

  • DWT_INT_RXPTO (0x00200000):前导码检测超时。如果没有在设定的时间内检测到前导码,表明没有帧在传输,就会触发这个超时事件。

  • DWT_INT_SFDT (0x04000000):SFD(Start of Frame Delimiter,帧起始界定符)超时。如果在指定的时间内没有检测到SFD,这个事件会被触发。

  • DWT_INT_ARFE (0x20000000):帧被拒绝。由于帧过滤配置的原因,接收到的帧不被接受。

在实际应用中,这些中断事件可以用来处理DWM1000在通信过程中的各种情况,例如确认数据是否发送/接收成功,或者在出现错误时采取相应的错误处理措施。开发者通常会在中断服务程序中检查这些状态位,以确定需要响应的具体事件。

外部中断

#define DECAIRQ                     GPIO_Pin_0          // 定义DWM1000中断引脚所对应的GPIO引脚编号,这里为GPIO_Pin_0,即第0号引脚
#define DECAIRQ_GPIO                GPIOB               // 指定DWM1000中断引脚连接的GPIO端口,这里为GPIOB
#define DECAIRQ_EXTI                EXTI_Line0          // 指定与DWM1000中断引脚相对应的外部中断线路,这里为EXTI_Line0
#define DECAIRQ_EXTI_PORT           GPIO_PortSourceGPIOB // 定义配置外部中断时使用的GPIO端口源,这里为GPIOB端口
#define DECAIRQ_EXTI_PIN            GPIO_PinSource0     // 定义配置外部中断时使用的GPIO引脚源,这里为第0位源
#define DECAIRQ_EXTI_IRQn           EXTI0_IRQn          // 指定外部中断的中断请求编号(IRQn),这里为EXTI0_IRQn
#define DECAIRQ_EXTI_USEIRQ         ENABLE              // 定义一个宏,用于启用外部中断
#define DECAIRQ_EXTI_NOIRQ          DISABLE             // 定义一个宏,用于禁用外部中断

这段代码定义了一组宏,用于配置STM32微控制器上的一个外部中断(EXTI),以便与DWM1000模块的中断引脚相连。每个宏都有特定的目的:

  • DECAIRQ:定义了与DWM1000中断引脚连接的GPIO引脚编号,这里是GPIO的第0位(Pin 0)。

  • DECAIRQ_GPIO:指定DWM1000中断引脚连接的GPIO端口,在这里是GPIOB。

  • DECAIRQ_EXTI:指定与DECAIRQ引脚相对应的外部中断线路,在这里是EXTI的线路0。

  • DECAIRQ_EXTI_PORT:定义了配置外部中断时要使用的GPIO端口源,在这里是GPIOB端口。

  • DECAIRQ_EXTI_PIN:定义了配置外部中断时要使用的GPIO引脚源,在这里是GPIO的第0位源。

  • DECAIRQ_EXTI_IRQn:指定了外部中断的中断请求编号(IRQn),在这里是EXTI的0号中断。

  • DECAIRQ_EXTI_USEIRQ:定义一个宏来启用外部中断,在配置中断时使用。

  • DECAIRQ_EXTI_NOIRQ:定义一个宏来禁用外部中断,在配置中断时使用。

在STM32的配置代码中,这些宏将被用来指定和配置DWM1000的中断引脚,以确保当DWM1000产生中断信号时,STM32的相应外部中断可以正确地被触发。这通常涉及到设置GPIO引脚为输入模式,并且配置中断优先级和中断服务例程(ISR)。这样做可以确保当中断发生时,微控制器能够响应并执行ISR中定义的代码。

中断配置

int NVIC_Configuration(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;// 启用作为DECAIRQ的GPIO用于中断GPIO_InitStructure.GPIO_Pin = DECAIRQ;  // 指定中断引脚为DECAIRQGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;  // 将IRQ引脚设置为下拉输入,防止DW1000进入睡眠模式时产生不必要的外部中断GPIO_Init(DECAIRQ_GPIO, &GPIO_InitStructure);  // 初始化GPIO配置/* 将EXTI线路连接到GPIO引脚 */GPIO_EXTILineConfig(DECAIRQ_EXTI_PORT, DECAIRQ_EXTI_PIN); // 配置GPIO引脚与EXTI线路的连接/* 配置EXTI线路 */EXTI_InitStructure.EXTI_Line = DECAIRQ_EXTI;  // 指定EXTI线路为DECAIRQ_EXTIEXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;  // 设置EXTI模式为中断EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  // 设置触发方式为上升沿触发,因为DWM1000默认中断极性为高EXTI_InitStructure.EXTI_LineCmd = DECAIRQ_EXTI_USEIRQ;  // 启用EXTI线路的中断EXTI_Init(&EXTI_InitStructure);  // 初始化EXTI配置/* 设置NVIC分组为16组中断无子分组 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);  // 配置NVIC优先级分组为16组/* 启用并设置EXTI中断为最低优先级 */NVIC_InitStructure.NVIC_IRQChannel = DECAIRQ_EXTI_IRQn;  // 指定NVIC中断通道为DECAIRQ_EXTI_IRQnNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;  // 设置抢占优先级为最低(15)NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  // 设置子优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd = DECAIRQ_EXTI_USEIRQ;  // 启用NVIC中断通道NVIC_Init(&NVIC_InitStructure);  // 初始化NVIC配置return 0;
}

这段代码是STM32微控制器固件中的一个函数,其目的是配置中断向量控制器(NVIC),以便能够处理来自DWM1000模块的中断信号。代码分几个部分进行配置:

  1. 首先,函数NVIC_Configuration定义了三个结构体变量,分别用于初始化GPIO(通用输入/输出),EXTI(外部中断/事件控制器),和NVIC。

  2. 在启用用作DECAIRQ的GPIO引脚(即DWM1000的中断引脚)后,该引脚被配置为下拉输入模式。这是为了防止在DWM1000进入睡眠模式时产生不必要的外部中断。

  3. 使用GPIO_EXTILineConfig函数将EXTI的特定线路连接到之前配置的GPIO引脚上。

  4. 接下来,配置EXTI线路的具体参数,包括指定的线路DECAIRQ_EXTI、设置中断模式为EXTI_Mode_Interrupt、设置触发方式为上升沿触发EXTI_Trigger_Rising(因为DWM1000的中断极性默认是高电平),并启用该线路的中断。

  5. 通过NVIC_PriorityGroupConfig函数设置NVIC的分组,此处使用的是16个中断组的配置,没有子组。

  6. 配置NVIC的中断通道,即前面通过EXTI连接的DECAIRQ中断线路。设置中断的抢占优先级为最低(15),子优先级为0,并启用该中断通道。

  7. 最后调用NVIC_Init函数应用NVIC的配置,并且函数返回0表示成功配置。

这个函数是STM32配置中断处理的典型示例,确保当DWM1000模块产生中断信号时,STM32能够正确识别该信号并调用相应的中断服务例程(ISR)来处理。

使能中断

  • 使能DWM1000 RX中断,注意这里需要将一些ERROR信息都加入,不能只考虑DWT_INT_RFCG
// 设置DWM1000的中断,以便对各种接收情况做出响应
dwt_setinterrupt(DWT_INT_RFCG | (DWT_INT_ARFE | DWT_INT_RFSL | DWT_INT_SFDT | DWT_INT_RPHE | DWT_INT_RFCE | DWT_INT_RFTO /*| DWT_INT_RXPTO*/), 1);
// 启用接收带有正确CRC的帧的中断,以及其他几种错误情况的中断。// 重新配置,仅启用接收到带有正确CRC的帧时触发的中断
dwt_setinterrupt(DWT_INT_RFCG , 1);
// 这可能是为了重置之前的中断设置,只关注接收正确的CRC帧的情况。// 启用自动接收重新使能功能
dwt_setautorxreenable(1);
// 开启此功能后,DWM1000会在完成一次数据接收处理后自动返回接收模式,连续接收数据包无需软件重置。

这段代码涉及对DWM1000设备的中断设置。DWM1000是一种集成无线收发器,广泛用于精准的室内定位和距离测量。以下是对每一行代码的详细解释:

  1. dwt_setinterrupt(DWT_INT_RFCG | (DWT_INT_ARFE | DWT_INT_RFSL | DWT_INT_SFDT | DWT_INT_RPHE | DWT_INT_RFCE | DWT_INT_RFTO /| DWT_INT_RXPTO/), 1);

    • dwt_setinterrupt函数用于设置DWM1000的中断。这里配置多个中断源,使用位或操作(|)来组合它们。
    • DWT_INT_RFCG:接收到带有正确CRC的帧时触发的中断。
    • DWT_INT_ARFE:由于帧过滤规则,被拒绝的帧触发的中断。
    • DWT_INT_RFSL:接收同步丢失错误触发的中断。
    • DWT_INT_SFDT:帧起始定界符超时触发的中断。
    • DWT_INT_RPHE:接收PHY头错误触发的中断。
    • DWT_INT_RFCE:接收CRC错误触发的中断。
    • DWT_INT_RFTO:接收帧等待超时触发的中断。
    • 第二个参数1表示启用这些中断。
    • 注:DWT_INT_RXPTO(前导码检测超时)中断在这里被注释掉了,意味着在当前配置中不启用这个中断。
  2. dwt_setinterrupt(DWT_INT_RFCG , 1);

    • 这行代码再次调用dwt_setinterrupt函数,但这次只启用DWT_INT_RFCG中断。这可能是为了重置之前的中断设置,只关注接收正确的CRC帧的情况。
  3. dwt_setautorxreenable(1);

    • dwt_setautorxreenable函数用于设置自动重新启用接收功能。传入的参数1意味着启用这项功能。
    • 当启用自动接收重新使能时,DWM1000在完成一次数据接收处理后会自动返回到接收模式,这样可以连续接收多个数据包而无需软件介入重新启动接收过程。

这些函数一起配置了DWM1000的中断行为和接收模式,为连续接收和处理数据包提供了便利,同时通过中断通知主系统各种重要事件。这是在实现基于DWM1000的定位和测距系统时常见的设置步骤。

中断响应

//extern void Simple_Rx_Callback(void);
extern void (*bphero_rxcallback)(void);  // 声明一个外部函数指针bphero_rxcallback,指向一个无参数无返回值的函数
void EXTI0_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line0)!= RESET)  // 检查EXTI_Line0是否触发了中断{// Simple_Rx_Callback();  // 本来可以直接调用一个预定义的回调函数(*bphero_rxcallback)();  // 调用通过函数指针指向的回调函数EXTI_ClearITPendingBit(EXTI_Line0);  // 清除EXTI_Line0上的中断等待位,准备接收下一次中断}
}

这段代码定义了一个名为EXTI0_IRQHandler的中断服务例程(ISR),它是STM32微控制器用来响应外部中断0(EXTI0)的函数。代码的主要功能如下:

  1. extern void (*bphero_rxcallback)(void);

    • 这行代码声明了一个外部定义的函数指针bphero_rxcallback。这个函数指针指向一个没有参数和返回值的函数,即一个回调函数。由于它是用extern关键字声明的,意味着这个函数指针的定义在别的地方,可能是其他源文件中。
  2. void EXTI0_IRQHandler(void)

    • 这是EXTI0的中断服务例程(ISR)的定义。当EXTI0线上的中断事件发生时,这个函数将被系统调用。
  3. if(EXTI_GetITStatus(EXTI_Line0) != RESET)

    • 在ISR内部,首先调用EXTI_GetITStatus函数检查EXTI_Line0是否真的是触发了中断。EXTI_GetITStatus函数会返回中断线的状态,如果不是RESET状态(通常在STM32库中,RESET被定义为0),则说明EXTI_Line0上的中断事件已经发生。
  4. (*bphero_rxcallback)();

    • 如果检测到中断,接下来调用之前声明的回调函数。这个回调函数是通过函数指针bphero_rxcallback调用的,意味着在运行时可以指向任何具有相应签名的函数。这提供了代码的灵活性,因为可以在不修改ISR代码的情况下改变中断响应的行为。
  5. EXTI_ClearITPendingBit(EXTI_Line0);

    • 最后,调用EXTI_ClearITPendingBit函数清除EXTI_Line0上的中断等待位,这样做是为了防止中断服务例程被连续不断地调用。清除中断标志位是告诉中断控制器这次中断已经被处理完毕,可以继续监听后续的中断请求。

注释中被注释掉的// Simple_Rx_Callback();这行代码示例了另一种直接调用预定义回调函数的方式,但在这个例子中它被替换为了使用函数指针的方式。

中断调用回调函数

void Simple_Rx_Callback()
{uint32 status_reg = 0,i=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;char dist_str[16] = {0};for (i = 0 ; i < FRAME_LEN_MAX; i++ ){rx_buffer[i] = '\0';  // 清空接收缓冲区}/* 禁用接收,准备读取状态。注释2相关 */dwt_enableframefilter(DWT_FF_RSVD_EN);//禁用接收status_reg = dwt_read32bitreg(SYS_STATUS_ID);  // 读取状态寄存器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);  // 读取接收到的数据到缓冲区msg_f = (srd_msg_dsss*)rx_buffer;  // 转换缓冲区数据到结构体以便处理// 将源地址作为目标地址复制msg_f_send.destAddr[0] = msg_f->sourceAddr[0];msg_f_send.destAddr[1] = msg_f->sourceAddr[1];// 复制源序列号msg_f_send.seqNum = msg_f->seqNum;switch(msg_f->messageData[0])  // 根据消息类型处理{case 'P':  // 处理Poll消息/* 提取接收时间戳 */msg_f_send.messageData[0]='A';  // 设置回应消息类型为Poll ackint temp = (int)(distance[msg_f_send.destAddr[0]]*100);//将距离转换为厘米msg_f_send.messageData[1]=temp/100;  // 距离的整数部分msg_f_send.messageData[2]=temp%100;  // 距离的小数部分dwt_writetxdata(14, (uint8 *)&msg_f_send, 0);  // 写入待发送数据dwt_writetxfctrl(14, 0);  // 设置发送帧控制dwt_starttx(DWT_START_TX_IMMEDIATE);  // 开始发送while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS)){ };  // 等待发送完成poll_rx_ts = get_rx_timestamp_u64();  // 获取接收时间戳break;case 'F':  // 处理Final消息/* 提取发送和接收时间戳 */resp_tx_ts = get_tx_timestamp_u64();final_rx_ts = get_rx_timestamp_u64();/* 提取嵌入在最终消息中的时间戳 */final_msg_get_ts(&msg_f->messageData[FINAL_MSG_POLL_TX_TS_IDX], &poll_tx_ts);final_msg_get_ts(&msg_f->messageData[FINAL_MSG_RESP_RX_TS_IDX], &resp_rx_ts);final_msg_get_ts(&msg_f->messageData[FINAL_MSG_FINAL_TX_TS_IDX], &final_tx_ts);/* 计算飞行时间。即使时钟环绕,32位减法也能给出正确答案 */poll_rx_ts_32 = (uint32)poll_rx_ts;  // 将poll_rx_ts转换为32位无符号整型并赋值给poll_rx_ts_32resp_tx_ts_32 = (uint32)resp_tx_ts;  // 将resp_tx_ts转换为32位无符号整型并赋值给resp_tx_ts_32final_rx_ts_32 = (uint32)final_rx_ts;  // 将final_rx_ts转换为32位无符号整型并赋值给final_rx_ts_32Ra = (double)(resp_rx_ts - poll_tx_ts);  // 计算响应接收时间与轮询发送时间的差,并转换为双精度浮点数Rb = (double)(final_rx_ts_32 - resp_tx_ts_32);  // 计算最终接收时间与响应发送时间的32位差值,并转换为双精度浮点数Da = (double)(final_tx_ts - resp_rx_ts);  // 计算最终发送时间与响应接收时间的差,并转换为双精度浮点数Db = (double)(resp_tx_ts_32 - poll_rx_ts_32);  // 计算响应发送时间与轮询接收时间的32位差值,并转换为双精度浮点数tof_dtu = (int64)((Ra * Rb - Da * Db) / (Ra + Rb + Da + Db));  // 根据Ra, Rb, Da, Db计算飞行时间(ToF)并转换为64位整数tof = tof_dtu * DWT_TIME_UNITS;  // 计算飞行时间distance_temp = tof * SPEED_OF_LIGHT;  // 计算距离distance[msg_f_send.destAddr[0]] = distance_temp - dwt_getrangebias(config.chan,(float)distance_temp, config.prf);//距离减去矫正系数// 如果需要,可以在这里加入Kalman滤波或其他逻辑处理距离
#if 0 //如果一个标签可以打开kalman滤波distance[msg_f_send.destAddr[0]] =  KalMan(distance[msg_f_send.destAddr[0]]);
#endif#if 0 //为了加快测距频率,基站尽量不要显示距离// 如果不需要在基站显示距离,可以跳过下面的显示代码break;case 'M':  // 处理M消息// 将收集到的距离信息发送到电脑,数据长度16字节USART1WriteDataToBuffer(&msg_f->messageData[1],16);break;default:// 对于未知的消息类型不进行处理break;}}// 清除错误标志并重新启用接收dwt_write32bitreg(SYS_STATUS_ID, (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR));dwt_enableframefilter(DWT_FF_DATA_EN);dwt_setrxtimeout(0);  // 设置接收超时dwt_rxenable(0);  // 重新启用接收}else{// 清除错误标志并重新启用接收dwt_write32bitreg(SYS_STATUS_ID, (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR));dwt_enableframefilter(DWT_FF_DATA_EN);dwt_rxenable(0);}
}

这段代码是一个名为Simple_Rx_Callback的函数,用于处理DWM1000模块的接收回调。它主要包括对接收到的消息的处理和对特定消息类型的响应。下面是对该函数中每部分代码的详细解释:

  1. 变量初始化

    • 定义了多个变量,包括状态寄存器status_reg,迭代变量i,时间戳变量poll_tx_tsresp_rx_tsfinal_tx_ts等,以及计算时间飞行(ToF)所需的变量RaRbDaDbtof_dtu。同时,定义了一个字符数组dist_str来存储距离字符串。
  2. 清空接收缓冲区

    • 通过一个循环将接收缓冲区rx_buffer的内容清空。
  3. 禁用接收并读取状态寄存器

    • 调用dwt_enableframefilter函数禁用接收功能,然后通过dwt_read32bitreg读取系统状态寄存器SYS_STATUS_ID
  4. 检查是否接收到有效帧

    • 通过与SYS_STATUS_RXFCG(表示接收到一个CRC校验正确的帧)的位运算来检查是否成功接收到一个有效帧。
  5. 帧处理

    • 如果接收到有效帧,则读取帧长度,并根据帧长度读取接收到的数据到rx_buffer中。
    • 根据接收到的消息的第一个字节(消息类型)进行不同的处理:
      • 'P’消息:处理Poll消息,计算并发送回应。
      • 'F’消息:处理Final消息,从中计算ToF,并据此更新距离信息。
      • 'M’消息:处理汇总距离信息的消息,并发送到电脑。
  6. 重新启用接收功能

    • 无论是否成功接收到有效帧,最后都将清除错误标志,并重新启用接收功能,准备接收下一个消息。

    • 通过与SYS_STATUS_RXFCG(表示接收到一个CRC校验正确的帧)的位运算来检查是否成功接收到一个有效帧。

  7. 帧处理

    • 如果接收到有效帧,则读取帧长度,并根据帧长度读取接收到的数据到rx_buffer中。
    • 根据接收到的消息的第一个字节(消息类型)进行不同的处理:
      • 'P’消息:处理Poll消息,计算并发送回应。
      • 'F’消息:处理Final消息,从中计算ToF,并据此更新距离信息。
      • 'M’消息:处理汇总距离信息的消息,并发送到电脑。
  8. 重新启用接收功能

    • 无论是否成功接收到有效帧,最后都将清除错误标志,并重新启用接收功能,准备接收下一个消息。

这个函数对接收到的消息进行解析,根据不同的消息类型执行不同的逻辑,并计算设备间的距离。这是典型的超宽带(UWB)通信中的时间差测距(TDoA)或双向测距(TWR)的实现,用于计算发送者和接收者之间的距离。此代码段特别适用于具有定位功能的系统,如室内定位、资产追踪等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/629141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.goLand基础语法

目录 概述语法for常量与变量数组切片 slice切片问题问题1问题2 Make 和 New结构体和指针结构体标签 结束 概述 从 java 转来学 go &#xff0c;在此记录&#xff0c;方便以后翻阅。 语法 for package mainimport "fmt"func main() {for i : 0; i < 3; i {fmt.…

深度学习记录--偏差/方差(bias/variance)

误差问题 拟合神经网络函数过程中会出现两种误差&#xff1a;偏差(bias)和方差(variance) 偏差和误差的区别 欠拟合(underfitting) 当偏差(bias)过大时&#xff0c;如左图&#xff0c;拟合图像存在部分不符合值&#xff0c;称为欠拟合(underfitting) 过拟合(overfitting) …

系统的可观察性是指什么?

系统的可观察性是指什么&#xff1f; 本文转自 公众号 ByteByteGo&#xff0c;如有侵权&#xff0c;请联系&#xff0c;立即删除 系统的可观察性是系统设计的重要一环。不可观察的系统无法度量、无法监控、无法改进。 日志、追踪和度量是系统可观测性的三大支柱。 下图显示了…

链表练习 Leetcode234.回文链表

题目传送门&#xff1a;Leetcode234 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&…

语聚AI集成抖音丨集简云助力北京自由引擎无缝连接AI大模型,为企业提供即时专业支持

客户介绍 北京自由引擎有限公司作为一家快速发展的初创企业&#xff0c;公司以“创业斯基”为主要运营账号&#xff0c;致力于为B2B用户提供AI营销服务。北京自由引擎迅速崭露头角&#xff0c;成为业内瞩目的新星。核心业务包括提供课程和企业服务&#xff0c;尤其专注于使用A…

基于WebSocket双向通信技术实现-下单提醒和催单(后端)

学习复盘和总结项目亮点。 扩展&#xff1a;该功能能应用在&#xff0c;各种服务类项目中。&#xff08;例如&#xff1a;酒店、洗脚城等系ERP系中提醒类服务&#xff09; 4. 来单提醒 4.1 需求分析和设计 用户下单并且支付成功后&#xff0c;需要第一时间通知外卖商家。通…

C++ 程序文档生成器(doxygen)使用说明

程序文档&#xff0c;是每个程序员必看文档&#xff0c;在日常业务开发中&#xff0c;难免会封装一些组件。没有很好的组件文档&#xff0c;再好的组件都是废物&#xff0c;。因此大型业务中&#xff0c;文档和思维导图&#xff0c;两个都是必备&#xff01; 一、注释风格 …

Google上架:2024年一月政策限制之用户生成的内容

为确保 Google Play 用户能够获得安全、值得信赖的使用体验&#xff0c;Google会定期更新开发者计划政策。今天就来讲解一下关于一月新政策《用户生成的内容》。 目录 公布日期&#xff1a;2023-10-25内容公告相关博客截止时间2024-1-31 公布日期&#xff1a;2023-10-25 内容…

【Java】源码文件开头添加注释

需求 应公司质量部要求&#xff0c;需要对代码做静态检查。质量部要求&#xff0c;源码文件必须在起始行起设置一些注释&#xff0c;然而项目已经开发了一年之久&#xff0c;且没有维护这个注释。 此时&#xff0c;面对好几千个源码文件&#xff0c;我们如何快速添加相应的注…

HTML--基本结构构成

基本结构&#xff1a; 文档声明: <!DOCTYPE html> htm标签对 :<html> </html> head标签对&#xff1a; <head> </head> body标签对&#xff1a;<body> </body> 如下结构&#xff1a; <html> <head> <title>这是一…

Vue-22、总结Vue数据监测

1、功能 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Vue总结数据监测</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.js"…

FFmpeg之SWScale

文章目录 一、概述二、函数调用结构图三、Libswscale处理数据流程四、重要结构体4.1、SwsContext4.2、SwsFilter 五、重要函数5.1、sws_getContext5.1.1、sws_alloc_context5.1.2、sws_init_context 5.2、sws_scale5.2.1、SwsContext中的swscale()5.2.2、check_image_pointers5…

电脑技巧:BitLocker是啥,有啥用,看完本文你就懂了

目录 一、 介绍 二、BitLocker用途 三、 工作原理 四、 配置和管理 五、安全性和适用性 六、总结 一、 介绍 BitLocker是由微软开发的全磁盘加密工具&#xff0c;它旨在保护计算机上的数据免受未经授权的访问或窃取。BitLocker通过对整个磁盘进行加密&#xff0c;可以在计…

1、机器学习模型的工作方式

第一步,如果你是机器学习新手。 本课程所需数据集夸克网盘下载链接:https://pan.quark.cn/s/9b4e9a1246b2 提取码:uDzP 文章目录 1、简介2、决策树优化3、继续1、简介 我们将从机器学习模型如何工作以及如何使用它们的概述开始。如果你以前做过统计建模或机器学习,这可能感…

DDOS攻击,一篇文章给你讲清!

1、互联网安全现状 随着网络世界的高速发展&#xff0c;各行业数字化转型也在如火如荼的进行。但由于TCP/IP网络底层的安全性缺陷&#xff0c;钓鱼网站、木马程序、DDoS攻击等层出不穷的恶意攻击和高危漏洞正随时入侵企业的网络&#xff0c;如何保障网络安全成为网络建设中的刚…

【征服redis6】Redis的内存淘汰详解

目录 1.redis的基本策略 2.Redis中的缓存淘汰策略 3.Redis内存不足的情况 4.几种淘汰策略的实现原理 5.项目实践与优化策略 5.1 配置案例 5.2 项目优化策略参考 数据库存储会将数据保存到磁盘中&#xff0c;而Redis的核心数据是在内存中的&#xff0c;而Redis本身主要用来…

安全狗方案入选工信部《2023年工业和信息化领域数据安全典型案例名单》

近日&#xff0c;工业和信息化部网络安全管理局公布了2023年工业和信息化领域数据安全典型案例名单。 安全狗与厦门卫星定位应用股份有限公司、中移 (上海) 信息通信科技有限公司联合申报的智慧交通云数据安全与隐私保障典型案例也成功入选。 厦门服云信息科技有限公司&#…

Vue-24、Vue过滤器

1、效果 2、过滤器实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>过滤器</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.…

OpenCV-Python(45):立体图像中的深度地图

基础 在OpenCV中&#xff0c;深度地图通常是通过计算立体视觉&#xff08;stereo vision&#xff09;或结构光&#xff08;structured light&#xff09;技术得到的。立体视觉是通过将两个或多个摄像机&#xff08;或图像&#xff09;的视角结合起来&#xff0c;计算物体的深度…

Kafka 的架构

实验过程 1.三个虚拟机中解压kafka软件包 tar -zxvf kafka_2.11-1.1.1.tgz 2.修改 3 个节点配置文件 在 zookeeper 节点&#xff0c;进入 kafka_2.11-1.1.1/config 目录下&#xff0c;编辑 server.properties 文件 [rootdb1 ~]# cd kafka_2.11-1.1.1/config [rootdb1 con…