蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛
正文:
室内定位兴起,DWM1000 作为超宽带UWB的代表,在国内用的越来越多,但是可见资料非常少。 一方面是官方代码写的实在有点太差,另一方面是现在国内普及者将自己的代码当作是商业机密,当作是卖点,很少出来分享解析的。
我计划花一段时间来梳理DWM1000 代码,之前稍微接触过一点,感觉还能理解DWM1000 一点思路。 放在这里供大家参考。
作为穷人,目前我淘到一块DWM1000 模块,与我老旧的STM32 还没有互连,也就是说,还没有调试。这里的代码主要是分析思路,难免有误,请大家甄别参考。
拿到DWM1000 定位代码后发现需要CoCox编译,其实这个编译环境我试了试还是挺好的,免费的东西做成这样已经非常棒了,没有必要换成Keil 了。 另外我分析代码使用了source insight,我本人更偏向用vim 。 推荐大家用SI,有兴趣用vim。
好了,第一节,我想主要是清理一下Main 函数,因为太多LCD相关的,我们分析code,假定没有液晶,也不考虑LED以及USB把相关代码先全部注释掉。
int main(void) { int i = 0; int toggle = 1; double range_result = 0; double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs peripherals_init(); spi_peripheral_init(); /* Sleep(1000); //wait for LCD to power on initLCD(); memset(dataseq, 0, LCD_BUFF_LEN); memcpy(dataseq, (const uint8 *) "DECAWAVE ", 16); writetoLCD( 40, 1, dataseq); //send some data memcpy(dataseq, (const uint8 *) SOFTWARE_VER_STRING, 16); // Also set at line #26 (Should make this from single value !!!) writetoLCD( 16, 1, dataseq); //send some data Sleep(1000);*/ /* #ifdef USB_SUPPORT // enable the USB functionality usb_init(); Sleep(1000); #endif*/ s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2 | is_switch_on(TA_SW1_3) << 2 | is_switch_on(TA_SW1_4) << 3 | is_switch_on(TA_SW1_5) << 4 | is_switch_on(TA_SW1_6) << 5 | is_switch_on(TA_SW1_7) << 6 | is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device //test EVB1000 - used in EVK1000 production if((is_button_low(0) == S1_SWITCH_ON) && (is_switch_on(TA_SW1_8) == S1_SWITCH_ON)) //using BOOT1 switch for test { test_application_run(); //does not return.... } else if(is_switch_on(TA_SW1_3) == S1_SWITCH_OFF) { /* int j = 1000000; uint8 command; memset(dataseq, 0, LCD_BUFF_LEN); while(j--); //command = 0x1 ; //clear screen //writetoLCD( 1, 0, &command); command = 0x2 ; //return cursor home writetoLCD( 1, 0, &command); memcpy(dataseq, (const uint8 *) "DECAWAVE ", 12); writetoLCD( 40, 1, dataseq); //send some data #ifdef USB_SUPPORT //this is set in the port.h file memcpy(dataseq, (const uint8 *) "USB to SPI ", 12); #else #endif writetoLCD( 16, 1, dataseq); //send some data j = 1000000; while(j--); command = 0x2 ; //return cursor home writetoLCD( 1, 0, &command);*/ /* #ifdef USB_SUPPORT //this is set in the port.h file // enable the USB functionality //usb_init(); NVIC_DisableDECAIRQ(); // Do nothing in foreground -- allow USB application to run, I guess on the basis of USB interrupts? while (1) // loop forever { usb_run(); } #endif*/ return 1; } else //run DecaRanging application { /* uint8 dataseq[LCD_BUFF_LEN]; uint8 command = 0x0; command = 0x2 ; //return cursor home writetoLCD( 1, 0, &command); memset(dataseq, ' ', LCD_BUFF_LEN); memcpy(dataseq, (const uint8 *) "DECAWAVE RANGE", 15); writetoLCD( 15, 1, dataseq); //send some data led_off(LED_ALL); #ifdef USB_SUPPORT //this is set in the port.h file usb_printconfig(16, (uint8 *)SOFTWARE_VER_STRING, s1switch); #endif*/ if(inittestapplication(s1switch) == (uint32)-1) { /* led_on(LED_ALL); //to display error.... dataseq[0] = 0x2 ; //return cursor home writetoLCD( 1, 0, &dataseq[0]); memset(dataseq, ' ', LCD_BUFF_LEN); memcpy(dataseq, (const uint8 *) "ERROR ", 12); writetoLCD( 40, 1, dataseq); //send some data memcpy(dataseq, (const uint8 *) " INIT FAIL ", 12); writetoLCD( 40, 1, dataseq); //send some data*/ return 0; //error } //sleep for 5 seconds displaying "Decawave" /* i=30; while(i--) { if (i & 1) led_off(LED_ALL); else led_on(LED_ALL); Sleep(200); } i = 0; led_off(LED_ALL); command = 0x2 ; //return cursor home writetoLCD( 1, 0, &command); memset(dataseq, ' ', LCD_BUFF_LEN);*/ if(s1switch & SWS1_ANC_MODE) { instance_mode = ANCHOR; /led_on(LED_PC6); }/ else { instance_mode = TAG; // led_on(LED_PC7); } /*if(instance_mode == TAG) { //if TA_SW1_2 is on use fast ranging (fast 2wr) if(is_button_low(0) == S1_SWITCH_ON) { memcpy(&dataseq[2], (const uint8 *) " Fast Tag ", 12); writetoLCD( 40, 1, dataseq); //send some data memcpy(&dataseq[2], (const uint8 *) " Ranging ", 12); writetoLCD( 16, 1, dataseq); //send some data } else { memcpy(&dataseq[2], (const uint8 *) " TAG BLINK ", 12); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq[0], "%llX", instance_get_addr()); writetoLCD( 16, 1, dataseq); //send some data } } else { memcpy(&dataseq[2], (const uint8 *) " AWAITING ", 12); writetoLCD( 40, 1, dataseq); //send some data memcpy(&dataseq[2], (const uint8 *) " POLL ", 12); writetoLCD( 16, 1, dataseq); //send some data } command = 0x2 ; //return cursor home writetoLCD( 1, 0, &command);*/ } #if (DWINTERRUPT_EN == 1)//CN:define1 port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting #endif /* memset(dataseq, ' ', LCD_BUFF_LEN); memset(dataseq1, ' ', LCD_BUFF_LEN); #ifdef USART_SUPPORT printf2(" %s ", SOFTWARE_VER_STRING); #endif*/ // main loop while(1) { /* #if (DWINTERRUPT_EN == 0) process_deca_irq(); //poll DW1000 IRQ line when using polling of interrupt line #endif*/ instance_run(); //if delayed TX scheduled but did not happen after expected time then it has failed... (has to be < slot period) //if anchor just go into RX and wait for next message from tags/anchors //if tag handle as a timeout if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms)) { instance_data[0].wait4ack = 0; if(instance_mode == TAG) { inst_processrxtimeout(&instance_data[0]); } else //if(instance_mode == ANCHOR) { dwt_forcetrxoff(); //this will clear all events //enable the RX instance_data[0].testAppState = TA_RXE_WAIT ; } instance_data[0].monitor = 0; } if(instancenewrange()) { int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw; ranging = 1; //send the new range information to LCD and/or USB range_result = instance_get_idist(); avg_result = instance_get_adist(); //set_rangeresult(range_result); /* dataseq[0] = 0x2 ; //return cursor home writetoLCD( 1, 0, dataseq); memset(dataseq, ' ', LCD_BUFF_LEN); memset(dataseq1, ' ', LCD_BUFF_LEN); sprintf((char*)&dataseq[1], "LAST: %4.2f m", range_result); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq1[1], "AVG8: %4.2f m", avg_result); writetoLCD( 16, 1, dataseq1); //send some data*/ l = instance_get_lcount(); //txl = instance_get_txl(); //rxl = instance_get_rxl(); aaddr = instancenewrangeancadd(); taddr = instancenewrangetagadd(); txa = instancetxantdly(); rxa = instancerxantdly(); rng = (int) (range_result*1000); rng_raw = (int) (instance_get_idistraw()*1000); /* if(instance_mode == TAG) { //n = sprintf((char*)&dataseq[0], "ia%04x t%04x %04x %04x %04x %04x %04x %02x %02x t", aaddr, taddr, rng, rng_raw, l, txa, rxa, txl, rxl); n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x t", aaddr, taddr, rng, rng_raw, l, txa, rxa); } else { //n = sprintf((char*)&dataseq[0], "ia%04x t%04x %04x %04x %04x %04x %04x %02x %02x a", aaddr, taddr, rng, rng_raw, l, txa, rxa, txl, rxl); //n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x %2.2f a", aaddr, taddr, rng, rng_raw, l, txa, rxa, instance_data[0].clockOffset); n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x a", aaddr, taddr, rng, rng_raw, l, txa, rxa); } #ifdef USB_SUPPORT //this is set in the port.h file send_usbmessage(&dataseq[0], n); #endif*/ /* #ifdef USART_SUPPORT { //printf2("R= %i mm ",rng); printf2("R= %-3.2f m ",range_result); } #endif*/ } /* #ifdef USART_SUPPORT { int nrm = 0; if(nrm = instancenorange()) { if(nrm == 1) { printf2("I= No Response "); } else if(nrm == 2) { printf2("I= No Report "); } else if(nrm == 3) { printf2("I= No Final "); } } } #endif*/ if(ranging == 0) { if(instance_mode != ANCHOR) { if(instancesleeping()) { //dataseq[0] = 0x2 ; //return cursor home // writetoLCD( 1, 0, dataseq); if(toggle) { /* toggle = 0; memcpy(&dataseq[0], (const uint8 *) " AWAITING ", 16); writetoLCD( 40, 1, dataseq); //send some data memcpy(&dataseq[0], (const uint8 *) " RESPONSE ", 16); writetoLCD( 16, 1, dataseq); //send some data*/ } else { /* toggle = 1; memcpy(&dataseq[2], (const uint8 *) " TAG BLINK ", 16); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq[0], "%llX", instance_get_addr()); writetoLCD( 16, 1, dataseq); //send some data*/ } } if(instanceanchorwaiting() == 2) { ranging = 1; /* dataseq[0] = 0x2 ; //return cursor home writetoLCD( 1, 0, dataseq); memcpy(&dataseq[0], (const uint8 *) " RANGING WITH", 16); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq[0], "%016llX", instance_get_anchaddr()); writetoLCD( 16, 1, dataseq); //send some data*/ } } else //if(instance_mode == ANCHOR) { if(instanceanchorwaiting()) { /* toggle+=2; if(toggle > 300000) { dataseq[0] = 0x2 ; //return cursor home writetoLCD( 1, 0, dataseq); if(toggle & 0x1) { toggle = 0; memcpy(&dataseq[0], (const uint8 *) " AWAITING ", 16); writetoLCD( 40, 1, dataseq); //send some data memcpy(&dataseq[0], (const uint8 *) " POLL ", 16); writetoLCD( 16, 1, dataseq); //send some data } else { toggle = 1; memcpy(&dataseq[0], (const uint8 *) " DISCOVERY MODE ", 16); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq[0], "%llX", instance_get_addr()); writetoLCD( 16, 1, dataseq); //send some data } }*/ } else if(instanceanchorwaiting() == 2) { /* dataseq[0] = 0x2 ; //return cursor home writetoLCD( 1, 0, dataseq); memcpy(&dataseq[0], (const uint8 *) " RANGING WITH", 16); writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq[0], "%llX", instance_get_tagaddr()); writetoLCD( 16, 1, dataseq); //send some data*/ } } } /* #ifdef USB_SUPPORT //this is set in the port.h file usb_run(); #endif*/ } return 0; }
上面代码不用看,如果你看了,恭喜你,帮我找一下看我注释掉的代码是否有问题, 我把注释掉的直接先删掉吧,虽然不是处女座,但是我看code 非常有洁癖的。
int main(void) { int i = 0; int toggle = 1; double range_result = 0; double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs peripherals_init(); spi_peripheral_init(); s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2 | is_switch_on(TA_SW1_3) << 2 | is_switch_on(TA_SW1_4) << 3 | is_switch_on(TA_SW1_5) << 4 | is_switch_on(TA_SW1_6) << 5 | is_switch_on(TA_SW1_7) << 6 | is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device //test EVB1000 - used in EVK1000 production if((is_button_low(0) == S1_SWITCH_ON) && (is_switch_on(TA_SW1_8) == S1_SWITCH_ON)) //using BOOT1 switch for test { test_application_run(); //does not return.... } else if(is_switch_on(TA_SW1_3) == S1_SWITCH_OFF) { return 1; } else //run DecaRanging application { if(inittestapplication(s1switch) == (uint32)-1) { return 0; //error } if(s1switch & SWS1_ANC_MODE) { instance_mode = ANCHOR; /led_on(LED_PC6); }/ else { instance_mode = TAG; } } #if (DWINTERRUPT_EN == 1)//CN:define1 port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting #endif // main loop while(1) { instance_run(); if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms)) { instance_data[0].wait4ack = 0; if(instance_mode == TAG) { inst_processrxtimeout(&instance_data[0]); } else //if(instance_mode == ANCHOR) { dwt_forcetrxoff(); //this will clear all events //enable the RX instance_data[0].testAppState = TA_RXE_WAIT ; } instance_data[0].monitor = 0; } if(instancenewrange()) { int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw; ranging = 1; //send the new range information to LCD and/or USB range_result = instance_get_idist(); avg_result = instance_get_adist(); l = instance_get_lcount(); //txl = instance_get_txl(); //rxl = instance_get_rxl(); aaddr = instancenewrangeancadd(); taddr = instancenewrangetagadd(); txa = instancetxantdly(); rxa = instancerxantdly(); rng = (int) (range_result*1000); rng_raw = (int) (instance_get_idistraw()*1000); if(ranging == 0) { if(instance_mode != ANCHOR) { if(instancesleeping()) { if(toggle) { } else { } } if(instanceanchorwaiting() == 2) { ranging = 1; } } else //if(instance_mode == ANCHOR) { if(instanceanchorwaiting()) { } else if(instanceanchorwaiting() == 2) { } } } } return 0; }
删除注释,一下清爽很多,可能删除了一些有用的code,如果后面分析不同,我们再补回来。
下面再删除一个关于test的东西, Main 函数开始通过按键选择执行,有个test函数还不返回,我们定位不执行这部分,再次删除。
删除函数: test_application_run(); //does not return....
int main(void) { int i = 0; int toggle = 1; double range_result = 0; double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs peripherals_init(); spi_peripheral_init(); s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2 | is_switch_on(TA_SW1_3) << 2 | is_switch_on(TA_SW1_4) << 3 | is_switch_on(TA_SW1_5) << 4 | is_switch_on(TA_SW1_6) << 5 | is_switch_on(TA_SW1_7) << 6 | is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device else //run DecaRanging application { if(inittestapplication(s1switch) == (uint32)-1) { return 0; //error } if(s1switch & SWS1_ANC_MODE) { instance_mode = ANCHOR; /led_on(LED_PC6); }/ else { instance_mode = TAG; } } #if (DWINTERRUPT_EN == 1)//CN:define1 port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting #endif // main loop while(1) { instance_run(); if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms)) { instance_data[0].wait4ack = 0; if(instance_mode == TAG) { inst_processrxtimeout(&instance_data[0]); } else //if(instance_mode == ANCHOR) { dwt_forcetrxoff(); //this will clear all events //enable the RX instance_data[0].testAppState = TA_RXE_WAIT ; } instance_data[0].monitor = 0; } if(instancenewrange()) { int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw; ranging = 1; //send the new range information to LCD and/or USB range_result = instance_get_idist(); avg_result = instance_get_adist(); l = instance_get_lcount(); //txl = instance_get_txl(); //rxl = instance_get_rxl(); aaddr = instancenewrangeancadd(); taddr = instancenewrangetagadd(); txa = instancetxantdly(); rxa = instancerxantdly(); rng = (int) (range_result*1000); rng_raw = (int) (instance_get_idistraw()*1000); if(ranging == 0) { if(instance_mode != ANCHOR) { if(instancesleeping()) { if(toggle) { } else { } } if(instanceanchorwaiting() == 2) { ranging = 1; } } else //if(instance_mode == ANCHOR) { if(instanceanchorwaiting()) { } else if(instanceanchorwaiting() == 2) { } } } } return 0; }
再来看现在代码,直接从else 开始了,直奔主题。
if(inittestapplication(s1switch) == (uint32)-1) { return 0; //error } if(s1switch & SWS1_ANC_MODE) { instance_mode = ANCHOR; /led_on(LED_PC6); }/ else { instance_mode = TAG; } } #if (DWINTERRUPT_EN == 1)//CN:define1 port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting #endif // main loop while(1) { instance_run();
上面代码中,红色字体的两个函数是整个定位中非常重要的两个函数。
第一节,就分析到这里,主要是删除多余代码