正点原子STM32F103学习笔记(十一)——ADC&DAC

ADC(Analog-to-Digital Converter)

STM32F10x ADC特点

  • 12位(位数决定精度)逐次逼近型的模拟数字转换器。
  • 最多带3个ADC控制器(每个控制器有多个通道)
  • 最多支持18个通道,可最多测量16个外部和2个内部信号源。
  • 支持单次和连续转换模式
  • 转换结束,注入转换结束,和发生模拟看门狗事件时产生中断。
  • 通道0到通道n的自动扫描模式
  • 自动校准
  • 采样间隔可以按通道编程
  • 规则通道和注入通道均有外部触发选项
  • 转换结果支持左对齐或右对齐方式存储在16位数据寄存器
  • ADC转换时间:最大转换速率 1us。(最大转换速度为1MHz,在ADCCLK=14M,采样周期为1.5个ADC时钟下得到。)
  • ADC供电要求:2.4V-3.6V(通常0-3.3)
  • ADC输入范围: V R E F ≤ V I N ≤ V 0 R E F + V_{REF}≤ V_{IN} ≤ V_{0REF+} VREFVINV0REF+

STM32F10x系列芯片ADC通道和引脚对应关系

正点原子STM32F103学习笔记(十一)——ADC&DAC_第1张图片

ADC引脚

正点原子STM32F103学习笔记(十一)——ADC&DAC_第2张图片

模拟参考负极: 一般接地GND
模拟参考正极: 接VDDA
模拟电源: 接数字电源
模拟电源地: 接数字电源地
模拟输入信号: 不可超过模拟参考正极

STM32通道组

  • 规则通道组: 相当正常运行的程序。最多16个通道。
    规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中
  • 注入通道组: 相当于中断。 最多4个通道。
    注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中
    正点原子STM32F103学习笔记(十一)——ADC&DAC_第3张图片

单次转化&连续转换

正点原子STM32F103学习笔记(十一)——ADC&DAC_第4张图片

正点原子STM32F103学习笔记(十一)——ADC&DAC_第5张图片

ADC时钟配置

不要让ADC时钟超过14MHz,否则可能不准。

RCC_ADCCLKConfig(RCC_PCLK2_Div6); 

扫描模式在最后一个通道转换结束才会产生中断

ADC的采样时间

正点原子STM32F103学习笔记(十一)——ADC&DAC_第6张图片

最小转换时间1us(ADC时钟=14MHz,采样周期为1.5周期下得到)

常用库函数

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);//初始化函数
void ADC_DeInit(ADC_TypeDef* ADCx)
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);//使能函数
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);//中断配置函数
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//软件其中转换
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);//配置规则通道
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

//下面两个是校准代码,直接复制即可
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

ADC初始化函数ADC_Init

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

typedef struct
{
  uint32_t ADC_Mode;//ADC模式:配置ADC_CR1寄存器的位[19:16]  :DUALMODE[3:0]位
  FunctionalState ADC_ScanConvMode; //是否使用扫描模式。ADC_CR1位8:SCAN位 
  FunctionalState ADC_ContinuousConvMode; //单次转换OR连续转换:ADC_CR2的位1:CONT
  uint32_t ADC_ExternalTrigConv;  //触发方式:ADC_CR2的位[19:17] :EXTSEL[2:0]                
  uint32_t ADC_DataAlign;   //对齐方式:左对齐还是右对齐:ADC_CR2的位11:ALIGN         
  uint8_t ADC_NbrOfChannel;//规则通道序列长度:ADC_SQR1的位[23:20]: L[3:0]       
}ADC_InitTypeDef;

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//不开启扫描 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次转换模式,一个通道不需要开启
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发软件 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure);	

ADC使能函数 ADC_Cmd();

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1

ADC使能软件转换函数 ADC_SoftwareStartConvCmd

不使用外部触发可以使用软件转换

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能ADC1的软件转换启动

ADC 规则通道配置函数ADC_RegularChannelConfig

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx,uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime);

ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1,ADC_SampleTime_239Cycles5 );
//ADC1的通道1在规则序列里的第一个转换,单通道单词转换

ADC 获取转换结果函数ADC_GetConversionValue

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

ADC_GetConversionValue(ADC1);//获取ADC1转换结果

