【ADC】AD单/多通道

需要用到的ADC配置函数
RCC_ADCCLKConfig();//配置ADCCLK分频器(对APB2的72MHz时钟进行2、4、6、8分频输入到ADCCLK)
ADC_Init();//ADC初始化
ADC_StructInit();//ADC结构体赋默认值
ADC_Cmd();//使能/失能ADC
ADC_DMACmd();// 使能/失能 DMA输出信号,需要DMA转运数据就用
ADC_RegularChannelConfig();//ADC规则组通道配置
ADC_ResetCalibration();//复位校准
ADC_GetResetCalibrationStatus();//获取复位校准状态
ADC_StartCalibration();//开始校准
ADC_GetCalibrationStatus();//获取开始校准状态
ADC_SoftwareStartConvCmd();//ADC软件触发转换开始
ADC_ExternalTrigConvCmd();//是否允许外部触发转换
ADC_GetFlagStatus();//获取【EOC】标志位状态,可以判断转换是否结束
//转换结束【EOC】置1,转换未结束【EOC】置0
ADC_GetConversionValue();//获取ADC转换值(读取ADC数据寄存器中的转换结果)
ADC_AnalogWatchdogCmd();//使能/失能模拟看门狗
ADC_AnalogWatchdogThresholdsConfig();//配置高低阈值
ADC_AnalogWatchdogSingleChannelConfig();//配置看门的通道
ADC_TempSensorVrefintCmd();// 使能/失能 ADC温度传感器、内部参考电压控制

