首页 > 其他分享 >STM32案例学习 GY-39环境监测传感器模块

STM32案例学习 GY-39环境监测传感器模块

时间:2023-08-04 19:32:04浏览次数:43  
标签:SCL 39 void uint8 GY STM32 SDA GPIO I2C

STM32案例学习 GY-39环境监测传感器模块

硬件平台

  1. 野火STM32F1系列开发板
  2. 正点STM32F1系列开发板
  3. STM32F103ZET6核心板
  4. GY-39环境监测传感器模块

STM32案例学习  GY-39环境监测传感器模块_GY39

GY-39环境监测传感器模块

  1. GY-39 是一款低成本,气压,温湿度,光强度传感器模块。工作电压 3-5v,功耗小,安装方便。
  2. 其工作原理是,MCU 收集各种传感器数据,统一处理,直接输出计算后的结果。此模块,有两种方式读取数据,即**串口 UART(TTL 电平)**或者 IIC(2 线)。串口的波特率有 9600bps 与 115200bps,可配置,有连续,询问输出两种方式,可掉电保存设置。可适应不同的工作环境,与单片机及电脑连接。
  3. 模块另外可以设置单独传感器芯片工作模式,作为简单传感器模块,MCU 不参与数据处理工作
  4. 参考资料网站https://www.gysensor.cn/air-gy39/

技术参数(传感器精度请参考芯片手册)

STM32案例学习  GY-39环境监测传感器模块_STM32_02

模块引脚声明

Pin1

VCC

电源+ (3v-5v)

Pin2

CT

串口UART_TX / IIC_SCL

Pin3

DR

串口UART_RX / IIC_SDA

Pin4

GND

电源地

Pin5

NC

保留,不要连接

Pin6

INT

max44009光强芯片中断 S1=0(接GND时启用)

Pin7

SDA

芯片数据线S1=0(接GND时启用)

Pin8

SCL

芯片时钟线S1=0(接GND时启用)

PinA

S0

串口/MCU_IIC模式选择,接地为MCU_IIC模式

PinB

S1

仅使用传感器芯片选择

模块通信协议描述

  1. 串口通信 (1) 串口通信参数(默认波特率值 9600bps,可通过软件设定) 波特率:9600 bps 校验位:N 数据位:8 停止位:1 波特率:115200 bps 校验位:N 数据位:8 停止位:1 (2) 模块输出格式,每帧包含 8-13 个字节(十六进制): ① .Byte0: 0x5A 帧头标志 ②. Byte1: 0x5A 帧头标志 ③. Byte2: 0x15 本帧数据类型(参考含义说明) ④. Byte3: 0x04 数据量 ⑤. Byte4: 0x00~0xFF 数据前高 8 位 ⑤. Byte5: 0x00~0xFF 数据前低 8 位 ⑥. Byte6: 0x00~0xFF 数据后高 8 位 ⑦. Byte7: 0x00~0xFF 数据后低 8 位 ⑧. Byte8: 0x00~0xFF 校验和(前面数据累加和,仅留低 8 位)
    (3) Byte2 代表的含义说明

Byte2

0x15

0x45

0x55

说明

光照强度

温度,湿度,气压,海拔

IIC地址

(4) 数据计算方法 ①光照强度计算方法(当 Byte2=0x15 时,数据:Byte4~Byte7) : Lux=(前高8位<<24) | (前低8位<<16) | (后高8位<<8) | 后低8位 单位lux 例:一帧数据

<5A- 5A- 15 -04- 00 -00- FE- 40- 0B >

Lux=(0x00<<24)|(0x00<<16)|(0xFE<<8)|0x40 Lux=Lux/100 =650.88 (lux) ②温度、气压、湿度、海拔,计算方法(当 Byte2=0x45 时): 温度:Byte4~Byte5 T=(高 8 位<<8)|低 8 位 T=T/100 单位℃ 气压:Byte6~Byte9 P=(前高 8 位<<24) | (前低 8 位<<16) | (后高 8 位<<8) | 后低 8 位 P=P/100 单位 pa 湿度:Byte10~Byte11 Hum=(高 8 位<<8)|低 8 位 Hum=Hum/100 百分制 海拔:Byte12~Byte13 H=(高 8 位<<8)|低 8 位 单位 m 例:一帧数据

