第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 。