第七部分:1. STM32之ADC实验--单通道实验(滑动变阻器调节电压)

主要利用一个模拟量的电位器来实时改变电压值,通过STM32自带的ADC通道来采集这个数据,并打印出来!本实验是单通道实验

一句话,学完STM32,我就往南走,我的工资只有5000.~~~~Whappy

实验代码:

AD.c

#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);		//配置ADC时钟分频器	GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;   //ADC模拟输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//配置规则组的输入通道ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//配置ADC1模1块初始化ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right ;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent ;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_Init(ADC1,&ADC_InitStructure);/*	
ADC_ContinuousConvMode = DISABLE关闭连续转换模式。ADC在每次触发时仅进行一次转换,转换完成后停止,适用于单次采样的场合。
ADC_DataAlign = ADC_DataAlign_Right数据右对齐。ADC转换结果存储时,低位对齐方式,通常选择右对齐便于读取和处理。
ADC_ExternalTrigConv = ADC_ExternalTrigConv_None外部触发关闭。ADC转换不依赖外部触发源,适用于单次软件触发或内部定时触发的场景。
ADC_Mode = ADC_Mode_Independent独立模式。ADC模块工作在独立模式下,不与其他ADC模块联动。
ADC_NbrOfChannel = 1仅采样一个通道。配置当前ADC转换序列中包含的通道数量为1,适用于单通道采样的情况。
ADC_ScanConvMode = DISABLE关闭扫描转换模式。ADC仅对一个通道进行采样,不自动扫描多个通道。
*/	//中断//模拟看门狗//开启ADC电源ADC_Cmd(ADC1,ENABLE);//ADC校准ADC_ResetCalibration(ADC1);while((ADC_GetResetCalibrationStatus(ADC1) == SET));ADC_StartCalibration(ADC1);while((ADC_GetCalibrationStatus(ADC1))  == SET);}//启动转换,获取结果uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1,ENABLE);while((ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET));return ADC_GetConversionValue(ADC1);
}

这段代码实现了在STM32F10x系列单片机中初始化并配置ADC(模数转换器),并通过软件触发启动ADC转换并获取结果。下面逐行分析代码:

1. 初始化ADC相关硬件

 

c

复制代码

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 开启ADC1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 开启GPIOA的时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 配置ADC时钟分频器

  • RCC_APB2PeriphClockCmd():这两个函数调用用于开启ADC1和GPIOA的时钟,使得这些外设能够正常工作。
  • RCC_ADCCLKConfig(RCC_PCLK2_Div6):配置ADC的时钟源和分频器,RCC_PCLK2_Div6表示将PCLK2时钟分频为6,用于给ADC提供时钟。ADC通常需要较低的时钟频率,避免过快的采样导致精度下降。

2. GPIO配置

 

c

复制代码

GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 设置为模拟输入模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 配置PA0(GPIOA的第0引脚) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的最大输出速度 GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA的引脚

  • 通过这些设置,配置PA0(GPIOA的第0引脚)为模拟输入模式,供ADC进行采样。模拟输入模式意味着该引脚不会输出数字信号,而是用于接收模拟信号。

3. 配置ADC的转换通道

 

c

复制代码

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

  • ADC_RegularChannelConfig():配置ADC的常规通道(Regular),并指定使用的通道和采样时间。
    • ADC_Channel_0表示使用通道0(即PA0引脚连接的模拟信号)。
    • 1表示该通道在转换序列中的位置(第1个通道)。
    • ADC_SampleTime_55Cycles5表示采样时间为55.5个时钟周期,这在采样较慢的信号时可以提高精度。

4. 初始化ADC

 

c

复制代码

ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_Init(ADC1, &ADC_InitStructure);

  • ADC_ContinuousConvMode = DISABLE:关闭连续转换模式。每次触发时,ADC仅进行一次转换,完成后停止,适合单次采样。
  • ADC_DataAlign = ADC_DataAlign_Right:设置ADC数据右对齐,这样在读取时可以直接获取较低的位,便于处理。
  • ADC_ExternalTrigConv = ADC_ExternalTrigConv_None:关闭外部触发信号,表示ADC转换不依赖外部信号触发,而是由软件或其他方式启动。
  • ADC_Mode = ADC_Mode_Independent:选择独立模式,表示ADC1单独工作,不与其他ADC模块联动。
  • ADC_NbrOfChannel = 1:配置ADC转换序列中只有一个通道。
  • ADC_ScanConvMode = DISABLE:关闭扫描模式,表示ADC仅会转换一个通道。

5. ADC电源开启和校准

 

c

复制代码

