首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【安富莱二代示波器教程】第6章 示波器设计—双通道ADC驱动

【安富莱二代示波器教程】第6章 示波器设计—双通道ADC驱动

作者头像
Simon223
发布2018-09-04 10:17:49
8540
发布2018-09-04 10:17:49
举报

第6章        示波器设计—双通道ADC驱动

本章节为大家讲解示波器的ADC驱动,采用STM32自带ADC实现。关于STM32F429的ADC,可以说处处有地雷,不小心就踩上了,如果简单的使用,不会发现,复杂使用就很容易踩到了。

6.1    3个ADC的快速交替采样

6.2    双通道ADC采样

6.3    拓展阅读

6.4     总结

6.1  3个ADC的快速交替采样

起初二代示波器是打算像一代示波器那样,准备做成3ADC(ADC1,ADC2和ADC3)快速交替采样,后期才改成双通道。这里将3ADC的各种奇葩问题也给大家做个说明,防止大家踩坑。

3个ADC快速交替采样的两个可选的方案及其存在的问题。

6.1.1      方案一

依然采用一代示波器那种方式,3个ADC都独立配置自己的DMA通道和相应的定时器进行触发。经过详细的测试发现,在最高采样率2.8Msps * 3 = 8.4Msps的情况下,F429的总线矩阵已经处理不过来了,导致的现象就是3个ADC中有两个已经停止工作。

下面的测试都是在我们STM32-V6开发板上面进行的,主频168MHz。

测试方法

直接调试状态看ADC1,2,3的三个大缓冲即可,看数据缓冲的数据是否在变化。

ADC1:

ADC2:

ADC3:

(1)测试一

条件:

开启ADC1,ADC2和ADC3及其配套的DMA,采用定时器触发,未开启emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)。

现象:

这种情况下,3个ADC可以正常工作。

(2)测试二

条件:

开启ADC1,ADC2和ADC3及其配套的DMA,采用定时器触发。仅使用ADC1,开启emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)。

现象:

ADC1在最高采样率2.8Msps的情况下,工作几秒钟,停止工作。

(3)测试三

条件:

开启ADC1,ADC2和ADC3及其配套的DMA,采用定时器触发。仅使用ADC2,开启emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)。

现象:

ADC2在最高采样率2.8Msps的情况下,停止工作。

(4)测试四

条件:

开启ADC1,ADC2和ADC3及其配套的DMA,采用定时器触发。仅使用ADC3,开启emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)。

现象:

ADC3在最高采样率2.8Msps的情况下,正常工作。

(5)测试五

条件:

开启ADC1,ADC2和ADC3及其配套的DMA,采用定时器触发。同时使用ADC3,ADC2和ADC1,开启emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)。

现象:

每个ADC都是在最高采样率2.8Msps,刚开始ADC1还工作,过会ADC1停止工作,ADC2一直没有工作,ADC3一直在工作。

测试现象

ADC工作不正常时,二代示波器波形显示效果如下:

总结

对于STM32F429来说,如果三个ADC配合自己的DMA采用最高采样率2.8Msps * 3,且采用的定时器触发,在未使用emWin(要用到LTDC,DMA2D和FMC外接的SDRAM)时,可以正常工作,使用了的话,将会出现ADC1和ADC2不工作的情况。

可能的原因是定时器触发太快,F429总线矩阵在这种情况下已经无法正常工作。

6.1.2      方案二

采用F429自带的3个ADC快递交替采样模式,这个模式的问题最多,表现在以下三个方面:

(1)这种方式不能用于定时器触发,因为这三个ADC之间的采样间隔只有5个ADC时钟周期到20个ADC时钟周期可选,这样采用定时器触发的时候就没有办法做到等间隔采样。

(2)采集出来的波形效果比较差,基本没有使用价值。

(3)这种方式的3个ADC快递交替采样外加开启emWin(使能DMA2D,LTDC和FMC驱动的SDRAM),轻轻松松就将F429的总线矩阵干趴下了,直接导致ADC不工作了。

测试条件:STM32-V6开发板,采用STM32F429支持的3个ADC快速交替采样,使能DMA,采用的软件触发。

测试一

配置采样率2.1Msps。

/****************************************************************************  

  PCLK2 = HCLK / 2

  下面选择的是2分频

  ADCCLK = PCLK2 /4 = HCLK / 4 = 168 / 4 = 42M

  三ADC采样频率: 42 / 20 = 2.1Mbps

*****************************************************************************/

 

