01、ADC简介
02、STM32的ADC外设
03、STM32ADC框图讲解
04、触发源
05、转换周期
数据寄存器
07、中断
08、电压转换
09、电路图设计
10、代码设计
01、ADC简介
ADC是Analog-to-DigitalConverter缩写。指模拟/数字转换器或模拟/数字转换器。是指将连续变量模拟信号转换为离散数字信号的装置。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
从STM32F从207数据手册中下图可以看出,STM32F207VC有3个精度为12bit的ADC控制器有16个外部通道,144英尺STM32F207Zx和176脚的STM32F207Ix因为带PF脚,所以多8个通道,24个外部通道。各通道的A/D转换可以单次、连续、扫描或间执行,ADC转换结果可以左对齐或右对齐存储在16位数据寄存器中。
02、STM32的ADC外设
上面说到,STM32F207有3个12bit的ADC控制器,制器ADC3通道10讲解。
首先,让我们确认一下ADC外设所在地址总线,从STM32F从207数据手册中下图可以看出,ADC属于APB2总线下,APB2时钟频率是60MHz。具体STM如果通过外部2532M晶振得到的60MHz的APB2,请看《STM32F207时钟系统分析。
对应GPIO,我们从STM32F我们可以在207数据手册中使用它PC0作为ADC3的通道10。
这里需要说明的是,之前的文章使用其他外设时,比如《STM32PWM在输出中,当我们寻找相应的管脚时,我们都是从STM32F207数据手册的Alternatefunctionmapping因为ADC使用相应的管脚Additionalfunctions,PWM使用相应的管脚Alternatefunctions。
区别是:
附加,辅助功能,引脚连接到其他模块,使用时可以直接配置,如ADC模拟输入采用输入通道。
即将重用功能IO除普通输入输出外,口用作串口输入输出等功能,使用时需配置复用模式。
以前的文章《STM32GPIO详细介绍如下。
STM32标准外设库中有以下代码
typedef enum { GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */ }GPIOMode_TypeDef;
其中GPIO_Mode_AF对应的就是Alternate functions:复用功能,GPIO_Mode_AN对应的就是Additional functions:附加,辅助功能。
03、STM32ADC框图讲解
下图是STM32ADC我们将结构框图分为七个部分进行解释。
ADC测量的电压范围是VREF-≤ VIN ≤ VREF ,把VSSA和VREF-接地,把VREF 和VDDA接3V3,得到ADC输入电压范围为:0~3.3V。
ADC当信号通过输入通道进入单片机时,单片机通过ADC模块将模拟信号转换为数字信号。上图标记②连接的部分显示了16个外部通道GPIO,如上所述,需要解释相应的关系STM32F207数据手册的STM32F20xpin and ball definitions在表格中寻找。实际上STM32还有内部通道,ADC1的通道16连接到芯片内部的温度传感器,Vrefint连接到了通道17。ADC2的模拟通道16和17连接到内部VSS。
转换时,外部16个通道分为规则通道和注入通道,其中规则通道最多16条,注入通道最多4条(注入通道似乎使用不多)。以下是两个通道的简要介绍:
顾名思义,规则通道是最常用的通道,也是最常用的通道。ADC规则通道用于转换。规则通道及其转换顺序ADC_SQRx选择寄存器,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。
与规则通道相比,注入通道可在规则通道转换时强行插入转换,相当于中断通道。当需要转换注入通道时,规则通道的转换将停止,注入通道的转换将优先考虑。当注入通道的转换完成后,返回以前的规则通道进行转换。注入组及其转换顺序最多为4个通道ADC_JSQR寄存器中选择。注入组转换的总数应写入ADC_JSQR寄存器的L[1:0]中。
一个ADC控制器有多个通道,这涉及到使用多个通道进行转换的问题。毕竟,规则转换通道只有一个数据寄存器。多个通道的使用顺序分为两种情况:规则通道的转换顺序和注入通道的转换顺序。
三个寄存器控制规则通道中的转换顺序:SQR1、SQR2、SQR三、都是32位寄存器。SQR只要在相应的寄存器位置,寄存器控制转换通道的数量和转换顺序SQx通过写入相应的通道,这个通道是第x转换,通过SQR寄存器可以理解寄存器上转换顺序的实现。
和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR控制寄存器的关系如下:
需要注意的是,只有当JL=4.注入通道的转换顺序将遵循JSQ1、JSQ2、JSQ3、JSQ4的顺序执行JL<4时,注入通道的转换顺序恰恰相反,即执行顺序为:JSQ4、JSQ3、JSQ2、JSQ1。
函数配置转换顺序
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime)
04、触发源
ADC已经说明了转换的输入、通道和顺序,但是ADC如何触发转换?就像通信协议一样,在传输信息之前,必须规定一个初始信号,ADC模/数转换也需要触发信号。
一是通过直接配置寄存器触发,通过配置控制寄存器CR2的ADON写1时开始转换,写0时停止转换。只要在程序运行过程中调用库函数,就会CR2寄存器的ADON可以进行位置1换,比较好理解。
另外,还可以通过内部定时器或者外部IO触发转换,也就是说可以利用内部时钟让ADC进行周期性的转换,也可以利用外部IO使ADC在需要时转换,具体的触发由控制寄存器CR2决定。
05、转换周期
可独立设置各通道采样时间
ADC会在数个ADCCLK周期内对输入电压进行采样,可使用ADC_SMPR1和ADC_SMPR2
寄存器中的SMP[2:0]位修改周期数。每个通道均可以使用不同的采样时间进行采样。
总转换时间的计算公式如下:
Tconv=采样时间+12个周期
示例:
ADCCLK = 30 MHz且采样时间=3个周期时:
Tconv= 3+12=15个周期=0.5us (APB2为60MHz时)
最小采样时间0.42us(ADC时钟=36MHz,采样周期为3周期下得到)。
06、数据寄存器
转换完成后的数据就存放在数据寄存器中,但数据的存放也分为规则通道转换数据和注入通道转换数据的。
规则数据寄存器负责存放规则通道转换的数据,通过32位寄存器ADC_DR来存放。
注入通道转换的数据寄存器有4个,由于注入通道最多有4个,所以注入通道转换的数据都有固定的存放位置,不会跟规则寄存器那样产生数据覆盖的问题。 ADC_JDRx是 32位的,低 16位有效,高 16位保留,数据同样分为左对齐和右对齐,具体是以哪一种方式存放,由ADC_CR2的 11 位ALIGN 设置。
07、中断
可以产生4种中断
①
当配置了DMA,且DMA溢出时产生中断
②
规则通道数据转换完成之后,可以产生一个中断,可以在中断函数中读取规则数据寄存器的值。这也是单通道时读取数据的一种方法。
③
注入通道数据转换完成之后,可以产生一个中断,并且也可以在中断中读取注入数据寄存器的值,达到读取数据的作用。
④
当输入的模拟量(电压)不再阈值范围内就会产生看门狗事件,就是用来监视输入的模拟量是否常。
08、电压转换
转换后的数据是一个12位的二进制数,我们需要把这个二进制数代表的模拟量(电压)用数字表示出来。比如测量的电压范围是0~3.3V,转换后的二进制数是x,因为12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,所以转换后的二进制数x代表的真实电压的计算方法就是:
y=3.3* x / 4096
09、电路图设计
电路图很简单,可以在ADC引脚上输入不同的电压,也可以直接方便的使用滑动变阻器实现不同的电压变化。
10、代码设计
ADC外设配置的结构体
typedef struct
{
uint32_t ADC_Resolution; /*!< Configures the ADC resolution dual mode.
This parameter can be a value of @ref ADC_resolution */
FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion
is performed in Scan (multichannels)
or Single (one channel) mode.
This parameter can be set to ENABLE or DISABLE */
FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion
is performed in Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE. */
uint32_t ADC_ExternalTrigConvEdge; /*!< Select the external trigger edge and
enable the trigger of a regular group.
This parameter can be a value of
@ref ADC_external_trigger_edge_for_regular_channels_conversion */
uint32_t ADC_ExternalTrigConv; /*!< Select the external event used to trigger
the start of conversion of a regular group.
This parameter can be a value of
@ref ADC_extrenal_trigger_sources_for_regular_channels_conversion */
uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment
is left or right. This parameter can be
a value of @ref ADC_data_align */
uint8_t ADC_NbrOfConversion; /*!< Specifies the number of ADC conversions
that will be done using the sequencer for
regular channel group.
This parameter must range from 1 to 16. */
}ADC_InitTypeDef;
ADC 工作模式选择,ADC分辨率
ADC 扫描(多通道)或者单次(单通道)模式选择
ADC 单次转换或者连续转换选择
ADC 外部触发极性配置
ADC 转换触发信号选择
ADC 数据寄存器对齐格式
ADC转换通道数目
typedef struct
{
uint32_t ADC_Mode;//多重ADC模式选择
uint32_t ADC_Prescaler; //ADC预分频
uint32_t ADC_DMAAccessMode; //DMA访问模式
uint32_t ADC_TwoSamplingDelay; //2个采样阶段之间的延迟
}ADC_CommonInitTypeDef;
ADC_CommonInitTypeDef用来配置ADC_CCR寄存器的相关参数
ADC外设和DMA配置代码
/**
* @brief ADC3 channel10 with DMA configuration
* @param None
* @retval None
*/
void ADC3_CH10_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
/* DMA2 Stream0 channel2 configuration **************************************/
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 = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_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_HalfFull;
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);
/* Configure ADC3 Channel10 pin as analog input ******************************/
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);
/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC3 regular channel7 configuration *************************************/
ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADC3, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);
}
代码下载验证测试
硬件和软件开源地址:
https://github.com/labelercjd/STM32F207VCT6
点击查看本文所在的专辑,
关注公众号,。评论区不能及时看到,需要交流可以到公众号沟通