【STM32标准库】【基础知识】ADC转换,非DMA的单通道和多通道

2023-10-27


文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。

ADC概述

A是指模拟信号,D是指数字信号,C是指变换

故名思意,ADC即将模拟信号转换为数字信号的一种变换。

STM32F4的ADC为逐次逼近型ADC
原理是利用DAC产生不同大小的电压,与输入的电压比较,得到输入电压的大体范围,这个范围的误差即为分辨率

如为8位分辨率的ADC,则分度值为3.3/2^8,即与真实值的误差不会超过12.89mV

具体原理请看微机原理

ADC初始化

流程

  1. GPIO初始化
  2. 打开时钟
  3. 全局ADC设置
  4. 单独ADC设置

GPIO初始化

之前文章中介绍过,传送门,需要设置为模拟模式
例程

GPIO_InitTypeDef GPIO_InitStruct;						//GPIO初始化结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	//打开时钟
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;				//模拟模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;				//随意设置
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;		//端口
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;			//随意设置
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;			//高速
GPIO_Init(GPIOA, &GPIO_InitStruct);	

时钟

本系列单片机只有1个ADC,ADC1,端口对应请看这篇文章,传送门

使用这句命令打开ADC的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

全局ADC设置

这部分的设置是对全部的ADC有效的(本单片机即ADC1)

定义结构体

ADC_CommonInitTypeDef ADC_CommonInitStruct;

是否使用DMA

ADC_CommonInitStruct.ADC_DMAAccessMode

可以的选择使用或不使用,本文为不使用的情况。

ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	   //不使用DMA

工作模式

可以选择外部触发源或者不使用触发
本文为不使用外部触发(独立工作模式)

ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;					   //独立工作模式

分频

ADC需要频率在12MHz以下,以AHB1的频率(与系统频率相等)为基准进行分频
本文选择8分频

ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;				   //分频,建议分频后小于12MHZ	

采样延迟

这个只有在多ADC时才有效,作为两个ADC采样之间的时间间隔

ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采样延迟,多ADC使用才有效
	

例程

ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	   //不使用DMA
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;					   //独立工作模式
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;				   //分频,建议分频后小于12MHZ
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采样延迟,多ADC使用才有效
ADC_CommonInit(&ADC_CommonInitStruct);

单独ADC设置

下面的设置是针对单独的ADC的

定义结构体

ADC_InitTypeDef ADC_InitStruct;

连续转换

将所有开启的通道采集转换完一轮后自动开启下一轮的采集转换,这是连续模式

ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							 //连续模式

数据对齐

选择右对齐即可,其他基本上用不到

ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						 //右对齐

外部触发

可以选择边沿触发或者定时器中断触发,或者不使用外部触发
这里选择的不使用外部触发

ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //选择外部触发事件,这里随意即可,因为使用了不允许外部触发
	ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //软件触发

通道数量

即选择打开了几个通道

ADC_InitStruct.ADC_NbrOfConversion = 1;									 //通道数量
	

分辨率

即最大误差范围,这个数据的选择与后期计算电压值相关
可以是

分辨率 分割数量
6bit 64
8bit 256
10bit 1024
12bit 4096
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;						 //分辨率

扫描模式

用于多通道扫描,完成全部打开的通道的扫描后中断标志置位
但是后接受的数据会被覆盖,需要使用DMA
这里是单通道(非DMA多通道是软件模拟的),因此此处设置与不设置均可

ADC_InitStruct.ADC_ScanConvMode = ENABLE;								 //扫描模式

例程

ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							 //连续模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						 //右对齐
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //选择外部触发事件,这里随意即可,因为使用了不允许外部触发
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //软件触发
ADC_InitStruct.ADC_NbrOfConversion = 1;									 //通道数量
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;						 //分辨率
ADC_InitStruct.ADC_ScanConvMode = ENABLE;								 //扫描模式
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);

设置规则

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

使用此函数设置对应规则
分别输入ADC号(本单片机只有ADC1),ADC通道号,标记号,采样时间

标记号只能小于等于通道数,从1开始,采样时间是会将这段时间内的数据平均后输出

ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles); //设置通道规则

打开软件调用ADC

如果使用软件读取ADC,需要事先调用此函数

ADC_SoftwareStartConv(ADC1);

需要在设置后才可以使用软件调用ADC
因此可以使用这段代码确保已经设置成功

	while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;

模拟多通道采集(非DMA)

思路

每次调用此读取ADC时,改变ADC对应的通道,设置成功后读取ADC并返回数据

