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

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-08 04:58:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-08 04:58:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-08 04:58:02       82 阅读
  4. Python语言-面向对象

    2024-02-08 04:58:02       91 阅读

热门阅读

  1. 从前序遍历和后序遍历恢复二叉树

    2024-02-08 04:58:02       49 阅读
  2. ssh和sftp服务分离

    2024-02-08 04:58:02       38 阅读
  3. 算法刷题day07

    2024-02-08 04:58:02       56 阅读
  4. muduo库的模拟实现——TcpServer部分

    2024-02-08 04:58:02       45 阅读
  5. Rust入门

    2024-02-08 04:58:02       52 阅读
  6. 使用python启动一个roslaunch文件

    2024-02-08 04:58:02       55 阅读
  7. prometheus之redis_exporter部署

    2024-02-08 04:58:02       49 阅读
  8. 如何快速入门深度学习

    2024-02-08 04:58:02       59 阅读
  9. 获取目标进程导入DLL模块地址的方法

    2024-02-08 04:58:02       41 阅读
  10. Acwing---835. Trie字符串统计

    2024-02-08 04:58:02       39 阅读
  11. 方了个方(来源于羊了个羊,python)

    2024-02-08 04:58:02       56 阅读
  12. PHP实现阿里OSS文件上传

    2024-02-08 04:58:02       58 阅读
  13. springboot在线文档的集成方式

    2024-02-08 04:58:02       53 阅读