STM32-ADC

ADC(模拟-数字转化器)

  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁;
  • AD转换步骤:采样、保持、量化、编码;
  • 12位逐次逼近型ADC,1us转换时间;
  • 输入电压范围:0~3.3V,转换结果范围:0~4095;
  • 18个输入通道,可以测量16个外部和2个内部信号源(整个系列);
  • 有规则组和注册组两个转换单位;
  • 模拟看门狗自动监测输入电压范围;
  • 总转换时间:T = 采样时间 + 12.5个ADC周期;
  • STM32F1003C8T6 ADC资源:ADC1、ADC2、10个外部输入通道。

整个ADC的基本结构图如下:

一、ADC单通道测量

本实验用PA0连接一个简易继电器对模拟信号进行转换。

先对ADC模块进行编写,ADC.c文件:

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

void ADC_init(void)
{
    //打开ADC1时钟
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1 ,ENABLE);
	//打开GPIOA时钟
    RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE);
	
    //对ADC时钟进行分频配置,ADC频率不能超过14MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
    //对PA0进行初始化配置,这里使用模拟输入模式(ADC专属模式)
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init (GPIOA ,&GPIO_InitStruct);
	
	//"点菜"对规则组的通道进行配置
	ADC_RegularChannelConfig(ADC1 ,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	
    //对ADC进行初始化配置
	ADC_InitTypeDef ADC_InitStructer;
	ADC_InitStructer.ADC_Mode =ADC_Mode_Independent;//使用的是ADC单通道模式
	ADC_InitStructer.ADC_DataAlign =ADC_DataAlign_Right;//选择右对齐方式
	ADC_InitStructer.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None;
    //软件触发,这里不需要外部触发
	ADC_InitStructer.ADC_ContinuousConvMode =DISABLE;//单次转换模式
	ADC_InitStructer.ADC_ScanConvMode =DISABLE;//非扫描模式
	ADC_InitStructer.ADC_NbrOfChannel =1;//需要转换的通道数量
	ADC_Init(ADC1 ,&ADC_InitStructer);
	
    //打开ADC1
	ADC_Cmd(ADC1 ,ENABLE);
	
    //对ADC进行校正,标志位是独立的,完成了某个操作才会将对应的标志位SET
	ADC_ResetCalibration(ADC1 );//复位校正
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//检测是否复位校正
	ADC_StartCalibration(ADC1);//进行校正
	while(ADC_GetCalibrationStatus(ADC1) == SET);//检测是否进行校正
	
}

//读值函数:将ADC转换后的值读取出来
uint16_t Get_Value(void)
{
	ADC_SoftwareStartConvCmd(ADC1 ,ENABLE );//选择软件触发方式
	while(ADC_GetFlagStatus(ADC1 ,ADC_FLAG_EOC) == RESET);//判断是否完成转换
	uint16_t value = ADC_GetConversionValue(ADC1);//将DR中的值读出来
	ADC_ClearFlag(ADC1 ,ADC_FLAG_EOC);//清除标志位
	return value;//返回读取值
}

ADC.h文件:

复制代码
#ifndef _ADC_H
#define _ADC_H
void ADC_init(void);
uint16_t Get_Value(void);

#endif

再在主函数中对各模块函数进行调用,main.c文件:

复制代码
#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"
#include "ADC.h"

uint16_t Value;//创建变量用于存储转换后直接读取值
float Voltage;//创建变量用于存储电压值
int main(void)
{	
	OLED_Init();
	ADC_init ();//各模块初始化值
	OLED_ShowString (1,1,"Value:");//显示提示字符串
	OLED_ShowString (2,1,"Voltage:0.000");//显示提示字符串
	while(1)
	{
		Value = Get_Value();//实时读取值
		Voltage = (float)Get_Value() / 4095 * 3.3;//对电压进行转换
		OLED_ShowNum (1,7,Value,4);//实时显示直接读取值
		OLED_ShowNum (2,9,Voltage,1);
        //实时显示电压值,由于函数的局限性,将其分为整数、小数两部分进行显示
		OLED_ShowNum (2,11,(uint16_t)(Voltage *1000) % 1000,3);
		Delay_ms (500);//延时500ms,让ADC转换效果更加明显
	}
}

二、ADC多通道

本实验分别用PA0~PA3连接继电器、光敏传感器、热敏传感器、发射式红外传感器,将使用ADC1的0~3四个通道接收各模块的模拟量,并将其转换为数字量。(由于ADC规则组,只有一个寄存器用于寄存数据,这里还是选择使用单次转换、非扫描模式进行转换)

先对ADC模块进行编写,ADC.c文件:

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


