stm32入门-----ADC模数转换器(实践篇——下)

目录

前言

硬件元器件

ADC相关函数

1.ADC时钟分频

2.初始化配置

3.使能上电

4.校准

5.ADC软件开始转换控制

6.判断转换是否结束

7.规则组的配置

8.配置间断模式

9.ADC获取转换值

10.注入组相关函数

项目实践

项目一:AD单通道转换

项目二:AD多通道转换


前言

上一期我们学习了ADC模数转换器的相关理论知识点(上一期:stm32入门-----ADC模数转换器(理论篇------上)-CSDN博客),那么本期就来进行项目的实操练习,本期有两个项目,分别是AD单通道转换和AD多通道转换。(视频:[7-2] AD单通道&AD多通道_哔哩哔哩_bilibili

本期相关代码我已经上传至百度网盘可自行下载,

链接:https://pan.baidu.com/s/1bPoG6o-p0keTbHuUV5sobA?pwd=0721

提取码:0721

硬件元器件

本期要用到的有滑动电阻和传感器这两者元器件,滑动电阻大家都再熟悉不过了,传感器的话我们之前是用过的,不过与之前不同,之前是用传感器的DO口作为高低电平的输入,而我们本期是需要用到实时电压的输入这时候就需要AO口了,而DO口是不需要的。

传感器(从左到右依次光敏传感器、温度传感器、对射红外线传感器、红外线反射传感器):

传感器电路图(传感器本质上电路都是一致的):

ADC相关函数

1.ADC时钟分频

根据ADC的时钟频率要求,频率是小于14MHz的,而我们如果选择内部时钟的话那么至少要选择6分频,才能使得时钟变为12MHz。

cpp 复制代码
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

2.初始化配置

ADC_DeInit恢复缺省配置、ADC_Init初始化、ADC_StructInit结构体初始化

cpp 复制代码
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);

3.使能上电

ADC_Cmd:这个是用于给ADC上电的,就是ADC基本结构图里的开关控制。

cpp 复制代码
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

4.校准

接下来四个函数分别是复位校准、获取复位校准状态、开始校准、获取开始校准状态,这是用于控制校准的函数。我们使能完成后下面这四个直接去调用就行了。

cpp 复制代码
void ADC_ResetCalibration(ADC_TypeDef* ADCx);//复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);//获取复位校准完成标志位
void ADC_StartCalibration(ADC_TypeDef* ADCx);//开始校准
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);//获取开始校准完成标志位

5.ADC软件开始转换控制

这里我们调用这个函数的时候就开始触发ADC转换。

cpp 复制代码
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

6.判断转换是否结束

下面这个函数是判断是否转换结束的。获取标志位状态,然后参数给EOC的标志位,判断EOC标志位是不是置1了。如果转换结束,EOC标志位置1,然后调用这个函数,判断标志位。这样才是正确的判断转换是否结束的方法。

cpp 复制代码
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

这里再提一下,下面这个函数看上去好像是跟转换结束相关的函数,实际上不要被误导,实际上是ADC获取软件开始转换状态的函数,一般不怎么用到。

cpp 复制代码
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

7.规则组的配置

下面这个函数就比较重要的了,是用来配置规则组相关的参数的。

cpp 复制代码
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
  • ADC_TypeDef* ADCx:是选择ADC(ADC1, ADC2, ADC3)
  • uint8_t ADC_Channel:第二参数是选择指定的通道(通道有16个)
  • uint8_t Rank:是指选择的序列位置(1~16) 是数字
  • uint8_t ADC_SampleTime:是值转换的时间设置

下面看个示例:

cpp 复制代码
//ADC1  选择通道0   放入序列1  时间为ADC_SampleTime_28Cycles5
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5);

8.配置间断模式

下面这两个函数,是用来配置间断模式的。

cpp 复制代码
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);//每隔几个通道间断一次。
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//使能操作,是否开启间断模式

9.ADC获取转换值

这个函数是用来获取指定ADC转换后数据寄存器的值。

cpp 复制代码
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

下面这个是ADC获取双模式转换值,这个是双ADC模式读取转换结果的函数,暂时不用。

cpp 复制代码
uint32_t ADC_GetDualModeConversionValue(void);

10.注入组相关函数

下面是注入组相关函数,本期不用到注入组,了解一下就行了。

cpp 复制代码
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);

项目实践

项目一:AD单通道转换

现象:

AD单通道转换

电路连接图:

主要工程文件:

代码如下

AD.c文件代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header

void AD_init() {
    //1.开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);//选择时钟分频

    //2.配置GPIO
    GPIO_InitTypeDef GPIO_initstruct;
	GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN; //选择模拟输入 ,是ADC专属模式,其他是无效的
	GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_initstruct);

    //规则组列表中的第一个通道,序列1写入通道0,
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5);
    // 如果还想添加其他通道,可以复制修改通道和对应填入的序列即可,采样时间也可以单独设置
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5);
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_28Cycles5);
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_28Cycles5);

    // ADC结构体初始化
    ADC_InitTypeDef ADC_initstruct;
    ADC_initstruct.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,左右可选,这里选择右对齐
    ADC_initstruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//选择外部触发源,这里选择none是用软件触发
    ADC_initstruct.ADC_Mode = ADC_Mode_Independent;//选择ADC的模式,独立和双模式选择,这里选择独立模式
    //选择模式
    ADC_initstruct.ADC_ContinuousConvMode = ENABLE; //连续转换,这里选择非连续转换
    ADC_initstruct.ADC_ScanConvMode = DISABLE;  // 扫描模式,这里选择非扫描模式
    ADC_initstruct.ADC_NbrOfChannel = 1;//通道数目,当前通道为1,这里选择1
    ADC_Init(ADC1, &ADC_initstruct);

    //后继如果需要配置中断可以选择

    //开启ADC电源
    ADC_Cmd(ADC1, ENABLE);

    //校准
    ADC_ResetCalibration(ADC1); //复位校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET); //获取复位校准状态,如果复位完成了之后就标志位就会清理
    ADC_StartCalibration(ADC1); //开启校准
    while (ADC_GetCalibrationStatus(ADC1) == SET);//如果标志位清零的话说明校准完成,不然就一直等待校准标志位

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//选择软件触发,调用一下就能进行软件触发控制,开始转换

}

