STM32F4+薄膜压力传感器(FSR)AO模拟输出程序ADC模数转换器详解

前言:博主在使用STM32F4加薄膜压力传感器用来测量压力时,发现给的例程只有STM32F1系列的,而STM32F4系列库函数程序不太一致,博主实战解决了该问题,用STM32F4标准库开发。有关ADC模数转换器的详细知识点详情点击我的博文 (ADC模数转换器详解链接):https://archie.blog.csdn.net/article/details/136723340?spm=1001.2014.3001.5502

STM32F4+薄膜压力传感器(FSR)AO模拟输出程序:

main.c

main.c是用于读取薄膜压力传感器(FSR)的模拟输出,并将其映射到实际压力值范围内。主要功能是读取薄膜压力传感器的模拟输出,并将其转换为相应的压力值。

  1. 首先包含了一些必要的头文件,包括STM32的相关头文件以及自定义的延迟、串口、ADC和FSR的头文件。

  2. 定义了一些常量,如最小和最大量程、最小和最大电压范围等。

  3. main()函数中,初始化延迟、中断和串口,并进行ADC的初始化。

  4. 进入主循环后,通过Get_Adc_Average()函数获取ADC的10次平均值,并将其映射到电压值范围内。然后根据电压值的情况,计算相应的压力值。

  5. 使用printf()函数输出ADC值、电压值和压力值。

  6. 最后通过延迟一段时间,实现数据的周期性读取。

#include "stm32f4xx.h"                  // Device header
#include <stdint.h>
#include <stdbool.h>  
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "usart1.h"
#include "adc.h"


//最小量程
#define PRESS_MIN	20
//最大量程 
#define PRESS_MAX	6000
#define VOLTAGE_MIN 100
#define VOLTAGE_MAX 3300
u8 state = 0;
u16 val = 0;
u16 value_AD = 0;

long PRESS_AO = 0;
int VOLTAGE_AO = 0;

long map(long x, long in_min, long in_max, long out_min, long out_max);



int main(void)
{
	
	I2C_Configuration();//配置CPU的硬件I2C	
	OLED_Init();
	Adc_Init();
	
	
	OLED_CLS();//清屏

	
	while(1)
	{
		
		value_AD = Get_Adc_Average(13,10);	//10次平均值
		VOLTAGE_AO = map(value_AD, 0, 4095, 0, 3300);
		if(VOLTAGE_AO < VOLTAGE_MIN)
		{
			PRESS_AO = 0;
		}
		else if(VOLTAGE_AO > VOLTAGE_MAX)
		{
			PRESS_AO = PRESS_MAX;
		}
		else
		{
			PRESS_AO = map(VOLTAGE_AO, VOLTAGE_MIN, VOLTAGE_MAX, PRESS_MIN, PRESS_MAX);
		}
		//printf("AD值 = %d,电压 = %d mv,压力 = %ld g\r\n",value_AD,VOLTAGE_AO,PRESS_AO);
		OLED_ShowNum(1,1,value_AD,5);
		OLED_ShowNum(2,1,VOLTAGE_AO,5);
		OLED_ShowNum(3,1,PRESS_AO,5);
		Delay_ms(500);
	}	
}
long map(long x, long in_min, long in_max, long out_min, long out_max) {
 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}

adc.c

博主使用的adc通道是PC3-ADC123_IN13(adc1和adc2和adc3的通道13)

首先Adc_Init初始化adc

  1. 定义了需要用到的结构体:GPIO_InitTypeDef、ADC_InitTypeDef和ADC_CommonInitTypeDef。
  2. 使能了ADC1通道的时钟和GPIOC端口的时钟。
  3. 配置PC3引脚作为模拟通道输入引脚,设置为模拟输入引脚并且不使用上拉或下拉。
  4. 对ADC1进行复位操作。
  5. 初始化ADC Common 结构体参数,包括禁止DMA直接访问模式、独立ADC模式、时钟分频等。
  6. 初始化ADC Init 结构体参数,包括单通道模式、数据右对齐、外部触发通道、ADC分辨率等。
  7. 根据ADC_Init结构体中的参数初始化ADC1外设寄存器。
  8. 使能ADC1。

然后是获取ADC转换结果的函数。函数名称为Get_Adc(u8 ch)

  1. 使用ADC_RegularChannelConfig函数设置ADC规则组通道和采样时间。
  2. 使用ADC_SoftwareStartConv函数启动ADC转换。
  3. 使用while循环等待ADC转换结束,通过检查ADC_FLAG_EOC标志位来判断转换是否完成。
  4. 使用ADC_GetConversionValue函数获取最近一次ADC转换的结果,并将其返回。

