请教,为什么STM32L452的ADC实际采样率和理论采样率差这么多?

2019-03-23 17:28发布

本帖最后由 littleshrimp 于 2017-10-24 17:19 编辑

数据手册上说STM32L452的ADC最大支持5.33MSPS为了验证ADC的采样率使用一个单片机产生10KHz的方波,50%占空比将输出连接到STM32L542的ADC输入引脚 STM32L542的ADC使用系统时钟不分频,系统时钟为80MHz使用12位分辨率,开始的时候使用DMA方式,数据长度为4096使用STM32Cube_FW_L4_V1.9.0中的ADC_DMA_Transfer例程Sampling time设置为640.5cycles时采样到的波形如下 image001.png Sampling time设置为247.5 cycles时采样到的波形如下可以看到,使用DMA时采到的数据一点规律没有 image002.png DMA测试代码
  1. /**
  2.   ******************************************************************************
  3.   * @file    ADC/ADC_DMA_Transfer/Src/main.c
  4.   * @author  MCD Application Team
  5.   * [url=home.php?mod=space&uid=159083]@brief[/url]   This example describes how to use the DMA to convert continuously data.
  6.   ******************************************************************************
  7.   * @attention
  8.   *
  9.   * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  10.   *
  11.   * Redistribution and use in source and binary forms, with or without modification,
  12.   * are permitted provided that the following conditions are met:
  13.   *   1. Redistributions of source code must retain the above copyright notice,
  14.   *      this list of conditions and the following disclaimer.
  15.   *   2. Redistributions in binary form must reproduce the above copyright notice,
  16.   *      this list of conditions and the following disclaimer in the documentation
  17.   *      and/or other materials provided with the distribution.
  18.   *   3. Neither the name of STMicroelectronics nor the names of its contributors
  19.   *      may be used to endorse or promote products derived from this software
  20.   *      without specific prior written permission.
  21.   *
  22.   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23.   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25.   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  26.   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  28.   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29.   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30.   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31.   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.   *
  33.   ******************************************************************************
  34.   */

  35. /* Includes ------------------------------------------------------------------*/
  36. #include "main.h"

  37. /** @addtogroup STM32L4xx_HAL_Examples
  38.   * @{
  39.   */

  40. /** @addtogroup ADC_DMA_Transfer
  41.   * @{
  42.   */

  43. /* Private typedef -----------------------------------------------------------*/
  44. /* Private define ------------------------------------------------------------*/

  45. /* Definitions of data related to this example */
  46.   /* Definition of ADCx conversions data table size */
  47.   #define ADC_CONVERTED_DATA_BUFFER_SIZE   ((uint32_t)  4096)   /* Size of array aADCxConvertedData[] */

  48. /* Private macro -------------------------------------------------------------*/
  49. /* Private variables ---------------------------------------------------------*/
  50. /* ADC handle declaration */
  51. ADC_HandleTypeDef             AdcHandle;

  52. /* ADC channel configuration structure declaration */
  53. ADC_ChannelConfTypeDef        sConfig;

  54. /* Variable containing ADC conversions data */
  55. static uint16_t   aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE];

  56. /* Private function prototypes -----------------------------------------------*/
  57. void SystemClock_Config(void);
  58. static void Error_Handler(void);


  59. /* Private typedef -----------------------------------------------------------*/
  60. #define  PERIOD_VALUE       (uint32_t)(1600 - 1)  /* Period Value  */
  61. #define  PULSE1_VALUE       (uint32_t)(PERIOD_VALUE/2)        /* Capture Compare 1 Value  */
  62. #define  PULSE2_VALUE       (uint32_t)(PERIOD_VALUE*37.5/100) /* Capture Compare 2 Value  */
  63. #define  PULSE3_VALUE       (uint32_t)(PERIOD_VALUE/4)        /* Capture Compare 3 Value  */
  64. #define  PULSE4_VALUE       (uint32_t)(PERIOD_VALUE*12.5/100) /* Capture Compare 4 Value  */
  65. /* Timer handler declaration */
  66. TIM_HandleTypeDef    TimHandle;

  67. /* Timer Output Compare Configuration Structure declaration */
  68. TIM_OC_InitTypeDef timConfig;

  69. /* Counter Prescaler value */
  70. uint32_t uhPrescalerValue = 0;
  71. /* Private functions ---------------------------------------------------------*/
  72. void pwm_init(void)
  73. {
  74.   
  75.   /* Compute the prescaler value to have TIM1 counter clock equal to 16000000 Hz */
  76.   uhPrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
  77.     /*##-1- Configure the TIM peripheral #######################################*/
  78.   /* -----------------------------------------------------------------------
  79.   TIM1 Configuration: generate 4 PWM signals with 4 different duty cycles.

  80.     In this example TIM1 input clock (TIM1CLK) is set to APB1 clock (PCLK1),
  81.     since APB1 prescaler is equal to 1.
  82.       TIM1CLK = PCLK1
  83.       PCLK1 = HCLK
  84.       => TIM1CLK = HCLK = SystemCoreClock

  85.     To get TIM1 counter clock at 16 MHz, the prescaler is computed as follows:
  86.        Prescaler = (TIM1CLK / TIM1 counter clock) - 1
  87.        Prescaler = ((SystemCoreClock) /16 MHz) - 1

  88.     To get TIM1 output clock at 24 KHz, the period (ARR)) is computed as follows:
  89.        ARR = (TIM1 counter clock / TIM1 output clock) - 1
  90.            = 665

  91.     TIM1 Channel1 duty cycle = (TIM1_CCR1/ TIM1_ARR + 1)* 100 = 50%
  92.     TIM1 Channel2 duty cycle = (TIM1_CCR2/ TIM1_ARR + 1)* 100 = 37.5%
  93.     TIM1 Channel3 duty cycle = (TIM1_CCR3/ TIM1_ARR + 1)* 100 = 25%
  94.     TIM1 Channel4 duty cycle = (TIM1_CCR4/ TIM1_ARR + 1)* 100 = 12.5%

  95.     Note:
  96.      SystemCoreClock variable holds HCLK frequency and is defined in system_stm32l4xx.c file.
  97.      Each time the core clock (HCLK) changes, user had to update SystemCoreClock
  98.      variable value. Otherwise, any configuration based on this variable will be incorrect.
  99.      This variable is updated in three ways:
  100.       1) by calling CMSIS function SystemCoreClockUpdate()
  101.       2) by calling HAL API function HAL_RCC_GetSysClockFreq()
  102.       3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
  103.   ----------------------------------------------------------------------- */

  104.   /* Initialize TIMx peripheral as follows:
  105.        + Prescaler = (SystemCoreClock / 16000000) - 1
  106.        + Period = (666 - 1)
  107.        + ClockDivision = 0
  108.        + Counter direction = Up
  109.   */
  110.   TimHandle.Instance = TIMx;

  111.   TimHandle.Init.Prescaler         = uhPrescalerValue;
  112.   TimHandle.Init.Period            = PERIOD_VALUE;
  113.   TimHandle.Init.ClockDivision     = 0;
  114.   TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
  115.   TimHandle.Init.RepetitionCounter = 0;
  116.   if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
  117.   {
  118.     /* Initialization Error */
  119.     Error_Handler();
  120.   }

  121.   /*##-2- Configure the PWM channels #########################################*/
  122.   /* Common configuration for all channels */
  123.   timConfig.OCMode       = TIM_OCMODE_PWM1;
  124.   timConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
  125.   timConfig.OCFastMode   = TIM_OCFAST_DISABLE;
  126.   timConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
  127.   timConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;

  128.   timConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;

  129.   /* Set the pulse value for channel 1 */
  130.   timConfig.Pulse = PULSE1_VALUE;
  131.   if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &timConfig, TIM_CHANNEL_1) != HAL_OK)
  132.   {
  133.     /* Configuration Error */
  134.     Error_Handler();
  135.   }

  136.   /* Set the pulse value for channel 2 */
  137.   timConfig.Pulse = PULSE2_VALUE;
  138.   if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &timConfig, TIM_CHANNEL_2) != HAL_OK)
  139.   {
  140.     /* Configuration Error */
  141.     Error_Handler();
  142.   }

  143.   /* Set the pulse value for channel 3 */
  144.   timConfig.Pulse = PULSE3_VALUE;
  145.   if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &timConfig, TIM_CHANNEL_3) != HAL_OK)
  146.   {
  147.     /* Configuration Error */
  148.     Error_Handler();
  149.   }

  150.   /* Set the pulse value for channel 4 */
  151.   timConfig.Pulse = PULSE4_VALUE;
  152.   if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &timConfig, TIM_CHANNEL_4) != HAL_OK)
  153.   {
  154.     /* Configuration Error */
  155.     Error_Handler();
  156.   }

  157.   /*##-3- Start PWM signals generation #######################################*/
  158.   /* Start channel 1 */
  159.   if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
  160.   {
  161.     /* PWM Generation Error */
  162.     Error_Handler();
  163.   }
  164.   /* Start channel 2 */
  165.   if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
  166.   {
  167.     /* PWM Generation Error */
  168.     Error_Handler();
  169.   }
  170.   /* Start channel 3 */
  171.   if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
  172.   {
  173.     /* PWM generation Error */
  174.     Error_Handler();
  175.   }
  176.   /* Start channel 4 */
  177.   if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_4) != HAL_OK)
  178.   {
  179.     /* PWM generation Error */
  180.     Error_Handler();
  181.   }
  182.   
  183. }
  184. /**
  185.   * @brief  Main program.
  186.   * @param  None
  187.   * @retval None
  188.   */
  189. int main(void)
  190. {
  191. /* This sample code shows how to convert an analog input and read the converted
  192.     data using DMA transfer.
  193.     To proceed, 4 steps are required: */
  194.    
  195.   /* STM32L4xx HAL library initialization:
  196.        - Configure the Flash prefetch and Buffer caches
  197.        - Systick timer is configured by default as source of time base, but user
  198.          can eventually implement his proper time base source (a general purpose
  199.          timer for example or other time source), keeping in mind that Time base
  200.          duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
  201.          handled in milliseconds basis.
  202.        - Set NVIC Group Priority to 4
  203.        - Low Level Initialization
  204.      */
  205.   HAL_Init();

  206.   /* Configure the system clock to 80 MHz */
  207.   SystemClock_Config();

  208.   /* Configure LED2 */
  209.   BSP_LED_Init(LED2);

  210. //  pwm_init();
  211.   /* ### - 1 - Initialize ADC peripheral #################################### */
  212.   AdcHandle.Instance          = ADCx;
  213.   if (HAL_ADC_DeInit(&AdcHandle) != HAL_OK)
  214.   {
  215.     /* ADC de-initialization Error */
  216.     Error_Handler();
  217.   }

  218.   AdcHandle.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV1;      /* Synchronous clock mode, input ADC clock divided by 2*/
  219.   AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;            /* 12-bit resolution for converted data */
  220.   AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;           /* Right-alignment for converted data */
  221.   AdcHandle.Init.ScanConvMode          = DISABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
  222.   AdcHandle.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;           /* EOC flag picked-up to indicate conversion end */
  223.   AdcHandle.Init.LowPowerAutoWait      = DISABLE;                       /* Auto-delayed conversion feature disabled */
  224.   AdcHandle.Init.ContinuousConvMode    = ENABLE;                        /* Continuous mode enabled (automatic conversion restart after each conversion) */
  225.   AdcHandle.Init.NbrOfConversion       = 1;                             /* Parameter discarded because sequencer is disabled */
  226.   AdcHandle.Init.DiscontinuousConvMode = DISABLE;                       /* Parameter discarded because sequencer is disabled */
  227.   AdcHandle.Init.NbrOfDiscConversion   = 1;                             /* Parameter discarded because sequencer is disabled */
  228.   AdcHandle.Init.ExternalTrigConv      = ADC_SOFTWARE_START;            /* Software start to trig the 1st conversion manually, without external event */
  229.   AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
  230.   AdcHandle.Init.DMAContinuousRequests = ENABLE;                        /* ADC DMA continuous request to match with DMA circular mode */
  231.   AdcHandle.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;      /* DR register is overwritten with the last conversion result in case of overrun */
  232.   AdcHandle.Init.OversamplingMode      = DISABLE;                       /* No oversampling */
  233.   /* Initialize ADC peripheral according to the passed parameters */
  234.   if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  235.   {
  236.     Error_Handler();
  237.   }
  238.   
  239.   
  240.   /* ### - 2 - Start calibration ############################################ */
  241.   if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED) !=  HAL_OK)
  242.   {
  243.     Error_Handler();
  244.   }
  245.   
  246.   /* ### - 3 - Channel configuration ######################################## */
  247.   sConfig.Channel      = ADCx_CHANNEL;                /* Sampled channel number */
  248.   sConfig.Rank         = ADC_REGULAR_RANK_1;          /* Rank of sampled channel number ADCx_CHANNEL */
  249.   sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;   /* Sampling time (number of clock cycles unit) */
  250.   sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
  251.   sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */
  252.   sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
  253.   if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  254.   {
  255.     Error_Handler();
  256.   }
  257.   
  258.   /* ### - 4 - Start conversion in DMA mode ################################# */
  259.   if (HAL_ADC_Start_DMA(&AdcHandle,
  260.                         (uint32_t *)aADCxConvertedData,
  261.                         ADC_CONVERTED_DATA_BUFFER_SIZE
  262.                        ) != HAL_OK)
  263.   {
  264.     Error_Handler();
  265.   }
  266.   
  267.   /* Infinite Loop */
  268.   while (1)
  269.   {
  270.   }
  271. }

  272. /**
  273.   * @brief  System Clock Configuration
  274.   *         The system Clock is configured as follows :
  275.   *            System Clock source            = PLL (MSI)
  276.   *            SYSCLK(Hz)                     = 80000000
  277.   *            HCLK(Hz)                       = 80000000
  278.   *            AHB Prescaler                  = 1
  279.   *            APB1 Prescaler                 = 1
  280.   *            APB2 Prescaler                 = 1
  281.   *            MSI Frequency(Hz)              = 4000000
  282.   *            PLL_M                          = 1
  283.   *            PLL_N                          = 40
  284.   *            PLL_R                          = 2
  285.   *            PLL_P                          = 7
  286.   *            PLL_Q                          = 4
  287.   *            Flash Latency(WS)              = 4
  288.   * @param  None
  289.   * @retval None
  290.   */
  291. void SystemClock_Config(void)
  292. {
  293.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  294.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  295.   /* MSI is enabled after System reset, activate PLL with MSI as source */
  296.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  297.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  298.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  299.   RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  300.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  301.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  302.   RCC_OscInitStruct.PLL.PLLM = 1;
  303.   RCC_OscInitStruct.PLL.PLLN = 40;
  304.   RCC_OscInitStruct.PLL.PLLR = 2;
  305.   RCC_OscInitStruct.PLL.PLLP = 7;
  306.   RCC_OscInitStruct.PLL.PLLQ = 4;
  307.   if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  308.   {
  309.     /* Initialization Error */
  310.     while(1);
  311.   }
  312.   
  313.   /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
  314.      clocks dividers */
  315.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  316.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  317.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  318.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  
  319.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  320.   if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  321.   {
  322.     /* Initialization Error */
  323.     while(1);
  324.   }
  325. }
  326. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
  327. {
  328.   __NOP();
  329. }
  330. /**
  331.   * @brief  This function is executed in case of error occurrence.
  332.   * @param  None
  333.   * @retval None
  334.   */
  335. static void Error_Handler(void)
  336. {
  337.   /* Turn LED2 on*/
  338.   BSP_LED_On(LED2);
  339.   while (1)
  340.   {
  341.   }
  342. }

  343. #ifdef  USE_FULL_ASSERT

  344. /**
  345.   * @brief  Reports the name of the source file and the source line number
  346.   *         where the assert_param error has occurred.
  347.   * @param  file: pointer to the source file name
  348.   * @param  line: assert_param error line source number
  349.   * @retval None
  350.   */
  351. void assert_failed(char *file, uint32_t line)
  352. {
  353.   /* User can add his own implementation to report the file name and line number,
  354.      ex: printf("Wrong parameters value: file %s on line %d ", file, line) */

  355.   /* Infinite loop */
  356.   while (1)
  357.   {
  358.   }
  359. }

  360. #endif

  361. /**
  362.   * @}
  363.   */

  364. /**
  365.   * @}
  366.   */

  367. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