uint16_t AD_getvalue() {
    //ADC_SoftwareStartConvCmd(ADC1, ENABLE);//选择软件触发,调用一下就能进行软件触发控制,开始转换
    //while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //获取转换结束的标志位,当EOC为1的时候就转换完成
    //获取结果
    return ADC_GetConversionValue(ADC1);//这个函数是去直接读取DR寄存器里面的数据
}

AD.h文件代码 :

cpp 复制代码
#ifndef __AD_h
#define __AD_h

void AD_init();
uint16_t AD_getvalue();

#endif // !__AD_h#define __AD_h

主文件main.c代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
#include "LED.h"

uint16_t AD_value;
float Volatge;

int main(void)
{
	LED_init();
	OLED_Init();
	AD_init();
	OLED_ShowString(1, 1, "ADvalue:");
	OLED_ShowString(2, 1, "Volatge:0.00V");
	while (1) {
		if (Volatge < 1.3) {
			LED1_ON();
		}
		else
			LED1_OFF();
		
		AD_value = AD_getvalue();
		Volatge = (float)AD_value / 4095 * 3.3;
		OLED_ShowNum(1, 9, AD_value, 4);
		//显示浮点数
		OLED_ShowNum(2, 9, Volatge, 1);
		OLED_ShowNum(2, 11, (uint16_t)(Volatge * 100) % 100, 2);
		Delay_ms(100);

	}
}


 

项目二:AD多通道转换

现象:

电路连接图:

主要工程文件:

代码如下

AD.c文件代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header

void AD_init() {
    //1.开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);//选择时钟分频

    //2.配置GPIO
    GPIO_InitTypeDef GPIO_initstruct;
	GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN; //选择模拟输入 ,是ADC专属模式,其他是无效的
    GPIO_initstruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_initstruct);

    //规则组列表中的第一个通道,序列1写入通道0,
    
    // 如果还想添加其他通道,可以复制修改通道和对应填入的序列即可,采样时间也可以单独设置
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5);
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_28Cycles5);
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_28Cycles5);

    // 3.ADC结构体初始化
    ADC_InitTypeDef ADC_initstruct;
    ADC_initstruct.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,左右可选,这里选择右对齐
    ADC_initstruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//选择外部触发源,这里选择none是用软件触发
    ADC_initstruct.ADC_Mode = ADC_Mode_Independent;//选择ADC的模式,独立和双模式选择,这里选择独立模式
            //选择模式
    ADC_initstruct.ADC_ContinuousConvMode = DISABLE; //连续转换,这里选择非连续转换
    ADC_initstruct.ADC_ScanConvMode = DISABLE;  // 扫描模式,这里选择非扫描模式
    ADC_initstruct.ADC_NbrOfChannel = 1;//通道数目,当前通道为1,这里选择1

    ADC_Init(ADC1, &ADC_initstruct);

    //后继如果需要配置中断可以选择

    //4.开启ADC电源
    ADC_Cmd(ADC1, ENABLE);

    //5.校准
    ADC_ResetCalibration(ADC1); //复位校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET); //获取复位校准状态,如果复位完成了之后就标志位就会清理
    ADC_StartCalibration(ADC1); //开启校准
    while (ADC_GetCalibrationStatus(ADC1) == SET);//如果标志位清零的话说明校准完成,不然就一直等待校准标志位


}

//这里只需要改为传入通道的参数,然后对指定通道去获取AD转换的结果
uint16_t AD_getvalue(uint8_t ADC_Channel) {

    //ADC1  选择通道0   放入序列1  时间为ADC_SampleTime_28Cycles5
    ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_28Cycles5);

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//选择软件触发,调用一下就能进行软件触发控制,开始转换
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //获取转换结束的标志位,当EOC为1的时候就转换完成
    //获取结果
    return ADC_GetConversionValue(ADC1);//这个函数是去直接读取DR寄存器里面的数据
}

AD.h文件代码:

cpp 复制代码
#ifndef __AD_h
#define __AD_h

void AD_init();
uint16_t AD_getvalue(uint8_t ADC_Channel);
#endif // !__AD_h#define __AD_h

主文件main.c代码:

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
#include "LED.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);

	}
}


 

以上就是本期的全部内容了,我们下次见!

今日壁纸:

相关推荐
Qingniu0114 分钟前
【青牛科技】应用方案 | RTC实时时钟芯片D8563和D1302
科技·单片机·嵌入式硬件·实时音视频·安防·工控·储能
Mortal_hhh1 小时前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器
深圳市青牛科技实业有限公司2 小时前
【青牛科技】应用方案|D2587A高压大电流DC-DC
人工智能·科技·单片机·嵌入式硬件·机器人·安防监控
Mr.谢尔比3 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie3 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
鹿屿二向箔3 小时前
STM32外设之SPI的介绍
stm32
西瓜籽@3 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
远翔调光芯片^138287988726 小时前
远翔升压恒流芯片FP7209X与FP7209M什么区别?做以下应用市场摄影补光灯、便携灯、智能家居(调光)市场、太阳能、车灯、洗墙灯、舞台灯必看!
科技·单片机·智能家居·能源
极客小张7 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
m0_739312879 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件