ADC_Cmd(ADC1, ENABLE); // 启动ADC1 ADC_ResetCalibration(ADC1); // 复位ADC1的校准 while ((ADC_GetResetCalibrationStatus(ADC1) == SET)); // 等待校准复位完成 ADC_StartCalibration(ADC1); // 启动校准 while ((ADC_GetCalibrationStatus(ADC1)) == SET); // 等待校准完成

  • ADC_Cmd(ADC1, ENABLE):启用ADC1,使ADC模块开始工作。
  • ADC_ResetCalibration(ADC1):复位ADC的校准寄存器,清除可能的校准数据。
  • ADC_StartCalibration(ADC1):启动ADC的校准过程,确保转换结果的精确性。
  • 等待校准完成while ((ADC_GetCalibrationStatus(ADC1)) == SET) 等待校准完成,确保ADC在进行实际采样前已被校准。

6. 获取ADC值

 

c

复制代码

uint16_t AD_GetValue(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动ADC转换 while ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)); // 等待转换完成 return ADC_GetConversionValue(ADC1); // 返回ADC转换结果 }

  • ADC_SoftwareStartConvCmd(ADC1, ENABLE):通过软件启动ADC1的转换。
  • while ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)):等待转换完成。ADC_FLAG_EOC是"End of Conversion"标志,表示ADC转换结束。当该标志被置位时,转换完成。
  • return ADC_GetConversionValue(ADC1):返回ADC的转换结果。

总结

  • 这段代码初始化并配置了STM32F10x的ADC1,将其设置为单通道(PA0),并进行校准。
  • 通过AD_GetValue()函数启动ADC转换并返回转换结果。
  • 整个过程包括了开启时钟、配置GPIO、初始化ADC、启动ADC转换及等待转换完成,确保ADC可以用于后续的模拟信号采样。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t Value;
float Voltage;int main(void)
{OLED_Init();AD_Init();OLED_ShowString(1,1,"Value:");OLED_ShowString(2,1,"Voltge:0.00V");while (1){Value = AD_GetValue();Voltage =  (float)Value / 4095 * 3.3 ;OLED_ShowNum(1,7,Value,4);OLED_ShowNum(2,8,Voltage,1);OLED_ShowNum(2,10,(uint16_t)(Voltage * 100) % 100,2);Delay_ms(100);}
}

这个主函数结合了前面分析的ADC初始化、获取ADC值并显示到OLED屏幕上的功能。具体来说,代码使用OLED显示屏来实时显示ADC的数字值以及对应的电压值。

代码解析

  1. 头文件包含
 

c

复制代码

#include "stm32f10x.h" // Device header #include "Delay.h" // 延时函数库 #include "OLED.h" // OLED显示库 #include "AD.h" // ADC驱动库

  • stm32f10x.h:STM32F10x的设备头文件,包含所有外设的定义和函数声明。
  • Delay.h:延时函数头文件,包含用于延时的函数,例如 Delay_ms
  • OLED.h:OLED显示相关函数头文件,包含初始化、显示数字、字符串等功能。
  • AD.h:ADC相关函数头文件,包含ADC初始化和获取ADC值的函数。
  1. 全局变量声明
 

c

复制代码

uint16_t Value; // 用于存储ADC转换的原始值 float Voltage; // 用于存储电压值(计算得到)

  1. main() 函数初始化
 

c

复制代码

