0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32的ADC详解和代码设计

GReq_mcu168 来源:玩转单片机 作者:玩转单片机 2021-02-20 14:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

01ADC简介

ADC是Analog-to-DigitalConverter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。

STM32F207的数据手册中下图看到,STM32F207VC有3个精度为12bit的ADC控制器,有16个外部通道,而144脚的STM32F207Zx和176脚的STM32F207Ix因为带PF脚,所以多8个通道,为24个外部通道。各通道的A/D转换可以单次、连续、扫描或间断执行,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。

fe6eeafe-71b8-11eb-8b86-12bb97331649.png

02STM32的ADC外设

上面说到,STM32F207有3个12bit的ADC控制器,下文将以ADC3的通道10讲解。

首先我们确认下ADC外设所在的地址总线,从STM32F207数据手册中下图看到,ADC属于APB2总线下,APB2时钟频率是60MHz。具体STM32如果通过外部25M晶振得到的60MHz的APB2,请看《STM32F207时钟系统解析》。

fecd920c-71b8-11eb-8b86-12bb97331649.png

对应GPIO,我们从STM32F207数据手册中看到,我们可以使用PC0作为ADC3的通道10。

0089603a-71b9-11eb-8b86-12bb97331649.png

这里需要说明的是,之前的文章使用其他外设时,比如《STM32PWM输出》中,寻找对应的管脚时,我们都是从STM32F207数据手册的Alternatefunctionmapping表中寻找,这是因为ADC对应的管脚使用的是Additionalfunctions,PWM对应的管脚使用的是Alternatefunctions。

区别是:

Additionalfunctions:附加,辅助功能,引脚被连接到其他模块使用,使用时直接普通配置即可,例如ADC的采用输入通道,配置为模拟输入。

Alternate functions:复用功能,即将IO口用作普通输入输出以外的功能,例如串口输入输出,使用时需要配置复用模式。

在之前的文章《STM32GPIO详解》中有如下介绍。

00e44496-71b9-11eb-8b86-12bb97331649.png

STM32标准外设库中有如下代码

typedef enum{ GPIO_Mode_IN = 0x00, /*!《 GPIO Input Mode */ GPIO_Mode_OUT = 0x01, /*!《 GPIO Output Mode */ GPIO_Mode_AF = 0x02, /*!《 GPIO Alternate function Mode */ GPIO_Mode_AN = 0x03 /*!《 GPIO Analog Mode */}GPIOMode_TypeDef;

其中GPIO_Mode_AF对应的就是Alternatefunctions:复用功能,GPIO_Mode_AN对应的就是Additionalfunctions:附加,辅助功能。

03STM32ADC框图讲解

下图是STM32ADC的结构框图,我们将其划分为7个部分进行讲解。

0122430e-71b9-11eb-8b86-12bb97331649.png

1、输入电压范围

ADC所能测量的电压范围就是VREF-≤ VIN ≤ VREF+,把VSSA 和VREF-接地,把VREF+和VDDA 接3V3,得到ADC的输入电压范围为:0~3.3V。

0163dfee-71b9-11eb-8b86-12bb97331649.png

2、输入通道

ADC的信号时通过输入通道进入单片机内部的,单片机通过ADC模块将模拟信号转换为数字信号。上图标记②的部分显示了外部的16个通道,连接的GPIO,对应的关系如上面讲解的,需要在STM32F207数据手册的STM32F20xpin and ball definitions表格中寻找。实际上STM32还有内部通道,ADC1的通道 16连接到了芯片内部的温度传感器,Vrefint 连接到了通道17。ADC2的模拟通道 16和 17连接到了内部的VSS。

3、转换通道

外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路(注入通道貌似使用不多),下面简单介绍一下俩种通道:

规则通道

规则通道顾名思义就是,最平常的通道、也是最常用的通道,平时的ADC转换都是用规则通道实的。规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。

注入通道

注入通道是相对于规则通道的,注入通道可以在规则通道转换时,强行插入转换,相当于一个“中断通道”吧。当有注入通道需要转换时,规则通道的转换会停止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到之前规则通道进行转换。最多4个通道,注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。

一个ADC控制器有多个通道,这就涉及使用多个通道进行转换就涉及到一个先后顺序的问题了,毕竟规则转换通道只有一个数据寄存器。多个通道的使用顺序分为俩种情况:规则通道的转换顺序和注入通道的转换顺序。

规则通道转换顺序

规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通道就是第x个转换,通过SQR1寄存器就能了解其转换顺序在寄存器上的实现了。

注入通道转换顺序

和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系如下:

0202410c-71b9-11eb-8b86-12bb97331649.png

需要注意的是,只有当JL=4的时候,注入通道的转换顺序才会按照JSQ1、JSQ2、JSQ3、JSQ4的顺序执行。当JL《4时,注入通道的转换顺序恰恰相反,也就是执行顺序为:JSQ4、JSQ3、JSQ2、JSQ1。

配置转换顺序的函数

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

04触发源