后来使用ADC_RegularConversion_Interrupt例程采样时间设置为640.5时,高低电平各为6个样本左右,一个周期12个样本 image003.png 实际采样率为10KHz*12 = 120KSPS理论采样率为80MHz/(640.9+12.5) = 122.5KSPS理论和实际基本一致 采样时间设置为247.5时采集到的数据,高电平15个样本低电平15个样本,一个周期共采集30个样本 image004.png 实际采样率为10KHz*30=300KSPS理论采样率为80MHz/(247.5+12.5) = 307.6KSPS理论和实际基本一致 将SamplingTime改为92.5时高低电平各26个,一个周期为52个样本 image005.png 实际采样率为10KHz * 52 = 520KSPS 理论采样率为80MHz / (92.5+12.5) = 761.9KSPS 实际采样率比理论低很多,是理论采样率的68.2% 将SamplingTime改为47.5时高低电平各31个,一个周期为62个样本 image006.png 实际采样率为10KHz * 62= 620KSPS 理论采样率为80MHz / (47.5+12.5) = 1333.3KSPS 实际采样率比理论低很多,是理论采样率的46.5% ADC_RegularConversion_Interrupt测试代码
  1. /**
  2.   ******************************************************************************
  3.   * @file    ADC/ADC_RegularConversion_Interrupt/Src/main.c
  4.   * @author  MCD Application Team
  5.   * @brief   This example describes how to use an Interrupt to convert
  6.   *          continuously data
  7.   ******************************************************************************
  8.   * @attention
  9.   *
  10.   * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  11.   *
  12.   * Redistribution and use in source and binary forms, with or without modification,
  13.   * are permitted provided that the following conditions are met:
  14.   *   1. Redistributions of source code must retain the above copyright notice,
  15.   *      this list of conditions and the following disclaimer.
  16.   *   2. Redistributions in binary form must reproduce the above copyright notice,
  17.   *      this list of conditions and the following disclaimer in the documentation
  18.   *      and/or other materials provided with the distribution.
  19.   *   3. Neither the name of STMicroelectronics nor the names of its contributors
  20.   *      may be used to endorse or promote products derived from this software
  21.   *      without specific prior written permission.
  22.   *
  23.   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24.   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26.   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  27.   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  29.   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  30.   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  31.   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32.   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33.   *
  34.   ******************************************************************************
  35.   */

  36. /* Includes ------------------------------------------------------------------*/
  37. #include "main.h"

  38. /** @addtogroup STM32L4xx_HAL_Examples
  39.   * @{
  40.   */

  41. /** @addtogroup ADC_RegularConversion_Interrupt
  42.   * @{
  43.   */

  44. /* Private typedef -----------------------------------------------------------*/
  45. /* Private define ------------------------------------------------------------*/
  46. /* Private macro -------------------------------------------------------------*/
  47. /* Private variables ---------------------------------------------------------*/
  48. /* ADC handler declaration */
  49. ADC_HandleTypeDef    AdcHandle;

  50. /* Variable used to get converted value */
  51. __IO uint16_t uhADCxConvertedValue[4096];
  52. uint16_t uhADCxConvertedValueIndex = 0;
  53. /* Private function prototypes -----------------------------------------------*/
  54. void SystemClock_Config(void);
  55. static void Error_Handler(void);

  56. /* Private functions ---------------------------------------------------------*/

  57. /**
  58.   * @brief  Main program.
  59.   * @param  None
  60.   * @retval None
  61.   */
  62. int main(void)
  63. {
  64.   ADC_ChannelConfTypeDef sConfig;

  65.   
  66.   /* STM32L4xx HAL library initialization:
  67.        - Configure the Flash prefetch and Buffer caches
  68.        - Systick timer is configured by default as source of time base, but user
  69.          can eventually implement his proper time base source (a general purpose
  70.          timer for example or other time source), keeping in mind that Time base
  71.          duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
  72.          handled in milliseconds basis.
  73.        - Set NVIC Group Priority to 4
  74.        - Low Level Initialization
  75.      */
  76.   HAL_Init();


  77.   /* Configure LED2 */
  78.   BSP_LED_Init(LED2);

  79.   /* Configure the system clock to 80 MHz */
  80.   SystemClock_Config();

  81.   /*##-1- Configure the ADC peripheral #######################################*/
  82.   AdcHandle.Instance          = ADCx;
  83.   
  84.   if (HAL_ADC_DeInit(&AdcHandle) != HAL_OK)
  85.   {
  86.     /* ADC de-initialization Error */
  87.     Error_Handler();
  88.   }
  89.   
  90.   AdcHandle.Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV1;          /* Asynchronous clock mode, input ADC clock not divided */
  91.   AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;            /* 12-bit resolution for converted data */
  92.   AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;           /* Right-alignment for converted data */
  93.   AdcHandle.Init.ScanConvMode          = DISABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
  94.   AdcHandle.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;           /* EOC flag picked-up to indicate conversion end */
  95.   AdcHandle.Init.LowPowerAutoWait      = DISABLE;                       /* Auto-delayed conversion feature disabled */
  96.   AdcHandle.Init.ContinuousConvMode    = ENABLE;                        /* Continuous mode disabled to have only 1 conversion at each conversion trig */
  97.   AdcHandle.Init.NbrOfConversion       = 1;                             /* Parameter discarded because sequencer is disabled */
  98.   AdcHandle.Init.DiscontinuousConvMode = DISABLE;                       /* Parameter discarded because sequencer is disabled */
  99.   AdcHandle.Init.NbrOfDiscConversion   = 1;                             /* Parameter discarded because sequencer is disabled */
  100.   AdcHandle.Init.ExternalTrigConv      = ADC_SOFTWARE_START;            /* Software start to trig the 1st conversion manually, without external event */
  101.   AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
  102.   AdcHandle.Init.DMAContinuousRequests = DISABLE;                       /* DMA one-shot mode selected (not applied to this example) */
  103.   AdcHandle.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;      /* DR register is overwritten with the last conversion result in case of overrun */
  104.   AdcHandle.Init.OversamplingMode      = DISABLE;                       /* No oversampling */

  105.   if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  106.   {
  107.     /* ADC initialization Error */
  108.     Error_Handler();
  109.   }

  110.   /*##-2- Configure ADC regular channel ######################################*/
  111.   sConfig.Channel      = ADCx_CHANNEL;                /* Sampled channel number */
  112.   sConfig.Rank         = ADC_REGULAR_RANK_1;          /* Rank of sampled channel number ADCx_CHANNEL */
  113.   sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5;    /* Sampling time (number of clock cycles unit) */
  114.   sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
  115.   sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */
  116.   sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
  117.   if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  118.   {
  119.     /* Channel Configuration Error */
  120.     Error_Handler();
  121.   }

  122.   /* Run the ADC calibration in single-ended mode */
  123.   if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED) != HAL_OK)
  124.   {
  125.     /* Calibration Error */
  126.     Error_Handler();
  127.   }

  128.   /*##-3- Start the conversion process #######################################*/
  129.   if (HAL_ADC_Start_IT(&AdcHandle) != HAL_OK)
  130.   {
  131.     /* Start Conversation Error */
  132.     Error_Handler();
  133.   }

  134.   /* Infinite loop */
  135.   while (1)
  136.   {
  137.   }
  138. }

  139. /**
  140.   * @brief  System Clock Configuration
  141.   *         The system Clock is configured as follows :
  142.   *            System Clock source            = PLL (MSI)
  143.   *            SYSCLK(Hz)                     = 80000000
  144.   *            HCLK(Hz)                       = 80000000
  145.   *            AHB Prescaler                  = 1
  146.   *            APB1 Prescaler                 = 1
  147.   *            APB2 Prescaler                 = 1
  148.   *            MSI Frequency(Hz)              = 4000000
  149.   *            PLL_M                          = 1
  150.   *            PLL_N                          = 40
  151.   *            PLL_R                          = 2
  152.   *            PLL_P                          = 7
  153.   *            PLL_Q                          = 4
  154.   *            Flash Latency(WS)              = 4
  155.   * @param  None
  156.   * @retval None
  157.   */
  158. void SystemClock_Config(void)
  159. {
  160.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  161.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  162.   /* MSI is enabled after System reset, activate PLL with MSI as source */
  163.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  164.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  165.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  166.   RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  167.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  168.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  169.   RCC_OscInitStruct.PLL.PLLM = 1;
  170.   RCC_OscInitStruct.PLL.PLLN = 40;
  171.   RCC_OscInitStruct.PLL.PLLR = 2;
  172.   RCC_OscInitStruct.PLL.PLLP = 7;
  173.   RCC_OscInitStruct.PLL.PLLQ = 4;
  174.   if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  175.   {
  176.     /* Initialization Error */
  177.     while(1);
  178.   }
  179.   
  180.   /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
  181.      clocks dividers */
  182.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  183.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  184.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  185.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  
  186.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  187.   if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  188.   {
  189.     /* Initialization Error */
  190.     while(1);
  191.   }
  192. }



  193. /**
  194.   * @brief  This function is executed in case of error occurrence.
  195.   * @param  None
  196.   * @retval None
  197.   */
  198. static void Error_Handler(void)
  199. {
  200.   /* Turn LED2 on */
  201.   BSP_LED_On(LED2);
  202.   while (1)
  203.   {
  204.   }
  205. }

  206. /**
  207.   * @brief  Conversion complete callback in non blocking mode
  208.   * @param  AdcHandle : AdcHandle handle
  209.   * @note   This example shows a simple way to report end of conversion, and
  210.   *         you can add your own implementation.
  211.   * @retval None
  212.   */
  213. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
  214. {
  215.   /* Get the converted value of regular channel */
  216.   uhADCxConvertedValue[uhADCxConvertedValueIndex++] = HAL_ADC_GetValue(AdcHandle);
  217.   if(uhADCxConvertedValueIndex >= 4096)
  218.   {
  219.     uhADCxConvertedValueIndex = 0;
  220.     __NOP();
  221.   }
  222. }

  223. #ifdef  USE_FULL_ASSERT

  224. /**
  225.   * @brief  Reports the name of the source file and the source line number
  226.   *         where the assert_param error has occurred.
  227.   * @param  file: pointer to the source file name
  228.   * @param  line: assert_param error line source number
  229.   * @retval None
  230.   */
  231. void assert_failed(char *file, uint32_t line)
  232. {
  233.   /* User can add his own implementation to report the file name and line number,
  234.      ex: printf("Wrong parameters value: file %s on line %d ", file, line) */

  235.   /* Infinite loop */
  236.   while (1)
  237.   {
  238.   }
  239. }

  240. #endif

  241. /**
  242.   * @}
  243.   */

  244. /**
  245.   * @}
  246.   */

  247. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
