目录

ADC

简介:

逐次逼近型ADC

ADC框图:

触发控制:

ADC基本结构

输入通道:

转换模式:

对齐方式:

转换时间:

校准:

硬件电路:

程序源码:

配置步骤:

AD.h模块:

main.c模块:

AD.c模块:

ADC配置代码:


ADC

简介:

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

STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

逐次逼近型ADC

1.通道选择开关,有八路模拟电压输入,由下方的地址锁存和译码控制。

例如:地址锁存输入011,那就是IN3号通道输入

2.比较器:把输入电压跟DAC的输出电压进行比较

3.DAC把SAR里面的数字量转换成模拟量跟输入电压进行比较。采用二分法

4.二分法:如果DAC输出量大于输入电压,那么DAC的输出量就会取一半再跟输入量进行比较,最多比较八次

5.当他们近似相等时,就会把结果输出到8位三态锁存缓冲器中,等到OE输出使能有效时,才会输出结果到总线中

6.定时和控制逻辑:输入START和CLOCK信号,是一个开工指令。当转换完成后,会置EOC标志位提醒转换完成

ADC框图:

GPIO端口控制模拟输入,进入多路开关。

软件配置通道选择,多路开关选通你指定的那一路信号。

选中的信号被送入 “注入通道” 或 “规则通道”,再进入 “模拟至数字转换器”,转换成数字量。

转换结果存入对应的寄存器,供 CPU 或 DMA 读取

注入通道数据寄存器可以同时存储四条通路的数据,但是规则通路数据寄存器只能存储最新的一个通道的数据。

上方注入和规则数据寄存器会引出一条导线通向一个或门,最后通向EOC标志位。(即注入和规则任意通路完成发出的完成信号都会通向EOC标志位)

注入通道数据寄存器转换结束后,也会输出一个注入转换结束的信号置JEOC标志位。

另外还可以设置一个模拟看门狗,对输出结果进行一个操作,只输出阈值内的量

(为什么要单独把注入数据寄存器单独引出一条信号通路呢?因为注入和规则一起连接了一个或门,当这条通路被规则单独使用时,注入组则可以使用另外一条路)

上方的EOC,JEOC和AWD都是中断标志位,后面的是中断使能信号。这里不做中断说明

下面的注入组和规则组的开始触发信号是START信号。

触发源有两种:

  • 软件触发:调用一条代码
  • 硬件触发:就是图中的部分

这些通道通过一个多路选择器来触发注入/规则数据寄存器的开始信号

触发控制:

ADC基本结构

输入通道:

转换模式:

  1. 单次转换,非扫描模式
  2. 多次转换,非扫描模式
  3. 单次转换,扫描模式
  4. 多次转换,扫描模式

1.

2.

3.

4.

注意:扫描模式下只能储存最后一个通道的数据。其他数据要通过DMA转运

对齐方式:

转换时间:

校准:

这一步直接被封装好了,不用理解原理。直接调用几个函数就行了

硬件电路:

程序源码:

配置步骤:

  • 开启RCC时钟,包括ADC和GPIO的时钟。ADCCLK的分频器也要配置
  • 配置GPIO为模拟输入模式
  • 配置多路开关,把左边的通道接入右边的规则组里面(点菜)
  • 配置ADC转换器
  • 中断和看门狗,需要的自行配置
  • 校准

AD.h模块:

#ifndef __AD__H
#define __AD__H

void AD_Init(void);
uint16_t ADC_GetValue(void);

#endif

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,"ADValue:");
	OLED_ShowString(2,1,"Voltage:0.00V");
	
	while(1)
	{
		ADValue = ADC_GetValue();
		Voltage = (float)ADValue / 4095 * 3.3;
		
		OLED_ShowNum(1,9,ADValue,5);
		OLED_ShowNum(2,9,Voltage,1);
		OLED_ShowNum(2,11,(uint16_t)(Voltage * 100) % 100, 2);
		
		Delay_ms(100);
	}
}

AD.c模块:

#include "stm32f10x.h"                  // Device header

/*
 *
 *  1.开启RCC时钟,包括ADC和GPIO的时钟。ADCCLK的分频器也要配置
 *  2.配置GPIO为模拟输入模式
 *  3.配置多路开关,把左边的通道接入右边的规则组里面(点菜)
 *  4.配置ADC转换器
 *	(中断和看门狗,需要的自行配置)
 *	5.校准
*/


void AD_Init(void)
{
	//1.开启RCC时钟,包括ADC和GPIO的时钟。ADCCLK的分频器也要配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);     //ADCCLK时钟最大14MHz 6分频后是12MHz
	
	
	//2.配置GPIO为模拟输入模式
	GPIO_InitTypeDef GPIOA_InitStructure;
	/*这里的模拟输入模式是ADC的专属模式,让GPIO的输入输出失效,信号直接进入板子里面的ADC外设*/
	GPIOA_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIOA_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIOA_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIOA_InitStructure);
	
	//3.配置多路开关,把左边的通道接入右边的规则组里面(点菜)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	/*ADC1的菜单里,菜品:通道0,排在第一位,采样时间是55.5个ADC周期*/
	
	//还想再点几个菜的话,就多调用计次这个函数
	//ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

	//4.配置ADC转换器
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  //配置ADC的工作模式(独立模式/双ADC模式)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //设置右对齐还是左对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发转换选择
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 //选择 连续/单次 转换模式 ENABLE(连续)/DISABLE(单次)
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       //选择扫描模式(ENABLE)还是非扫描模式(DISABLE)
	ADC_InitStructure.ADC_NbrOfChannel = 1;                             //通道数目:在扫描模式下,总共会用到几个通道
	ADC_Init(ADC1, &ADC_InitStructure);
	
	
	ADC_Cmd(ADC1, ENABLE);
	
	//5.对ADC进行校准
	ADC_ResetCalibration(ADC1);                   //复位校准
	/*软件置1,开启复位校准,复位校准完成后,硬件自动清零*/
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);   //等待复位校准完成(未完成则一直开始等待)
	ADC_StartCalibration(ADC1);                   //开始校准
	/*软件置1,开启校准,校准完成后,硬件自动清零*/
	while(ADC_GetCalibrationStatus(ADC1) == SET);               //等待校准完成
}

uint16_t ADC_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);   //软件开启转换命令
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}


ADC配置代码:

	//4.配置ADC转换器
	ADC_InitTypeDef ADC_InitStructure;

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  
    /*配置ADC的工作模式(独立模式/双ADC模式)*/

	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              
    /*设置右对齐还是左对齐*/

	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
    /*外部触发转换选择*/

	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 
    /*选择 连续/单次 转换模式 ENABLE(连续)/DISABLE(单次)*/

	ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       
    /*选择扫描模式(ENABLE)还是非扫描模式(DISABLE)*/

	ADC_InitStructure.ADC_NbrOfChannel = 1;                             
    /*通道数目:在扫描模式下,总共会用到几个通道*/

	ADC_Init(ADC1, &ADC_InitStructure);

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