当前位置:首页 > 单片机 > 单片机
[导读] 一、Adc特性1.1 Adc概述Stm32的Adc具有12位的精度,共有16个外部通道和2个内部通道。不同通道的 A/D 转换可以在单一、连续、扫描或者间断模式下进行。它的其他特性还包括支持模拟看门狗和DMA。1.2 Adc初

一、Adc特性1.1 Adc概述

Stm32的Adc具有12位的精度,共有16个外部通道和2个内部通道。不同通道的 A/D 转换可以在单一、连续、扫描或者间断模式下进行。它的其他特性还包括支持模拟看门狗和DMA。

1.2 Adc初始化

和大多数外设一样,Adc在使用前必须初始化时钟源,并从掉电模式唤醒该设备。建议在初始化Adc后立即运行一次校准,以减少准确性错误。

1.3 通道的选择

对于16个可复用的通道,可以将通道分成两种类型的组。常规组和注入组,组序列保存在寄存器ADC_SQRx和ADC_JSQR中。常规组可以包含最多16个通道,注入组最多包含4个通道。

注入组可以理解为常规组的一种中断,当注入组的采集被触发时,常规组的采集会被中断。直到注入组采集完之后,常规组才开始继续采集。

如果只想采集一个通道的数值,只将一个通道写入组里。想采集多个通道的数值,就将多个通道写入组里。当一个组包含多个通道时,要开启扫描模式, adc对组中的每一个通道根据寄存器里的序列进行一次转换。

1.4 触发方式

要触发一次ad转换,可以由内部软件触发,或者外部触发。要不要使用外部触发由控制寄存器里的EXTTRIG位来指定。

内部触发自然是通过写控制寄存器里的相应位来触发。而外部触发则可以有八种触发源可供选择,所以常规组和注入组在控制寄存器里各有3个位来指定哪个外部事件可触ad转换。外部触发源一般是定时器或者是外部中断线事件。

1.5 单一和连续

一次采集被由内部或者外部触发后,可以只采集一次,也可以一直连续采集。如果是一组通道,采集完最后一个通道时,会回到序列中的第一个通道继续采集。

每次采集完成后都会将转换后的数据存在一个寄存器里,并置位采集完成位,根据设定产生中断。

1.6 间断模式

间断模式是将常规和注入组里的序列再切割成更小的组。

比如一个常规组含有9个频道,利用间断模式并设置控制寄存器的位,可以将9个频道分成3组。这样一次触发只会采集3个通道,而不是采集9个通道,连续触发3次才能采集完9个通道。

1.7 采样频率

Adc模块允许对采样频率进行修改,以满足对采样速率的不同需求。考虑到Adc时序里需要一个稳定期,实际使用时还要面临各种DMA请求和中断嵌套,建议不要使用过高的采样频率,并考虑系统运行时负载的临界值。

可以通过修改ADC_SMPR1 和 ADC_SMPR2 寄存器中的 SMP[2:0]来设置采样频率。

1.8 模拟看门狗

设置相应的寄存器可以为Adc指定上下阀值,当采集到电压值超过阀值时,系统会产生中断。

1.9 DMA

当在扫描模式和连续模式下,显然每次都将保存采集值的寄存器数据读出来处理是来不及的。设置Adc的DMA使能,可以让每次转换过的数值都经DMA传到指定的内存空间里。

1.10 字节序

对于转换后的数据,可以设置左对齐或是右对齐,以支持不同的处理和传输的需要。

1.11 双adc模式

具有两个adc的设备可以使用的模式。在这种模式下,通常adc1做主设备,adc2做从设备。从设备的触发有主设备来发起。

主设备的常规组/注入组的触发成为从设备触发的条件,而主设备可以被设置为等待从设备采集一段时间后才开始采集,双adc模式下有许多种方式可以支持不同的主从同步。

二、Adc的库函数

HAL里的Adc函数相较stmlib里的结构更加简单,它的私有成员就不做叙述了,因为如何实现HAL的结构性代码并不是我们关心的问题。这里只描述一下Adc的输出函数。

2.1 初始化函数

同GPIO的初始化一样,Adc的初始化使用几个结构体来进行。不同的是由于Adc较之GPIO更加复杂,所以对Adc属性的描述分成了几个不同的结构体。

ADC_InitTypeDef结构体原型

typedef struct

{

uint32_t DataAlign;

uint32_t ScanConvMode;

uint32_t ContinuousConvMode;

uint32_t NbrOfConversion;

uint32_t DiscontinuousConvMode;

uint32_t NbrOfDiscConversion;

uint32_t ExternalTrigConv;

}ADC_InitTypeDef;

从上到下依次描述:

字节序、是否使用扫描模式、单一/连续模式、常规组序列、是否使用间断模式、间断模式中一个组的通道数量、外部触发的方式。

HAL_ADC_init函数的参数是一个指向ADC_HandleTypeDef结构体的指针,这个结构体的第一个元素,就是一个指向ADC_InitTypeDef结构体的指针。所以初始化ADC前,要先定义一个ADC_InitTypeDef结构体,赋值给每个成员变量。然后把它的地址写入一个ADC_HandleTypeDef结构体的成员。

ADC_InitTypeDef结构体原型

/**

* @brief ADC handle Structure definition

*/

typedef struct