ADC转换的输入、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通信协议一样,都要规定一个起始信号才能传输信息,ADC也需要一个触发信号来实行模/数转换。

其一就是通过直接配置寄存器触发,通过配置控制寄存器CR2的ADON位,写1时开始转换,写0时停止转换。在程序运行过程中只要调用库函数,将CR2寄存器的ADON位置1就可以进行转换,比较好理解。

另外,还可以通过内部定时器或者外部IO触发转换,也就是说可以利用内部时钟让ADC进行周期性的转换,也可以利用外部IO使ADC在需要时转换,具体的触发由控制寄存器CR2决定。

05转换周期

可独立设置各通道采样时间

ADC会在数个ADCCLK周期内对输入电压进行采样,可使用ADC_SMPR1和ADC_SMPR2

寄存器中的SMP[2:0]位修改周期数。每个通道均可以使用不同的采样时间进行采样。

总转换时间的计算公式如下:

Tconv=采样时间+12个周期

示例:

ADCCLK = 30 MHz且采样时间=3个周期时:

Tconv= 3+12=15个周期=0.5us (APB2为60MHz时)

最小采样时间0.42us(ADC时钟=36MHz,采样周期为3周期下得到)。

06数据寄存器

转换完成后的数据就存放在数据寄存器中,但数据的存放也分为规则通道转换数据和注入通道转换数据的。

规则数据寄存器

规则数据寄存器负责存放规则通道转换的数据,通过32位寄存器ADC_DR来存放。

注入数据寄存器

注入通道转换的数据寄存器有4个,由于注入通道最多有4个,所以注入通道转换的数据都有固定的存放位置,不会跟规则寄存器那样产生数据覆盖的问题。 ADC_JDRx是 32位的,低 16位有效,高 16位保留,数据同样分为左对齐和右对齐,具体是以哪一种方式存放,由ADC_CR2的 11 位ALIGN 设置。

07中断

可以产生4种中断

0236aadc-71b9-11eb-8b86-12bb97331649.png

DMA溢出中断

当配置了DMA,且DMA溢出时产生中断

②规则通道转换完成中断

规则通道数据转换完成之后,可以产生一个中断,可以在中断函数中读取规则数据寄存器的值。这也是单通道时读取数据的一种方法。

③注入通道转换完成中断

注入通道数据转换完成之后,可以产生一个中断,并且也可以在中断中读取注入数据寄存器的值,达到读取数据的作用。

④模拟看门狗事件

当输入的模拟量(电压)不再阈值范围内就会产生看门狗事件,就是用来监视输入的模拟量是否常。

08电压转换

转换后的数据是一个12位的二进制数,我们需要把这个二进制数代表的模拟量(电压)用数字表示出来。比如测量的电压范围是0~3.3V,转换后的二进制数是x,因为12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,所以转换后的二进制数x代表的真实电压的计算方法就是:

y=3.3* x / 4096

09电路图设计

电路图很简单,可以在ADC引脚上输入不同的电压,也可以直接方便的使用滑动变阻器实现不同的电压变化。

02862152-71b9-11eb-8b86-12bb97331649.png

10代码设计

ADC_Resolution:ADC 工作模式选择,ADC分辨率ADC_ScanConvMode:ADC 扫描(多通道)或者单次(单通道)模式选择ADC_ContinuousConvMode:ADC 单次转换或者连续转换选择ADC_ExternalTrigConvEdge:ADC 外部触发极性配置ADC_ExternalTrigConv:ADC 转换触发信号选择ADC_DataAlign:ADC 数据寄存器对齐格式ADC_NbrOfConversion:ADC转换通道数目

typedef struct{ uint32_t ADC_Mode;//多重ADC模式选择 uint32_t ADC_Prescaler; //ADC预分频 uint32_t ADC_DMAAccessMode; //DMA访问模式 uint32_t ADC_TwoSamplingDelay; //2个采样阶段之间的延迟 }ADC_CommonInitTypeDef;

ADC_CommonInitTypeDef用来配置ADC_CCR寄存器的相关参数ADC外设和DMA配置代码:

/** * @brief ADC3 channel10 with DMA configuration * @param None * @retval None */void ADC3_CH10_DMA_Config(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;

/* Enable ADC3, DMA2 and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

/* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc =

DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode =

DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE);

/* Configure ADC3 Channel10 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure);

/* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure);

/* ADC3 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC3, &ADC_InitStructure);

/* ADC3 regular channel7 configuration *************************************/ ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);

/* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

/* Enable ADC3 DMA */ ADC_DMACmd(ADC3, ENABLE);

/* Enable ADC3 */ ADC_Cmd(ADC3, ENABLE);}

原文标题:STM32 ADC详解

文章出处:【微信公众号:玩转单片机】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • adc
    adc
    +关注

    关注

    100

    文章

    7378

    浏览量

    553672
  • STM32
    +关注

    关注

    2305

    文章

    11120

    浏览量

    371046

