第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 = ;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;

    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 = *;

     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 = *;

     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 = ;

    /* ADC3 规则通道配置 */

     ADC_Init(ADC3, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC3, ADC_Channel_10, , ADC_SampleTime_3Cycles);

    /* 使能 ADC3 DMA */

     ADC_DMACmd(ADC3, ENABLE);

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

    ADC_AnalogWatchdogThresholdsConfig(ADC3, , );

    /* 配置模拟看门狗监测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 = ;

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

     ADC_Init(ADC1, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, , 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 = ;

    /* ADC2 规则通道配置 */

     ADC_Init(ADC2, &ADC_InitStructure);

     ADC_RegularChannelConfig(ADC2, ADC_Channel_10, , 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 =  /g_SampleFreqTable[TimeBaseId][] - ;

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

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

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/;  

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-;

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

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

  1. 【安富莱二代示波器教程】第17章 附件B---功能扩展和改进方向

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=45785 第17章      附件B---功能扩展和改进方向   ...

  2. 【安富莱二代示波器教程】第16章 附件A---电阻屏触摸校准

    第16章      附件A---电阻屏触摸校准 二代示波器的触摸校准比较简单,随时随地都可以做触摸校准,按下K1按键即可校准.有时候我们做触摸校准界面,需要在特定的界面才可以进入触摸校准状态,非常繁琐 ...

  3. 【安富莱二代示波器教程】第19章 附件E---参考资料

    第19章      附件E---参考资料 DSP教程 http://forum.armfly.com/forum.php?mod=viewthread&tid=3886 . FreeRTOS教 ...

  4. 【安富莱二代示波器教程】第18章 附件C---波形拟合

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=45785 第18章      附件C---波形拟合 emWin5. ...

  5. 【安富莱TCPnet网络教程】HTTP通信实例

    第41章      HTTP超文本传输协议基础知识 本章节为大家讲解HTTP(HyperText Transfer Protocol,超文本传输协议),从本章节开始,正式进入嵌入式Web的设计和学习. ...

  6. 【安富莱】V6,V5开发板用户手册,重在BSP驱动包设计方法,HAL库的框架学习,授人以渔(2019-11-04)

    说明: 1.本教程重在BSP驱动包设计方法和HAL库的框架学习,并将HAL库里面的各种弯弯绕捋顺,从而方便我们的程序设计. 2.本次工程延续以往的代码风格,从底层BSP驱动包到应用代码,变量命名,文件 ...

  7. 【安富莱STM32H7教程】第1章 初学STM32H7的准备工作

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第1章   初学STM32H7的准备工作 俗话说万事开头 ...

  8. 【安富莱】RTX嵌入式操作系统教程发布,支持F103,F407和F429,含81个配套例程(2017-10-17)

    前言说明:1. 首先感谢大家对我们安富莱电子一年来的支持,2016年我们会再接再厉推出更好的教程. 2. 估计也有网友会问RTX的优势在那里,针对这个问题,教程中第一章分为6条专门回答了这个问题,有兴 ...

  9. 【安富莱】【RL-TCPnet网络教程】第10章 RL-TCPnet网络协议栈移植(FreeRTOS)

    第10章     RL-TCPnet网络协议栈移植(FreeRTOS) 本章教程为大家讲解RL-TCPnet网络协议栈的FreeRTOS操作系统移植方式,学习了第6章讲解的底层驱动接口函数之后,移植就 ...

随机推荐

  1. ios手机访问H5页面中$(document).on绑定无效问题

    1.问题描述 用amazeUI做了个手机端网站,网站头部是一个点击按钮下拉菜单,点击页面其余区域下拉菜单隐藏.在chrome模拟安卓和iOS都可以正常触发,但是在真机实测的时候,iOS上面失效了.简单 ...

  2. python 对Excel表格的读取

    import xlrd flbrd = "D:\\考勤系统.xlsx" ws = xlrd.open_workbook(flbrd) # 获取所有sheet名字:ws.sheet_ ...

  3. 关于父窗口获取跨域iframe子窗口中的元素

    这几天在项目中遇到,一个难点, 就是需要异步加载一个pdf插件, 同时又需要获取这个插件中的点击事件来生成用户的下载记录. 刚开始也是想了很多方法,网上搜的 格式1:$("#iframe的I ...

  4. python的学习之路(二)

    1.字符串内置功能练习#!/usr/bin/env python# *_*coding:utf-8 *_*# Author: harsonname = 'harson'name =str('harso ...

  5. Redis实战 - 2.list、set和Sorted Set

    List Redis的List是通过Linked List(链表)来实现的String集合,所以插入数据的速度很快. 但是缺点就是在数据量比较大的时候,访问某个数据的时间可能会很长,但针对这种情况,可 ...

  6. Android OS 源码 引入和编译 jar / so库

    Android -- 源码平台下JAR包的引入与编译https://blog.csdn.net/csdn_of_coder/article/details/64538227 BUILD_JAVA_LI ...

  7. virtualenv Mac版

    环境 MAC python 3.6.7 安装python python官网下载3.6.7版本,默认安装 安装完成后检查是否安装成功: python3.6 确认安装目录:which python3.6 ...

  8. 将source类中的属性值赋给target类中对应的属性

    /** * 对象的属性值拷贝 * <p> * 将source对象中的属性值赋值到target对象中的属性,属性名一样,类型一样 * <p> * example: * <p ...

  9. java 基本数据类型的取值

    一. 1.基本类型:short 二进制位数:16 包装类:java.lang.Short 最小值:Short.MIN_VALUE=-32768 (-2的15此方)最大值:Short.MAX_VALUE ...

  10. Unity Rain Ai 插件基本使用(二)

    前言 在前面的教程中我们已经基本实现了路径导航和障碍物规避. 但是这样我们并没有让我们的角色学会思考,他只是机械的去完成一些步骤,这并不能体现Rain插件的智能. 一个角色他应该有多个不同的状态,待机 ...