STM32-ADC
ADC模数转换:将模拟信号转换为数字信号
3个;12位分辨率;18个通道(16个外部通道;2个内部通道);有单次和连续转换;可以开启双重模式;有DMA请求
- 输入电压范围:3.3v
- 输入通道
- 通道选择:注入通道:4路;类似中断在规则通道进行的时候可以打断;规则通道:SQR3;SQR2;SQR1;使用的时候给通道赋值
- 触发沿:上升沿、下降沿、静止
- 时钟:APB2;14频率最大;一般配置12M;
- 数据寄存器:左对齐:4-15;右对齐:0-11;
- 中断
代码设计流程:
- 使能端口时钟和ADC时钟,模拟输入
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //模拟输入
- 设置ADC分频因子
/*** @brief 配置ADC的时钟源* @param RCC_PCLK2: 指定ADC的时钟来源,可以是以下值之一:* - RCC_PCLK2_Div2: ADC时钟 = PCLK2 / 2* - RCC_PCLK2_Div4: ADC时钟 = PCLK2 / 4* - RCC_PCLK2_Div6: ADC时钟 = PCLK2 / 6* - RCC_PCLK2_Div8: ADC时钟 = PCLK2 / 8* @retval 无*/
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
- 初始化ADC参数(模式;扫描模式;连续转换;触发信号;寄存器对齐;通道数)
typedef struct
{uint32_t ADC_Mode; /*!< 配置ADC工作在独立模式或双ADC模式此参数可以是 @ref ADC_mode 中的一个值 */FunctionalState ADC_ScanConvMode; /*!< 指定转换是在扫描模式(多通道)还是单通道模式下执行此参数可以设置为ENABLE或DISABLE */FunctionalState ADC_ContinuousConvMode; /*!< 指定转换是在连续模式还是单次模式下执行此参数可以设置为ENABLE或DISABLE */uint32_t ADC_ExternalTrigConv; /*!< 定义用于启动规则通道组的模数转换的外部触发源此参数可以是 @ref ADC_external_trigger_sources_for_regular_channels_conversion 中的一个值 */uint32_t ADC_DataAlign; /*!< 指定ADC数据是左对齐还是右对齐此参数可以是 @ref ADC_data_align 中的一个值 */uint8_t ADC_NbrOfChannel; /*!< 指定使用规则通道组的序列器进行转换的ADC通道数量此参数必须在1到16的范围内 */
}ADC_InitTypeDef;
- 使能ADC并校验
/*** @brief 启用或禁用指定的ADC外设* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要配置的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @param NewState: ADC外设的新状态* 该参数可以是:ENABLE 或 DISABLE* @retval 无*/
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
要复位在开启
/*** @brief 重置指定ADC的校准寄存器* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要操作的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @retval 无* @note 在校准ADC之前,必须先调用此函数重置校准寄存器* 然后等待校准寄存器重置完成(通过ADC_GetResetCalibrationStatus函数检查)* 最后调用ADC_StartCalibration函数开始新的校准过程*/
void ADC_ResetCalibration(ADC_TypeDef* ADCx)
//等待校准寄存器重置完成;返回0校准完成1未完成
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx)
/*** @brief 启动指定ADC的校准过程* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要操作的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @retval 无* @note 必须在调用ADC_ResetCalibration()并确认校准寄存器已重置完成后调用此函数* 校准时,ADC将停止转换,校准完成后才能继续进行正常的转换操作* 可通过ADC_GetCalibrationStatus()函数检查校准是否完成*/
void ADC_StartCalibration(ADC_TypeDef* ADCx)
//等待校准完成
* @retval FlagStatus: 校准状态* - SET: 校准过程正在进行中* - RESET: 校准过程已完成* @note 在校准过程中(返回SET),ADC无法进行正常的转换操作* 只有在校准完成(返回RESET)后,才能开始或继续ADC转换*/
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx)
/*** @brief 启用或禁用指定ADC的软件触发转换功能* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要配置的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @param NewState: 软件触发转换的新状态* 该参数可以是:ENABLE 或 DISABLE* @retval 无* @note 当设置为ENABLE时,软件触发将启动ADC对规则通道组的转换* 转换完成后,若要再次触发转换,需先将此状态设置为DISABLE再重新ENABLE* 仅当ADC配置为不使用外部触发(ADC_ExternalTrigConv设置为ADC_ExternalTrigConv_T1_CC1等外部触发源以外的值)时,此函数才有效*/
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
- 读取ADC转换值
配置 ADC 规则通道组的转换顺序和采样时间
/*** @brief 配置ADC规则通道组中的指定通道* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要配置的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @param ADC_Channel: 指定要配置的ADC通道* 该参数可以是 @ref ADC_channels 中的一个值(如ADC_Channel_0、ADC_Channel_1等)* @param Rank: 指定通道在规则序列中的位置(1到16)* 例如,Rank=1表示该通道是第一个被转换的通道* @param ADC_SampleTime: 指定通道的采样时间* 该参数可以是 @ref ADC_sample_time 中的一个值(如ADC_SampleTime_1Cycles5、ADC_SampleTime_7Cycles5等)* @retval 无* @note 采样时间越长,ADC转换结果越准确,但转换速度会降低* 对于输入阻抗较高的信号源,建议使用较长的采样时间*/
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
开启软件转换并等待转换完成
//开启软件转换
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
/*** @brief 检查指定ADC的特定标志位状态* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要检查的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @param ADC_FLAG: 指定要检查的标志位* 该参数可以是 @ref ADC_flags_definition 中的一个值,例如:* - ADC_FLAG_AWD: 模拟看门狗标志* - ADC_FLAG_EOC: 规则通道转换完成标志* - ADC_FLAG_JEOC: 注入通道转换完成标志* - ADC_FLAG_JSTRT: 注入通道开始转换标志* - ADC_FLAG_STRT: 规则通道开始转换标志* @retval FlagStatus: 标志位的当前状态* - SET: 标志位被设置(发生了对应的事件)* - RESET: 标志位被清除(未发生对应的事件)* @note 某些标志位需要手动清除,可使用ADC_ClearFlag()函数* 例如,ADC_FLAG_EOC在单次转换模式下需要手动清除*/
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
获取ADC值
/*** @brief 获取指定ADC的规则通道组最近一次转换的结果* @param ADCx: 指向ADC_TypeDef结构体的指针,标识要读取的ADC外设* 可以是ADC1、ADC2或ADC3(取决于具体的微控制器型号)* @retval uint16_t: 最近一次规则通道转换的结果* - 对于12位分辨率的ADC,返回值范围为0~4095(0x0000~0x0FFF)* @note 该函数返回的是规则通道组的转换结果* 若使用了多通道扫描模式,返回的是最后一个转换通道的结果* 转换结果的对齐方式(左对齐或右对齐)由ADC_DataAlign配置决定* 读取此值后,某些ADC_FLAG_EOC标志可能会自动清除(取决于具体型号)*/
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
软件如下:
#include "adc.h"
#include "SysTick.h"/*******************************************************************************
* 函 数 名 : ADCx_Init
* 函数功能 : ADC初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void ADCx_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量 ADC_InitTypeDef ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14MGPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//ADCGPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //模拟输入GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止触发检测,使用软件触发ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1;//1个转换在规则序列中 也就是只转换规则序列1 ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化ADC_Cmd(ADC1, ENABLE);//开启AD转换器ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器while(ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态ADC_StartCalibration(ADC1);//开始指定ADC的校准状态while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC的校准程序ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能或者失能指定的ADC的软件转换启动功能
}
/*******************************************************************************
* 函 数 名 : Get_ADC_Value
* 函数功能 : 获取通道ch的转换值,取times次,然后平均
* 输 入 : ch:通道编号times:获取次数
* 输 出 : 通道ch的times次转换结果平均值
*******************************************************************************/
u16 Get_ADC_Value(u8 ch,u8 times)
{u32 temp_val=0;u8 t;//设置指定ADC的规则组通道,一个序列,采样时间ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); //ADC1,ADC通道,239.5个周期,提高采样时间可以提高精确度 for(t=0;t<times;t++){ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束temp_val+=ADC_GetConversionValue(ADC1);delay_ms(5);}return temp_val/times;
}
主函数代码( PA1连接电位器;串口输出)
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart1.h"
#include "adc.h"/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{u8 i=0;u16 value=0;float vol;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组LED_Init();USART1_Init(115200);ADCx_Init();while(1){i++;if(i%20==0){LED1=!LED1;}if(i%50==0){value=Get_ADC_Value(ADC_Channel_1,20);printf("检测AD值为:%d\r\n",value);vol=(float)value*(3.3/4096);//转换成电压printf("检测电压值为:%.2fV\r\n",vol);}delay_ms(10); }
}