6条回答
dontium
1楼-- · 2019-03-23 19:00
 精彩回答 2  元偷偷看……
littleshrimp
2楼-- · 2019-03-23 21:19
dontium 发表于 2017-10-24 17:43
我也遇到这个问题。

楼主别使用库,使用直接寄存器操作试试!
特别是那些中断函数、CALL BACK,害人得 ...

ADC_RegularConversion_Interrupt例程应该和HAL_ADC_IRQHandler中断有关
每执行一次ADC_RegularConversion_Interrupt都要做很多判断还要清中断标志

现在只能考虑DMA,为什么使用DMA例程读到的数据会是乱的应该和使用库没有关系
估计还有哪些地方我还没弄明白,再试试看
柠檬酸钠
3楼-- · 2019-03-23 23:11
之前碰到过用库函数,io口刷屏,速度会比直接操作IO口要慢一点
freebsder
4楼-- · 2019-03-24 03:05
 精彩回答 2  元偷偷看……
littleshrimp
5楼-- · 2019-03-24 06:22
freebsder 发表于 2017-10-25 09:26
SAR的保持时间与外部输入电容,内部采样电容,内外阻抗等因素有关。输出处理虽然会有消耗,DMA记录本身的顺 ...

现在来看应该不是这部分的问题
使用中断方式读到的数据虽然比理论慢很多,但最少还能达到1Msp以上
而使用DMA无论怎么设置读取到的数据都是乱的
使用DMA方式读取10KHz方波基本都是2~3个低电平2~3个高电平样本
修改采样时间和ADC时钟分频数居然不会对采集到的数据产生太大影响
甚至昨天晚上我把输入频率改成100Hz时使用DMA采样到的数据还是这样

如果把ADC引脚接在3.3V基本上是4095接在GND基本是0,这又说明ADC的输入是正常的
我还尝试过使用STM32F469I Discovery使用官方的ADC DMA例程遇到的问题和STM32L452是一样的

现在来看有可能是在DMA状态下的采样触发没有设置正确,或者还有其它地方和不使用DMA的配置有区别
huaiqiao
6楼-- · 2019-03-24 11:59
hal的库,读起来真的很晦涩,我也不太想碰他。。。。。。
我基本都用的是标准外设库。

一周热门 更多>