你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F303使用定时器触发双ADC常规同步采样模式

[复制链接]
与非网的L先生 提问时间:2018-1-5 17:14 /
本帖最后由 与非网的L先生 于 2018-1-5 17:28 编辑

之前已经实现了使用软件触发的方式,实现基于DMA方式的双ADC常规同步采样,但是这种方式有个问题,基于DMA方式的双ADC常规同步采样在两次采样之间是不存在间隔的,如下图所示: 捕获01.PNG
所以,当我需要调整采样率的时候,就只能去修改ADC时钟、采样周期数,每次调整后,都得重新初始化ADC,而且这样的采样率没法很自由调整。
所以我采样定时器去触发,每次只采样一次(所以不需要用到DMA?),那么通过设置定时器的时间间隔来设定采样率就很自由了,如下图所示:
捕获03.PNG

我的代码如下:
  1. void ADC_Config(void)
  2. {
  3.   ADC_MultiModeTypeDef multimode;
  4.   ADC_ChannelConfTypeDef sConfig;
  5.         
  6.   /*##-1- Configuration of ADCx peripheral (ADC master) ######################*/
  7.   AdcHandle_master.Instance = AdcMasterInstance;
  8.         
  9.   AdcHandle_master.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
  10.   AdcHandle_master.Init.Resolution = ADC_RESOLUTION_12B;
  11.   AdcHandle_master.Init.DataAlign   = ADC_DATAALIGN_RIGHT;
  12.   AdcHandle_master.Init.ScanConvMode = ADC_SCAN_DISABLE;
  13.   AdcHandle_master.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  14.   AdcHandle_master.Init.LowPowerAutoWait = DISABLE;
  15.   AdcHandle_master.Init.ContinuousConvMode = DISABLE;
  16.         AdcHandle_master.Init.NbrOfConversion  = 1;
  17.   AdcHandle_master.Init.DiscontinuousConvMode = DISABLE;
  18.   AdcHandle_master.Init.NbrOfDiscConversion = 1;
  19.         AdcHandle_master.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
  20.   AdcHandle_master.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  21.   AdcHandle_master.Init.DMAContinuousRequests = DISABLE;
  22.   AdcHandle_master.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  23.         
  24.   if (HAL_ADC_Init(&AdcHandle_master) != HAL_OK)
  25.   {
  26.     Error_Handler();
  27.   }
  28.         
  29.   /*##-2- Configuration of ADCy peripheral (ADC slave) #######################*/
  30.   AdcHandle_slave.Instance = AdcSlaveInstance;
  31.         
  32.   /* Configuration of ADCy init structure: ADC parameters and regular group */
  33.   /* Same configuration as ADCx */
  34.   AdcHandle_slave.Init = AdcHandle_master.Init;
  35.         
  36.   if (HAL_ADC_Init(&AdcHandle_slave) != HAL_OK)
  37.   {
  38.     Error_Handler();
  39.   }
  40.         
  41.   /*##-3- Configuration of channel on ADCx regular group on rank 1 ###########*/
  42.   sConfig.Channel                 = AdcMasterChannel;
  43.   sConfig.Rank                     = ADC_REGULAR_RANK_1;
  44.   sConfig.SingleDiff              = ADC_DIFFERENTIAL_ENDED;
  45.   sConfig.SamplingTime        = ADC_SAMPLETIME_7CYCLES_5;
  46.   sConfig.OffsetNumber        = ADC_OFFSET_NONE;
  47.   sConfig.Offset                   = 0;
  48.   if (HAL_ADC_ConfigChannel(&AdcHandle_master, &sConfig) != HAL_OK)
  49.   {
  50.     Error_Handler();
  51.   }
  52.         
  53.   /*##-4- Configuration of channel on ADCy regular group on rank 1 ###########*/
  54.   sConfig.Channel = AdcSlaveChannel;

  55.   if (HAL_ADC_ConfigChannel(&AdcHandle_slave, &sConfig) != HAL_OK)
  56.   {
  57.     Error_Handler();
  58.   }
  59.         
  60.   /*##-5- Configuration of multimode #########################################*/
  61.   /* Multimode parameters settings and set ADCy (slave) under control of  */
  62.   /* ADCx (master).  */
  63.   multimode.Mode                           = ADC_DUALMODE_REGSIMULT;
  64.   multimode.DMAAccessMode           = ADC_DMAACCESSMODE_12_10_BITS;
  65.   multimode.TwoSamplingDelay        = ADC_TWOSAMPLINGDELAY_5CYCLES;
  66.   if (HAL_ADCEx_MultiModeConfigChannel(&AdcHandle_master, &multimode) != HAL_OK)
  67.   {
  68.     Error_Handler();
  69.   }
  70.         
  71.   /* Run the ADC calibration in differential-ended mode */  
  72.   if (HAL_ADCEx_Calibration_Start(&AdcHandle_master, ADC_DIFFERENTIAL_ENDED) != HAL_OK)
  73.   {
  74.     Error_Handler();
  75.   }
  76.   if (HAL_ADCEx_Calibration_Start(&AdcHandle_slave, ADC_DIFFERENTIAL_ENDED) != HAL_OK)
  77.   {
  78.     Error_Handler();
  79.   }

  80. }
