当前位置: 首页 > article >正文

LVGL+FreeRTOS实战项目:智能健康助手(xgzp6847a篇)

XGZP6847A 压力传感器简介

  • 功能:用于测量气压或液压,输出模拟信号,与外部 ADC 结合使用以获取压力值。

  • 接口:输出电压与压力成线性关系。

  • 应用:广泛用于工业控制、环境监测、医疗设备等领域。

硬件连接

XGZP6847A 引脚功能STM32 连接
VCC电源输入 (+3.3V)3.3V
GNDGND
OUT模拟信号输出PA0

软件部分

XGZP6847A 输出模拟信号,因此无需通信协议,通过 STM32 内部 ADC 对信号进行采样即可实现数据读取,我们搭配DMA一起使用,以提高CPU利用率。

我们先看一下源文件:

#include "xgzp6847a.h"

	
__IO uint16_t ADC_ConvertedValue;

void XGZP_ADC_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 使能 GPIO 时钟
	RCC_AHB1PeriphClockCmd(XGZP_ADC_GPIO_CLK, ENABLE);
		
	// 配置 IO
	GPIO_InitStructure.GPIO_Pin = XGZP_ADC_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	    
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
	GPIO_Init(XGZP_ADC_GPIO_PORT, &GPIO_InitStructure);		
}

void XGZP_ADC_Mode_Init(void)
{ 	
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
  // 开启ADC时钟
	RCC_APB2PeriphClockCmd(XGZP_ADC_CLK , ENABLE);
	
	// ------------------DMA Init 结构体参数 初始化--------------------------
  // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
  // 开启DMA时钟
	RCC_AHB1PeriphClockCmd(XGZP_ADC_DMA_CLK, ENABLE); 
	// 外设基址为:ADC 数据寄存器地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = XGZP_ADC_DR_ADDR;	
  // 存储器地址,实际上就是一个内部SRAM的变量	
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&ADC_ConvertedValue;  
  // 数据传输方向为外设到存储器	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;	
	// 缓冲区大小为1,缓冲区的大小应该等于存储器的大小
	DMA_InitStructure.DMA_BufferSize = 1;	
	// 外设寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  // 存储器地址固定
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 
  // // 外设数据大小为半字,即两个字节 
	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 FIFO	,使用直连模式
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  
  // FIFO 大小,FIFO模式禁止时,这个不用配置	
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
	// 选择 DMA 通道,通道存在于流中
  DMA_InitStructure.DMA_Channel = XGZP_ADC_DMA_CHANNEL; 
  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
	DMA_Init(XGZP_ADC_DMA_STREAM, &DMA_InitStructure);
	// 使能DMA流
  DMA_Cmd(XGZP_ADC_DMA_STREAM, ENABLE);

  // -------------------ADC Common 结构体 参数 初始化------------------------
	// 独立ADC模式
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  // 时钟为fpclk x分频	
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  // 禁止DMA直接访问模式	
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  // 采样时间间隔	
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;  
  ADC_CommonInit(&ADC_CommonInitStructure);
	
  // -------------------ADC Init 结构体 参数 初始化--------------------------
	ADC_StructInit(&ADC_InitStructure);
  // ADC 分辨率
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 禁止扫描模式,多通道采集才需要	
  ADC_InitStructure.ADC_ScanConvMode = DISABLE; 
  // 连续转换	
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  //外部触发通道,本例子使用软件触发,此值随便赋值即可
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐	
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1个
  ADC_InitStructure.ADC_NbrOfConversion = 1;                                    
  ADC_Init(XGZP_ADC, &ADC_InitStructure);
  //---------------------------------------------------------------------------
	
  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
  ADC_RegularChannelConfig(XGZP_ADC, XGZP_ADC_CHANNEL, 1, ADC_SampleTime_3Cycles); 
  // 使能DMA请求 after last transfer (Single-ADC mode)
  ADC_DMARequestAfterLastTransferCmd(XGZP_ADC, ENABLE);
  // 使能ADC DMA
  ADC_DMACmd(XGZP_ADC, ENABLE);
  // 使能ADC
  ADC_Cmd(XGZP_ADC, ENABLE);  
  //开始adc转换,软件触发
  ADC_SoftwareStartConv(XGZP_ADC);

}

void XGZP_Init(void)
{
	XGZP_ADC_GPIO_Init();
	XGZP_ADC_Mode_Init();
}

u16 Get_Adc_Average(u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=ADC_ConvertedValue;
		delay_ms(5);
	}
	return temp_val/times;
} 	 

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;
}