最后是获取指定通道(ch参数)的ADC转换结果,并对转换结果进行多次采样(times次),然后计算这些采样值的平均值。

  1. 使用for循环对指定通道进行多次采样,每次采样后将转换值累加到temp_val变量中。
  2. 在每次采样之间通过Delay_ms函数添加延时,这有助于确保每次转换之间有足够的间隔。
  3. 最后,将temp_val除以采样次数times,得到平均值,并将其返回。
 #include "adc.h"
 #include "Delay.h"
	   
/*
Ao:接ADC模拟电压信号输出--PC3-ADC123_IN13(adc1和adc2和adc3的通道13)
*/	  


//初始化ADC
//规则通道																   
void  Adc_Init(void)
{ 	
	//定义结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure; 
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
	//使能ADC1通道时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );	  
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	
	
	//PC3 作为模拟通道输入引脚 不上拉不下拉                        
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//不上拉不下拉
	GPIO_Init(GPIOC, &GPIO_InitStructure);	
	
	
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);   //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);    //复位结束
	
	//ADC Common 结构体 参数 初始化
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 禁止DMA直接访问模式	
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;// 时钟为fpclk x分频	
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔	
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	//ADC Init 结构体 参数 初始化
	ADC_StructInit(&ADC_InitStructure);
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//模数转换工作在单通道模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//外部触发通道,本例子使用软件触发,此值随便赋值即可
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_NbrOfConversion = 1;//顺序进行规则转换的ADC通道的数目
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;// ADC 分辨率
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//模数转换工作在单次转换模式
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1

}				  
//获得ADC值
//返回值:转换结果
u16 Get_Adc(u8 ch)   
{
		    
	ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_56Cycles);//设置ADC规则组通道,一个序列,采样时间480
	ADC_SoftwareStartConv(ADC1);//使能指定的ADC1的软件转换启动功能
	while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//读取状态寄存器的状态位EOC,等待转换结束
	return ADC_GetConversionValue(ADC1);//返回最近一次的ADC1规则组的转换结果
	
}

//获取通道ch的转换值,取times次,然后平均
//ch:通道编号  times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);//取times次通道值进行求和
		Delay_ms(5);
	}
	return temp_val/times; //返回平均值
} 	 

adc.h

#ifndef __ADC_H
#define __ADC_H	

#include "stm32f4xx.h"                  // Device header

typedef uint16_t u16;
typedef uint8_t u8;

void Adc_Init(void);
u16  Get_Adc(u8 ch); 
u16 Get_Adc_Average(u8 ch,u8 times); 
 
#endif 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度长文】聊一聊 Java AbstractQueuedSynchronizer 以及在 ReentrantLock 中的应用

文章目录 AQS 原理简述内部数据结构公平锁 vs. 非公平锁ReentrantLock 非公平锁ReentrantLock 公平锁 AQS 源码分析加锁过程addWaiteracquireQueuedshouldParkAfterFailedAcquirecancelAcquire 解锁过程unparkSuccessor AbstractQueuedSynchronizer (AQS) 是 Java 并发包中&…

【AUTOSAR】【通信栈】Fls

AUTOSAR专栏——总目录-CSDN博客文章浏览阅读592次。本文主要汇总该专栏文章,以方便各位读者阅读。https://blog.csdn.net/qq_42357877/article/details/132072415?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132072415%22…

【电路笔记】-MOSFET作为开关

MOSFET 作为开关 文章目录 MOSFET 作为开关1、概述2、MOSFET特性曲线2.1 截住区域2.2 饱和区域3、MOSFET作为开关的示例4、功率MOSFET电机控制5、P沟道MOSFET作为开关6、互补MOSFET作为开关电机控制器当 MOSFET 在截止区和饱和区之间工作时,MOSFET 是非常好的电子开关,用于控…

RK3588 Buildroot 增加本地模块(单独编译/加入系统配置)

前言 本文基于 RK3588 Buildroot 编写. 在RK3588开发板环境下&#xff0c;开发者通常利用Buildroot来定制适合RK3588芯片特性的嵌入式Linux系统。通过Buildroot&#xff0c;开发者能够根据实际需求裁剪系统组件、添加特定驱动、配置内核特性&#xff0c;并集成用户应用程序&a…

哪里有视频素材网站免费下载?高清烟花视频素材哪里有?

如果你在寻找那些能点亮夜空的绚丽烟花视频素材&#xff0c;或者无水印的高清视频素材&#xff0c;那下面这些资源网站将会是你的宝库。今天&#xff0c;我要分享给你一些最佳的无水印视频素材下载网站&#xff0c;让你的视频制作闪耀起来。 1.蛙学府 这个网站是视频创作者的天…

C++之入门一

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

网安渗透攻击作业(4)