复制代码
  1. void ADC_Timer_Init(uint32_t uPrescaler,uint32_t uPeriod)
  2. {
  3.   TIM_ClockConfigTypeDef sClockSourceConfig;
  4.   TIM_MasterConfigTypeDef sMasterConfig;

  5.   hadc_Timer.Instance                            = ADC_TIMn;
  6.   hadc_Timer.Init.Prescaler                     = uPrescaler-1;
  7.   hadc_Timer.Init.CounterMode               = TIM_COUNTERMODE_UP;        //向上计数模式
  8.   hadc_Timer.Init.Period                         = uPeriod;
  9.   hadc_Timer.Init.ClockDivision               = TIM_CLOCKDIVISION_DIV1;        //系统时钟不分频72MHz
  10.   hadc_Timer.Init.RepetitionCounter        = 0x00;        //发生0+1次updata事件产生中断
  11.   hadc_Timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  12.   if (HAL_TIM_Base_Init(&hadc_Timer) != HAL_OK)
  13.   {
  14.     _Error_Handler(__FILE__, __LINE__);
  15.   }

  16.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  17.   if (HAL_TIM_ConfigClockSource(&hadc_Timer, &sClockSourceConfig) != HAL_OK)
  18.   {
  19.     _Error_Handler(__FILE__, __LINE__);
  20.   }
  21.         
  22.         /* Timer TRGO selection */
  23.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;        //选择update事件更新为触发源
  24.   sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  25.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  26.   if (HAL_TIMEx_MasterConfigSynchronization(&hadc_Timer, &sMasterConfig) != HAL_OK)
  27.   {
  28.     _Error_Handler(__FILE__, __LINE__);
  29.   }
  30. }
复制代码
ADC每次装换完成后做处理,判断是否采样了1024个点:
  1. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
  2. {
  3.         if(Sample_Finish == 0)
  4.         {
  5.                 aADCDualConvertedValue[Sample_Index] = HAL_ADC_GetValue(hadc);
  6.                 Sample_Index++;
  7.         }
  8.         if(Sample_Index>=1024)        //判断完成1024次采样
  9.         {
  10.                 Sample_Index = 0;
  11.                 HAL_TIM_Base_Stop_IT(&hadc_Timer);
  12.                 Sample_Finish = 1;
  13.         }
  14. }