{

ADC_TypeDef *Instance; /*!< Register base address */


ADC_InitTypeDef Init; /*!< ADC required parameters */


__IO uint32_t NbrOfConversionRank ; /*!< ADC conversion rank counter */


DMA_HandleTypeDef *DMA_Handle; /*!< Pointer DMA Handler */


HAL_LockTypeDef Lock; /*!< ADC locking object */


__IO HAL_ADC_StateTypeDef State; /*!< ADC communication state */


__IO uint32_t ErrorCode; /*!< ADC Error code */

}ADC_HandleTypeDef;


可以看到它除了包含一个指向ADC_InitTypeDef的指针之外,还包含指向寄存器的指针、互斥锁、一个描述状态的变量、一个保存错误代码的变量、一个指向DMA结构体的指针。所有与对Adc进行操作的函数都使用这个结构体的指针作为参数。

HAL有一个自己的锁,这样即使程序员在多个线程里没有使用信号量来对外设进行读写控制,HAL层也会独立保证对外设进行特殊操作时的原子性。

ADC_InitTypeDef结构体只描述了一部分Adc的属性。所以有ADC_ChannelConfTypeDef结构体来描述单个通道在组序列里的排序位置及它的工作速率,ADC_AnalogWDFConfTypeDef结构体来描述一个模拟看门狗的阀值和中断模式。而HAL_ADC_ConfigChannel和HAL_ADC_AnalogWDGconfig()函数用来处理这两个结构体。

在初始化Adc时钟和使能设备后,至少需要设置四个结构体,调用三个函数,才能将Adc初始化完毕。

2.2 Adc的操作

开始与结束

HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);

HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc);


HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);

HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);


HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);

HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc);


HAL_ADC_START()、HAL_ADC_START_DMA()、HAL_ADC_START_IT()三个函数分别表示开始一次采集(直接软触发或者等待外部触发),后两个函数表示数据用DMA传输和使能中断。中断处理函数是HAL_ADC_IRQHander()。


callback函数


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc);

void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc);

void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc);


Adc中断、DMA传输、看门狗超过阀值、发生Adc错误,这些函数返回前都调用了Callback函数,用来在非中断模式下处理Adc数据,如果想进行一些操作可以直接修改Callback函数。


取转换后的数值


/* ADC retrieve conversion value intended to be used with polling or interruption */

uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);


HAL_ADC_GetValue()用来区寄存器值。


等待函数


HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);

HAL_StatusTypeDef HAL_ADC_PollForEvent(ADC_HandleTypeDef* hadc, uint32_t EventType, uint32_t Timeout);

1

2

在非中断和DMA模式下,采集数据需要等待一次采集的完成,或者某些事件的发生。HAL_ADC_PollForConversion函数和HAL_ADC_PollForEvent函数用来等待这两者。


三、例子


只用一个通道采集的初始化例子

static void ADC_Config(void)

{

ADC_ChannelConfTypeDef sConfig;

ADC_AnalogWDGConfTypeDef AnalogWDGConfig;


/* Configuration of ADCx init structure: ADC parameters and regular group */

AdcHandle.Instance = ADCx;


AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;

AdcHandle.Init.ScanConvMode = ADC_SCAN_DISABLE;

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

系统设计师通常侧重于为应用选择最合适的数据转换器,在向数据转换器提供输入的时钟发生器件的选择上往往少有考虑。然而,如果不慎重考虑时钟发生器、相位噪声和抖动性能,数据转换器、动态范围和线性度性能可能受到严重的影响。

关键字: 时钟发生器 adc

专注于引入新品并提供海量库存的电子元器件分销商贸泽电子 (Mouser Electronics) 即日起开始备货TI TLV915x运算放大器和ADS7128 12位模数转换器 (ADC)。

关键字: 贸泽 adc 模数转换器

自然界产生的信号,都是模拟信号,比如我们说话的声音,看到的景色,感受到的温度、湿度、压力、流速、光、电、风及个人的呼吸、血压、体温、心跳、体重、血糖,体脂等等。这些模拟信号都得最终放在电脑,手机等数字领域进行处理,存储或...

关键字: adc 模拟信号

为增进大家对ADC的认识和了解,本文将基于两方面对ADC予以介绍:1.什么是并行ADC,并行ADC的基本原理是什么?2.流水线ADC与其它ADC有何区别。

关键字: adc 指数 流水线adc

ADC是电子电路中常用器件,大家对于ADC也较为熟悉。为增进大家对ADC的了解,本文将对高速ADC以及流水线ADC结构予以介绍。

关键字: adc 指数 流水线adc

ADC也即数模转换器,在现实中,ADC具备重要作用。对于ADC,电子相关专业的朋友想必相当熟悉。为增进大家对ADC的认识,本文将对管道ADC以及其原理予以介绍。

关键字: adc 指数 管道adc

设计人员有各种模数转换器(ADC)可以选择,数字数据输出类型是选择过程中需要考虑的一项重要参数。

关键字: 高速转换器 数字数据 adc

ADC包括三个基本功能:抽样、量化和编码。如何实现这三个功能,就决定了ADC的形式和性能。

关键字: 模数转换 adc

自然界产生的信号,都是模拟信号,比如我们说话的声音,看到的景色,感受到的温度、湿度、压力、流速、光、电、风及个人的呼吸、血压、体温、心跳、体重、血糖,体脂等。这些模拟信号都得最终放在电脑,手机等数字领域进行处理,存储或者...

关键字: adc 电源设计

在设计ADC电路时,一个常见的问题是“如何在过压条件下保护ADC输入”。那么,在过压情形中,可能出现哪些问题?发生的频率又是怎样的?有木有潜在的补救措施?

关键字: adc 电源设计
关闭