【STM32】ADC|多通道ADC采集

ops/2025/2/11 23:55:35/

本次实现的是ADC实现数字信号与模拟信号的转化,数字信号时不连续的,模拟信号是连续的。

1.ADC转化的原理

模拟-数字转换技术使用的是逐次逼近法,使用二分比较的方法来确定电压值
在这里插入图片描述
单片机对应的参考电压为3.3v时,0~ 3.3v(模拟信号)对应0~4095(数字信号),假如我们知道一个数字信号的值为x,那么他对应的模拟信号
x/4095=y/3.3
y就是x对应的模拟信号
假如要确定0.8v对应的数字信号的值
在这里插入图片描述
他会将0.8v电压保存在电容中,然后先和3.3v的一半对应的1.65v(2048)做比较,如果小于1.65v的话,12位最高位就是0,因为1000 0000 0000 对应的就是2048

在这里插入图片描述
接着就是和1.65的一半比较,0.825v(1024)>0.8v,所以12位中倒数第二高位就是0,因为0.825(1024)对应二进制就是0100 0000 0000
在这里插入图片描述
接着0.8v和0.825的一半比较->0.4125v(512),0.8v>0.4125v,所以第三位为1,因为512对应的二进制为0010 00000000
在这里插入图片描述
按这个方法依次确定0.8v对应的12位的二进制数,然后这个二进制对应的十进制就是0.8v对应的数字信号的值
所以对应的过程是1.启动ADC 2.采样&转换 3.获取&计算,针对STM32F103C8T6芯片有10个外部通道,和两个内部通道(内部温度传感器,内部参考电压)进行ADC的转化,ADC1和ADC2,两个转化结构,每个转化结构都有一个注入组和一个规则组,我们现在只讲讲规则组,我们要对一个通道的电压值进行采集的时候,我们需要将这个通道注册进这个通道中,当启动ADC,然后采样转化的电压值就会放在规则通道数据寄存器(12位二进制值)中,等待获取

2.实操

