Estudio de caso STM32 Módulo de sensor de monitoreo ambiental GY-39

Estudio de caso STM32 Módulo de sensor de monitoreo ambiental GY-39

plataforma de hardware

  1. Placa de desarrollo de la serie Wildfire STM32F1
  2. Placa de desarrollo puntual de la serie STM32F1
  3. Tablero central STM32F103ZET6
  4. Módulo de sensor de monitoreo ambiental GY-39
    productos STM32
    inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Módulo de sensor de monitoreo ambiental GY-39

  1. GY-39 es un módulo de sensor de intensidad de luz, presión de aire, temperatura y humedad de bajo costo. Voltaje de trabajo 3-5v, bajo consumo de energía, fácil instalación.
  2. Su principio de funcionamiento es que la MCU recopila varios datos de sensores, los procesa de manera unificada y genera directamente los resultados calculados. Este módulo tiene dos formas de leer datos, a saber, **UART serial (nivel TTL)** o IIC (2 hilos ). La velocidad en baudios del puerto serie es de 9600 bps y 115200 bps , que se pueden configurar, hay dos formas de salida continua y de consulta, y la configuración se puede guardar después del apagado. Puede adaptarse a diferentes entornos de trabajo y conectarse con microcomputadoras y computadoras de un solo chip.
  3. Además, el módulo puede configurar el modo de trabajo de un chip de sensor separado.Como un módulo de sensor simple, la MCU no participa en el procesamiento de datos .
  4. Sitio web de referencia https://www.gysensor.cn/air-gy39/
    inserte la descripción de la imagen aquí

Parámetros técnicos (consulte el manual del chip para conocer la precisión del sensor)

inserte la descripción de la imagen aquí

Declaración de pines del módulo

Pin1 CCV Potencia + (3v-5v)
Pin2 Connecticut Serie UART_TX / IIC_SCL
Pin3 DR Serie UART_RX / IIC_SDA
Pin4 TIERRA toma de tierra
Pin5 CAROLINA DEL NORTE mantener, no conectar
Pin6 EN T max44009 interrupción de chip de intensidad de luz S1 = 0 (habilitado cuando se conecta a GND)
Pin7 ASD Chip de línea de datos S1=0 (habilitado cuando está conectado a GND)
Pin8 SCL Chip clock line S1=0 (habilitado cuando está conectado a GND)
PinA S0 Selección de modo puerto serie/MCU_IIC, conectado a tierra para modo MCU_IIC
Pasador B S1 Utilizar solo selección de chip de sensor

Descripción del protocolo de comunicación del módulo

  1. Comunicación en serie
    (1) Parámetros de comunicación en serie (la velocidad en baudios predeterminada es 9600 bps, que puede configurarse mediante software)
    Velocidad en baudios: 9600 bps Dígito de control: N Bits de datos: 8 Bits de parada: 1
    Velocidad en baudios: 115200 bps Dígito de control: N Datos bits: 8 Bits de parada: 1
    (2) Formato de salida del módulo, cada marco contiene 8-13 bytes (hexadecimal):
    ① .Byte0: encabezado de marco 0x5A
    ② Byte1: encabezado de marco 0x5A
    ③ .Byte2: 0x15 El tipo de datos de este marco (consulte la descripción del significado)
    ④. Byte3: 0x04 Cantidad de datos
    ⑤. Byte4: 0x00~0xFF Los 8 bits superiores de los datos
    ⑤. Byte5: 0x00~0xFF Los 8 bits inferiores de los datos
    ⑥. Byte6: 0x00~ 0xFF Alto 8 bits después de los datos
    ⑦ Byte 7: 0x00~0xFF 8 bits bajos después de los datos ⑧
    Byte 8: 0x00~0xFF suma de comprobación (suma acumulada de datos anteriores, solo deja 8 bits bajos)

    (3) Explicación del significado representado por Byte2

    Byte2 0x15 0x45 0x55
    ilustrar intensidad de luz temperatura, humedad, presión barométrica, altitud dirección de la CII

    (4) Método de cálculo de datos
    ① Método de cálculo de la intensidad de la luz (cuando Byte2=0x15, datos: Byte4~Byte7):
    Lux=(frontal alto 8 bits<<24) | (frontal bajo 8 bits<<16) | (trasero alto 8-bit<<8) | El ejemplo de lux de la unidad inferior de 8 bits
    : un marco de datos

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

    Lux=(0x00<<24)|(0x00<<16)|(0xFE<<8)|0x40
    Lux=Lux/100 =650,88 (lux)
    ②Temperatura, presión atmosférica, humedad, altitud, método de cálculo (cuando Byte2=0x45 hora):
    temperatura: Byte4~Byte5
    T=(8 bits altos<<8)|8 bits bajos
    T=T/100 unidad °C

    presión: Byte6~Byte9
    P=(primeros 8 bits altos<<24) | Bit<< 16) | (8 bits más altos<<8) | 8 bits bajos
    P=P/100 unidad pa

    humedad: Byte10~Byte11
    Hum=(8 bits altos<<8)|8 bits más bajos
    Hum=Hum/ 100 por ciento

    de altitud del sistema: Byte12~Byte13
    H=(8 bits altos<<8)|8 bits bajos unidad m
    Ejemplo: una trama de datos

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

    T=(0x0B<<8)|0x2D=2861
    temperatura T=2861/100=28,61 (℃)
    P=(0x00<<24)|(0x97<<16)|(C4<<8)|3F=9946175
    aire presión P=9946175/100=99461.75 (pa)
    Hum=(0x12<<8)| 77=4727
    humedad Hum=4727/100=47.27 (%)
    altitud H=(0x00<<8)|0x9c=156 (m)

(5) Byte de comando, enviado por controlador externo al módulo GY-39 (hexadecimal)
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
2. Comunicación IIC
inserte la descripción de la imagen aquí

prueba de hardware

Diagrama de cableado

inserte la descripción de la imagen aquí

el código

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


}

efecto de prueba

Enlace de referencia del código
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_43599390/article/details/131817046
Recomendado
Clasificación