/* ADC公共部分初始化---------------------------------------------------------------*/

ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;

ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; 

ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;

ADC_CommonInit(&ADC_CommonInitStructure);

凑合还能干活,但是显示效果很差:

测试二

配置采样率4.2Msps,直接停止工作。

/****************************************************************************  

  PCLK2 = HCLK / 2

  下面选择的是2分频

  ADCCLK = PCLK2 /4 = HCLK / 4 = 168 / 4 = 42M

  三ADC采样频率: 42 / 10 = 4.2Mbps

*****************************************************************************/

 

/* ADC公共部分初始化---------------------------------------------------------------*/

ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;

ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; 

ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;

ADC_CommonInit(&ADC_CommonInitStructure);

显示效果直接死机:

总结

相比于三个ADC独立配置实现快速交替采样,F429自带的这种3ADC快速交替采样的显示效果极其差,基本没有利用价值,而且最重要的是这种方式轻轻松松就将F429的总线矩阵干趴下了。结果就是ADC不干活了。

再来欣赏下F429的总线矩阵长什么样子:

6.1.3     选择方案一还是方案二

最终决定继续采用方案一,将最高采样率锁定在6Msps,这样才稳定些。

6.2  双通道ADC采样

相对于前面三通道ADC实现的快速交替采样,通过ADC1和ADC3实现双通道示波器,F429的硬件负担就稍轻松一些,不过依然存在一些问题。下面优先为大家说明ADC1和ADC3的驱动设计问题。

1、ADC1和ADC3被设置为定时器触发,DMA方式。其中ADC3使能了模拟看门狗,用于示波器上升沿的正常触发功能。另外,使用定时器触发是为了设置不同的采样率。

2、ADC2用于简单电压采集,未使用定时器和DMA。

/*

*********************************************************************************************************

*    函 数 名: bsp_InitADC

*    功能说明: ADC初始化

*    形    参: 无

*    返 回 值: 无

*********************************************************************************************************

*/

void bsp_InitADC(void)