< 5A -5A -45 -0A -0B -2D -00 -97 -C4 -3F -12- 77 -00- 9C- FA >

T=(0x0B<<8)|0x2D=2861 温度 T=2861/100=28.61 (℃) P=(0x00<<24)|(0x97<<16)|(C4<<8)|3F=9946175 气压 P=9946175/100=99461.75 (pa) Hum=(0x12<<8)| 77=4727 湿度 Hum=4727/100=47.27 (%) 海拔 H=(0x00<<8)|0x9c=156 (m)

(5) 命令字节,由外部控制器发送至 GY-39 模块(十六进制)

STM32案例学习  GY-39环境监测传感器模块_GY39_03

STM32案例学习  GY-39环境监测传感器模块_STM32_04

2. IIC通信

STM32案例学习  GY-39环境监测传感器模块_STM32_05

硬件测试

接线示意图

STM32案例学习  GY-39环境监测传感器模块_GY39_06

代码

#include "main.h"
 void I2C_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
		/* 使能与 I2C有关的时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );  

	 /* PC3-I2C_SCL、PC5-I2C_SDA*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6| GPIO_Pin_7; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 
	GPIO_Init(GPIOB, &GPIO_InitStructure); 
	SCL_H;
	SDA_H;
}
void delay_1us(uint8_t x)//粗略延时,iic_40K
{
	uint8_t i=20;
	x=i*x;
	while(x--);
}
////////IIC起始函数//////////
/*
IIC起始:当SCL处于高电平期间,SDA由高电平变成低电平出现一个下降沿,然后SCL拉低
*/
uint8_t I2C_Start(void)
{
		SDA_H; 
		delay_1us(5);	//延时保证时钟频率低于40K,以便从机识别
		SCL_H;
		delay_1us(5);//延时保证时钟频率低于40K,以便从机识别
		if(!SDA_read) return 0;//SDA线为低电平则总线忙,退出
		SDA_L;   //SCL处于高电平的时候,SDA拉低
		delay_1us(5);
	  if(SDA_read) return 0;//SDA线为高电平则总线出错,退出
		SCL_L;
	  delay_1us(5);
	  return 1;
}
//**************************************
//IIC停止信号
/*
IIC停止:当SCL处于高电平期间,SDA由低电平变成高电平出现一个上升沿
*/
//**************************************
void I2C_Stop(void)
{
    SDA_L;
		SCL_L;
		delay_1us(5);
		SCL_H;
		delay_1us(5);
		SDA_H;//当SCL处于高电平期间,SDA由低电平变成高电平             //延时
}
//**************************************
//IIC发送应答信号
//入口参数:ack (0:ACK 1:NAK)
/*
应答:当从机接收到数据后,向主机发送一个低电平信号
先准备好SDA电平状态,在SCL高电平时,主机采样SDA
*/
//**************************************
void I2C_SendACK(uint8_t i)
{
    if(1==i)
			SDA_H;	             //准备好SDA电平状态,不应答
    else 
			SDA_L;  						//准备好SDA电平状态,应答 	
	  SCL_H;                    //拉高时钟线
    delay_1us(5);                 //延时
    SCL_L ;                  //拉低时钟线
    delay_1us(5);    
} 
///////等待从机应答////////
/*
当本机(主机)发送了一个数据后,等待从机应答
先释放SDA,让从机使用,然后采集SDA状态
*/
/////////////////
uint8_t I2C_WaitAck(void) 	 //返回为:=1有ACK,=0无ACK
{
	uint16_t i=0;
	SDA_H;	        //释放SDA
	SCL_H;         //SCL拉高进行采样
	while(SDA_read)//等待SDA拉低
	{
		i++;      //等待计数
		if(i==500)//超时跳出循环
		break;
	}
	if(SDA_read)//再次判断SDA是否拉低
	{
		SCL_L; 
		return RESET;//从机应答失败,返回0
	}
  delay_1us(5);//延时保证时钟频率低于40K,
	SCL_L;
	delay_1us(5); //延时保证时钟频率低于40K,
	return SET;//从机应答成功,返回1
}
//**************************************
//向IIC总线发送一个字节数据
/*
一个字节8bit,当SCL低电平时,准备好SDA,SCL高电平时,从机采样SDA
*/
//**************************************
void I2C_SendByte(uint8_t dat)
{
  uint8_t i;
	SCL_L;//SCL拉低,给SDA准备
  for (i=0; i<8; i++)         //8位计数器
  {
		if(dat&0x80)//SDA准备
		SDA_H;  
		else 
		SDA_L;
    SCL_H;                //拉高时钟,给从机采样
    delay_1us(5);        //延时保持IIC时钟频率,也是给从机采样有充足时间
    SCL_L;                //拉低时钟,给SDA准备
    delay_1us(5); 		  //延时保持IIC时钟频率
		dat <<= 1;          //移出数据的最高位  
  }					 
}
//**************************************
//从IIC总线接收一个字节数据
//**************************************
uint8_t I2C_RecvByte()
{
    uint8_t i;
    uint8_t dat = 0;
    SDA_H;//释放SDA,给从机使用
    delay_1us(1);         //延时给从机准备SDA时间            
    for (i=0; i<8; i++)         //8位计数器
    { 
		  dat <<= 1;
			
      SCL_H;                //拉高时钟线,采样从机SDA
     
		  if(SDA_read) //读数据    
		   dat |=0x01;      
       delay_1us(5);     //延时保持IIC时钟频率		
       SCL_L;           //拉低时钟线,处理接收到的数据
       delay_1us(5);   //延时给从机准备SDA时间
    } 
    return dat;
}
//**************************************
//向IIC设备写入一个字节数据
//**************************************
uint8_t Single_WriteI2C_byte(uint8_t Slave_Address,uint8_t REG_Address,uint8_t data)
{
	  if(I2C_Start()==0)  //起始信号
		{I2C_Stop(); return RESET;}           

    I2C_SendByte(Slave_Address);   //发送设备地址+写信号
 	  if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
   
		I2C_SendByte(REG_Address);    //内部寄存器地址,
 	  if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
   
		I2C_SendByte(data);       //内部寄存器数据,
	  if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
		
		I2C_Stop();   //发送停止信号
		
		return SET;
}
//**************************************
//从IIC设备读取一个字节数据
//**************************************
uint8_t Single_ReadI2C(uint8_t Slave_Address,uint8_t REG_Address,uint8_t *REG_data,uint8_t length)
{
 if(I2C_Start()==0)  //起始信号
		{I2C_Stop(); return RESET;}          
	 
	I2C_SendByte(Slave_Address);    //发送设备地址+写信号
 	if(!I2C_WaitAck()){I2C_Stop(); return RESET;} 
	
	I2C_SendByte(REG_Address);     //发送存储单元地址
 	if(!I2C_WaitAck()){I2C_Stop(); return RESET;} 
	
	if(I2C_Start()==0)  //起始信号
			{I2C_Stop(); return RESET;}            

	I2C_SendByte(Slave_Address+1);  //发送设备地址+读信号
 	if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
	
	while(length-1)
	{
		*REG_data++=I2C_RecvByte();       //读出寄存器数据
		I2C_SendACK(0);               //应答
		length--;
	}
	*REG_data=I2C_RecvByte();  
	I2C_SendACK(1);     //发送停止传输信号
	I2C_Stop();                    //停止信号
	return SET;
}
#ifndef _GY39_H
#define _GY39_H	 
#include "main.h"

