ST意法半导体
直播中

tr12345

9年用户 1021经验值
擅长:制造/封装
私信 关注
[问答]

为什么使用定时器触发STM32F103C8T6上的ADC1会失败呢

我正在尝试使用定时器触发 STM32F103C8T6 上的 ADC1。ADC 使用 DMA,转换完成后,我尝试通过 USB(虚拟 COM 端口)将缓冲区发送到我的计算机。我使用 HAL 在 STM32CubeIDE 中工作。
我使用 tiM4 及其第 4 个通道作为触发器。我需要生成 500 kHz,我设法做到了。我用示波器测试了它,如果我使用“PWM Generation CH4”选项,我可以获得 500 kHz 方波。
  • TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  •   TIM_MasterConfigTypeDef sMasterConfig = {0};
  •   TIM_OC_InitTypeDef sConfigOC = {0};
  •   /* USER CODE BEGIN TIM4_Init 1 */
  •   /* USER CODE END TIM4_Init 1 */
  •   htim4.Instance = TIM4;
  •   htim4.Init.Prescaler = 0;
  •   htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  •   htim4.Init.Period = 143;
  •   htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  •   htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  •   if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  •   if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  •   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  •   if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   sConfigOC.OCMode = TIM_OCMODE_PWM1;
  •   sConfigOC.Pulse = 35;
  •   sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  •   sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  •   if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
然后,我的 ADC1 设置如下:
  • ADC_ChannelConfTypeDef sConfig = {0};
  •   /* USER CODE BEGIN ADC1_Init 1 */
  •   /* USER CODE END ADC1_Init 1 */
  •   /** Common config
  •   */
  •   hadc1.Instance = ADC1;
  •   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  •   hadc1.Init.ContinuousConvMode = ENABLE;
  •   hadc1.Init.DiscontinuousConvMode = DISABLE;
  •   hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T4_CC4;
  •   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  •   hadc1.Init.NbrOfConversion = 1;
  •   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   /** Configure Regular Channel
  •   */
  •   sConfig.Channel = ADC_CHANNEL_3;
  •   sConfig.Rank = ADC_REGULAR_RANK_1;
  •   sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  •   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
然后,在 while(1) 循环中,我定期(重新)启动 ADC,在它启动后,我还在 ADC 启动后以一种脉冲模式启动另外 2 个定时器。缓冲区的大小为 4000。
  • while(1)
  • {
  • HAL_ADC_Start_DMA(&hadc1, (uint32_t*) Buffer, BufferSize);
  •          HAL_Delay(1);
  •          __HAL_TIM_ENABLE(&htim1);
  •          __HAL_TIM_ENABLE(&htim3);
  • HAL_Delay(50);
  • }
最后,我尝试使用 ADC 转换完成回调通过 USB 推送我的缓冲区:
  • void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
  • {
  •     CDC_Transmit_FS((uint8_t*) Buffer, BufferSize);
  • }
似乎由于我的经验不足,我忽略了一些东西。
我将我的代码分成两个较小的代码以查看可能出现的问题。我测试了我在 while(1) 中启动的另外两个单脉冲定时器是否正常工作。是的,他们有。然后我在没有这些定时器的情况下为 ADC 编写了相同的代码,它似乎也可以工作(ADC 由 TIM4 CH4 触发)。我用电位计测试了它,ADC 将预期数据发送到我 PC 上的终端。
但是,当我将这两个代码结合起来时,似乎有些东西不起作用。我还尝试在 ADC 的回调中放置一个标志,并在 while(1) 中进行 USB 传输,然后重置标志,但它也不起作用。我还尝试在 ADC 的回调中停止 ADC 和 TIM4,并在 USB 传输后重新启动它,但没有帮助。我的电脑上仍然显示零。
如果有人有任何想法,我将不胜感激!谢谢!

回帖(1)

王桂花

2022-12-20 10:47:34
ADC 配置中存在一个错误:连续与周期性 ADC 转换(触发模式)之间的混淆:


  • 连续模式:ADC 在第一个触发事件后连续、自动且无延迟地执行转换
  • 触发模式:ADC 在每次触发事件后执行一次转换(在定时器触发的情况下,它将引起周期性的 ADC 转换)

如果您同时使用两者,就像在您的配置中一样:ADC 将等待来自定时器的第一个触发事件,然后将自动转换而不使用进一步的定时器事件。
(不禁止配置,但不符合典型用例)。
=> 你必须设置:hadc1.Init.ContinuousConvMode = DISABLE;
那么你的应用程序应该基本上可以工作了。
您不必在每次传输时停止 ADC 或使用棘手的定时器启动:仅 ADC 启动,然后定时器启动,仅此而已。
如果是 STM32F1 FW 包,有一个演示 ADC+DMA+timer 的例子:
...FirmwareProjectsSTM3210C_EVALExamplesADCADC_Regular_injected_groups
(它可以很容易地移植到你的目标STM32F103)
一些改进建议:
你应该一半一半地管理数据缓冲区(当一半由ADC+DMA填充时,另一半由USB传输)
可以使用回调函数来完成:
- HAL_ADC_ConvHalfCpltCallback()
- HAL_ADC_ConvCpltCallback()
它还需要在每次传输后更新 USB 缓冲区(hcdc->TxBuffer、hcdc->TxLength)。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分