int xgzp_adc;
const float VCC =3300;         // ADC参考电压为mV
float Pressure_V=0.0;
long pressure=0;
const float Voltage_0 =160;    // 零点电压值mV  校准时需修改
const float Voltage_40 =3750 ; // 满量程输出电压值mV  需修改
char P_disbuff[6]={0};

//void Get_XGZP_Data(void)
//{
//	xgzp_adc = Get_Adc_Average(10);
//	Pressure_V=(xgzp_adc*VCC)/4096;
//	pressure = map(Pressure_V, Voltage_0, Voltage_40, 0, 40000.0);	
//	/*显示气压值*/
//	if(pressure<=0){pressure=0;}
//	if(pressure>=40000){pressure=40000;}

//	P_disbuff[0]=(int)((pressure))/10000+'0';	
//	P_disbuff[1]=(int)((pressure))%10000/1000+'0';
//	P_disbuff[2]=(int)((pressure))%1000/100+'0';
//	P_disbuff[3]=(int)((pressure))%100/10+'0';
//	P_disbuff[4]=(int)((pressure))%10+'0';
//	//OLED_ShowStr(27,4,P_disbuff,2);	
	ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值
//	//LCD_Show_Info(0,80, "ADC: %s", P_disbuff);
//}


void Get_XGZP_Data(char *buffer)
{
	xgzp_adc = Get_Adc_Average(10);
	Pressure_V=(xgzp_adc*VCC)/4096;
	pressure = map(Pressure_V, Voltage_0, Voltage_40, 0, 40000.0);	
	/*显示气压值*/
	if(pressure<=0){pressure=0;}
	if(pressure>=40000){pressure=40000;}

	buffer[0]=(int)((pressure))/10000+'0';	
	buffer[1]=(int)((pressure))%10000/1000+'0';
	buffer[2]=(int)((pressure))%1000/100+'0';
	buffer[3]=(int)((pressure))%100/10+'0';
	buffer[4]=(int)((pressure))%10+'0';
	
	//OLED_ShowStr(27,4,P_disbuff,2);	
//	ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值
	//LCD_Show_Info(0,80, "ADC: %s", P_disbuff);
}

我们这里其实就是一套经典ADC+DMA的模板了,这里我给大家说一下大概思路,讲解注释里面几乎都写得非常清楚,如果有看不懂的,说明有关这两个外设的STM32知识没学明白,可以先去重新学习一下。

我们接的是PA0,通过查表可以知道,用的是ADC1的通道0,所以我们ADC配置的时候配置的是ADC1的通道0,如下所示:

 然后就是DMA了,我们继续查看芯片手册:

可以看到对应的是DMA2的数据流0的通道2,所以我们按如图所下配置:

之后我们手动开启ADC转换,那么就可以实现ADC+DMA转换了,之后需要知道ADC值,只需要查看数据所转移到地址中的数据值,我们这里的是ADC_ConvertedValue 。

获取XGZP6847A传感器值  

我们在获取传感器任务里面进行获取,我们先不用关注FreeRTOS,我们先去关注一下如何获取传感器数值。

Get_XGZP_Data(sens_data.P_disbuff);

这里就是把我们的ADC转换值进行一定的处理之后(均值处理以及误差消除),通过公式就可以算出我们当前的压力值了,代码非常简单,如下所示: 


http://www.kler.cn/a/518246.html

相关文章:

  • 【算法工程】VS Code问题解决:Failed to parse remote port from server output
  • Java多线程的面试面试题及答案解析
  • Golang之Context详解
  • 【pytorch 】miniconda python3.11 环境安装pytorch
  • 无公网IP 外网访问媒体服务器 Emby
  • GS论文阅读--GeoTexDensifier
  • 如何实现分页相关功能
  • 比简单工厂更好的 - 工厂方法模式(Factory Method Pattern)
  • Lambda 表达式
  • 笔记《Effective Java》01: 创建和销毁对象
  • 软件测试丨消息管道(Kafka)测试体系
  • 电路研究9.2.1——合宙Air780EP音频的AT控制指令
  • 【工程篇】01:GPU可用测试代码
  • python学opencv|读取图像(四十四)原理探究:bitwise_and()函数实现图像按位与运算
  • UGUI判断点击坐标是否在UI内部,以及子UI内部
  • 运行虚幻引擎UE设置Visual Studio
  • spark sql中对array数组类型操作函数列表
  • android studio搭建NDK环境,使用JNI (Java 调 C) 二 通过CMake
  • Couchbase UI: Server
  • 期权帮|如何利用股指期货进行对冲套利?