#define SCL_H         GPIOB->BSRR = GPIO_Pin_6
#define SCL_L         GPIOB->BRR  = GPIO_Pin_6
   
#define SDA_H         GPIOB->BSRR = GPIO_Pin_7
#define SDA_L         GPIOB->BRR  = GPIO_Pin_7

#define SCL_read      GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
#define SDA_read      GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)

void I2C_GPIO_Config(void);
void I2C_Stop(void);
uint8_t Single_WriteI2C_byte(uint8_t Slave_Address,uint8_t REG_Address,uint8_t data);
uint8_t Single_ReadI2C(uint8_t Slave_Address,uint8_t REG_Address,uint8_t *REG_data,uint8_t length);

#endif
/**
  ************************************* Copyright ****************************** 
  *    
  * FileName   : main.c   
  * Version    : v5.0		
  * Author     : dele			
  * Date       : 2023-07-19   
******************************************************************************
 */
/*
STLink 连接 SWDIO PA13 SWCLK PA14 不要使用这两个端口
*/
//--------------------------------------------------------------------------------------------------
//  包含头文件    |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   
//--------------------------------------------------------------------------------------------------
#include "main.h"

//--------------------------------------------------------------------------------------------------
//  定义引用变量    |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   
//--------------------------------------------------------------------------------------------------
float gy_temp,gy_hum;
float aht_temp,aht_hum;//温湿度  


