STM32-ADC模数转换

目录

[1.0 逐次逼近型ADC](#1.0 逐次逼近型ADC)

[2.0 ADC触发](#2.0 ADC触发)

[3.0 ADC时钟](#3.0 ADC时钟)

[4.0 转换模式](#4.0 转换模式)

[5.0 转换时间](#5.0 转换时间)

[6.0 校准](#6.0 校准)

[7.0 硬件电路](#7.0 硬件电路)

[8.0 数据手册](#8.0 数据手册)

[9.0 程序实现](#9.0 程序实现)

[9.0.1 时钟初始化](#9.0.1 时钟初始化)

[9.0.2 GPIO结构体初始化](#9.0.2 GPIO结构体初始化)

[9.0.3 ADC结构体初始化](#9.0.3 ADC结构体初始化)

[9.0.4 ADC转换](#9.0.4 ADC转换)

[9.0.5 AD初始化](#9.0.5 AD初始化)

[9.0.6 获取ADC值](#9.0.6 获取ADC值)

[9.0.7 ADC头文件](#9.0.7 ADC头文件)

[9.0.8 MAIN函数](#9.0.8 MAIN函数)

[10.0 AD多通道](#10.0 AD多通道)

[10.0.1 RCC时钟初始化](#10.0.1 RCC时钟初始化)

[10.0.2 GPIO初始化](#10.0.2 GPIO初始化)

[10.0.3 ADC结构体初始化](#10.0.3 ADC结构体初始化)

[10.0.4 头文件](#10.0.4 头文件)

[10.0.5 主函数文件](#10.0.5 主函数文件)


定义:


ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC【表示转化的范围是0-2^12 - 1】,1us转换时间 输入电压范围:0~3.3V,转换结果范围:0~4095 18个输入通道,可测量16个外部和2个内部信号源 规则组和注入组两个转换单元 模拟看门狗自动监测输入电压范围 STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

注:单片机内部将采集到的模拟信号转换为单片机可以识别的数组信号


1.0 逐次逼近型ADC




2.0 ADC触发


ADC的触发方式有两种一种是软件的触发方式,一种是硬件的促发方式,ADC的硬件结构如下图所示:


3.0 ADC时钟


外部通道对应的GPIOA口对应引脚,ADC1和ADC2的引脚是相同的,还有双ADC模式,以下是通道和引脚的转换关系,以及对应的引脚关系图。


4.0 转换模式







二进制的特定:将数据左移一次相当于是把数据X2也就是扩大了一倍,左移了4次就相当于把结果X16,一般是选择右对齐


5.0 转换时间


AD转换的步骤:采样,保持量化,编码 STM32

ADC的总转换时间为: TCONV = 采样时间【采样,保持 】 + 12.5个ADC周期【量化,编码

例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期 TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs


6.0 校准


ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差

建议在每次上电后执行一次校准 启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期


7.0 硬件电路



8.0 数据手册

......


9.0 程序实现


9.0.1 时钟初始化

cpp 复制代码
	// RCC开启ADC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	// RCC开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	// 设置ADC时钟,分频系数是6分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

9.0.2 GPIO结构体初始化

cpp 复制代码
	// 初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	// GPIO_Mode_AIN 模拟输入模式,该模数下所有的GPIO口无效
	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);

9.0.3 ADC结构体初始化

cpp 复制代码
	// 配置规则组通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

	// ADC 初始化
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode 				 = ADC_Mode_Independent;      // ADC 模式,选择独立模式
	ADC_InitStructure.ADC_DataAlign 		 = ADC_DataAlign_Right;       // ADC 数据对齐模式
	ADC_InitStructure.ADC_ExternalTrigConv 	 = ADC_ExternalTrigConv_None; // ADC 触发模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;					  // 转换模式是单次转换还是连续

9.0.4 ADC转换

cpp 复制代码
	ADC_InitStructure.ADC_ScanConvMode       = DISABLE;					  // 扫描模式
	ADC_InitStructure.ADC_NbrOfChannel 		 = 1;						  // 指定ADC转换的通道数目
	// ADC 结构体初始化
	ADC_Init(ADC1, &ADC_InitStructure);									  // 初始化ADC结构体

	// 使能ADC
	ADC_Cmd(ADC1, ENABLE);

	// ADC 校准
	ADC_ResetCalibration(ADC1);
	// 获取ADC校准寄存器的状态
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	// 等待校准是否完成
	while (ADC_GetCalibrationStatus(ADC1) == SET);

9.0.5 AD初始化


cpp 复制代码
// AD 初始化函数
void AD_Init(void)
{
	// RCC开启ADC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	// RCC开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	// 设置ADC时钟,分频系数是6分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

	// 初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	// GPIO_Mode_AIN 模拟输入模式,该模数下所有的GPIO口无效
	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_InitStructure;
	ADC_InitStructure.ADC_Mode 				 = ADC_Mode_Independent;      // ADC 模式,选择独立模式
	ADC_InitStructure.ADC_DataAlign 		 = ADC_DataAlign_Right;       // ADC 数据对齐模式
	ADC_InitStructure.ADC_ExternalTrigConv 	 = ADC_ExternalTrigConv_None; // ADC 触发模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;					  // 转换模式是单次转换还是连续转换
	ADC_InitStructure.ADC_ScanConvMode       = DISABLE;					  // 扫描模式
	ADC_InitStructure.ADC_NbrOfChannel 		 = 1;						  // 指定ADC转换的通道数目
	// ADC 结构体初始化
	ADC_Init(ADC1, &ADC_InitStructure);									  // 初始化ADC结构体

	// 使能ADC
	ADC_Cmd(ADC1, ENABLE);

	// ADC 校准
	ADC_ResetCalibration(ADC1);
	// 获取ADC校准寄存器的状态
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	// 等待校准是否完成
	while (ADC_GetCalibrationStatus(ADC1) == SET);

}

9.0.6 获取ADC值

cpp 复制代码
// 获取ADC的值
uint16_t AD_GetValue(void)
{
	// 软件触发AD转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	// reset 转换未完成
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

9.0.7 ADC头文件


cpp 复制代码
#ifndef __AD_H_
#define __AD_H_

void AD_Init(void);
uint16_t AD_GetValue(void);

#endif

9.0.8 MAIN函数


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

uint16_t ADValue;			//定义AD值变量
float Voltage;				//定义电压变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();			//OLED初始化
	AD_Init();				//AD初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "Voltage:0.00V");
	
	while (1)
	{
		ADValue = AD_GetValue();					//获取AD转换的值
		Voltage = (float)ADValue / 4095 * 3.3;		//将AD值线性变换到0~3.3的范围,表示电压
		
		OLED_ShowNum(1, 9, ADValue, 4);				//显示AD值
		OLED_ShowNum(2, 9, Voltage, 1);				//显示电压值的整数部分
		OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);	//显示电压值的小数部分
		
		Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间
	}
}

10.0 AD多通道


10.0.1 RCC时钟初始化

时钟初始化:开启RCC与ADC时钟,ADC时钟控制设置为6分频

cpp 复制代码
	// RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	// ADC时钟初始化
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

10.0.2 GPIO初始化

GPIO结构体初始化,分别设置引脚,模式,时钟频率

cpp 复制代码
	// GPIO结构体初始化
	GPIO_InitTypeDef GPIO_InitStructure;
	// 模拟输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	// 引脚初始化
	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);

10.0.3 ADC结构体初始化

cpp 复制代码
    // ADC初始化

    ADC_InitTypeDef ADC_InitStructure;

    // ADC模式为独立模式

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

    // 数据对齐,对齐方式为右对齐

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

    // 触发方式,内部软件触发

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

    // ADC是否使用连续转换模式,此处每转换一次规则组转换方式失能

    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

    // 扫描模式,失能,只转换规则组的序列1这一个位置

    ADC_InitStructure.ADC_ScanConvMode = DISABLE;

    // 通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1

    ADC_InitStructure.ADC_NbrOfChannel = 1;

    // 将结构体变量交给ADC_Init,配置ADC1

    ADC_Init(ADC1, &ADC_InitStructure);

ADC使能与校准

cpp 复制代码
	// 使能ADC1,ADC开始运行
	ADC_Cmd(ADC1, ENABLE);

	/*ADC校准*/
	ADC_ResetCalibration(ADC1); 	// 固定流程,内部有电路会自动执行校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);

ADC结构体初始化

cpp 复制代码
/**
  * 函    数:获取AD转换的值
  * 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3
  * 返 回 值:AD转换的值,范围:0~4095
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前,根据函数形参灵活更改规则组的通道1
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束
	return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

10.0.4 头文件


10.0.5 主函数文件

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

uint16_t AD0, AD1, AD2, AD3;	//定义AD值变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();				//OLED初始化
	AD_Init();					//AD初始化
	
	/*显示静态字符串*/
	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);		//单次启动ADC,转换通道0
		AD1 = AD_GetValue(ADC_Channel_1);		//单次启动ADC,转换通道1
		AD2 = AD_GetValue(ADC_Channel_2);		//单次启动ADC,转换通道2
		AD3 = AD_GetValue(ADC_Channel_3);		//单次启动ADC,转换通道3
		
		OLED_ShowNum(1, 5, AD0, 4);				//显示通道0的转换结果AD0
		OLED_ShowNum(2, 5, AD1, 4);				//显示通道1的转换结果AD1
		OLED_ShowNum(3, 5, AD2, 4);				//显示通道2的转换结果AD2
		OLED_ShowNum(4, 5, AD3, 4);				//显示通道3的转换结果AD3
		
		Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间
	}
}

......

相关推荐
冰糖雪莲IO2 小时前
【江协STM32】9-4/5 USART串口数据包、串口收发HEX数据包&串口收发文本数据包
网络·stm32·嵌入式硬件
无聊到发博客的菜鸟2 小时前
STM32中的MCO
stm32·单片机·嵌入式硬件
Echo_cy_2 小时前
STM32 I2C通信外设
stm32·单片机·嵌入式硬件
半个番茄2 小时前
STM32 : PWM 基本结构
stm32·单片机·嵌入式硬件
小猪写代码2 小时前
STM32 拓展 RTC案例1:使用闹钟唤醒待机模式 (HAL库)
stm32·嵌入式硬件·实时音视频
半个番茄4 小时前
STM32 : GPIO_TypeDef
stm32·单片机·嵌入式硬件
厉昱辰5 小时前
51单片机入门基础
单片机·嵌入式硬件·51单片机
JaneZJW5 小时前
江科大STM32入门——UART通信笔记总结
笔记·stm32·单片机·嵌入式
就叫飞六吧6 小时前
51 单片机和 STM32 引脚命名对照表与解析
c++·stm32·单片机·嵌入式硬件·51单片机