查看: 8591|回复: 10

[原创] 七夕鹊桥搭建-基于超宽带技术的心动“鹊桥”设计

[复制链接]
  • TA的每日心情
    开心
    2020-10-20 18:19
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2019-8-7 20:43:29 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 AUST 于 2019-8-8 21:19 编辑

    “那一眼看见你,就知道这辈子都逃不掉了”。曾听过这样一句话:“从不想独身,却有预感晚婚,我想在茫茫人海中寻找那唯一与之契合的灵魂伴侣。”

    因为今天,又到了牛郎织女见面的日子——七夕。

    同样,今天也是2019年大学生电子设计竞赛开赛的日子,祝愿赛场上的你们都取得好成绩!


    一、思路篇


    本人和女友也是在异地中,常常以“两情若是久长时,又岂在朝朝暮暮。”来安慰自己。晚上无意看到这个征集帖,就想利用手上的UWB模块做一个“心动鹊桥”。主要功能:在有效范围内,两个模块距离越近,红色LED闪烁越快,寓意着心跳越快。当两个模块完全接近时,红色LED常亮,寓意着彼此惺惺相惜。


    二、原理篇

    双向飞行时间法(TW-TOF,two way-time of flight)每个模块从启动开始即会生成一条独立的时间戳。模块 A 的发射机在其时间戳上的 Ta1 发射请求性质的脉冲信号,模块 B 在 Tb2 时刻发射一个响应性质的信号,被模块 A 在自己的时间戳 Ta2 时刻接收。有次可以计算出脉冲信号在两个模块之间的飞行时间,从而确定飞行距离 S。

    S=Cx[(Ta2-Ta1)-(Tb2-Tb1)]/2  (C 为光速)

    二、软件篇

    SPI初始化

    1. /***************************************************************************************************
    2. *函 数 名: Spi_Init
    3. *功能说明: SPI从机设备CS引脚初始化
    4. *形    参: 无
    5. *返 回 值: 无
    6. ***************************************************************************************************/
    7. void SPI_Configuration(void)
    8. {
    9.     SPI_InitTypeDef SPI_InitStructure;
    10.     GPIO_InitTypeDef GPIO_InitStructure;

    11.     SPI_I2S_DeInit(SPIx);
    12.     GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    13.         
    14.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    15.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    16.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    17.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    18.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    19.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    20.     SPI_InitStructure.SPI_BaudRatePrescaler = SPIx_PRESCALER;
    21.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    22.     SPI_InitStructure.SPI_CRCPolynomial = 7;
    23.     SPI_Init(SPIx, &SPI_InitStructure);

    24.     // SPIx SCK and MOSI pin setup
    25.     GPIO_InitStructure.GPIO_Pin = SPIx_SCK | SPIx_MOSI;
    26.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    27.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    28.     GPIO_Init(SPIx_GPIO, &GPIO_InitStructure);

    29.     // SPIx MISO pin setup
    30.     GPIO_InitStructure.GPIO_Pin = SPIx_MISO;
    31.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    32.     GPIO_Init(SPIx_GPIO, &GPIO_InitStructure);

    33.     // SPIx CS pin setup
    34.     GPIO_InitStructure.GPIO_Pin = SPIx_CS;
    35.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    36.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    37.     GPIO_Init(SPIx_CS_GPIO, &GPIO_InitStructure);

    38.     // Disable SPIx SS Output
    39.     SPI_SSOutputCmd(SPIx, DISABLE);

    40.     // Enable SPIx
    41.     SPI_Cmd(SPIx, ENABLE);

    42.     // Set CS high
    43.     GPIO_SetBits(SPIx_CS_GPIO, SPIx_CS);
    44. }
    复制代码

    USART2初始化

    1. /***************************************************************************************************
    2. *函 数 名: uart_init
    3. *功能说明: USART2初始化
    4. *形    参: bound波特率
    5. *返 回 值: 无
    6. ***************************************************************************************************/
    7. void uart_init(u32 bound){
    8.         GPIO_InitTypeDef gpioInitStruct;
    9.         USART_InitTypeDef usartInitStruct;
    10.         NVIC_InitTypeDef nvicInitStruct;
    11.         
    12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    13.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    14.         
    15.         //PA2        TXD
    16.         gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    17.         gpioInitStruct.GPIO_Pin = GPIO_Pin_2;
    18.         gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    19.         GPIO_Init(GPIOA, &gpioInitStruct);
    20.         
    21.         //PA3        RXD
    22.         gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    23.         gpioInitStruct.GPIO_Pin = GPIO_Pin_3;
    24.         gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    25.         GPIO_Init(GPIOA, &gpioInitStruct);
    26.         
    27.         usartInitStruct.USART_BaudRate = bound;
    28.         usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;        //无硬件流控
    29.         usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                        //接收和发送
    30.         usartInitStruct.USART_Parity = USART_Parity_No;                                        //无校验
    31.         usartInitStruct.USART_StopBits = USART_StopBits_1;                                //1位停止位
    32.         usartInitStruct.USART_WordLength = USART_WordLength_8b;                                //8位数据位
    33.         USART_Init(USART2, &usartInitStruct);
    34.         
    35.         USART_Cmd(USART2, ENABLE);           //使能串口
    36.         
    37.         USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);        //使能接收中断
    38.         
    39.         nvicInitStruct.NVIC_IRQChannel = USART2_IRQn;
    40.         nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
    41.         nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    42.         nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
    43.         NVIC_Init(&nvicInitStruct);
    44. }
    复制代码

    调用DWM1000官方的API函数

    1. int instance_run(void)
    2. {
    3.     int instance = 0 ;
    4.     int done = INST_NOT_DONE_YET;
    5.     int message = instance_peekevent(); //get any of the received events from ISR

    6.     while(done == INST_NOT_DONE_YET)
    7.     {
    8.         //int state = instance_data[instance].testAppState;
    9.         done = testapprun(&instance_data[instance], message) ;                                               // run the communications application

    10.         //we've processed message
    11.         message = 0;
    12.     }

    13.     if(done == INST_DONE_WAIT_FOR_NEXT_EVENT_TO) //we are in RX and need to timeout (Tag needs to send another poll if no Rx frame)
    14.     {
    15.         if(instance_data[instance].mode == TAG) //Tag (is either in RX or sleeping)
    16.         {
    17.             int32 nextPeriod ;

    18.             // next period will be a positive number because correction is -0.5 to +1.5 periods, (and tagSleepTime_ms is the period)
    19.             nextPeriod = instance_data[instance].tagSleepRnd + instance_data[instance].tagSleepTime_ms + instance_data[instance].tagSleepCorrection;

    20.             instance_data[instance].nextSleepPeriod = (uint32) nextPeriod ; //set timeout time, CAST the positive period to UINT for correct wrapping.
    21.             instance_data[instance].tagSleepCorrection2 = instance_data[instance].tagSleepCorrection;
    22.             instance_data[instance].tagSleepCorrection = 0; //clear the correction
    23.             instance_data[instance].instanceTimerEn = 1; //start timer
    24.         }
    25.         instance_data[instance].stopTimer = 0 ; //clear the flag - timer can run if instancetimer_en set (set above)
    26.         instance_data[instance].done = INST_NOT_DONE_YET;
    27.     }

    28.     //check if timer has expired
    29.     if((instance_data[instance].instanceTimerEn == 1) && (instance_data[instance].stopTimer == 0))
    30.     {
    31.         if(instance_data[instance].mode == TAG)
    32.         {
    33.             if((portGetTickCount() - instance_data[instance].instanceWakeTime) > instance_data[instance].nextSleepPeriod)
    34.             {
    35.                 event_data_t dw_event;
    36.                 instance_data[instance].instanceTimerEn = 0;
    37.                 dw_event.rxLength = 0;
    38.                 dw_event.type = 0;
    39.                 dw_event.type_save = 0x80 | DWT_SIG_RX_TIMEOUT;
    40.                 //printf("PC timeout DWT_SIG_RX_TIMEOUT\n");
    41.                 instance_putevent(dw_event, DWT_SIG_RX_TIMEOUT);
    42.             }
    43.         }
    44. #if (ANCTOANCTWR == 1) //allow anchor to anchor ranging
    45.         else if(instance_data[instance].mode == ANCHOR)
    46.         {
    47.             uint32_t slotTime = portGetTickCount() % instance_data[instance].sframePeriod;

    48.             if(instance_data[instance].gatewayAnchor)
    49.             {
    50.                 //if we are in the last slot - then A0 ranges to A1 and A2
    51.                 if( slotTime >= instance_data[instance].a0SlotTime)
    52.                 {
    53.                     port_DisableEXT_IRQ(); //enable ScenSor IRQ before starting
    54.                     //anchor0 sends poll to anchor1
    55.                     instance_data[instance].mode = ANCHOR_RNG; //change to ranging initiator
    56.                     dwt_forcetrxoff(); //disable DW1000
    57.                     instance_clearevents(); //clear any events
    58.                     //change state to send a Poll
    59.                     instance_data[instance].testAppState = TA_TXPOLL_WAIT_SEND ;
    60.                     instance_data[instance].msg_f.destAddr[0] = 0x1 ;
    61.                     instance_data[instance].msg_f.destAddr[1] = (GATEWAY_ANCHOR_ADDR >> 8);
    62.                     instance_data[instance].instanceTimerEn = 0;
    63.                     instance_data[instance].rangeNumAnc++;
    64.                     port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
    65.                 }
    66.             }
    67.             else if (instance_data[instance].instanceAddress16 == A1_ANCHOR_ADDR) //A1 ranges to A2 in the 2nd half of last slot
    68.             {
    69.                 if(portGetTickCount() >= instance_data[instance].a1SlotTime)
    70.                 {
    71.                     port_DisableEXT_IRQ(); //enable ScenSor IRQ before starting
    72.                     //anchor1 sends poll to anchor2
    73.                     instance_data[instance].mode = ANCHOR_RNG; //change to ranging initiator
    74.                     dwt_forcetrxoff(); //disable DW1000
    75.                     instance_clearevents(); //clear any events
    76.                     //change state to send a Poll
    77.                     instance_data[instance].testAppState = TA_TXPOLL_WAIT_SEND ;
    78.                     instance_data[instance].msg_f.destAddr[0] = 0x2 ;
    79.                     instance_data[instance].msg_f.destAddr[1] = (GATEWAY_ANCHOR_ADDR >> 8);

    80.                     instance_data[instance].instanceTimerEn = 0;
    81.                     //instance_data[instance].a1SlotTime = 0;
    82.                     port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
    83.                 }
    84.             }
    85.         }
    86. #endif
    87.     }

    88. #if (ANCTOANCTWR == 1) //allow anchor to anchor ranging
    89.     else if (instance_data[instance].instanceTimerEn == 0)
    90.     {
    91.         if((instance_data[instance].mode == ANCHOR) && (instance_data[instance].gatewayAnchor))
    92.         {
    93.             uint32_t slotTime = portGetTickCount() % instance_data[instance].sframePeriod;
    94.             //enable the timer in 1st slot
    95.             if(slotTime < instance_data[instance].slotPeriod)
    96.             {
    97.                 instance_data[instance].instanceTimerEn = 1;
    98.             }
    99.         }
    100.     }
    101. #endif
    102.     return 0 ;
    103. }
    复制代码

    三、硬件篇

    2.1 硬件

    DW1000是完全集成的单芯片超宽带(UWB)符合IEEE802.15.4-2011标准的低功耗低成本收发器IC。它可用于双向测距或TDOA定位系统定位,精度为10厘米。它还支持高达6.8 Mbps的数据传输,相关的原理图官网有详细说明。整个原理图我放在文文末,喜欢的可以回复下载。


    • 通用软件:Altium Designer
    • 主控芯片:nRF52832
    • 通讯芯片:DWM1000

    4.jpg

    nRF52832外围原理图


    3.jpg

    DW1000外围原理图

    2.2 丝印

    如果有小伙伴不会制作logo的,这里把相关文件上传,以及“鹊桥”的丝印样板。


    • DXP-->Run Script-->Browse
    • 选择目录D:\Altium Design\Examples\Scripts\Delphiscript Scripts\PCB\PCB Logo Creator
    • 打开PCBLogoCreator.PRJSCR


    1.jpg

    效果图1

    1

    1

    效果图2

    5.jpg

    Top Overlay


    游客,如果您要查看本帖隐藏内容请回复

    丝印.zip (45.23 KB, 下载次数: 11)

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-10-20 18:19
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

     楼主| 发表于 2019-8-10 11:53:13 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-10-20 18:19
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

     楼主| 发表于 2019-8-10 22:07:43 | 显示全部楼层

    后续有更新,谢谢关注!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-8-11 13:37
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2019-8-11 10:53:15 | 显示全部楼层
    谢谢分享,学习了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-10-20 18:19
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

     楼主| 发表于 2019-8-11 15:27:36 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-10-20 18:19
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

     楼主| 发表于 2019-8-12 10:17:55 | 显示全部楼层

    共同学习,共同进步
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-11-26 15:38 , Processed in 0.203784 second(s), 34 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.