AD多通道采集
配置AD时参考该图流程
1、完成驱动文件导入操作和编写驱动程序基本代码(参考之前文章)
//将【AD】驱动文件放在【Hardware】文件夹中
2、在AD.c中初始化函数AD_Init
void AD_Init(void)//初始化AD
{
//第一步:RCC开启ADC和GPIO的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC都是APB2上的设备
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//需要配置ADCCLK分频器
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
//第二步:配置需要用到的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);
//目前配置为:在规则组菜单列表的第一个位置(序列1)写入通道0
    
    
//第四步:结构体配置ADC
    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//转换模式选择(连续[ENABLE]/单次[DISABLE]转换)
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//用于外部触发规则组转换的触发源
    //此处选择不使用外部触发,也就是选择使用软件触发    
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC工作模式(单/双AD转换)
    ADC_InitStructure.ADC_NbrOfChannel = 1;//在扫描模式时总共用到几个通道
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描转换选择(扫描[多通道][ENABLE]/非扫描[单通道][DISABLE]模式)
    
    ADC_Init(ADC1,&ADC_InitStructure);
//目前配置ADC模式为【单次转换】、【非扫描】
//这里还可以配置中断模拟看门狗,本例不用,这里不配置
    
//第五步:开关控制,开启ADC
    ADC_Cmd(ADC1,ENABLE);
    
//ADC配置完成,可以正常工作
//还要对ADC进行校准以减小误差
    ADC_ResetCalibration(ADC1);//复位校准
    while( ADC_GetResetCalibrationStatus(ADC1) == SET);//获取复位校准状态,等待复位校准完成
    //如果没校准完成(复位校准状态为SET),就在while空循环里一直等待,完成后跳出while
    ADC_StartCalibration(ADC1);//开始校准
    while( ADC_GetCalibrationStatus(ADC1) == SET);//获取开始校准状态,等待校准完成
    //如果没校准完成(校准状态为SET),就在while空循环里一直等待,完成后跳出while
}
3、在 AD.c中编写启动AD转换获取结果函数AD_GetValue
编写启动AD转换获取结果函数时参考本图(单次转换、非扫描)
//启动转换,获取结果
uint16_t AD_GetValue(void)
{
//首先由软件触发转换
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发,ADC开始转换
    
//等待转换完成(完成时EOC标志位置1)
    while( ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
    //如果转换未完成(EOC标志位为RESET),就在while空循环里一直等待,完成后跳出while
//读取结果(ADC数据寄存器)    
    return ADC_GetConversionValue(ADC1);
//此处直接给AD_GetValue函数返回结果
}
4、在AD.h中声明初始化函数AD_Init和启动AD转换获取结果函数AD_GetValue
void AD_Init(void);
uint16_t AD_GetValue(void);
5、在主程序main.c中#include "AD.h"
#include "AD.h"
6、在主循环之前先初始化AD
7、在主循环中编写程序主体
uint16_t ADValue;
float Voltage;
int main(void)
{
    AD_Init();
    OLED_Init();
    
    OLED_ShowString(1,1,"ADValue:");
    OLED_ShowString(2,1,"Voltage:0.00V");
    while(1)
    {
        ADValue = AD_GetValue();
        Voltage = ( (float) ADValue / 4095 ) * 3.3;//将AD值换算成电压
        OLED_ShowNum(1,9,ADValue,4);
        OLED_ShowNum(2,9,Voltage,1);//显示电压整数部分
        OLED_ShowNum(2,11,(uint16_t)(Voltage *100) % 100,2);//显示电压小数部分(先把电压放大100倍再取余)
        //浮点数不能取余,需要在这里强转为整数
        
        Delay_ms(100);//刷新的慢一些
    }
}
实现功能:上电后不断进行AD采集并通过OLED显示ADValue:和Voltage:,通过旋转电位器(滑动变阻器)改变电压值

上面的程序是【单次转换】、【非扫描】
如果是【连续转换】、【非扫描】则只需要更改部分AD.c
//第四步:结构体配置ADC
    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//转换模式选择(连续[ENABLE]/单次[DISABLE]转换)
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//用于外部触发规则组转换的触发源
    //此处选择不使用外部触发,也就是选择使用软件触发    
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC工作模式(单/双AD转换)
    ADC_InitStructure.ADC_NbrOfChannel = 1;//在扫描模式时总共用到几个通道
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描转换选择(扫描[多通道][ENABLE]/非扫描[单通道][DISABLE]模式)
    
    ADC_Init(ADC1,&ADC_InitStructure);
//目前配置ADC模式为【连续转换】、【非扫描】
//这里还可以配置中断模拟看门狗,本例不用,这里不配置
    
//第五步:开关控制,开启ADC
    ADC_Cmd(ADC1,ENABLE);
    
//ADC配置完成,可以正常工作
//还要对ADC进行校准以减小误差
    ADC_ResetCalibration(ADC1);//复位校准
    while( ADC_GetResetCalibrationStatus(ADC1) == SET);//获取复位校准状态,等待复位校准完成
    //如果复位校准未完成(复位校准状态为SET),就在while空循环里一直等待,完成后跳出while
    ADC_StartCalibration(ADC1);//开始校准
    while( ADC_GetCalibrationStatus(ADC1) == SET);//获取开始校准状态,等待校准完成
    //如果校准未完成(校准状态为SET),就在while空循环里一直等待,完成后跳出while
//【连续转换】只需要在最开始触发一次就行
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发,ADC开始转换
//之后内部的ADC就会连续不断地对指定通道进行转换,将结果放在数据寄存器里,数据寄存器会不断刷新最新的转换结果
-------------------------------------------------------------------------------------------------------------------------
//不需要在AD_GetValue中不断触发,也不需要用while等待转换完成
//获取结果
uint16_t AD_GetValue(void)
{
//读取结果(ADC数据寄存器)    
    return ADC_GetConversionValue(ADC1);
//此处直接给AD_GetValue函数返回结果
}
实现功能:上电后不断进行AD采集并通过OLED显示ADValue:和Voltage:,通过旋转电位器(滑动变阻器)改变电压值

【基于AD单通道采集】AD多通道采集
  • 使用【单次转换】、【非扫描】来实现多通道采集(只需要在每次触发转换之前,手动更改列表第一个位置的通道就行)
//EX:第一次转换,先写入【通道0】,之后触发,等待,读值
          第二次转换,先把【通道0】改为【通道1】,之后触发,等待,读值
          第三次转换…………
//使用【连续转换】模式需要配合【DMA】缓存数据,确保数据不被覆盖
  • 修改部分前面的【AD单通道采集】代码即可
一、将初始化函数AD_Init中的部分代码 剪切到启动AD转换获取结果函数AD_GetValue
//第三步:配置多路开关,选择规则组通道【查引脚定义表】
    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
//目前配置为:在规则组菜单列表的第一个位置(序列1)写入通道0
|
|
|
|
|
V
//启动转换,获取结果
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
//首先由软件触发转换
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发,ADC开始转换
//配置多路开关,选择规则组通道【查引脚定义表】
    ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);
