STM32AD模数转换


前言

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


一、介绍部分

ADC简介

在这里插入图片描述

逐次逼近型ADC

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

在这里插入图片描述

在这里插入图片描述

STM32的ADC框图

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

在这里插入图片描述

ADC基本结构

在这里插入图片描述

五个标志位

在这里插入图片描述

ADC通道选择

在这里插入图片描述

ADC通道与引脚关系

在这里插入图片描述

规则通道的转换模式

单次转换,非扫描模式

在这里插入图片描述

连续转换,非扫描模式

在这里插入图片描述

单次转换,扫描模式

在这里插入图片描述

连续转换,扫描模式

在这里插入图片描述

AD转换触发相关

在这里插入图片描述

数据对齐方式

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

在这里插入图片描述

AD转换时间

在这里插入图片描述

校准

在这里插入图片描述

硬件电路

在这里插入图片描述

二、代码部分

AD单通道读取电压

连接电路

在这里插入图片描述

代码实现

封装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来辅助处理,这里暂时先使用手动扫描的方式实现

连接电路

在这里插入图片描述

代码实现

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时钟设置相关
在这里插入图片描述

  • 35
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值