Unload-labs-01 function checkFile() { var file document.getElementsByName(upload_file)[0].value; if (file null || file "") { alert("请选择要上传的文件!"); return false; } //定义允许上传的文件类型 v…

PHP反序列化--引用

一、引用的理解&#xff1a; 引用就是给予一个变量一个恒定的别名。 int a 10; int b &a; a 20; cout<<a<<b<<endl; 输出结果 : a20、b20 二、靶场复现&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); include("flag.p…

10大漏洞评估和渗透测试工具【附安装包】

1、Netsparker Security Scanner 专为企业设计的强大的漏洞扫描和管理工具&#xff0c;它可以检测和利用 SQL 注入和 XSS 等漏洞。 https://www.netsparker.com/product/ 2、Acunetix Scanner 针对中小型企业的 Web 应用程序漏洞扫描程序&#xff0c;但也可以扩展到更大的组…

Jenkins实现CICD(3)_Jenkins连接到git

文章目录 1、如何完成上述操作&#xff0c;并且不报如下错&#xff1a;2、连接不上git&#xff0c;操作如下&#xff1a;3、将上边产生的3个文件拷贝到&#xff1a;C:\Windows\System32\config\systemprofile\.ssh4、新建下图凭证&#xff1a;创建步骤&#xff1a; 5、公钥填到…

搜索练习(地下城主,查找倍数)

地下城主 思路&#xff1a;这个其实就是bfs的板子&#xff0c;但是和以往的bfs不同&#xff0c;这个bfs适用于三维空间&#xff0c;也就是说多出一维需要进行搜索&#xff1a; 犯下的错误&#xff1a;在bfs的输出中我写成了cout<<q[tail].step1<<endl; 由于在之前…

机器人路径规划:基于流场寻路算法(Flow Field Pathfinding)的机器人路径规划(提供Python代码)

流场寻路算法(Flow Field Pathfinding)是一种基于流体动力学理论的路径规划算法&#xff0c;它模拟了流体在空间中的流动&#xff0c;并利用流体的运动特性来指导路径的选择。下面是流场寻路算法的基本介绍及算法描述&#xff1a; 1. 基本介绍 流场寻路算法通过将环境划分为网…

JWT原理

JWT 介绍 JWT&#xff08;JSON Web Token&#xff09;是一个开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种简洁的、自包含的方法用于通信双方之间以 JSON 对象的形式安全地传输信息。这种信息可以被验证和信任&#xff0c;因为它是数字签名的。JWT通常用于…

洛谷P1100 高低位交换

#先看题目 题目描述 给出一个小于 的非负整数。这个数可以用一个 32 位的二进制数表示&#xff08;不足 32 位用 0 补足&#xff09;。我们称这个二进制数的前 16 位为“高位”&#xff0c;后 16 位为“低位”。将它的高低位交换&#xff0c;我们可以得到一个新的数。试问这…

算法之前缀和

题目1: 【模板】一维前缀和&#xff08;easy&#xff09; 方法一: 暴力解法, 时间复杂度O(n*q), 当n10^5, q 10^5, 时间复杂度为O(10^10), 会超时. 方法二: 前缀和: 快速求出数组中某一段连续区间的和. 第一步: 预处理出来一个前缀和数组dp: 1. dp[i]表示区间[1,i]里所有元…

ConcurrentHashMap的相关介绍和使用

概述 ConcurrentHashMap是Java中提供的一个关于线程安全的哈希表实现&#xff0c;他是java.util.concurrent包的一部分&#xff0c;允许多个读操作并发进行&#xff0c;提高了并发环境下的性能。ConcurrentHashMap实现了ConcurrentMap接口&#xff0c;故而他也有ConcurrentMap…

2024.3.18

1、试编程 封装一个动物的基类&#xff0c;类中有私有成员:姓名&#xff0c;颜色&#xff0c;指针成员年纪再封装一个狗这样类&#xff0c;共有继承于动物类&#xff0c;自己拓展的私有成员有:指针成员:腿的个数(整型intcount)&#xff0c;共有成员函数:会叫:void speak() 要求…

ardupilot开发 --- 机载(边缘)计算机-VISP 篇

啊啊啊我的妻王氏宝钏 1. 一些概念 1. 一些概念 什么是VISP VISP即Visual servoing platform. Allows to control a robot equipped with a camera from measures extracted from the images.实现无人机飞行控制&#xff0c;机器人运动控制。实现实时目标检测。实现实时位姿估…

SpringCloud Sleuth 分布式请求链路跟踪

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十篇&#xff0c;即介绍 Sleuth 分布式请求链路跟踪。 二、概述 2.1 出现的原因 在微服务框架中&…

什么是IoT物联网平台?

在数字化浪潮的席卷下&#xff0c;物联网&#xff08;IoT&#xff09;技术逐渐渗透到我们生活的方方面面&#xff0c;从智能家居到智慧城市&#xff0c;从工业自动化到智能农业&#xff0c;IoT正以其独特的魅力改变着世界。然而&#xff0c;当我们谈论IoT时&#xff0c;我们究竟…
最新文章