//==================================================================================================
//  实现功能: 硬件初始化配置
//  函数说明: Hareware_Iint
//  函数备注: 
//--------------------------------------------------------------------------------------------------
//  |   -   |   -   |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   
void Hareware_Iint(void)
{
    delay_init();//延时函数初始化	  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	USART1_Config(115200);//串口初始化波特率为115200 
    USART2_Config(115200);//ESP8266 通讯串口2  波特率为115200 
    printf("串口1配置			[OK] \r\n");
    printf("串口2配置			[OK] \r\n");
 	LED_Init();//LED端口初始化
    printf("LED_Init			[OK] \r\n");
    Beep_Init();//蜂鸣器初始化
    printf("Beep_Init			[OK] \r\n");
    KEY_Init();	//按键初始化
    printf("KEY_Init			[OK] \r\n");
	LCD_Init();  //液晶屏初始化
    printf("LCD_Init			[OK] \r\n");
    I2C_GPIO_Config();
    AHT_I2C_UserConfig();
    printf("AHT_I2C_UserConfig			[OK] \r\n");
    //TIM1_Int_Init(1999,35999);//定时1s
    //printf("TIM1_Int_Init			[OK] \r\n");
    W25QXX_Init();//W25QXX初始化
    printf("W25QXX初始化			[OK] \r\n");
    POINT_COLOR=RED; 
    GBK_Lib_Init();   
    printf("硬件GBK字库初始化			[OK] \r\n");    
    //硬件GBK字库初始化--(如果使用不带字库的液晶屏版本,此处可以屏蔽,不做字库初始化) 	
 	tp_dev.init();//触摸屏初始化
    printf("触摸屏初始化			[OK] \r\n");
    
}
//==================================================================================================
//  实现功能: 传感器数据采集
//  函数说明: SensorGet_Data
//  函数备注: 
//--------------------------------------------------------------------------------------------------
//  |   -   |   -   |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   
//================================================================================================== 
typedef struct
{
    uint32_t Press;
    uint16_t Temperature;
    uint16_t Humidity;
    uint16_t Altitude;
} gy_module;

gy_module Bme={0,0,0,0};
//==================================================================================================
//  实现功能: 主函数
//  函数说明: main
//  函数备注: 
//--------------------------------------------------------------------------------------------------
//  |   -   |   -   |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   
//================================================================================================== 
int main(void)
{	   
	Hareware_Iint();
    printf("Hareware_Iint  [OK] \r\n");
    uint8_t  raw_data[13]={0};
	uint16_t data_16[2]={0};
	uint32_t Lux;

    while(1)
    {
        if(Single_ReadI2C(0xb6,0x04,raw_data,10))
		{
			Bme.Temperature=(raw_data[0]<<8)|raw_data[1];
			data_16[0]=(((uint16_t)raw_data[2])<<8)|raw_data[3];
			data_16[1]=(((uint16_t)raw_data[4])<<8)|raw_data[5];
			Bme.Press=(((uint32_t)data_16[0])<<16)|data_16[1];
			Bme.Humidity=(raw_data[6]<<8)|raw_data[7];
			Bme.Altitude=(raw_data[8]<<8)|raw_data[9];
		}
		if(Single_ReadI2C(0xb6,0x00,raw_data,4))
			data_16[0]=(((uint16_t)raw_data[0])<<8)|raw_data[1];
			data_16[1]=(((uint16_t)raw_data[2])<<8)|raw_data[3];
			Lux=(((uint32_t)data_16[0])<<16)|data_16[1];
			
            gy_temp = Bme.Temperature/100;
            gy_hum  = Bme.Humidity/100;
            
            printf("Temperature:%.2fDegC \r\n  ",(float)Bme.Temperature/100);
            printf("Prees:%.2fPa  \r\n",(float)Bme.Press/100);
            printf("Humidity: %.2f     \r\n ",(float)Bme.Humidity/100);
            printf("Altitude: %.2f m   \r\n ",(float)Bme.Altitude);
			printf("LightLux: %.2f lux \r\n ",(float)Lux/100);  
			delay_ms(200);
        
    }


}

