Arduino Nano 33 BLE Sense micros()耗时过高 求低时钟周期计时方案
方案1:使用Cortex-M4内核DWT周期计数器(最优)
NRF52840搭载的Cortex-M4内核自带DWT调试组件,其中CYCCNT寄存器会随内核时钟每周期自增1,读操作仅需1~2个时钟周期,精度为内核时钟周期(64MHz下为15.625ns),完全满足需求。
示例代码如下:
#include "nrf_gpio.h" #define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,11) uint32_t start_cnt, end_cnt, cycle_diff; // 初始化DWT计数器 void dwt_cycle_counter_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } void setup() { Serial.begin(115200); while (!Serial); nrf_gpio_cfg_output(OUTPUT_PIN); dwt_cycle_counter_init(); } void loop() { // 测试读计数器的开销 start_cnt = DWT->CYCCNT; end_cnt = DWT->CYCCNT; cycle_diff = end_cnt - start_cnt; Serial.print("读计数器耗时:"); Serial.print(cycle_diff); Serial.println(" 时钟周期"); // 测试减法操作耗时 uint32_t arithmeticMinuend = 4294967295; uint32_t arithmeticSubtrahend = 2147483648; uint32_t arithmeticDifference; start_cnt = DWT->CYCCNT; arithmeticDifference = arithmeticMinuend - arithmeticSubtrahend; end_cnt = DWT->CYCCNT; cycle_diff = end_cnt - start_cnt; Serial.print("减法操作耗时:"); Serial.print(cycle_diff); Serial.println(" 时钟周期"); // 示波器验证用代码 nrf_gpio_pin_toggle(OUTPUT_PIN); start_cnt = DWT->CYCCNT; end_cnt = DWT->CYCCNT; nrf_gpio_pin_toggle(OUTPUT_PIN); delay(1000); }
该方案注意事项:
- CYCCNT为32位寄存器,64MHz主频下约每67秒溢出一次,测量长间隔时需自行处理溢出逻辑
- 无需占用片上外设资源,无额外配置开销
方案2:使用nrfx_timer硬件定时器
如果需要更长的计数周期或者不使用DWT组件,可以用NRF52840自带的硬件定时器,配置为计数器模式后读操作仅需2~3个时钟周期:
示例代码如下:
#include "nrfx_timer.h" #include "nrf_gpio.h" #define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,11) // 使用TIMER0,避免与mbed系统默认占用的TIMER1/TIMER2冲突 static const nrfx_timer_t s_timer = NRFX_TIMER_INSTANCE(0); uint32_t start_cnt, end_cnt, time_diff; void timer_init(void) { nrfx_timer_config_t timer_cfg = { .frequency = NRF_TIMER_FREQ_64MHz, // 可配置为1MHz/16MHz等,64MHz时精度为15.625ns .mode = NRF_TIMER_MODE_TIMER, .bit_width = NRF_TIMER_BIT_WIDTH_32, .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, .p_context = NULL }; // 无需中断,回调函数设为NULL nrfx_timer_init(&s_timer, &timer_cfg, NULL); nrfx_timer_enable(&s_timer); } void setup() { Serial.begin(115200); while (!Serial); nrf_gpio_cfg_output(OUTPUT_PIN); timer_init(); } void loop() { start_cnt = nrfx_timer_capture(&s_timer, NRF_TIMER_CC_CHANNEL0); end_cnt = nrfx_timer_capture(&s_timer, NRF_TIMER_CC_CHANNEL1); time_diff = nrfx_timer_capture_diff_get(&s_timer, start_cnt, end_cnt); // 64MHz频率下时间单位为1/64us,转ns的话乘以15.625即可 Serial.print("读定时器耗时:"); Serial.print(time_diff); Serial.println(" 个定时器计数周期"); delay(1000); }
该方案注意事项:
- 32位位宽+64MHz频率下,计数溢出周期约为67秒,位宽改为24位时溢出周期为0.26秒,可根据需求调整
- 硬件捕获操作为硬件级实现,无软件开销,稳定性更高
内容的提问来源于stack exchange,提问作者Landon
相关产品推荐
相关产品推荐

