赞
踩
ADC(Analog-Digital Converter)模拟-数字转换器,ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
通过选取外部GPIO口,作为模拟信号量的输入,根据STM32不同型号引脚来选取ADC模拟输入引脚。(PS:以STM32F103R8T6为例,有ADC1,ADC2,并且有0~9十个ADC输入引脚复用在下图对应GPIO引脚,不同型号会有所不同,具体可以查看具体型号的引脚定义表)
STM32有16个多路通道。可以把转换组织成两组:规则组(最多16)和注入组(最多4)。在任意多个通道上以任意顺序进 行的一系列转换构成成组转换。(PS:可以如下顺序完成转换:通道3、通道8、通道2、通道 2、通道0、通道2、通道2、通道15。)
● 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规 则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。
● 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入 组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组
注入通道数据寄存器一共四个(4*16),对应注入通道每一个注入通道对应一个数据寄存器
规则通道数据寄存器就一个(1*16)。(这里需要注意当选择多规则通道时,需要DMA配合转运数据寄存器的值,如果转移不及时数据将会覆盖。
根据规则组与注入组的不同对应的触发源不同(具体触发源如下图,大部分的触发源是多定时器,这些触发源有硬件支持可以不需要进入中断(需要根据触发源配置不同定时器的更新事件),也可以选择定时器到达时选择进入中断进行ADC转换),ADC经常需要每隔一段时间来触发转换,这样我们可以根据对应通道的定时器触发源,设置定时时间来申请中断触发ADC转换。除了这些触发源我们也可以选择软件触发ADC,需要我们在程序当中调用触发转换的代码即可。
根据不同的通道有着不同的标志位,规则组对应的标志位是EOC,通道组对应的标注位是JEOC,当对应的标志位为1,表示转换完成。
ADC转换频率,来自RCC,通过ADC预分频器分频最大可以达到14MHZ
通过模拟开门狗对ADC转换结果进行监听(通过让ADC转换结果即数据寄存器的值与模拟看门狗的阈值对比),如果不在阈值内就会产生看门狗相应中断标志位触发NVIC中断可以在中断进行相应的处理。
1、单次转换,非扫描模式:只有一个通道,触发一次转换一次。
2、单次转换,扫描模式:只有一个通道,触发一次连续转换(数据需要及时取出否则容易被覆盖,可以使用DMA转移数据)。
3、多次转换,非扫描模式:有多个通道,触发一次每个通道转换一次(PS:这里是多通道所以需要DMA协调转运数据,否则数据容易覆盖)。
4、多次转换,扫描模式:有多个通道,触发一次每个通道转换一次,然后轮询每个通道转换一次(PS:这里是多通道所以需要DMA协调转运数据,否则数据容易覆盖)。
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换 中每个电容器上产生的误差。
通过设置ADC_CR2寄存器的CAL位启动校准。一旦校准结束,CAL位被硬件复位,可以开始正 常转换。
建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。
注意:
1 建议在每次上电后执行一次校准。
2 启动校准前,ADC必须处于关电状态(ADON=’0’)超过至少两个ADC时钟周期。
软件:win10、keil
硬件:STM32F103C8T6、OLED(4引脚)、电位器、杜邦线、串口烧录工具、螺丝刀。
通过螺丝刀调节电位器,产生不同模拟信号量通过ADC1通道0输入STM32F03C8T6,STM32通过ADC转换将模拟型号转换成数据信号通过OLED显示。
这里我们需要使用ADC1,与GPIOA_Pin_0,使用我们需要开始ADC1与GPIOA的时钟。
- /*开启时钟*/
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
配置ADC采集时钟,来自RCC系统时钟(系统时钟72MHz)通过ADC分配器分频系数可以选择RCC_PCLK2_Div2: ADC clock = PCLK2/2、RCC_PCLK2_Div4: ADC clock = PCLK2/4、RCC_PCLK2_Div6: ADC clock = PCLK2/6、 RCC_PCLK2_Div8: ADC clock = PCLK2/8。(PS:ADC采集时钟最大可以达到14MHz,所以只能选择6分频与8分频,达不到最大的采用频率)
- /*设置ADC时钟*/
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
因为我们需要配置GPIO口为ADC模拟信号输入,所以我们需要将对应的端口配置为模拟输入的模式。
- /*GPIO初始化*/
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
这里我们选择规则组通道,根据自己的要求可以选择ADC的端口(ADC1~ADC3)、输入频道(ADC的输入口具体看GPIO口,这里我使用的是GPIOA_Pin_0,对应ADC_Channel_0)、放入的通道序号(1~16一共16个通道)、以及优先级(安装自己的需求)。(PS:这里我们选择的是规则组通道,我们也可以选择注入组通道,使用ADC_InjectedChannelConfig(),可以根据自己的选择进行配置,这里通道只能选择1~4四个通道,其他同注入组相同)
- /*规则组通道配置*/
- ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
通过一个结构体来配置模式、数据对齐方式、触发方式,是否连续转换、是否扫描模式、通道个数。
- /*ADC初始化*/
- ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置
- ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
- ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
使用ADC之前需要使能ADC。
- /*ADC使能*/
- ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
开始使用ADC转换之前需要ADC校准,防止误差,具体步骤固定。
- /*ADC校准*/
- ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
- while (ADC_GetResetCalibrationStatus(ADC1) == SET);
- ADC_StartCalibration(ADC1);
- while (ADC_GetCalibrationStatus(ADC1) == SET);
通过ADC_SoftwareStartConvCmd(ADC1, ENABLE)软件触发ADC转换,通过while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)等待EOC标志位(EOC为1时表示转换完成,0没有转换完成),如果选择的是注入通道应该判断JEOC标志位。
- uint16_t AD_GetValue(void)
- {
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
- while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
- return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
- }
http://链接:https://pan.baidu.com/s/1r5dbjqI26ntK15U8znWE-A 提取码:xqct
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。