在这里插入图片描述
单片机有一个电位器,通过旋转电位器,使得PA5的输出电压发送变化,我们将其输出到串口上去
在这里插入图片描述
对应的PA5刚好是ADC1的通道5

  char message[50]="";float v=0.0;int value=0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){ HAL_ADC_Start(&hadc1);//开启ADC1HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//等待转换value=HAL_ADC_GetValue(&hadc1);//从寄存器中获取电压值v=(value/4095.0)*3.3;//转模拟信号sprintf(message,"v:%.2f,value:%d",v,value);HAL_UART_Transmit(&huart2,message,strlen(message),HAL_MAX_DELAY);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

在这里插入图片描述
但是发现一个问题,就是电位器扭到头
在这里插入图片描述
最大为3.25v,达不到3.3v,这是因为手册里面说
在这里插入图片描述

  char message[50]="";float v=0.0;int value=0;HAL_ADCEx_Calibration_Start(&hadc1);//校准/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_ADC_Start(&hadc1);//开启ADC1HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//等待转换value=HAL_ADC_GetValue(&hadc1);//从寄存器中获取电压值v=(value/4095.0)*3.3;//转模拟信号sprintf(message,"v:%.2f,value:%d",v,value);HAL_UART_Transmit(&huart2,(uint8_t*)message,strlen(message),HAL_MAX_DELAY);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

在这里插入图片描述
其实还有一种是循环转换,只需要开启一次ADC即可
在这里插入图片描述

  char message[50]="";float v=0.0;int value=0;HAL_ADCEx_Calibration_Start(&hadc1);//校准HAL_ADC_Start(&hadc1);//开启ADC1HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//等待转换/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){value=HAL_ADC_GetValue(&hadc1);//从寄存器中获取电压值v=(value/4095.0)*3.3;//转模拟信号sprintf(message,"v:%.2f,value:%d",v,value);HAL_UART_Transmit(&huart2,(uint8_t*)message,strlen(message),HAL_MAX_DELAY);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

3.ADC多路采集

在前面说过,如果要获取对应通道的电压值,就需要将这个通道注册进规则组中,然后数据准备就绪, HAL_ADC_PollForConversion函数不断的检测ADC状态寄存器中转换结束标志位(EOC)是否为1,如果是,转换完成,将转换的值放入规则通道数据寄存器中,然后调用HAL_ADC_GetValue读取规则通道数据寄存器,然后对应的ADC状态寄存器中的转换结束标志位置0.
在多采集中需要将多个通道打开实现转换,会按照规则组注册顺序,依次将对应通道的电压值放入规则通道数据寄存器,然后写到内存中。
我们可以使用DMA来对规则通道数据寄存器的值搬运到内存,当搬运完成,就会触发DMA完成中断,进行处理转换后的值
本次实现热敏电阻,电位器,单片机内部温度,内部参考电压的ADC转换,并通过串口将其发送
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PA4,PA5 ADC在ADC1的通道4,通道5上,以及内部温度通道,内部参考电压通道
在这里插入图片描述
注意将四个通道的多久采集值调到四个通道转换最大值,确保数据都已经被转换
在这里插入图片描述

uint16_t data[4];
char message[50]="";
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if(hadc==&hadc1){sprintf(message,"%d %d %d %d",data[0],data[1],data[2],data[3]);HAL_UART_Transmit(&huart2, (uint8_t*)message,sizeof(message),HAL_MAX_DELAY);}}
int main(void)
{HAL_Init();HAL_ADCEx_Calibration_Start(&hadc1);//校准while (1){HAL_ADC_Start_DMA(&hadc1,(uint32_t*)data,4);//开启ADC,DMA完成搬运调用DMA完成中断中断,在中断中发送转换值到串口HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

在这里插入图片描述
依次是电位器,热敏电阻,内部温度,内部参考电压未转化为模拟电压
除此之外我们可以使用循环转换,和DMA的循环搬运就可以实现开启一次ADC就可以一直将转换后的四个值发送到串口,因为会一直转换,不用知道什么时候转换完成,我们将发送到串口放到while中
在这里插入图片描述

uint16_t data[4];
char message[50]="";int main(void)
{HAL_Init();HAL_ADCEx_Calibration_Start(&hadc1);//校准HAL_ADC_Start_DMA(&hadc1,(uint32_t*)data,4);//开启ADC,DMA完成搬运调用DMA完成中断中断,在中断中发送转换值到串口while (1){sprintf(message,"%d %d %d %d",data[0],data[1],data[2],data[3]);HAL_UART_Transmit(&huart2, (uint8_t*)message,sizeof(message),HAL_MAX_DELAY);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

在这里插入图片描述


http://www.ppmy.cn/ops/157649.html

相关文章

【漫话机器学习系列】087.常见的神经网络最优化算法(Common Optimizers Of Neural Nets)

常见的神经网络优化算法 1. 引言 在深度学习中,优化算法(Optimizers)用于更新神经网络的权重,以最小化损失函数(Loss Function)。一个高效的优化算法可以加速训练过程,并提高模型的性能和稳定…

ESP8266配置为TCP客户端,连接电脑和手机(使用Arduino配置)

一、简介 基于 ESP8266 的 Arduino 代码,其主要功能是将 ESP8266 连接到指定的 Wi-Fi 网络,并与指定 IP 地址和端口号的服务器建立 TCP 连接。在连接成功后,实现了串口和网络数据的双向传输,也就是将从串口接收到的数据通过 Wi-Fi…

基于微信小程序的酒店管理系统设计与实现(源码+数据库+文档)

酒店管理小程序目录 目录 基于微信小程序的酒店管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 (1) 用户信息管理 (2) 酒店管理员管理 (3) 房间信息管理 2、小程序序会员模块的实现 (1)系统首页 &#xff…

故障显示C++

为了实现一个系统,其中不同模块可以上报故障(fault),并在一个界面上集中显示这些故障信息,我们可以设计一个简单的应用程序。以下是一个基本的实现思路和示例代码,使用C来模拟这一过程。 实现思路 故障模块…

x64、aarch64、arm与RISC-V64:详解四种处理器架构

x64、aarch64、arm与RISC-V64:详解四种处理器架构 x64架构aarch64架构ARM架构RISC-V64架构总结与展望在计算机科学领域,处理器架构是构建计算机系统的基石,它决定了计算机如何执行指令、管理内存和处理数据。x64、aarch64、arm与RISC-V64是当前主流的四种处理器架构,它们在…

后盾人JS -- 模块化开发

开发模块管理引擎 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </he…

【练习】图论

F. Friendly Group 图中选择一个点-1 边两端点都选择1 边一个端点选择-1 添加链接描述 #include<iostream> using namespace std; #include<vector> #include<cstring> const int N300010; int n,m; vector<int> G[N]; int temp1,temp2; bool vis[N…

MyBatis常见知识点

#{} 和 ${} 的区别是什么&#xff1f; 答&#xff1a; ${}是 Properties 文件中的变量占位符&#xff0c;它可以用于标签属性值和 sql 内部&#xff0c;属于原样文本替换&#xff0c;可以替换任意内容&#xff0c;比如${driver}会被原样替换为com.mysql.jdbc. Driver。 一个…