DWM1000 中断与STM32外部中断

DWM1000 中断与STM32外部中断

概述

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

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

原理图

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

中断

中断事件

c 复制代码
//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在通信过程中的各种情况,例如确认数据是否发送/接收成功,或者在出现错误时采取相应的错误处理措施。开发者通常会在中断服务程序中检查这些状态位,以确定需要响应的具体事件。

外部中断

c 复制代码
#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中定义的代码。

中断配置

c 复制代码
int NVIC_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 启用作为DECAIRQ的GPIO用于中断
    GPIO_InitStructure.GPIO_Pin = DECAIRQ;  // 指定中断引脚为DECAIRQ
    GPIO_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_EXTI
    EXTI_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_IRQn
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;  // 设置抢占优先级为最低(15)
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  // 设置子优先级为0
    NVIC_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
c 复制代码
// 设置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的定位和测距系统时常见的设置步骤。

中断响应

c 复制代码
//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();这行代码示例了另一种直接调用预定义回调函数的方式,但在这个例子中它被替换为了使用函数指针的方式。

中断调用回调函数

c 复制代码
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 ack
                    int 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_32
                    resp_tx_ts_32 = (uint32)resp_tx_ts;  // 将resp_tx_ts转换为32位无符号整型并赋值给resp_tx_ts_32
                    final_rx_ts_32 = (uint32)final_rx_ts;  // 将final_rx_ts转换为32位无符号整型并赋值给final_rx_ts_32
                    Ra = (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)的实现,用于计算发送者和接收者之间的距离。此代码段特别适用于具有定位功能的系统,如室内定位、资产追踪等。

相关推荐
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
zy张起灵2 小时前
48v72v-100v转12v 10A大功率转换电源方案CSM3100SK
经验分享·嵌入式硬件·硬件工程
PegasusYu4 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
lantiandianzi9 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
文弱书生6569 小时前
输出比较简介
stm32
哔哥哔特商务网9 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式9 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
电子科技圈10 小时前
IAR与鸿轩科技共同推进汽车未来
科技·嵌入式硬件·mcu·汽车
东芝、铠侠总代1361006839311 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi11 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件