原文标题:STM32 ADC详解

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    STM32CubeIDE使用教程

    内容详细,适合转向STM32CubeIDE,它免费,没有代码容量限制
    发表于 09-02 16:16 4次下载

    STM32项目分享:智能语音台灯(机智云)

    01—项目简介1.功能详解STM32智能语音台灯(机智云)功能如下:STM32F103C8T6单片机作为主控单元按键切换模式,支持自
    的头像 发表于 07-24 18:03 1015次阅读
    <b class='flag-5'>STM32</b>项目分享:智能语音台灯(机智云)

    技术干货 | 精准测试,高效分析——ADC直方图测试技术详解

    本章详解ADC线性度测试的两种核心方法:线性斜坡法和正弦波法,涵盖DNL/INL计算、测试参数优化及德思特高精度测试方案,助您快速掌握ADC性能评估关键技术。
    的头像 发表于 07-07 10:40 705次阅读
    技术干货 | 精准测试,高效分析——<b class='flag-5'>ADC</b>直方图测试技术<b class='flag-5'>详解</b>

    第十九章 ADC——电压采集

    本章介绍W55MH32的12位逐次逼近型ADC,含18个通道(16外部+2内部),支持多种转换模式。剖析功能框图,涉及电压范围、通道分类、转换顺序等,详解初始化结构体及单通道、双重ADC代码
    的头像 发表于 06-19 17:08 1302次阅读
    第十九章 <b class='flag-5'>ADC</b>——电压采集

    ADS129x设备如何将ADC输出代码转换为电压

    要将输出代码转换为电压,必须首先计算最低有效位或LSB的值。一个LSB代表一个代码的电压权重。换句话说,输入电压必须改变一个LSB大小,以增加/减少ADC输出。
    的头像 发表于 06-18 17:20 1005次阅读
    ADS129x设备如何将<b class='flag-5'>ADC</b>输出<b class='flag-5'>代码</b>转换为电压

    STM32与机智云连接实现步骤与技巧(下篇):机智云代码移植与优化

    在《STM32与机智云连接实现步骤与技巧(上篇)》中,我们介绍了硬件连接和通信协议配置。本篇将重点讲解如何将机智云相关代码移植到STM32,完成数据上传和设备控制。我们将介绍如何在STM32
    的头像 发表于 05-23 18:10 794次阅读
    <b class='flag-5'>STM32</b>与机智云连接实现步骤与技巧(下篇):机智云<b class='flag-5'>代码</b>移植与优化

    零死角玩转STM32——系统篇

    ,从裸奔到系统,让您零死角玩转 STM32。 目录内容: 1、官方源代码介绍 2、重要文件代码详解 3、uC/OS-II 移植到 STM32
    发表于 05-21 14:08

    基于STM32C8T6控制,FSR402压力传感器+oled屏幕显示代码

    基于STM32C8T6控制,FSR402压力传感器+oled屏幕显示代码
    发表于 04-14 15:06 6次下载

    STM32项目分享:STM32智能语音分类垃圾桶

    01—项目简介1.功能详解STM32智能语音分类垃圾桶功能如下:1.STM32F103C8T6单片机系统板作为主控单元2.舵机驱动垃
    的头像 发表于 03-15 10:02 2387次阅读
    <b class='flag-5'>STM32</b>项目分享:<b class='flag-5'>STM32</b>智能语音分类垃圾桶

    STM32项目分享:STM32智能语音台灯

    —项目简介1.功能详解STM32智能语音台灯功能如下:1.STM32F103C8T6单片机系统板作为主控单元2.按键切换模式,支
    的头像 发表于 03-15 10:02 2328次阅读
    <b class='flag-5'>STM32</b>项目分享:<b class='flag-5'>STM32</b>智能语音台灯

    STM32G030F6 ADC+DMA多通道非连续采样无法正常工作怎么解决?

    配置:使用STM32G030F6 ADC外设时,ADC使用两个通道。DMA配置为循环模式,ADC扫描模式+非连续采样。 问题:初始化阶段能进一次DMA传输完成中断,在main函数中再次
    发表于 03-12 07:10

    STM32CubeMX用于STM32配置和初始化C代码生成

    电子发烧友网站提供《STM32CubeMX用于STM32配置和初始化C代码生成.pdf》资料免费下载
    发表于 02-26 17:32 678次下载

    INA226 stm32的demo代码和规格书

    文档包含in226的规格书和stm32的demo代码
    发表于 02-08 17:32 10次下载

    STM32H743的高精度定时器触发ADC采样

    STM32Cubemx配置如下: Master Timer配置 Timer A配置 Timer B配置 Trigger 配置 ADC1配置 ADC2配置 启动的代码
    发表于 01-09 15:49

    ADC124S051按照datasheet时序写的代码无法达到驱动时钟8Mhz,怎么解决?

    我在用stm32F103RCT6驱动ADC124S051,可以驱动读数正确没有问题。 问题是:如果想达到500Khz的采样率(单通道工作),必须给ADC的clk提供8Mhz,我按照
    发表于 12-06 06:21