复制代码
main函数中调用下面这个用户函数:
  1. void DualRegularADCtest(uint8_t uRange)
  2. {
  3.         Sample_Index = 0;
  4.         Sample_Finish = 0;
  5.         switch(uRange)
  6.         {
  7.                 case 0:
  8.                         ADC_Timer_Init(2,36);
  9.                         break;
  10.                 case 1:
  11.                         ADC_Timer_Init(2,35);
  12.                         break;
  13.                 case 2:
  14.                         ADC_Timer_Init(3,73);
  15.                         break;
  16.                 case 3:
  17.                         ADC_Timer_Init(6,73);
  18.                         break;
  19.                 default:
  20.                         ADC_Timer_Init(2,36);
  21.                         break;
  22.         }
  23.         
  24.         // 使能ADC,开启定时器,触发双ADC采样
  25.   if (HAL_ADC_Start(&AdcHandle_master) != HAL_OK)  //STM例程中给的是使用HAL_ADC_Start_IT函数,试了不行
  26.   {
  27.     Error_Handler();
  28.   }
复制代码
我使用的是定时器3去触发,ADC3通道1和ADC4的通道8.
上面的代码在调试的时候,发现一直停在的了:
  1. while(Sample_Finish!=1);
复制代码
能进入定时器3中断里面,而且确定是Update事件触发了,但是Watch窗口观测到Sample_IndexSample_Finish 的值一直为零,这意味着ADC无法采样,之前软件触发基于DMA方式的双ADC采样还是可以,改成定时器触发就不行,也调试了很久,不知道有没有大神能帮我看看原因?
STM32给的例程是定时器触发基于DMA方式的单ADC多通道采样,我想实现定时器触发的双ADC同步采样(不需要用到DMA),有没有人实现过这种方式采样的?
收藏 3 评论8 发布时间:2018-1-5 17:14

举报

8个回答
与非网的L先生 回答时间:2018-1-5 17:16:33
本帖最后由 与非网的L先生 于 2018-1-5 17:31 编辑

不知道为啥 这个代码拷贝进来会出现不对齐和缩进异常问题,刚刚手动调了半天,凑合着看吧...Orz
与非网的L先生 回答时间:2018-1-8 09:11:15
没有人回么...
因为直接用定时器触发的方式不知道为何一直不进采样中断,所以换种方式,直接在定时器中断中启用采样,一步一步调试:
1、软件触发DMA方式的双ADC常规同步采样(一次1024个点)。    OK
2、软件触发DMA方式的双ADC常规同步采样(一次1个点,循环1024次)。     OK
3、定时器中启用采样(即在定时器中断中调用HAL_ADCEx_MultiModeStart_DMA函数去启用采样)。     NG
第三步遇到一个问题,在定时器中调用下面语句:
HAL_ADCEx_MultiModeStart_DMA(&AdcHandle_master, (uint32_t *)(aADCDualConvertedValue+Sample_Index), 1);
Sample_Index++;
传给DMA的目标地址按道理是每次自增的,但是实际结果却每次都填充到aADCDualConvertedValue[0],其余值一直为零,但是观测Sample_Index的确是自增了的。
而且这数组和变量的声明应该也没错:
__IO        uint16_t Sample_Index;
__IO  uint32_t aADCDualConvertedValue[1024];
而且这种方式在第二步调试的时候是成功的,目前还在调试中。。。
wenyangzeng 回答时间:2018-2-6 10:02:07

Sample_Index不用判断2次试看看:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
        if(Sample_Index==1024)        //判断完成1024次采样
        {
                Sample_Index = 0;
                HAL_TIM_Base_Stop_IT(&hadc_Timer);
                Sample_Finish = 1;
        }
       else
      {
                aADCDualConvertedValue[Sample_Index++] = HAL_ADC_GetValue(hadc);

        }

}

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

feixiang20 回答时间:2018-2-6 10:14:27
开始设置没错的话,检查下传送设置是不是对呢,感觉你在循环语句上可能有点问题,先精简几句,看看循环是不是正确,当循环出现问题的时候,确实会有异常
七哥 回答时间:2018-2-6 15:17:33
本帖最后由 toofree 于 2018-2-6 15:39 编辑

对一个疑问已验证,故回复删除


斜阳 回答时间:2018-2-6 19:36:36
加volatile  修饰语试试

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

dmspe 回答时间:2021-1-14 14:15:51
楼主,使用软件触发的基于DMA方式的双ADC常规同步的配置代码能否发出来看看
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版