7.2 AD单通道&AD多通道
1)AD单通道
函数说明:
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); //用来配置ADCCLK分频器的2,4,6,8(在rcc库函数里)
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
//ADC基本功能和规则组的配置
//Init三剑客
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
//
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); //给ADC上电
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); //开启DWA输出信号
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState); //中断输出控制
//用以校准的函数
void ADC_ResetCalibration(ADC_TypeDef* ADCx); //复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx); //获取复位校准状态
void ADC_StartCalibration(ADC_TypeDef* ADCx); //开始校准
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx); //获取开始校准状态
//触发控制
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //用于软件触发转换
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx); //获取软件触发开始转换状态(获取CR2的SWSTART)这个函数很少用
//配置间断模式
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number); //每隔几个通道间断一次
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //是否启用间断模式
//ADC规则组通道配置(配置点菜)
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
//ADC外部触发转换控制
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
//ADC获取转换值(获取AD转换的数据寄存器)
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
//ADC获取双模式转换值
uint32_t ADC_GetDualModeConversionValue(void);
——————————————————————————————————————————————————————————————————————————————————————————————————————————————
//对ADC注入组进行配置
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
——————————————————————————————————————————————————————————————————————————————————————————————————————————————
//看门狗
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog); //是否启动看门狗
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold); //配置高低阈值
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); //配置看门通道
//ADC温度传感器、内部参考电压控制(开启内部通道的函数)
void ADC_TempSensorVrefintCmd(FunctionalState NewState);
//标志位
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); //获取标志位状态EOC
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); //清除标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT); //获取中断状态
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT); //清除中断挂起位
流程:
第一步:RCC开启时钟,开启GPIO和ADC的时钟,ADCCLK分频器配置
第二部:配置GPIO,把需要用的GPIO口配置成输入模式
第三步:配置多路开关,把左边的通道接入到右边的规则组列表里
第四步:配置ADC转换器,用结构体来配置(AD转换器、AD数据寄存器、触发控制等)
第五步,调用ADC_Cmd(),开启ADC,然后进行校准
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
float voltage;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "ADValue:");
OLED_ShowString(2, 1, "Voltage:0.00V");
while (1)
{
ADValue = AD_GetValue();
voltage = (float)ADValue / 4095 * 3.3; //将ADValue强制转换为浮点数类型
OLED_ShowNum(1, 9, ADValue, 4);
OLED_ShowNum(2, 9, voltage, 1); //整数
OLED_ShowNum(2, 11, (uint16_t)(voltage * 100) % 100, 2); //小数:将浮点数乘以100,再强制转换为16位无符号整数,最后对100取模,得到小数点后两位的值。
Delay_ms(100);
}
}
AD.C
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
//第一步:RCC开启时钟,开启GPIO和ADC的时钟,ADCCLK分频器配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//第二部:配置GPIO,把需要用的GPIO口配置成输入模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_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上配置一个常规通道,使其可以采集ADC通道0的模拟电压值,并且使用55.5个时钟周期作为采样时间
//第四步:配置ADC转换器,用结构体来配置(AD转换器、AD数据寄存器、触发控制等)
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式,ADC可以单独工作,并不依赖其他STM32内部或外部的时钟或扫描机制。
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集到的ADC数据会在右对齐后被存入ADC转换缓存区中
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC外部触发转换配置代码,这里表示不使用外部触发方式来启动ADC转换(这里选择软件触发)
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //ADC连续转换模式配置代码,这里表示非连续转换,即采用单次转换
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //ADC扫描模式配置代码,这里表示非扫描模式
ADC_InitStructure.ADC_NbrOfChannel = 1; //ADC转换通道数量配置代码,只使用一个ADC通道进行转换
ADC_Init(ADC1,&ADC_InitStructure);
//第五步,调用ADC_Cmd(),开启ADC,然后进行校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1); //在进行ADC模块校准之前,需要先进行复位操作
while (ADC_GetResetCalibrationStatus(ADC1) == SET); //ADC校准复位后,需要等待校准重置完成。使用while语句判断校准复位是否完成
ADC_StartCalibration(ADC1); //校准复位完成后,开始进行ADC模块的校准
while (ADC_GetCalibrationStatus(ADC1) == SET); //ADC校准开始后,需要等待校准完成。使用while语句来判断校准是否完成,完成后继续执行下面的代码。
}
//启动转换,获取结果
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ADC转换开始前需要启动转换操作。这里使用了ADC_SoftwareStartConvCmd(ADC1, ENABLE)函数来启动ADC1的软件转换操作。
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //启动转换后,需要等待ADC的转换完成。这里使用while语句来判断,直到转换完成后,继续执行下面的代码。
return ADC_GetConversionValue(ADC1); //转换完成后,可以通过ADC_GetConversionValue(ADC1)函数来获取转换结果。
}
2)AD多通道
采用扫描模式实现多通道,最好配合AWA防止数据覆盖,本次利用单次转换非扫描模式,只要在每次触发转换之前,手动更改一下列表第一个位置通道即可。
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t AD0, AD1, AD2, AD3;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "AD0:");
OLED_ShowString(2, 1, "AD1:");
OLED_ShowString(3, 1, "AD2:");
OLED_ShowString(4, 1, "AD3:");
while (1)
{
AD0 = AD_GetValue(ADC_Channel_0);
AD1 = AD_GetValue(ADC_Channel_1);
AD2 = AD_GetValue(ADC_Channel_2);
AD3 = AD_GetValue(ADC_Channel_3);
OLED_ShowNum(1, 5, AD0, 4);
OLED_ShowNum(2, 5, AD1, 4);
OLED_ShowNum(3, 5, AD2, 4);
OLED_ShowNum(4, 5, AD3, 4);
Delay_ms(100);
}
}
AD.C
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
//第一步:RCC开启时钟,开启GPIO和ADC的时钟,ADCCLK分频器配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//第二部:配置GPIO,把需要用的GPIO口配置成输入模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_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上配置一个常规通道,使其可以采集ADC通道0的模拟电压值,并且使用55.5个时钟周期作为采样时间
//第四步:配置ADC转换器,用结构体来配置(AD转换器、AD数据寄存器、触发控制等)
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式,ADC可以单独工作,并不依赖其他STM32内部或外部的时钟或扫描机制。
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集到的ADC数据会在右对齐后被存入ADC转换缓存区中
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC外部触发转换配置代码,这里表示不使用外部触发方式来启动ADC转换(这里选择软件触发)
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //ADC连续转换模式配置代码,这里表示非连续转换,即采用单次转换
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //ADC扫描模式配置代码,这里表示非扫描模式
ADC_InitStructure.ADC_NbrOfChannel = 1; //ADC转换通道数量配置代码,只使用一个ADC通道进行转换
ADC_Init(ADC1,&ADC_InitStructure);
//第五步,调用ADC_Cmd(),开启ADC,然后进行校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1); //在进行ADC模块校准之前,需要先进行复位操作
while (ADC_GetResetCalibrationStatus(ADC1) == SET); //ADC校准复位后,需要等待校准重置完成。使用while语句判断校准复位是否完成
ADC_StartCalibration(ADC1); //校准复位完成后,开始进行ADC模块的校准
while (ADC_GetCalibrationStatus(ADC1) == SET); //ADC校准开始后,需要等待校准完成。使用while语句来判断校准是否完成,完成后继续执行下面的代码。
}
//启动转换,获取结果
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
//在触发转换前,指定通道,传参进去
ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ADC转换开始前需要启动转换操作。这里使用了ADC_SoftwareStartConvCmd(ADC1, ENABLE)函数来启动ADC1的软件转换操作。
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //启动转换后,需要等待ADC的转换完成。这里使用while语句来判断,直到转换完成后,继续执行下面的代码。
return ADC_GetConversionValue(ADC1); //转换完成后,可以通过ADC_GetConversionValue(ADC1)函数来获取转换结果。
}