{ 

ADC_InitTypeDef       ADC_InitStructure;

    ADC_CommonInitTypeDef ADC_CommonInitStructure;

    DMA_InitTypeDef       DMA_InitStructure;

    GPIO_InitTypeDef      GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

    

    /* 配置模拟看门狗中断NVIC */

    NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    

    /* 使能 ADC1, ADC2, ADC3,DMA2 和 GPIO 时钟 ****************************************/

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);

     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);

    

     /* DMA2 Stream1 channel1 配置用于ADC3 **************************************/

     //DMA_DeInit(DMA2_Stream1);

    DMA_InitStructure.DMA_Channel = DMA_Channel_2; 

     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;

     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;

     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

     DMA_InitStructure.DMA_BufferSize = 1024*10;

     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

     DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;

     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

     DMA_InitStructure.DMA_Priority = DMA_Priority_High;

     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        

     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

     DMA_Init(DMA2_Stream1, &DMA_InitStructure);

     DMA_Cmd(DMA2_Stream1, ENABLE);

    

     /* DMA2 Stream0 channel0 配置用于ADC1 **************************************/

     //DMA_DeInit(DMA2_Stream0);

     DMA_InitStructure.DMA_Channel = DMA_Channel_0; 

     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;

     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConvertedValue;

     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

     DMA_InitStructure.DMA_BufferSize = 1024*10;

     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

     DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;

     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

     DMA_InitStructure.DMA_Priority = DMA_Priority_High;

     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        

     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

     DMA_Init(DMA2_Stream0, &DMA_InitStructure);

     DMA_Cmd(DMA2_Stream0, ENABLE);

 

    /* 配置ADC引脚为模拟输入模式******************************/

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

     GPIO_Init(GPIOC, &GPIO_InitStructure);

    

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

     GPIO_Init(GPIOC, &GPIO_InitStructure);

        

    /*

     ***************************************************************************  

       PCLK2 = HCLK / 2

       下面选择的是2分频

       ADCCLK = PCLK2 /2 = HCLK / 4 = 168 / 4 = 42M

      ADC采样频率: Sampling Time + Conversion Time = 3 + 12 cycles = 15cyc

                    Conversion Time = 42MHz / 15cyc = 2.8Mbps.

     ****************************************************************************

     */

    

    /* ADC公共部分初始化**********************************************************/

    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_8Cycles;

    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;

    ADC_CommonInit(&ADC_CommonInitStructure);

    

     /////////////////////////////////////////////////////////////////////////////////////////////////

     /////////////////////////////////////////////////////////////////////////////////////////////////

 

      /*ADC3的配置*****************************************************************/

     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

     ADC_InitStructure.ADC_ScanConvMode = DISABLE;

     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;

     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

     ADC_InitStructure.ADC_NbrOfConversion = 1;

   

    /* ADC3 规则通道配置 */

     ADC_Init(ADC3, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);

 

    /* 使能 ADC3 DMA */

     ADC_DMACmd(ADC3, ENABLE);

    

     /* 配置模拟看门狗的阀值 注意别配置反了,要不一直进入中断 */

    ADC_AnalogWatchdogThresholdsConfig(ADC3, 4095, 0);

   

    /* 配置模拟看门狗监测ADC3的通道10 */

    ADC_AnalogWatchdogSingleChannelConfig(ADC3, ADC_Channel_10);

   

    /* 使能一个规则通道的看门狗 */

    ADC_AnalogWatchdogCmd(ADC3, ADC_AnalogWatchdog_SingleRegEnable);

 

    /* 使能模拟看门狗中断 */

    ADC_ITConfig(ADC3, ADC_IT_AWD, ENABLE);

   

     /* 使能DMA请求 (多ADC模式) --------------------------------------------------*/

     ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

 

     /* Enable ADC1 --------------------------------------------------------------*/

     ADC_Cmd(ADC3, ENABLE);

    

     /////////////////////////////////////////////////////////////////////////////////////////////////

     /////////////////////////////////////////////////////////////////////////////////////////////////

    

     /*ADC1的配置******************************************************************/

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

     ADC_InitStructure.ADC_ScanConvMode = DISABLE;

     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;

     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

     ADC_InitStructure.ADC_NbrOfConversion = 1;

   

    /* ADC1 规则通道配置 -------------------------------------------------------*/

     ADC_Init(ADC1, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_3Cycles);

 

    /* 使能 ADC1 DMA */

     ADC_DMACmd(ADC1, ENABLE);

    

     /* 使能DMA请求 (多ADC模式) --------------------------------------------------*/

     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

 

     /* Enable ADC1 --------------------------------------------------------------*/

     ADC_Cmd(ADC1, ENABLE);

    

     /////////////////////////////////////////////////////////////////////////////////////////////////

     /////////////////////////////////////////////////////////////////////////////////////////////////

 

    /*ADC2的配置*****************************************************************/

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

     ADC_InitStructure.ADC_ScanConvMode = DISABLE;

     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC2;

     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

     ADC_InitStructure.ADC_NbrOfConversion = 1;

   

    /* ADC2 规则通道配置 */

     ADC_Init(ADC2, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_480Cycles);

 

     /* 使能 ADC2 */

     ADC_Cmd(ADC2, ENABLE);

    

     /**定时器配置********************************************************************/

     TIM1_Config();

}

使用这个驱动要注意以下四个问题:

(1)当前ADC1和ADC3的DMA缓冲区都设置了10240个,这个大小已经够用。

(2)DMA的FIFO功能一定要关闭,这是一个大坑。详情在这个帖子里面做了总结,必看:

http://forum.armfly.com/forum.php?mod=viewthread&tid=77359

(3)ADC的采样率不要设置低了,ADC设置的时钟速度一定要大于等于定时器触发速度。当前ADC1和ADC3配置的采样率都是2.8Msps。如果设置的定时器触发速度大于这个,ADC的采样速度是跟不上的。

(4)ADC2的配置没有使用外部定时器触发和DMA,而且这里关闭了连续采样

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE。

如果用户使能为连续转换,调用函数ADC_SoftwareStartConv(ADC2)做一次软件触发即可。而我们将其关闭掉,触发一次读取一次,更方便些,适合做一些慢速的电压测量的工作。

说完了上面的问题,还有一个定时器触发的问题,看下面的驱动代码:

/*

*********************************************************************************************************

*    函 数 名: TIM1_Config

*    功能说明: 配置定时器1,用于触发ADC1和ADC3。

*             当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换。

*    形    参: 无

*    返 回 值: 无

*********************************************************************************************************

*/

static void TIM1_Config(void)