实验

实验目的: ADC1的通道1(PA1)进行单次转化

  1. 开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
GPIO_Init();      
APB2PeriphClockCmd();
  1. 复位ADC1,同时设置ADC1分频因子。
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_DeInit(ADC1);
  1. 初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
  1. 使能ADC并校准。
ADC_Cmd(ADC1, ENABLE);
  1. 配置规则通道参数:
ADC_RegularChannelConfig();
  1. 开启软件转换:
ADC_SoftwareStartConvCmd(ADC1);
  1. 等待转换完成,读取ADC值。
ADC_GetConversionValue(ADC1);

代码

adc.c

#include "adc.h"
#include "delay.h"

//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3																	   
void  Adc_Init(void)
{ 	
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;

	//PA1 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_InitStructure.GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );	  //使能GPIO1,ADC1通道时钟
 
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC时钟,设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

	//初始化ADC参数
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//扫描模式(是否连续转换)模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发设置,转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	
	//校准,直接复制就行
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	ADC_StartCalibration(ADC1);	 //开启AD校准
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
}	

//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//配置规则通道参数ADC1,ADC通道为ch,在规则序列中第一个转换,采样时间为239.5周期	  			    
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//开启(使能)指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束,EOC转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t

adc.h

#ifndef __ADC_H
#define __ADC_H	
#include "sys.h"

void Adc_Init(void);//初始化,步骤1-4
u16  Get_Adc(u8 ch); //获取某个通道转换结果,步骤5-7
u16 Get_Adc_Average(u8 ch,u8 times); //多次调用Get_Adc取平均值
 
#endif 

DAC数模转换

原理

  • 2个DAC转换器:每个转换器对应1个输出通道
  • 8位或者12位单调输出
  • DAC工作在12位模式时,数据可以设置成左对齐或右对齐。
  • 双DAC通道同时或者分别转换
  • 每个通道都有DMA功能
  • 同步更新功能
  • 噪声波形生成
  • 三角波形生成
  • 12位数字输入
  • 电压输出型的DAC
  • DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。

原理图

正点原子STM32F103学习笔记(十一)——ADC&DAC_第7张图片

VDDA和VSSA为DAC模块模拟部分的供电。
Vref+则是DAC模块的参考电压。
DAC_OUTx就是DAC的输出通道了(对应DAC_0UT1->PA4或者DAC_OUT2->PA5引脚)。
正点原子STM32F103学习笔记(十一)——ADC&DAC_第8张图片

正点原子STM32F103学习笔记(十一)——ADC&DAC_第9张图片

输出电压计算

正点原子STM32F103学习笔记(十一)——ADC&DAC_第10张图片

12位 0-4095

步骤

  1. 开启 PA 口时钟,设置 PA4 为模拟输入。
RCC_APB2PeriphClockCmd(RCC_APB2Per iph_GPIOA, ENABLE ); 使能 PORTA 时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 模拟输入
  1. 使能 DAC1 时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Peri ph_DAC, ENABLE ); 使能 DAC 通道时钟
  1. 初始化 DAC, 设置 DAC 的工作模式。
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct)

typedef struct
{
uint32_t DAC_Trigger;  //是否外部触发
uint32_t DAC_WaveGeneration;  //三角波形生成
uint32_t DAC_LFSRUnmask_TriangleAmplitude;//噪声波三角波生成
uint32_t DAC_OutputBuffer;//设置输出缓存控制位,不使用输出缓存,
}DAC_InitTypeDef
  1. 使能 DAC 转换通道
DAC_Cmd(DAC_Channel_1, ENABLE); // 使能 DAC1
  1. 设置 DAC 的输出值。
DAC_SetChannel1Data(DAC_Align_12b_R, 0);//输出0
DAC_ GetDataOutputValue(DAC_Channel_1);//获取输出值

程序

{
  
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );	  //使能PORTA通道时钟
   	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );	  //使能DAC通道时钟 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 		 //模拟输入
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_4)	;//PA.4 输出高
					
	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能 TEN1=0
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
    DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
  
    DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值

}


//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
	float temp=vol;
	temp/=1000;
	temp=temp*4096/3.3;
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}

你可能感兴趣的:(STM32,stm32,单片机,嵌入式)