ADC的时间误差

问题描述 投票:-1回答:1

我使用超声波信号测量距离。STM32F1产生超声波信号,STM32F4用麦克风写入该信号。两个STM32都是使用另一个设备产生的信号同步的,他们连接了一根线。

问题:为什么信号会有不同的时间?虽然我没有移动接收器或发射器,但为什么信号的时间不同?它的误差为50mm。

色散信号

接收器的代码在这里。

while (1)
{
  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) != 0x00) 
  {
    Get_UZ_Signal(uz_signal);
    Send_Signal(uz_signal);      
  }
}

void Get_UZ_Signal(uint16_t* uz_signal)
{
  int i,j;
  uint16_t uz_buf[10];

  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&uz_buf, 300000);

  for(i = 0; i<lenght_signal; i++)
  {      
    j=10;
    while(j>0)    
    {
      j--;    
    }
    uz_signal[i] = uz_buf[0];    
  }
  HAL_ADC_Stop_DMA(&hadc1);
}


  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

更多信息请点击这里

https:/github.comBooSooVIndoor Ultrasonic-Positioning-SystemtreemasterStudying_ultrasonic_signalsMeasured_lengths_dispersion.

解决的问题

分散信号最终

时间错误是由发射机造成的,我对它做了一些修改。现在同步信号在EXTI的帮助下,一直产生PWM,我用驱动器上的Enable或Disable引脚控制信号。现在我有5mm的色散,这对我来说已经足够了。

最终程序在这里

https:/github.comBooSooVIndoor-Ultrasonic-Positioning-SystemtreemasterStudying_ultrasonic_signalsMeasured_lengths_dispersion。

signal-processing stm32
1个回答
0
投票

可能是时间处理的问题。声波的速度是343米秒。那么,50毫米大约是0.15毫秒。

你有没有想过从main()调用HAL_ADC_Start_DMA()。

uint16_t uz_buf[10];
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&uz_buf, 10 );//300000);
//         Sizeof Buffer ---------------------^

你叫

void Get_UZ_Signal(uint16_t* uz_signal) {
  int i;
  // For debugging - Get the time to process
  // Get the Time from the System Tick. This counter wrap around
  // from 0 to SysTick->LOAD every 1 msec
  int32_t startTime = SysTick->VAL;
  __HAL_ADC_ENABLE(&hadc1); // Start the DMA

  // return remaining data units in the current DMA Channel transfer
  while(__HAL_DMA_GET_COUNTER(&hadc1) != 0)
    ;

  for(i = 0; i<lenght_signal; i++)  {   
    // uz_signal[i] = uz_buf[0];
    //    0 or i ------------^
    uz_signal[i] = uz_buf[i];

  __HAL_ADC_DISABLE(&hadc1); // Stop the DMA

  int32_t endTime = SysTick->VAL;
  // check if negative, case of wrap around
  int32_t difTime = endTime - startTime;
  if ( difTime < 0 )
     difTime += SysTick->LOAD

  __HAL_DMA_SET_COUNTER(&hadc1, 10); // Reset the counter 
  // If the DMA buffer is 10, the COUNTER will start at 10
  // and decrement 
  // Ref. Manual: 9.4.4 DMA channel x number of data register (DMA_CNDTRx) 

0
投票

在您的代码中

MX_USART1_UART_Init();

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&uz_signal, 30000);
// Must be stopped because is running now
// How long is the buffer: uint16_t uz_signal[ 30000 ] ?
__HAL_ADC_DISABLE(&hadc1); // must be disable
// reset the counter
__HAL_DMA_SET_COUNTER(&hdma_adc1, 30000);

 while (1)
 {
   if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) != 0x00) 
   {    
   __HAL_ADC_ENABLE(&hadc1);
  while(__HAL_DMA_GET_COUNTER(&hdma_adc1) != 0)
  ;
  __HAL_ADC_DISABLE(&hadc1);
  __HAL_DMA_SET_COUNTER(&hdma_adc1, 30000);
  // 30,000 is the sizeof your buffer?
 ...
  }
 }

0
投票

我用uC STM32F407 @ 168mHz做了一些测试。在测试过程中,我计算了处理ADC转换的时间,每次转换大约需要0.35uSec(60次)。每次转换大约需要0.35uSec(60次)。

        Result