函数

u16 ADC1_Read(u8 ch)
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles); //设置通道规则
	ADC_SoftwareStartConv(ADC1);									 //开启软件触发
	while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;
	return ADC_GetConversionValue(ADC1); //软件触发
}

总例程

void ADC_init()
{
	GPIO_InitTypeDef GPIO_InitStruct;
	ADC_InitTypeDef ADC_InitStruct;
	ADC_CommonInitTypeDef ADC_CommonInitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	   //不使用DMA
	ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;					   //独立工作模式
	ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;				   //分频,建议分频后小于12MHZ
	ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采样延迟,多ADC使用才有效
	ADC_CommonInit(&ADC_CommonInitStruct);

	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							 //连续模式
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						 //右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //选择外部触发事件,这里随意即可,因为使用了不允许外部触发
	ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //软件触发
	ADC_InitStruct.ADC_NbrOfConversion = 1;									 //通道数量
	ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;						 //分辨率
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;								 //扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	ADC_Cmd(ADC1, ENABLE);
}

u16 ADC1_Read(u8 ch)
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles); //设置通道规则
	ADC_SoftwareStartConv(ADC1);									 //开启软件触发
	while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;
	return ADC_GetConversionValue(ADC1); //软件触发
}

需要读取时只需要调用此函数即可,更改通道号即可读取多通道数据,例如这样