测试效果

代码参考链接

STM32案例学习  GY-39环境监测传感器模块_GY39_07

标签:SCL,39,void,uint8,GY,STM32,SDA,GPIO,I2C
From: https://blog.51cto.com/u_15090278/6966869

相关文章

  • STM32中SWD下载不进去的解决方法
    这是我第一次写自己的博客,希望以后写博客可以当做自己的个人习惯并坚持下去,作为技术分享,也欢迎各位大佬前来指正。本人本科学习的机械电子工程,了解机械制图、嵌入式编程、目前刚好学习了PCB制板,正在向着全栈工程师的目标进发(自嘲一波,各位见谅,哈哈)惨案现场以及经过第一次绘制PCB,......
  • 安全学习之路Day39
    ......
  • #轮廓线dp#HDU 1400 Mondriaan's Dream
    题目传送门分析状压dp会TLE,考虑用轮廓线dp,设\(dp[i][j][S]\)表示现在处理到\((i,j)\)这个位置轮廓线上状态为\(S\)的情况二进制位为1表示左边或者上方有骨牌跨过轮廓线,然后分类讨论转移一下即可代码#include<cstdio>#include<cstring>usingnamespacestd;con......
  • Newnode's NOI(P?)模拟赛 第二题 dp决策单调优化
    其实直接暴力O(n3)DP+O2O(n^3)DP+O_2O(n3)DP+O2优化能过…CODEO(n3)O(n^3)O(n3)先来个O(n3)O(n^3)O(n3)暴力DP(开了O2O_2O2)100分代码(极限数据0.5s0.5s0.5s)#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;......
  • POJ 1041 John's trip
    \(POJ\)\(1041\)\(John's\)\(trip\)一、题目大意多组数据,输入\(x,y,z\),表示结点\(x\)和结点\(y\)之间有一条序号为\(z\)的边,如果这个无向图中存在欧拉回路,就输出字典序最小的欧拉回路,如果不存在欧拉回路就输出Roundtripdoesnotexist.。当输入00表示一组数据输入结束......
  • STM32学习笔记
    目录时钟配置时钟配置时钟树系统时钟倍频到168MHzvoidSystemClock_Config(void){RCC_ClkInitTypeDefRCC_ClkInitStruct;RCC_OscInitTypeDefRCC_OscInitStruct;/*EnablePowerControlclock*/__HAL_RCC_PWR_CLK_ENABLE();/*Thevoltage......
  • LeetCode 739. 每日温度
    classSolution{public:vector<int>dailyTemperatures(vector<int>&t){stack<int>st;intn=t.size();vector<int>res(n);for(inti=n-1;i>=0;i--){while(st.size()&am......
  • Uncaught SyntaxError: Identifier 'originalPrompt' has already been declared
    控制台报错:UncaughtSyntaxError:Identifier'originalPrompt'hasalreadybeendeclared网上查询相关资料,预测是GoogleChrome浏览器安装了插件跟Vue项目运行代码出现了冲突。解决方法:关闭相关插件即可,【可能导致问题产生的插件有:SeleniumIDE】。参考文档:http://www.dtm......
  • Don't be clever
    Refhttps://stitcher.io/blog/dont-be-clever......
  • mysql插入报错java.sql.SQLException: Incorrect string value: '\xF0\x9F\x87\xA
    背景环境java8,centos7.9,mysql8.0.34新装的环境,默认给装了mysql8,想着与时俱进用下新版,结果插入就报错java.sql.SQLException:Incorrectstringvalue:'\xF0\x9F\x87\xA8\xF0\x9F...'forcolumn解决方法这个错误通常是由于MySQL数据库中的字符集不支持存储特定的字符或表情符......