ADC简介:
(主要用来测电压)
1us转换时间(最大支持1MHZ的信号转换)
12位(0~4095)就是分辨率
通过ADC0809外挂芯片来理解STM32中的ADC:
地址锁存和译码是用来选择通路的,通过调节DAC(数字-模拟转换器)中的电压(通过改变SAR值来调节)使得比较器两端电压近似相等时的SAR值就是该模拟信号的值(一般采用二分法逼近,如果是12路的话,最多判断12次),EOC是转换结束信号,START是开始转换信号,要给个脉冲,CLOCK是ADC的时钟,VREF是参考电压。
STM32的ADC:
可以看到注入组和规则组的区别,规则组可以一次性接收16个信号数据,但是每次只能往寄存器里写入处理好的一个信号,所以要立马把寄存器里的值拿走(可以用DMA),而注入一次性可以接收4个信号数据,也可以一次性放入4个信号数据到寄存器
这些相当于START(触发源选择触发的从模式或寄存器配置控制)
至于VREF(参考电压)和VDDA和VSSA ,STM32F103C8T6中已经将参考电压与单片机VDDA和VSSA相连了
相当于CLOCK
看门狗
结构简图:
输入通道:
但是STM32F103C8T6只有10个外部输入通道 ,且没有ADC3和PC0~PC5
规则组的4钟转换模式:(单次就是每次都要触发,连续就是只需要触发一次,扫描就是一个一个从头到尾,非扫描就是只能看一个)
为了防止寄存器被覆盖,要及时使用DMA挪走数据,当扫描数量等于通道数目并完成转换后(通过配置)的时候产生EOC信号
还有一个间断模式,就是在扫描的时候扫了几个后间断一下,要重新触发才能继续(了解即可)
——————————————————————————————————————————
规则组触发控制:
EXTI线11/TIM8_TRGO实践这一栏可以来自外部引脚也可以来自定时器内部信号,具体哪个通过AFIO重映射来决定
该ADC是12位的,转换结果是一个12位的二进制数,寄存器是16位,可以选择对齐方式,一般选择右对齐,因为读出来就是结果,左对齐的好处是可以裁剪分辨率,只取高8位舍弃掉后四位精度
转换时间:
校准:
在ADC初始化后加几条代码即可,无需知道如何校准
———————————————————————————————————————————
代码:
单通道单次测量代码:
#include "stm32f10x.h"void AD_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//打开ADC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIOA时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟分频,选择6分频,72/6 = 12MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专用模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//配置ADC1通道0放于序列1的位置,采样时间设为55.5个ADCCLK的周期ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//设置为单次模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发源ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//配置ADC模式为独立模式(非双ADC模式)ADC_InitStructure.ADC_NbrOfChannel = 1;//指定在扫描模式会用到的通道数为1(可以不用)ADC_InitStructure.ADC_ScanConvMode = DISABLE;//设置为非扫描模式ADC_Init(ADC1,&ADC_InitStructure);ADC_Cmd(ADC1,ENABLE);//以下是校准的代码ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);}uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发ADC1while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待转换完成EOC发出信号return ADC_GetConversionValue(ADC1);//返回寄存器里的值,读完EOC自动置0(RESET)
}
单通道连续测量代码:
void AD_continus_Init(void)//单通道连续扫描
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//打开ADC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIOA时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟分频,选择6分频,72/6 = 12MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专用模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//配置ADC1通道0放于序列1的位置,采样时间设为55.5个ADCCLK的周期ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//设置为单次模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发源ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//配置ADC模式为独立模式(非双ADC模式)ADC_InitStructure.ADC_NbrOfChannel = 1;//指定在扫描模式会用到的通道数为1(可以不用)ADC_InitStructure.ADC_ScanConvMode = DISABLE;//设置为非扫描模式ADC_Init(ADC1,&ADC_InitStructure);ADC_Cmd(ADC1,ENABLE);//以下是校准的代码ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);ADC_SoftwareStartConvCmd(ADC1,ENABLE);//只需软件触发ADC1一次即可,GetValue函数不需要再触发
}
uint16_t AD_Continus_GetValue(void)
{//因为连续的会一直更新状态所以不用等待了return ADC_GetConversionValue(ADC1);//返回寄存器里的值,读完EOC自动置0(RESET)
}
多通道测量代码(使用单次非扫描模式,不用DMA方法实现):
void AD_Much_NoneDMA_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//打开ADC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIOA时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟分频,选择6分频,72/6 = 12MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专用模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//配置ADC1通道0放于序列1的位置,采样时间设为55.5个ADCCLK的周期ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//设置为单次模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发源ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//配置ADC模式为独立模式(非双ADC模式)ADC_InitStructure.ADC_NbrOfChannel = 1;//指定在扫描模式会用到的通道数为1(可以不用)ADC_InitStructure.ADC_ScanConvMode = DISABLE;//设置为非扫描模式ADC_Init(ADC1,&ADC_InitStructure);ADC_Cmd(ADC1,ENABLE);//以下是校准的代码ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);}
uint16_t AD_Much_NoneDMA_GetValue(uint8_t ADC_Channel)
{//想看哪个通道电压就放哪个进序号1中,然后单次非扫描转换ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发ADC1while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待转换完成EOC发出信号return ADC_GetConversionValue(ADC1);//返回寄存器里的值,读完EOC自动置0(RESET)
}