Size             Corresponding
Array   Time     Distance
  100    0.041ms    14mm
 1600    0.571ms   196mm
10000    3.57ms   1225mm

在代码中,你会看到开始时间。小心,SysTick是一个递减计数器,从@uC速度开始(168MHz=从168000到0)。用HAL_GetTick()得到msec时间,用SysTick得到usec时间,是个好主意。

int main(void)
{
    ...
    MX_DMA_Init();
    MX_ADC1_Init();

    //  Configure the channel in the way you want
    ADC_ChannelConfTypeDef sConfig;
    sConfig.Channel = ADC_CHANNEL_0;    //ADC1_CHANNEL;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    sConfig.Offset = 0;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);

    //  Start the DMA channel and Stop it 
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&uz_signal, sizeof( uz_signal ) / sizeof( uint16_t ));

    HAL_ADC_Stop_DMA( &hadc1 );
    //  The SysTick is a decrement counter
    //  Can be use to count usec
    //  https://www.sciencedirect.com/topics/engineering/systick-timer
    tickLoad    =   SysTick->LOAD;

    while (1)
    {
        //  Set the buffer to zero
        for( uint32_t i=0; i < (sizeof( uz_signal ) / sizeof( uint16_t )); i++)
            uz_signal[i] = 0;

        //  Reset the counter ready to restart
        DMA2_Stream0->NDTR = (uint16_t)(sizeof( uz_signal ) / sizeof( uint16_t ));

        /* Enable the Peripheral */
        ADC1->CR2 |=  ADC_CR2_ADON;

        /* Start conversion if ADC is effectively enabled */
        /* Clear regular group conversion flag and overrun flag */
        ADC1->SR = ~(ADC_FLAG_EOC | ADC_FLAG_OVR);

        /* Enable ADC overrun interrupt */
        ADC1->CR1 |= (ADC_IT_OVR);

        /* Enable ADC DMA mode */
        ADC1->CR2 |= ADC_CR2_DMA;

        /* Start the DMA channel */
        /* Enable Common interrupts*/
        DMA2_Stream0->CR  |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_HT;
        DMA2_Stream0->FCR |= DMA_IT_FE;
        DMA2_Stream0->CR |=  DMA_SxCR_EN;

    //===================================================
    //  The DMA is ready to start
        //  Your if(HAL_GPIO_ReadPin( ... ) will be here
        HAL_Delay( 10 );
        //===================================================
        //  Get the time
        tickStart = SysTick->VAL;

        //  Start the DMA
        ADC1->CR2 |= (uint32_t)ADC_CR2_SWSTART;

        //  Wait until the conversion is completed
        while( DMA2_Stream0->NDTR != 0)
            ;
        //  Get end time
        tickEnd  = SysTick->VAL;

        /* Stop potential conversion on going, on regular and injected groups */
        ADC1->CR2 &=  ~ADC_CR2_ADON;

        /* Disable the selected ADC DMA mode */
        ADC1->CR2 &= ~ADC_CR2_DMA;

        /* Disable ADC overrun interrupt */
        ADC1->CR1 &= ~(ADC_IT_OVR);

        //  Get processing time
        tickDiff    = tickStart - tickEnd;
        //===================================================
        //  Your processing will go here
        HAL_Delay( 10 );
        //===================================================
    }
}

这样,你就有了开始和结束时间。我想你必须在开始时间上做公式。

祝您好运


0
投票

如果你想知道执行时间,你可以使用那个小函数。它返回微秒

static  uint32_t    timeMicroSecDivider = 0;
extern  uint32_t    uwTick;

//  The SysTick->LOAD matchs the uC Speed / 1000.
//  If the uC clock is 80MHz, the the LOAD is 80000
//  The SysTick->VAL is a decrement counter from (LOAD-1) to 0

//====================================================
uint64_t getTimeMicroSec()
{
    if ( timeMicroSecDivider == 0)
    {
        //  Number of clock by micro second
        timeMicroSecDivider = SysTick->LOAD  / 1000;
    }
    return( (uwTick * 1000) + ((SysTick->LOAD - SysTick->VAL) / timeMicroSecDivider));
}
© www.soinside.com 2019 - 2024. All rights reserved.