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

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 评论7 发布时间:2018-1-5 17:14

举报

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

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


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

评分

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

查看全部评分

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版