//目前配置为:在规则组菜单列表的第一个位置(序列1)写入需要的通道
//等待转换完成(完成时EOC标志位置1)
    while( ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
//如果转换未完成(EOC标志位为RESET),就在while空循环里一直等待,完成后跳出while
//读取结果(ADC数据寄存器)    
    return ADC_GetConversionValue(ADC1);
//此处直接给AD_GetValue函数返回结果
}
2、在AD.h中重新声明初始化函数AD_Init和启动AD转换获取结果函数AD_GetValue
void AD_Init(void);
uint16_t AD_GetValue(void);
3、在主循环中编写程序主体
uint16_t AD0,AD1,AD2,AD3;
//AD0:电位器
//AD1:光敏传感器
//AD2:热敏传感器
//AD3:反射传感器
int main(void)
{
    AD_Init();
    OLED_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);
        //依次启动4次转换,并且在转换之前指定了转换的通道
        //每次转换完成之后,把结果分别存在4个数据里
        
        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采集并通过OLED显示AD值

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/*************** 深圳市赛亿科技开发有限公司 ******************** * 文件名 : adc * 描述 :多通道AD采集(源文件) * 实验平台 :STM8S105开发板 * 库版本 :V1.0 * 作者 :hcr * QQ :630054913 * 修改时间 :2014-9-20 *******************************************************************************/ #include "adc.h" u16 AdcData_Buff[10]; //AD采集缓存 u16 AdcValue_Channel1; //通道1值 u16 AdcValue_Channel2; //通道2值 u16 AdcValue_Channel3; //通道3值 float Adc_V1; //通道1值电压值 float Adc_V2; //通道2值电压值 float Adc_V3; //通道3值电压值 /************************************************************************** * 函数名:Adc_Task(void) * 描述 :AD不通通道选择 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :10ms调用 *************************************************************************/ void Adc_Task(void) { static u8 Adc_Channel = 1; static u8 Adc_Timer = 0; static u16 Adc_GetValue; switch(Adc_Channel)//通道选择 { case 1: //通道1 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换数 AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel1=AdcData_Buff[5]; //取中间值 Adc_V1 = (3.28*AdcValue_Channel1)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 2; //另一通道 AdcChannel_Start(ADC1_CHANNEL_2); //ADC,通道2启动 } break; case 2: //通道2 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换数 AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel2=AdcData_Buff[5]; //取中间值 Adc_V2 = (3.28*AdcValue_Channel2)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 3; //另一通道 AdcChannel_Start(ADC1_CHANNEL_3); //ADC,通道3启动 } break; case 3: //通道3 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换数 AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel3=AdcData_Buff[5]; //取中间值 Adc_V3 = (3.28*AdcValue_Channel3)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 1; //另一通道 AdcChannel_Start(ADC1_CHANNEL_1); //ADC,通道1启动 } break; default: break; } } /************************************************************************** * 函数名:ADC_Init(void) * 描述 :ADC1初始化 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :系统初始化调用 *************************************************************************/ void ADC_Init(void) { ADC1_DeInit(); //恢复ADC1寄存器为默认值 ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2); //预分频2 ADC1_ITConfig(ADC1_IT_EOCIE,DISABLE); //使能中断 ADC1_Cmd(ENABLE); //启动ADC AdcChannel_Start(ADC1_CHANNEL_1); /* //恢复ADC1寄存器为默认值 ADC1->CSR = 0x00; ADC1->CR1 = 0x00; ADC1->CR2 = 0x00; ADC1->CR3 = 0x00; ADC1->TDRH = 0x00; ADC1->TDRL = 0x00; ADC1->HTRH = 0x03; ADC1->HTRL = 0xFF; ADC1->LTRH = 0x00; ADC1->LTRL = 0x00; ADC1->AWCRH = 0x00; ADC1->AWCRL = 0x00; ADC1->CR1 |= ADC1_PRESSEL_FCPU_D2; //选择2分频 ADC1->CR2 |= ADC1_ALIGN_RIGHT; //右对齐 ADC1->CR1 |= ADC1_CR1_CONT; //连续转换模式 ADC1->CSR |= ADC1_IT_EOCIE; //使能中断 ADC1->CR1 |= ADC1_CR1_ADON; //启动ADC */ } /************************************************************************** * 函数名:AdcChannel_Start(void) * 描述 :选择通道启动 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void AdcChannel_Start(ADC1_Channel_TypeDef ADC1_Channel) { ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_Channel,ADC1_ALIGN_RIGHT);/*配置通道的转换功能,连续右对齐*/ ADC1_StartConversion();//启动转换 /* ADC1->CSR &= (uint8_t)(~0x0F); // Clear the ADC1 channels ADC1->CSR |= ADC1_Channel; // Select the ADC1 channel ADC1->CR1 |= ADC1_CR1_ADON; //启动ADC */ } /************************************************************************** * 函数名:AdcData_Clean(void) * 描述 :清除缓存数据 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void AdcData_Clean(void) { u8 j; for(j=0;j<10;j++) AdcData_Buff[j]=0; } /************************************************************************** * 函数名:Temp_Choose(void) * 描述 :冒泡法取中间值 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void Temp_Choose(void)//冒泡法求中间值 { u8 i_Adc = 0; u8 j_Adc = 0; u16 Data_Buf; for(j_Adc=0;j_Adc<9;j_Adc++) { for(i_Adc=0;i_AdcAdcData_Buff[i_Adc+1]) { Data_Buf=AdcData_Buff[i_Adc]; AdcData_Buff[i_Adc]=AdcData_Buff[i_Adc+1]; AdcData_Buff[i_Adc+1]=Data_Buf; } } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值