int main()
{
	int i = 0;
	ADC_init();
	Usart_init();
	while (1)
	{
		i = 0;
		i = ADC1_Read(ADC_Channel_1);
		i = (i * 3300 / 0xfff);
		printf("ch1=%d mV \r\n", i);
		Delay_ms(300);
		i = 0;
		i = ADC1_Read(ADC_Channel_0);
		i = (i * 3300 / 0xfff);
		printf("ch0=%d mV \r\n", i);
		Delay_ms(300);
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32标准库】【基础知识】ADC转换,非DMA的单通道和多通道 的相关文章

  • C 嵌入式应用程序中 time() 函数的问题

    我在用time 在 ARM 微控制器上 处理器一到达此函数就会重新启动 奇怪的是 当我处于调试模式时 代码运行得很好 但一旦我想将其应用到独立模式 我就会遇到重置 我是否忽略了什么 这个功能有替代品吗 代码部分是这样的 include
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能
  • 为什么当大小大于 50 时,该程序花费的时间会呈指数级增长?

    所以我正在为类编写一个 ARM 汇编快速排序方法 我对大部分内容都有了解 除了复杂性没有意义 我们将其与我们制作的另一种冒泡排序方法进行比较 它对于具有 1 个参数和 10 个参数的示例表现更好 然而 我什至无法比较 100 个参数测试 因
  • 基于 Windows 8 ARM 的平板电脑上的 VB6

    随着 Windows 8 将支持 VB6 我的问题是 Microsoft 是否在任何地方表示 是或否 VB6 应用程序将在基于 ARM 的平板电脑上运行 如果没有 是否有任何 ARM 模拟器 以便我们可以在 Windows 8 ARM 平板
  • 如何模拟ARM处理器运行环境并加载Linux内核模块?

    我尝试加载我的vmlinux into gdb并使用 ARM 内核模拟器 但我不明白为什么我会得到Undefined target command sim 这是外壳输出 arm eabi gdb vmlinux GNU gdb GDB 7
  • ARM Chromebook 上的 Android 开发环境?

    我尝试了多次安装和使用安卓工作室 https developer android com studio index html on an ARM Chromebook C100P https archlinuxarm org platfor
  • 什么是遗留中断?

    我正在开发一个项目 试图弄清楚 ARM 架构的全局中断控制器中如何处理中断 我正在使用 pl390 中断控制器 我看到有一条线被称为传统中断 它绕过了分配器逻辑 假设有 2 个中断可以被编程为传统中断 任何人都可以帮助解释一下什么是遗留中断
  • GCC C++ (ARM) 和指向结构体字段的 const 指针

    假设有一个简单的测试代码 typedef struct int first int second int third type t define ADDRESS 0x12345678 define REGISTER type t ADDRE
  • 架构armv7的重复符号

    尝试在我现有的应用程序中使用 Layar SDK 时出现以下错误 我该如何解决这个问题 Ld Users pnawale Library Developer Xcode DerivedData hub afxxzaqisdfliwbzxbi
  • 交叉编译armv5,但它创建v7二进制文件

    我设法为arm926ej s创建了一个目标文件我在 qemu 上使用 Debian Arm arm linux gnueabi gcc 4 4 static O c mcpu arm926ej s hello c o hello root
  • 英特尔的最后分支记录功能是英特尔处理器独有的吗?

    最后分支记录是指存储与最近执行的分支相关的源地址和目标地址的寄存器对 MSR 的集合 它们受英特尔酷睿 2 英特尔至强和英特尔凌动处理器系列的支持 http css csail mit edu 6 858 2012 readings ia3
  • ARM NEON 矢量化失败

    我想在 ARM cortex a9 上启用 NEON 矢量化 但在编译时得到以下输出 未矢量化 不支持相关 stmt D 14140 82 D 14143 77 D 14141 81 这是我的循环 void my mul float32 t
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • ARM Cortex-M3 启动代码

    我试图了解 STM32 微控制器的 Keil realview v4 附带的初始化代码是如何工作的 具体来说 我试图了解堆栈是如何初始化的 In the 文档 http infocenter arm com help index jsp t
  • 上下文切换到安全模式(arm trustzone)的成本是多少

    我试图了解在arm中可信 安全 和非安全模式之间来回切换的成本 从非安全世界转移到安全世界时到底需要发生什么 我知道需要设置 ns 位 基于某些特殊指令 需要刷新和更新页表 刷新和更新处理器缓存 还有什么需要发生的吗 处理器缓存 它们是分段
  • 哪些 GCC 优化标志对二进制大小影响最大?

    我正在使用 GCC 为 ARM 开发 C 我遇到了一个问题 我没有启用优化 我无法创建二进制文件 ELF https en wikipedia org wiki Executable and Linkable Format 对于我的代码 因
  • 已编译 LKM 的互换性

    是否可以使用可加载内核模块 编译为3 0 8 mod unload ARMv5 我自制的内核 在具有版本的内核中3 0 31 gd5a18e0 SMP preempt mod unload ARMv7 安卓股票内核 该模块本身几乎不包含任何
  • 了解带有 pc 偏移的 Cortex-M 组件 LDR

    我正在查看这段 C 代码的反汇编代码 define GPIO PORTF DATA R volatile unsigned long 0x400253FC int main void Initialization code while 1
  • 支持 ARM 上的 Windows 10 桌面应用程序 - MFC 和 COM 以及 OPOS 可以工作吗?

    我试图了解将在 x86 Windows 10 上运行的 C MFC 应用程序移植到具有 Qualcomm Snapdragon 处理器的 ARM Windows 10 设备的障碍 32位应用程序具有以下特点 MFC 与 C 用于用户界面 C

随机推荐

  • 【华为机试真题 C++】高矮个子排队-100

    编程题目 100分 高矮个子排队 2021 H1 H2 2022 Q1 考试题 时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 本题可使用本地IDE编
  • 毕业设计 stm32智能扫地机器人 - 单片机 嵌入式

    文章目录 0 简介 1 课题背景 2 硬件系统总体框架 2 1 电机驱动 2 2 红外线传感器 2 3 超声波传感器 2 4 MPU6050 2 5 ATK ESP8266 WI FI 模块 2 6 电源管理模块 3 软件系统设计 3 1
  • Jupyterlab 3以及Kite代码补全插件安装

    Jupyterlab 3 以及Kite代码补全插件安装 为啥安个这玩意儿 之前一直用Jupyter写一些机器学习和深度学习的东西 尤其是去年一年里白嫖谷歌的Colab很长时间 甚至还开了pro 他们的工作台就是Jupyter类型的 用多了就
  • 【Bias 03】Benchmarking Robustness in Object Detection: Autonomous Driving when Winter is Coming

    Related work Improving corruption robustness 去除腐蚀 1 提出一种基于DNN 恢复雨雾图片质量的方法 2 预处理中去除雨 但这种方法都是针对某种腐蚀 数据增强 把腐蚀数据加入训练 1 blurr
  • C++类模板和static数据成员

    静态数据成员对象之间共享的 当静态数据成员遇上类模板式也是如此吗 现有demo类模板 类中包含static数据成员 template
  • Linux modules-load 启动时加载驱动模块

    Linux modules load 启动时加载驱动模块 Linux 内核包含非常多驱动以及其他功能模块 驱动开发时 我们可以通过insmod命令向内核中载入模块 rmmod卸载模块 lsmod列出加载的所有模块 一般情况下 模块会根据硬件
  • 【MATLAB】常见语法结构和实用操作

    目录 语法结构 循环 遍历 结构 函数结构 画图操作 绘制函数图像 ezplot figure多图绘制 创建多项式 按照系数创建多项式 利用多项式零点创建多项式 解方程组 语法结构 循环 遍历 结构 与其它编程语言类似 Matlab也有循环
  • 对象存储oss的使用

    分为两个大块 1 阿里云oss配置 2 写代码 阿里云oss配置的最终木电的拿到这几个东西 1 accessKeyId 相当于身份认证 在注册完成之后 就可以拿到 2 accessKeySecret 相当于认证的密码 同样注册完成之后 就会
  • word图片撑满_word图片满页 word图片铺满整个页面

    word中如何让图片占满整个页面 确定 再确定 不OK了 7厘米 页面设置 里设置页面方向及纸张大小 当然也要根据你打印机性能 请将下面 锁定纵横比 那个钩取消 如将页面边距设置为0 点 版式 如图片太大你打印机不一定打印得了 再点右下角的
  • Python报错:IndexError: invalid index of a 0-dim tensor. Use `tensor.item()` in

    Python报错如下 E anaconda envs pytorch gpu python exe D project graphsage graphsage model py D project graphsage graphsage e
  • 自动找Bug/插件-代码静态检查findbugs-idea安装以及使用

    目录 简介 IDEA安装FindBugs Findbugs配置 配置排除一些类 扫描级别 IDEA中使用FindBugs 一些常见错误 补充 简介 Findbugs是一个静态分析工具 它检查类或者JAR 文件 将字节码与一组缺陷模式进行对比
  • 闲谈云计算

    其实一直到处看到关于云计算的东西和话题 云计算一直是一个很火的关键字 最近几天才有时间找来一本 云那些事 来看看 只是很粗略的看了关于云计算发展方向的一些问题 具体的云技术是一盘丰盛的大餐 得慢慢吃 其实我一直在没有认真去看云计算的时候 觉
  • Future和FutureTask用法详细介绍

    Future和FutureTask 文章目录 Future和FutureTask Future FutureTask Demo code output 在并发编程中 多线程的实现有继承Thread和Runnable 因为单继承的原因我们往往
  • Java阿里巴巴代码规范

    目录 1 编程规约 1 1 方法参数类型必须一致 不要出现自动装箱拆箱操作 1 1 1 反例 1 1 2 正例 1 2 SimpleDateFormat是线程不安全的 1 2 1 反例 1 2 2 正例 1 3 使用equals方法应该注意
  • 软件项目管理(第二版 宁涛)问答题(个人背诵)

    目录 第一章 概述 1 什么是软件项目管理 2 项目管理的 9 大知识领域是什么 3 项目管理的 5 个过程组是什么 5 项目经理的主要职责是什么 6 项目的特点是什么 7 项目和运营的共同点有哪些 8 项目集成管理是什么 9 规划过程组的
  • Flutter学习 — 从新页面返回数据给上一个页面

    效果图一 点击按钮 效果图二 点击YES后 返回上一级页面并传值 效果图三 收到值 并用底部弹出框显示结果 注释 代码 import package flutter material dart void main runApp new Ma
  • 关于Git的一点思考

    GIT历史 很多人都知道 Linus在1991年创建了开源的Linux 从此 Linux系统不断发展 已经成为最大的服务器系统软件了 Linus虽然创建了Linux 但Linux的壮大是靠全世界热心的志愿者参与的 这么多人在世界各地为Lin
  • YOLOV5之TensorRT模型部署

    目录 一 环境版本 1 1 概述 1 2 Ubuntu版本 1 3 python pytorch与tensorrt版本 1 4 cudnn版本 1 5 驱动版本 1 6 opencv版本 二 TensorRT与opencv环境安装 2 1
  • 虚拟化概念详解

    虚拟化的定义 虚拟化技术可以认为是一种对物理资源抽象化 进而形成虚拟化的版本的技术 虚拟化的目的 物理资源组成庞大的资源池 然后可以按需分配 随意切割物理资源 虚拟化资源分类 服务器虚拟化 服务器虚拟化就是将虚拟化技术应用于服务器 将一台服
  • 【STM32标准库】【基础知识】ADC转换,非DMA的单通道和多通道

    文章目录 ADC概述 ADC初始化 GPIO初始化 时钟 全局ADC设置 定义结构体 是否使用DMA 工作模式 分频 采样延迟 例程 单独ADC设置 定义结构体 连续转换 数据对齐 外部触发 通道数量 分辨率 扫描模式 例程 设置规则 打开