zoukankan      html  css  js  c++  java
  • 【安富莱二代示波器教程】第6章 示波器设计—双通道ADC驱动

    第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

     

  • 相关阅读:
    100+ Python挑战性编程练习(1)
    python面试题--初级(二)
    python面试题--初级(一)
    centos查看iptables和firewall防火墙状态、开启、关闭防火墙
    Keepalived nginx HA负载均衡
    windows10安装SQLServer 2008 R2详细说明
    CentOS安装mysql5.7
    centOS7.5安装docker
    redis哨兵选举算法--raft
    CentOS7.5安装GitLab及汉化
  • 原文地址:https://www.cnblogs.com/armfly/p/9239446.html
Copyright © 2011-2022 走看看