蓝点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\n", 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\r\n",rng);
printf2("R= %-3.2f m\r\n",range_result);
}
#endif*/
}
/*
#ifdef USART_SUPPORT
{
int nrm = 0;
if(nrm = instancenorange())
{
if(nrm == 1)
{
printf2("I= No Response\r\n");
}
else if(nrm == 2)
{
printf2("I= No Report\r\n");
}
else if(nrm == 3)
{
printf2("I= No Final\r\n");
}
}
}
#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();
上面代码中,红色字体的两个函数是整个定位中非常重要的两个函数。
第一节,就分析到这里,主要是删除多余代码