一、ADC简介
以STM32f103 系列为例,3 个 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道。其中ADC1 和 ADC2 都有 16 个外部通道, ADC3 根据 CPU 引脚的不同通道数也不同,一般都有8 个外部通道。 ADC 的模式非常多,功能非常强大,具体的我们在功能框图中分析每个部分的功能。
ADC功能框图
图1 单个ADC功能框图
①电压输入范围
ADC 输入范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定。
在设计原理图的时候一般把 VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输入电压范围为: 0~3.3V。
如果想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,可以在外部加一个电压调理电路,把需要转换的电压抬升或者降压到 0~3.3V,这样 ADC 就可以测量。
②输入通道
确定好 ADC 输入电压之后,那么电压怎么输入到 ADC?这里我们引入通道的概念,STM32 的 ADC 多达 18 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0、ADCx_IN1…ADCx_IN5。这 16 个通道对应着不同的 IO 口, 具体是哪一个 IO 口可以从手册查询到。其中 ADC1/2/3 还有内部通道: ADC1 的通道 16 连接到了芯片内部的温度传感器, Vrefint 连接到了通道 17。 ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。ADC3 的模拟通道 9、 14、 15、 16 和 17 连接到了内部的 VSS。
图2 STM32F103VET6 ADC 通道
外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16路,注入通道最多有 4 路。那这两个通道有什么区别?在什么时候使用?
规则通道
规则通道:顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通道,或者应该说我们用到的都是这个通道。
注入通道
注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。
③转换顺序
规则序列
规则序列寄存器有 3 个,分别为 SQR3、 SQR2、 SQR1。 SQR3 控制着规则序列中的第一个到第六个转换,对应的位为: SQ1[4:0]~SQ6[4:0],第一次转换的是位 4:0 SQ1[4:0],如果通道 16 想第一次转换,那么在 SQ1[4:0]写 16 即可。 SQR2 控制着规则序列中的第 7 到第12 个转换,对应的位为: SQ7[4:0]~SQ12[4:0],如果通道 1 想第 8 个转换,则 SQ8[4:0]写 1即可。 SQR1 控制着规则序列中的第 13 到第 16 个转换,对应位为: SQ13[4:0]~SQ16[4:0],如果通道 6 想第 10 个转换,则 SQ10[4:0]写 6 即可。具体使用多少个通道,由 SQR1 的位L[3:0]决定,最多 16 个通道。
图3 规则序列寄存器
注入序列
注入序列寄存器 JSQR 只有一个,最多支持 4 个通道,具体多少个由 JSQR 的 JL[2:0]决定。如果 JL 的 值小于 4 的话,则 JSQR 跟 SQR 决定转换顺序的设置不一样,第一次转换的不是 JSQR1[4:0],而是 JCQRx[4:0] , x = (4-JL),跟 SQR 刚好相反。如果 JL=00(1 个转换),那么转换的顺序是从 JSQR4[4:0]开始,而不是从 JSQR1[4:0]开始。当 JL 等于 4 时,跟 SQR 一样。
图4 注入序列寄存器
④触发源
ADC 转换可以由ADC 控制寄存器 2: ADC_CR2 的 ADON 这个位来控制,写 1 的时候开始转换,写 0 的时候停止转换,这个是最简单也是最好理解的开启 ADC 转换的控制方式。
除了这种庶民式的控制方法, ADC 还支持触发转换,这个触发包括内部定时器触发和外部 IO 触发。触发源有很多,具体选择哪一种触发源,由 ADC 控制寄存器 2:ADC_CR2 的EXTSEL[2:0]和 JEXTSEL[2:0]位来控制。 EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由ADC 控制寄存器 2:ADC_CR2 的 EXTTRIG 和 JEXTTRIG 这两位来激活。其中 ADC3 的规则转换和注入转换的触发源与 ADC1/2 的有所不同,在框图上已经表示出来。
⑤转换时间
ADC 时钟
ADC 输入时钟 ADC_CLK 由 PCLK2 经过分频产生,最大是 14M,分频因子由 RCC 时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,注意这里没有 1 分频。一般我们设置 PCLK2=HCLK=72M。
采样时间
ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过 ADC采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置, ADC_SMPR2 控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是 1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为 1.5个周期,这里说的周期就是 1/ADC_CLK。
ADC 的转换时间跟 ADC 的输入时钟和采样时间有关,公式为: Tconv = 采样时间 +12.5 个周期。 当 ADCLK = 14MHZ (最高),采样时间设置为 1.5 周期(最快),那么总的转换时间(最短) Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。
一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us,这个才是最常用的。
⑥中断
转换结束中断
数据转换结束后,可以产生中断,中断分为三种:规则通道转换结束中断,注入转换通道转换结束中断,模拟看门狗中断。其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断
服务程序。
模拟看门狗中断
当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模拟看门狗中断,其中低阈值和高阈值由 ADC_LTR 和 ADC_HTR 设置。例如我们设置高阈值是 2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。
DMA 请求
规则和注入通道转换结束后,除了产生中断外,还可以产生 DMA 请求,把转换好的数据直接存储在内存里面。要注意的是只有 ADC1 和 ADC3 可以产生 DMA 请求。有关DMA 请求需要配合《STM32F10X-中文参考手册》 DMA 控制器这一章节来学习。一般我们在使用 ADC 的时候都会开启 DMA 传输。
电压转换
模拟电压经过 ADC 转换后,是一个 12 位的数字值,如果通过串口以 16 进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。
我们一般在设计原理图的时候会把 ADC 的输入电压范围设定在: 0~3.3v,因为 ADC是 12 位的,那么 12 位满量程对应的就是 3.3V, 12 位满量程对应的数字值是: 2^12。数值0 对应的就是 0V。 如果转换后的数值为 X , X 对应的模拟电压为 Y,那么会有这么一个等式成立: 2^12 / 3.3 = X / Y, => Y = (3.3 * X ) / 2^12。
二、ADC独立模式单通道中断采集实验
初始 ADC 用到的 GPIO;
设置 ADC 的工作参数并初始化;
设置 ADC 工作时钟;
设置 ADC 转换通道顺序及采样时间;
配置使能 ADC 转换完成中断,在中断内读取转换完数据;
使能 ADC;
使能软件触发 ADC 转换。
头文件相关宏定义
/*************ADC GPIO相关宏定义**************/
#define ADC_GPIO_APBxCLock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
/*************ADC 相关宏定义**************/
//选择ADC1
#define ADC_APBxCLock_FUN RCC_APB2PeriphClockCmd
#define ADC_CLK RCC_APB2Periph_ADC1
#define ADCx ADC1
//根据ADC引脚图 PC1为通道11
#define ADC_CHANNEL ADC_Channel_11
// ADC 中断相关宏定义
#define ADC_IRQ ADC1_2_IRQn
#define ADC_IRQHandler ADC1_2_IRQHandler
ADC配置
__IO uint16_t ADC_ConvertedValue;
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开ADC IO端口时钟
ADC_GPIO_APBxCLock_FUN(ADC_GPIO_CLK, ENABLE);
// 配置ADC IO引脚模式为模拟输入模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
// ADC为模拟输入,无需配置速度
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
// 打开ADC时钟
ADC_APBxCLock_FUN(ADC_CLK,ENABLE);
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 只使用一个 ADC,属于独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 转换通道 1 个
ADC_InitStructure.ADC_NbrOfChannel = 1;
// 禁止扫描模式,多通道才要,单通道不需要
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADCx, &ADC_InitStructure);
//配置ADC-CLK为6分频 72/6=12M
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
// 配置 ADC 通道转换顺序为 1,第一个转换,采样时间为 55.5 个时钟周期
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
//开启ADC转换结束中断,在中断服务函数中读取转换值☆
ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);//EOC--规则通道
//开启ADC,并开始转换
ADC_Cmd(ADCx, ENABLE);
//初始化ADC校准寄存器
ADC_ResetCalibration(ADCx);
//等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADCx));
/***********ADC校准开启(不开启也可)**********/
//ADC开始校准
ADC_StartCalibration(ADCx);
//等待校准完成
while(ADC_GetCalibrationStatus(ADCx));
//由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
ADC_NVIC_Config();
}
‘main函数’
extern __IO uint16_t ADC_ConvertedValue;
float ADC_ConvertedValueLocal;
int main(void)
{
USART_Config();
//ADC初始化
ADCx_Init();
printf("rn ----这是一个ADC实验(DMA传输)----rn");
while(1)
{
ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3;
printf("rn The current AD value = 0x%04X rn",
ADC_ConvertedValue);
printf("rn The current AD value = %f V rn",
ADC_ConvertedValueLocal);
printf("rnrn");
//简易延时
Delay(0xffffee);
}
}
三、ADC独立模式多通道DMA采集实验
多通道与单通道ADC,DMA传输区别
IO口定义
DMA存储器地址与地址增量
DMA缓冲区数量
ADC转化通道数量
ADC扫描模式
ADC转化顺序与采样时间
ADC相关宏定义
/*************ADC GPIO相关宏定义**************/
#define ADC_GPIO_APBxCLock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
/*************ADC 相关宏定义**************/
//选择ADC1
#define ADC_APBxCLock_FUN RCC_APB2PeriphClockCmd
#define ADC_CLK RCC_APB2Periph_ADC1
#define ADCx ADC1
//C1为通道11
#define ADC_CHANNEL ADC_Channel_11
// ADC 中断相关宏定义
#define ADC_IRQ ADC1_2_IRQn
#define ADC_IRQHandler ADC1_2_IRQHandler
// ADC1 对应 DMA1 通道 1, ADC3 对应 DMA2 通道 5, ADC2 没有 DMA 功能
#define ADC_DMA_CHANNEL DMA1_Channel1
#define ADC_DMA_APBxClock_FUN RCC_AHBPeriphClockCmd
#define ADC_DMA_CLK RCC_AHBPeriph_DMA1
// 转换通道个数
#define CHANNELNUM 5
#define ADC_PIN1 GPIO_Pin_0
#define ADC_CHANNEL1 ADC_Channel_10
#define ADC_PIN2 GPIO_Pin_1
#define ADC_CHANNEL2 ADC_Channel_11
#define ADC_PIN3 GPIO_Pin_3
#define ADC_CHANNEL3 ADC_Channel_13
#define ADC_PIN4 GPIO_Pin_4
#define ADC_CHANNEL4 ADC_Channel_14
#define ADC_PIN5 GPIO_Pin_5
#define ADC_CHANNEL5 ADC_Channel_15
ADC相关配置
__IO uint16_t ADC_ConvertedValue[CHANNELNUM] = {0,0,0,0,0};
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开ADC IO端口时钟
ADC_GPIO_APBxCLock_FUN(ADC_GPIO_CLK, ENABLE);
// 配置 ADC IO 引脚模式
GPIO_InitStructure.GPIO_Pin = ADC_PIN1|ADC_PIN2|ADC_PIN3|ADC_PIN4|ADC_PIN5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// ADC为模拟输入,无需配置速度
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
// DMA的时钟
ADC_DMA_APBxClock_FUN(ADC_DMA_CLK, ENABLE);
// 打开ADC时钟
ADC_APBxCLock_FUN(ADC_CLK,ENABLE);
/*****************DMA模式配置*******************/
// 复位 DMA 控制器
DMA_DeInit(ADC_DMA_CHANNEL);
// 配置 DMA 初始化结构体
// 外设基址为: ADC 数据寄存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&( ADCx->DR ));
// 存储器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
// 数据源来自外设
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 缓冲区大小,应该等于数据目的地的大小
DMA_InitStructure.DMA_BufferSize = CHANNELNUM;
// 外设寄存器只有一个,地址不用递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 存储器地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据大小为半字,即两个字节
DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;
// 内存数据大小也为半字,跟外设数据大小相同
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
// 循环传输模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// DMA 传输通道优先级为高,当使用一个 DMA 通道时,优先级设置不影响
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止存储器到存储器模式,因为是从外设到存储器
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 初始化 DMA
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能 DMA 通道
DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
/*****************ADC模式配置*******************/
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 只使用一个 ADC,属于独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 转换通道 1 个
ADC_InitStructure.ADC_NbrOfChannel = CHANNELNUM;
// 扫描模式,多通道才要,单通道不需要
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_Init(ADCx, &ADC_InitStructure);
上一篇:FreeRTOS笔记(一)
下一篇:STM32笔记(十二)---SPI读写FLASH
推荐阅读最新更新时间:2024-11-13 10:22
推荐帖子
- 基于MCU的家庭防盗报警系统
- 基于MCU的家庭防盗报警系统基于MCU的家庭防盗报警系统
- fish001 微控制器 MCU
- 【玄铁杯第三届RISC-V应用创新大赛】LicheePi 4A (3.5)ncnn的使用BUG补充
- 上一篇文章笔者试用NCNN出了大问题,模型训练完不能进行图像识别【玄铁杯第三届RISC-V应用创新大赛】LicheePi4A(3)ncnn训练和使用测试-平头哥芯片开放社区-平头哥(t-head.cn)本篇文章再次尝试试用NCNN模型识别固定图像,使用的硬件是荔枝派4a,训练平台是MAIXHUB。ncnn官方模型验证再次参考官方例程,先对官方WIKI里使用的模型进行验证下载GITHUB中的压缩包,提取其中的nanodet_m.bin和nanodet_m.pa
- 电子烂人 玄铁RISC-V活动专区
- 【得捷电子Follow me第1期】+基础练习
- //内容一:3-5分钟短视频//短视频:https://training.eeworld.com.cn/video/37028已完成,后续补充一个GPS定位的视频(已补充)由于是第一次录视频,质量可能不太行,如果不合格的麻烦指出重新录制。//内容二:项目总结报告//购买的模块简单介绍本次任务要求必须包含五个部分,分别为:主控板-PICOW,扩展板,屏幕,蜂鸣器,GPS模块。主控板为PICOW,其特性如下:采用了RaspberryP
- 白无常120 DigiKey得捷技术专区
- 谁知道这是什么太阳能板附图 急急急
- 这是什么种类的太阳能板,效率怎么样,最好给推荐生产厂家,谢谢!谁知道这是什么太阳能板附图急急急
- 齐齐123 综合技术交流
- D/A转换
- 数模转换器(D/A)就是一种把数字信号转换成为模拟电信号的器件。实际上,D/A转换器输出的电量并不真正能连续可调,而是以所用D/A转换器的绝对分辨率为单位递减,所以这实际上是准模拟量输出。1.D/A转换器的基本原理D/A转换器用来将数字量转换成模拟量。它的基本要求是输出电压Uo应该和输入数字量D成正比,即Uo=DVR式中VR———参考电压。每一个数字量都是数字代码的按位组合,每一位数字代码都有一定的“权”,对
- 一世轮回 综合技术交流
- 网络视频传输设计
- 随着网络视频服务器,光纤网的迅速普及,网上多媒体应用(如视频会议,数字监控等)正为传统的计算机应用注入新的技术和内容。网络多媒体技术的发展也导致了基于IP技术的网络远程现场视频浏览应运而生。从模拟监控到数字监控,实现了监控技术的一次飞跃,目前最先进的技术就是通过专用视频服务器(瘦服务器)把模拟图像信号转化为数字图像信号后上网,同时通过管理程序对多个视频流进行统一管理,获得授权的用户便可以通过网络看到任何一个监控现场的实时图象,并且可以控制监视器的视角和焦距。针对实时图像
- wuyugwz 安防电子
设计资源 培训 开发板 精华推荐
- STM32F103VET6开发板
- LTC3834-1 的典型应用 - 30 uA IQ 同步降压型控制器
- LM224DR2G高阻差分放大器典型应用
- 使用 LT3464 的 34V 偏置电源
- S12ZVMEVB: S12ZVM评估板
- MIKROE-3327,基于 CTHS15CIC05ARROW 电容式触摸传感器显示器的按钮播放点击板
- LT3755IMSE 50W 白色汽车 LED 前照灯驱动器的典型应用电路
- 无刷电调STC8H
- 使用 Analog Devices 的 LT1424IN8-9 的参考设计
- 具有 PowerPath 的 LTC4162IUFD-SAD 9V 至 35V、3.2A 降压型开关电池充电器的典型应用