void ADC_init(void)
{
    //打开ADC1和GPIOA
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1 ,ENABLE);
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE);
	
    //对ADC时钟进行分频配置
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
    //对PA0~PA3四个引脚进行初始化配置,这里均配置为:模拟输入模式
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
	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);

    //不在这里对ADC规则组通道进行配置
	
	//对ADC单元进行初始化配置
	ADC_InitTypeDef ADC_InitStructer;
	ADC_InitStructer.ADC_Mode =ADC_Mode_Independent;
	ADC_InitStructer.ADC_DataAlign =ADC_DataAlign_Right;
	ADC_InitStructer.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None;
	ADC_InitStructer.ADC_ContinuousConvMode =DISABLE;
	ADC_InitStructer.ADC_ScanConvMode =DISABLE;
	ADC_InitStructer.ADC_NbrOfChannel =1;
	ADC_Init(ADC1 ,&ADC_InitStructer);
	
    //打开ADC1
	ADC_Cmd(ADC1 ,ENABLE);
	
    //对ADC进行校正
	ADC_ResetCalibration(ADC1 );
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1) == SET);
	
}

//对ADC规则组进行灵活配置,对转换后的数值进行读取
uint16_t Get_Value(uint8_t ADC_Channel)//将具体通道作为函数参数
{
    //对ADC规则组进行灵活配置
	ADC_RegularChannelConfig(ADC1 ,ADC_Channel,1,ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1 ,ENABLE );//选择软件触发ADC转换
	while(ADC_GetFlagStatus(ADC1 ,ADC_FLAG_EOC) == RESET);//判断数据是否转换完成
	uint16_t value = ADC_GetConversionValue(ADC1);//读取转换值
	ADC_ClearFlag(ADC1 ,ADC_FLAG_EOC);//清除标志位
	return value;//返回读取值
}

ADC.h文件:

复制代码
#ifndef _ADC_H
#define _ADC_H
void ADC_init();
uint16_t Get_Value(uint8_t ADC_Channel);

#endif

最后在主函数中调用ADC模块函数实现ADC多通道转换,mian.c文件:

复制代码
#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"
#include "ADC.h"

uint16_t Value0;
uint16_t Value1;
uint16_t Value2;
uint16_t Value3;//创建四个变量,用于存储四个通道的读取值

int main(void)
{	
	OLED_Init();
	ADC_init();//各模块初始化
	OLED_ShowString (1,1,"Value0:");
	OLED_ShowString (2,1,"Value1:");
	OLED_ShowString (3,1,"Value2:");
	OLED_ShowString (4,1,"Value3:");//四个通道对应的提示字符串
	while(1)
	{
		Value0 = Get_Value(ADC_Channel_0);
		Value1 = Get_Value(ADC_Channel_1);
		Value2 = Get_Value(ADC_Channel_2);
		Value3 = Get_Value(ADC_Channel_3);//对四个通道实时读取值进行存储,函数要进行传参
		OLED_ShowNum (1,8,Value0,4);
		OLED_ShowNum (2,8,Value1,4);
		OLED_ShowNum (3,8,Value2,4);
		OLED_ShowNum (4,8,Value3,4);//对四个通道读取值进行实时显示
		Delay_ms (100);//延时增强观感
	}
}

最终效果:四个通道均能实时将模拟量转换为数字量,并在OLED屏幕上显示出来。

注意事项:

  • ADC的规则组只有一个寄存器,注入组有四个寄存器;
  • 在使用扫描模式进行转换时,转换完一个值需要将ADC中DR的值用DMA进行转运;
  • OLED_ShowNum()函数无法直接显示浮点数,需要使用取巧的方法进行显示。
相关推荐
Jason_zhao_MR4 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
BSD_CGQ5 小时前
FSR传感器STM32 DMA高速采样工程实现(高精度、低CPU占用)
stm32·单片机·嵌入式硬件·压力传感器·源头工厂·柔性薄膜压力传感器·可变电阻压力传感器
芯岭技术郦8 小时前
32 位 ARM® Cortex®-M0+ 内核MCU普冉MS32C001-C
单片机·嵌入式硬件
骑着毛驴数星星8 小时前
STM32 CAN波特率与采样点计算,基于HAL库
stm32·单片机·嵌入式硬件
zhangrelay9 小时前
Arduino-MEGA-ESP单片机理论课笔记02-硬件-2026
笔记·单片机·嵌入式硬件
艾芯微科技9 小时前
钰泰 ETA5055V330DD1E|SOT-223 3.3V LDO,低压差、大电流线性稳压选型分享
网络·单片机·嵌入式硬件·集成测试·51单片机
新晨单片机设计10 小时前
S023A-基于STM32单片机智能插座【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·单片机智能插座
威嵌神州10 小时前
恩智浦 T1022 性能怎么样?QorIQ 架构中端工业嵌入式优势解析
嵌入式硬件
weixin_6906547411 小时前
龙迅#LT9611EX 现MIPI转HDMI1.4功能主推型号,分辨率高达4K30HZ,IC内置I2C无需外部12C控制。
嵌入式硬件·音视频·信号处理
EatFans11 小时前
全栈自造 Status Deck(四):硬件终于到了,从点亮屏幕到跑通第一个 Demo
单片机·物联网