STM32单片机入门学习笔记——AD

笔记整理自B站UP主江科大自化协教程《STM32入门教程-2023持续更新中》,所用单片机也为教程推荐单片机。

STM32的ADC是12位的,所以AD结果最大值是4095,也就是2^12-1

DAC的应用主要是在波形生成这些领域,比如信号发生器、音频解码芯片等

本型号STM32也没有DAC的外设

ADC简介

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

逐次逼近型ADC

逐次逼近的含义:二分法,0~255取中间128,与128比较大小,如果大则在128~255之间选择…

STM32 ADC框图

ADC基本结构

输入通道

转换模式

单次转换,非扫描模式

在非扫描的模式下,只有第一个序列1的位置有效,同时选中一组的方式就退化为简单地选中一个的方式。转换完成结果存放在数据寄存器中,EOC标志位置1。

连续转换,非扫描模式

非扫描模式,菜单列表还是只用第一个,与单次转换不同的是,它在一次转换结束之后不会停止,而是立刻开始下一轮的转换,然后一直持续下去。

单次转换,扫描模式

单次转换,每触发一次,转换结束后就会停下来,下次转换就得再触发才能开始。

扫描模式:用到“菜单”模式,每个位置是通道几可以任意指定,并且也是可以重复的。转换的结果都放在数据寄存器中,为了防止数据被覆盖,需要用DMA及时将数据挪走,通道全部转换完成后,产生EOC信号,转换结束。

连续转换,扫描模式

扫描模式:一次转换完成后,立刻开始下一次的转换

触发控制

数据对齐

一般使用的都是右对齐

转换时间

AD转换的步骤:采样,保持,量化,编码

采样时间短,速度快;采样时间长,避免毛刺干扰

STM32 ADC的总转换时间为:TCONV = 采样时间 + 12.5个ADC周期

例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期

TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

校准

ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差

建议在每次上电后执行一次校准

启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

硬件电路

PA0~PA7、PB0、PB1这10个引脚是ADC的10个通道

AD单通道代码讲解

第一步:开启RCC时钟,包括ADC和GPIO时钟,ADCCLK的分频器

第二步:配置GPIO,把需要用的GPIO配置成模拟输入的模式

第三步:配置多路开关

第四步:配置ADC转换器(单次转换or多次转换、扫描or非扫描、有几个通道、…)

RCC_ADCCLKConfig——配置ADCCLK分频器,可以对APB2的72MHz时钟选择2、4、6、8分频,输入到ADCCLK,stm32f10x_rcc.h

再介绍一个ADC的相关函数,stm32f10x_adc.h

ADC_DeInit——恢复缺省配置

ADC_Init——初始化

ADC_StructInit——结构体初始化

ADC_Cmd——给ADC上电(开关控制)

ADC_DMACmd——开启DMA输出信号

ADC_ITConfig——中断输出控制

ADC_ResetCalibration——复位校准

ADC_GetResetCalibrationStatus——获取复位校准状态

ADC_StartCalibration——开始校准

ADC_GetCalibrationStatus——获取开始校准状态

ADC_SoftwareStartConvCmd——ADC软件开始转换控制,给SWSTRAT位置1

ADC_GetSoftwareStartConvStatus——ADC获取软件开始转换状态,返回SWSTART的状态,ADC_GetFlagStatus——获取标志位状态

ADC_DiscModeChannelCountConfig——每隔几个通道间断一次

ADC_DiscModeCmd——是否启用间断模式

ADC_RegularChannelConfig——ADC规则组通道配置

ADC_ExternalTrigConvCmd——ADC外部触发转化控制

ADC_GetConversionValue——ADC获取转换值

ADC_GetDualModeConversionValue——ADC获取双模式转换值

第一步——开启时钟

//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步——配置ADCCLK

//配置ADCCLK
RCC_ADCCLKConfig(RCC_PCLK2_Div6);           //72MHz / 6 = 12MHz

第三步——配置GPIO

IO口模拟输入

//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;               //模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                    //PA0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

第四步——选择规则组的输入通道

在规则组菜单列表的第一个位置,写入通道0

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

第五步——结构体初始化ADC

//结构体初始化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;                        //ADC工作模式
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitStructure);

第六步——开启ADC电源

//开启ADC电源
ADC_Cmd(ADC1, ENABLE);

第七步——ADC校准

//ADC校准
ADC_ResetCalibration(ADC1);                            //复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);

源代码

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
    //开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    //配置ADCCLK
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);           //72MHz / 6 = 12MHz
    
    //配置GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;               //模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                    //PA0
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //选择规则组的输入通道
    /*
    在规则组菜单列表的第一个位置,写入通道0
    */
    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;                        //ADC工作模式
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    //开启ADC电源
    ADC_Cmd(ADC1, ENABLE);
    
    //ADC校准
    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);
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC1);
}

经验总结

AD多通道代码讲解

区别于单通道

源代码

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
    //开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    //配置ADCCLK
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);           //72MHz / 6 = 12MHz
    
    //配置GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;               //模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;    //PA0
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //结构体初始化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;                        //ADC工作模式
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    //开启ADC电源
    ADC_Cmd(ADC1, ENABLE);
    
    //ADC校准
    ADC_ResetCalibration(ADC1);                            //复位校准
    while(ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
    //选择规则组的输入通道
    /*
    在规则组菜单列表的第一个位置,写入通道0
    */
    ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
    
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC1);
}

感谢抽出宝贵时间阅读的各位小读者们,创作不易,如果感觉有帮助的话,帮忙点个赞再走吧!你们的支持是我创作的动力,希望能带给大家更多优质的文章。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32单片机入门学习笔记——AD

发表评论