int main(void) { OLED_Init(); // 初始化OLED显示屏 AD_Init(); // 初始化ADC OLED_ShowString(1,1,"Value:"); // 在OLED屏幕的第一行显示"Value:" OLED_ShowString(2,1,"Voltge:0.00V"); // 在OLED屏幕的第二行显示"Voltage:0.00V" while (1) { Value = AD_GetValue(); // 获取ADC的转换值 Voltage = (float)Value / 4095 * 3.3 ; // 将ADC值转换为电压值,假设参考电压是3.3V,12位ADC分辨率为4095 // 显示ADC值 OLED_ShowNum(1,7,Value,4); // 将Value以4位数字显示在OLED的第1行第7列 // 显示电压值 OLED_ShowNum(2,8,Voltage,1); // 显示电压的整数部分(1位) OLED_ShowNum(2,10,(uint16_t)(Voltage * 100) % 100,2); // 显示电压的小数部分(2位) Delay_ms(100); // 延时100ms,防止屏幕更新过快 } }

代码详细解析

  1. OLED 初始化

     

    c

    复制代码

    OLED_Init();

    • OLED_Init() 初始化OLED显示屏,设置显示模式、清空屏幕等。
  2. ADC 初始化

     

    c

    复制代码

    AD_Init();

    • AD_Init() 函数初始化ADC,包括时钟配置、GPIO配置、ADC配置等(前面已经详细分析过)。
  3. OLED 显示字符串

     

    c

    复制代码

    OLED_ShowString(1, 1, "Value:"); OLED_ShowString(2, 1, "Voltge:0.00V");

    • OLED_ShowString(1, 1, "Value:") 在OLED屏幕的第1行第1列显示 "Value:",用于显示ADC的原始值。
    • OLED_ShowString(2, 1, "Voltge:0.00V") 在第2行第1列显示 "Voltage:0.00V",用于显示电压值。
  4. 主循环

     

    c

    复制代码

    while (1) { Value = AD_GetValue(); // 获取ADC值 Voltage = (float)Value / 4095 * 3.3; // 将ADC值转换为电压值 OLED_ShowNum(1, 7, Value, 4); // 显示ADC原始值 OLED_ShowNum(2, 8, Voltage, 1); // 显示电压值的整数部分 OLED_ShowNum(2, 10, (uint16_t)(Voltage * 100) % 100, 2); // 显示电压值的小数部分 Delay_ms(100); // 延时100ms }

    • AD_GetValue() 函数通过ADC获取一个模拟信号的数字值,返回一个12位的ADC转换值,范围从 0 到 4095。
    • ADC到电压的转换
      • 由于ADC的最大值为 4095(12位分辨率),而参考电压为 3.3V,使用公式: Voltage=Value4095×3.3\text{Voltage} = \frac{\text{Value}}{4095} \times 3.3Voltage=4095Value​×3.3
      • 计算得到的电压值被存储在 Voltage 变量中。
    • OLED显示
      • OLED_ShowNum(1, 7, Value, 4):显示ADC值,显示位置是第1行第7列,最多显示4位数字(Value是一个uint16_t,即0到4095范围)。
      • OLED_ShowNum(2, 8, Voltage, 1):显示电压的整数部分,显示位置是第2行第8列,显示1位数字。
      • OLED_ShowNum(2, 10, (uint16_t)(Voltage * 100) % 100, 2):显示电压的小数部分,显示位置是第2行第10列,显示2位数字。
    • 延时Delay_ms(100) 用于延时100ms,防止OLED屏幕刷新过快,使得显示的内容更容易被人眼观察。

总结

  • 功能:这个主程序通过获取ADC1的值并将其转换为电压值,显示在OLED屏幕上。通过持续读取ADC值并转换成电压值,不断更新OLED显示,实时显示采样的模拟信号的数值和电压。
  • OLED显示:在OLED屏幕上显示了ADC值和电压值,电压值保留两位小数,且实时更新。
  • ADC的精度:假设使用的是12位ADC(分辨率为4095),通过将读取到的数字值映射到3.3V的电压范围来显示实际电压。

可改进的地方

  1. 电压计算:可以在电压计算中加入更高精度的浮点计算,确保显示的电压值准确。
  2. 数据刷新:可以增加ADC转换触发的频率,使得显示的电压值更新更快,适应不同应用场景。
  3. OLED显示优化:如果显示的内容较多,可以考虑增加滚动或分页显示等功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8114.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

50岁+人群月活超1亿,短剧迎来新对手,小程序游戏“收割”中老年

抢夺中老年流量:微短剧向左,小游戏向右 作者|AgeClub 干货抢先看 1.《黑神话:悟空》走红,吸引大量玩家入坑单机市场。与硬核单机游戏不同,在渗透率更高的小游戏领域,聚集了更多“网瘾”中老年…

MySQL OnlineDDL添加字段

alter 添加字段 5.7 默认是algorithminplace以及locknone来进行DDL操作,但是添加列整个执行过程中也会部分涉及到Copy Table。 如果有碎片比较大,因为会copy表会碎片整理, 添加字段成功后有可能磁盘使用空间降低,添加过程中磁盘…

WPF中如何简单的使用MvvmLight创建一个项目并进行 增删改查

目录 第一步:创建项目后下载如下两个NuGet程序包,然后删除删掉using Microsoft.Practices.ServiceLocation; 并且引入using CommonServiceLocator; 第二步:删除原来的XAML文件并创建如下的包结构然后创建一个在View文件夹中创建一个Main窗体 …

ssm校园媒体信息发布系统—计算机毕业设计源码42272

目 录 摘要 1 绪论 1.1研究背景与意义 1.2国内外研究现状 1.3研究内容 1.4 ssm框架介绍 1.5论文结构与章节安排 2 校园媒体信息发布系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.2.2数据修改流程 2.2.3数据删除流程 2.3 系统功能分析 2.3…

【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十一章 制作Ubuntu文件系统

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐…

【数据结构】线性表——链表

写在前面 本篇笔记记录线性表——链表的主要形式,虽然链表有8种形式,但是只要精通笔记中编写的两种,即可触类旁通。 文章目录 写在前面一、链表的概念及结构二、链表的分类三、无头单向非循环链表3.1、链表的实现3.1.1、链表的结构体定义3.1…

Java:168 springboot小区团购管理

作者主页:舒克日记 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 ​ 系统有管理员,用户两个角色。 主要的功能有用户信息管理、商品信息管理、商品类型管理、商品订单管理、公告信息管理、公告类型管理 …

CSS如何改变滚动条的颜色样式粗细?

默认滚动条很丑怎么办?如何改版滚动条的粗细,颜色,让它更美观?CSS如何改变滚动条的粗细? 干货来了 /* Webkit内核浏览器的滚动条样式 */ ::-webkit-scrollbar {width: 4px; /* 设置滚动条的宽度 */ }::-webkit-scroll…

idea连接docker并构建镜像

安装docker 安装docker idea连接docker 安装docker插件 设置docker连接 设置docker.exe 这个docker.exe是为了运行docker,可以通过安装docker desktop获取 docker desktop下载地址 右键图标找到文件位置 在同级的resource中 编写Dockerfile # 使用官方 Nginx…

你竟然赶我走

目录 解题思路 题目设计原理 总结 解题思路 拿到图看属性没问题,格式是 jpg 的,但是这张图片肯定不简单。 文件分离不出东西。 使用 stegsolve 打开,使用文件格式分析功能,拉到最底下,flag 浮出水面。好吧&#xff…

ssm065基于JAVA WEB技术大健康综合咨询问诊平台的设计与实现+jsp(论文+源码)_kaic

毕 业 设 计(论 文) 题目:健康综合咨询问诊平台设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本健康综合咨询…

masm汇编字符输入换行输出演示

从键盘读取一个字符并换行输出 assume cs:codecode segmentstart:mov ah, 1int 21hmov bl, almov dl, 10 mov ah, 2int 21h mov dl, blmov ah, 2int 21hmov ah, 4chint 21hcode ends end start 效果演示:

设备管理网关(golang版本)

硬件设备:移远EC200A-CN LTE Cat 4 无线通信模块 操作系统:openwrt 技术选型:layui golang sqlite websocket 工程结构 界面展示 区域管理 设备管理 运行监控 系统参数 资源文件 版本信息

变电站接地电阻监测装置-输电铁塔接地电阻监测装置:实时监测,预防故障

变电站接地电阻监测装置 接地电阻对电力系统的安全和稳定性至关重要,但在高压环境和极端气候下,接地系统可能出现性能下降,增加故障和跳闸的风险。传统的人工检测方法常常无法及时发现这些问题,并且操作繁琐。为此,我…

【ArcGIS】绘制各省碳排放分布的中国地图

首先,准备好各省、自治区、直辖市及特别行政区(包括九段线)的shp文件: 通过百度网盘分享的文件:GS(2022)1873 链接:https://pan.baidu.com/s/1wq8-XM99LXG_P8q-jNgPJA 提取码&#…

maven plugin:在自定义插件中获取当前项目的依赖库列表

我的项目中需要在自定义maven插件中调用javadoc获取java源码的注释,就需要为了javadoc能正常解析源码,还需要源码所在项目的依赖库列表(java 9以上版本的javadoc这是必须的)作为-classpath. 方案一:dependency:build-classpath 如果在项目安装(install)阶段(phase),这个参数通…

linux基础2

声明 学习视频来自B站UP主泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 一,linux目录简介 1,根目录(/) 根目录是Linux文件系统的…

Leecode热题100-78.子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集 (幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,2,3] 输出:[[],[1],[2],[1,2]…

【NRM】npm镜像源地址管理

【NRM】npm镜像源地址管理 1.背景 因为公司有npm内网源地址,很多外网依赖拉取很慢。使用nrm管理npm的源地址,更方便切换使用 2.NRM是什么 nrm(npm registry manager,nrm )是npm的镜像源管理工具,有时候国外资源太慢&#xff0…

uniapp—android原生插件开发(1环境准备)

本篇文章从实战角度出发,将UniApp集成新大陆PDA设备RFID的全过程分为四部曲,涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程,轻松应对安卓原生插件开发与打包需求! 项目背景: UniApp集成新大陆P…