STM32AD模数转换

文章目录

  • 前言
  • 一、介绍部分
    • ADC简介
    • 逐次逼近型ADC
    • STM32的ADC框图
    • ADC基本结构
      • 五个标志位
    • ADC通道选择
    • ADC通道与引脚关系
    • 规则通道的转换模式
      • 单次转换,非扫描模式
      • 连续转换,非扫描模式
      • 单次转换,扫描模式
      • 连续转换,扫描模式
    • AD转换触发相关
    • 数据对齐方式
    • AD转换时间
    • 校准
    • 硬件电路
  • 二、代码部分
    • AD单通道读取电压
      • 连接电路
      • 代码实现
    • AD多通道
      • 连接电路
      • 代码实现
  • 总结
    • 相关函数
    • ADC时钟分频


前言

介绍AD,了解逐次逼近型ADC的原理,了解STM32的ADC运行流程以及通道选择,介绍STM32ADC规则通道组的部分使用方法,了解使用相关库函数。


一、介绍部分

ADC简介

STM32AD模数转换_第1张图片

逐次逼近型ADC

逐次逼近:对8位依次判断,若小于这个值则置0判断下一位,若大于这个值则置1继续判断下一位

STM32AD模数转换_第2张图片

STM32AD模数转换_第3张图片

STM32的ADC框图

也是逐次逼近型的,不过是16位,即从256开始二分查找

STM32AD模数转换_第4张图片

ADC基本结构

STM32AD模数转换_第5张图片

五个标志位

STM32AD模数转换_第6张图片

ADC通道选择

STM32AD模数转换_第7张图片

ADC通道与引脚关系

STM32AD模数转换_第8张图片

规则通道的转换模式

单次转换,非扫描模式

STM32AD模数转换_第9张图片

连续转换,非扫描模式

STM32AD模数转换_第10张图片

单次转换,扫描模式

STM32AD模数转换_第11张图片

连续转换,扫描模式

STM32AD模数转换_第12张图片

AD转换触发相关

STM32AD模数转换_第13张图片

数据对齐方式

寄存器是16位的,数据12位

STM32AD模数转换_第14张图片

AD转换时间

STM32AD模数转换_第15张图片

校准

STM32AD模数转换_第16张图片

硬件电路

STM32AD模数转换_第17张图片

二、代码部分

AD单通道读取电压

连接电路

STM32AD模数转换_第18张图片

代码实现

封装AD相关设置AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 设置ADC时钟 72/6=12MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	// 初始化GPIO
	GPIO_InitTypeDef GPIO_Structure;
	GPIO_Structure.GPIO_Pin = GPIO_Pin_0;
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Structure.GPIO_Mode = GPIO_Mode_AIN;		// 模拟输入模式(ADC专用)
	GPIO_Init(GPIOA,&GPIO_Structure);
	
	// 使用规则组
	// 配置规则组通道(ADC、此ADC的通道、序号、采样时间)
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	
	// 初始化ADC
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;										// 连续模式还是单次模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;								// 数据对齐,右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;		// 触发转换的触发源,不使用外部触发使用软件触发
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;										// 独立模式or双ADC模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;																// 指定要使用多少个通道
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;													// 扫描模式还是非扫描模式
	ADC_Init(ADC1,&ADC_InitStructure);
	
	
	// 开启ADC
	ADC_Cmd(ADC1,ENABLE);
	
	// 校准
	ADC_ResetCalibration(ADC1);													// 复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);	// 获取复位校准的状态,等待复位完成
	ADC_StartCalibration(ADC1);													// 开始校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);				// 获取校准状态,等待校准完成
}

uint16_t AD_GetValue(void){
	// 软件触发转换
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	// 获取转换标志位,等待转换完成EOC(规则通道或注入通道完成)置1,未完成时循环
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	// ADC获取转换值,会自动清除EOC标志位
	return ADC_GetConversionValue(ADC1);
}

主函数main.c

#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,"AD:");
	OLED_ShowString(2,1,"Voltage:  .  V");
	while (1)
	{
		ADValue = AD_GetValue();
		// 4095 对应 3.3V
		Voltage = (float)ADValue/4095*3.3;
		OLED_ShowNum(1,10,ADValue,4);
		OLED_ShowNum(2,10,Voltage,1);
		OLED_ShowNum(2,12,(int16_t)(Voltage*100)%100,2);	// 小数部分
		Delay_ms(100);
	}
}

AD多通道

由于扫描模式需要DMA来辅助处理,这里暂时先使用手动扫描的方式实现

连接电路

STM32AD模数转换_第19张图片

代码实现

AD.c修改如下:

#include "stm32f10x.h"                  // Device header

void AD_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 设置ADC时钟 72/6=12MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	// 初始化GPIO
	GPIO_InitTypeDef GPIO_Structure;
	GPIO_Structure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Structure.GPIO_Mode = GPIO_Mode_AIN;		// 模拟输入模式(ADC专用)
	GPIO_Init(GPIOA,&GPIO_Structure);
	
	// 使用规则组
	// 配置规则组通道(ADC、此ADC的通道、序号、采样时间)
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	
	// 初始化ADC
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;										// 连续模式还是单次模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;								// 数据对齐,右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;		// 触发转换的触发源,不使用外部触发使用软件触发
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;										// 独立模式or双ADC模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;																// 指定要使用多少个通道
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;													// 扫描模式还是非扫描模式
	ADC_Init(ADC1,&ADC_InitStructure);
	
	
	// 开启ADC
	ADC_Cmd(ADC1,ENABLE);
	
	// 校准
	ADC_ResetCalibration(ADC1);													// 复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);	// 获取复位校准的状态,等待复位完成
	ADC_StartCalibration(ADC1);													// 开始校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);				// 获取校准状态,等待校准完成
}

uint16_t AD_GetValue(uint8_t ADC_Channel){
	// 手动修改通道
	ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);
	// 软件触发转换
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	// 获取转换标志位,等待转换完成EOC(规则通道或注入通道完成)置1,未完成时循环
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	// ADC获取转换值,会自动清除EOC标志位
	return ADC_GetConversionValue(ADC1);
}

主函数main.c

#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);
	}
}


总结

根据实列反复对照ADC框图与基本结构来加深理解。

相关函数

// ADC初始化
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
// 为ADC初始化结构体赋初值
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
// 启动ADC
void ADC_Cmd(ADC_TypeDef* ADCx, 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);
// 选择ADC通道以及所在序号
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
// 获取转换值
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
// 获取转换成功标志位(EOC,JEOC,AWD)
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 清除转换成功标志位
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 适用于中断函数内,获取转换成功标志位(EOC,JEOC,AWD)
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
// 适用于中断函数内,清除转换成功标志位
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
// 设置ADC时钟,此函数在rcc相关文件中
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

ADC时钟分频

参考STM32时钟树,ADC时钟设置相关
STM32AD模数转换_第20张图片

你可能感兴趣的:(STM32学习记录,stm32,嵌入式硬件,单片机)