{

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    TIM_OCInitTypeDef  TIM_OCInitStructure;

   

     /* 使能定时器1 */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);    

   

     /* 先禁能再配置 */

    TIM_Cmd(TIM1, DISABLE);

    

    /*

     ********************************************************************************

    system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

 

    HCLK = SYSCLK / 1     (AHB1Periph)

    PCLK2 = HCLK / 2      (APB2Periph)

    PCLK1 = HCLK / 4      (APB1Periph)

 

    因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;

    因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

 

    APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14

    APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

         

    TIM1 更新周期是 = TIM1CLK / (TIM_Period + 1)/(TIM_Prescaler + 1)

    ********************************************************************************

    */

    //初始化定时器1的寄存器为复位值

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

//ARR自动重装载寄存器周期的值(定时时间)到设置频率后产生个更新或者中断(也是说定时时间到)

TIM_TimeBaseStructure.TIM_Period =  168000000/g_SampleFreqTable[TimeBaseId][0] - 1;

//PSC时钟预分频数 例如:时钟频率=TIM1CLK/(时钟预分频+1)

TIM_TimeBaseStructure.TIM_Prescaler = g_SampleFreqTable[TimeBaseId][1]-1;

TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;                 //CR1->CKD时间分割值

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     //CR1->CMS[1:0]和DIR定时器模式 向上计数

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000;          /* TIM1 和 TIM8 必须设置 */   

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

 

    /**************ADC1的触发***********************************************/

    //CCMR2在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                  

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //CCER 输出使能

//CCR3同计数器TIMx_CNT的比较,并在OC1端口上产生输出信号           

TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period/2;  

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;       //CCER输出极性设置

/* only for TIM1 and TIM8. 此处和正相引脚不同 */   

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;   /* only for TIM1 and TIM8. */

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; /* only for TIM1 and TIM8. */

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;/* only for TIM1 and TIM8. */  

TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    

     /**************ADC3的触发***********************************************/

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                   

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    

    TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period-1;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

/* only for TIM1 and TIM8. 此处和正相引脚不同 */   

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;    

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;  /* only for TIM1 and TIM8. */

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; /* only for TIM1 and TIM8. */

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;/* only for TIM1 and TIM8. */       

    TIM_OC3Init(TIM1, &TIM_OCInitStructure);

    //TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); //CMR2 设置预装载使能  更新事件产生时写入有效

    //TIM_ARRPreloadConfig(TIM1, ENABLE);               //CR1  设置ARR自动重装 更新事件产生时写入有效

    TIM_Cmd(TIM1, ENABLE); 

    

    /* 使能PWM输出 */

    TIM_CtrlPWMOutputs(TIM1, ENABLE);         

}

关于这个驱动设计,注意以下三个问题:

(1)定时器TIM1是16位定时器,下面两个参数的配置切勿超过65535。

TIM_TimeBaseStructure.TIM_Period

TIM_TimeBaseStructure.TIM_Prescaler

(2)关于定时器触发的配置,要特别注意下面参数的设置:

TIM_OCInitStructure.TIM_Pulse

如果大家将TIM1的OC1和OC3设置成一样的,那么定时器的触发频率大于2MHz时,很容易导致ADC触发失败。而且这种触发失败的现象还比较神奇,程序初始的触发频率大于2MHz,上电后导致ADC触发失败,但是切换几次不同频率,再切换回来,又正常工作了。为了安全起见这里将其区分开了。

(3)另外使用TIM1或者TIM8做ADC采样触发,要注意结构体成员的配置,这两个定时器比其他定时器多一些参数要配置,大家配置的时候切勿忘记初始化,因为我们这里用的是局部变量,未初始化的话,它的值是随机的。

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;               TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;      TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

6.3  拓展阅读

ADC的外部输入阻抗只有50KΩ,大家测量时要特别注意。另外,这里重点推荐两篇提高ADC精度的文档,是ST官方做的,对于阻抗和精度问题做了详细说明,下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=82543

6.4  总结

关于ADC的驱动就为大家讲解这么多,一定要实际操作配置下。如果需要ADC其它的配置方式,在我们论坛置顶帖STM32-V5的裸机例子基础篇里面下载即可:http://forum.armfly.com/forum.php?mod=viewthread&tid=1285

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-06-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第6章        示波器设计—双通道ADC驱动
    • 6.1  3个ADC的快速交替采样
      • 6.1.1      方案一
      • 6.1.2      方案二
      • 6.1.3     选择方案一还是方案二
    • 6.2  双通道ADC采样
      • 6.3  拓展阅读
        • 6.4  总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档