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转换值进行一定的处理之后(均值处理以及误差消除),通过公式就可以算出我们当前的压力值了,代码非常简单,如下所示: 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值