STM32案例學(xué)習(xí) GY-39環(huán)境監(jiān)測(cè)傳感器模塊
硬件平臺(tái)
- 野火STM32F1系列開發(fā)板
- 正點(diǎn)STM32F1系列開發(fā)板
- STM32F103ZET6核心板
- GY-39環(huán)境監(jiān)測(cè)傳感器模塊
GY-39環(huán)境監(jiān)測(cè)傳感器模塊
- GY-39 是一款低成本,氣壓,溫濕度,光強(qiáng)度傳感器模塊。工作電壓 3-5v,功耗小,安裝方便。
- 其工作原理是,MCU 收集各種傳感器數(shù)據(jù),統(tǒng)一處理,直接輸出計(jì)算后的結(jié)果。此模塊,有兩種方式讀取數(shù)據(jù),即**串口 UART(TTL 電平)**或者 IIC(2 線)。串口的波特率有 9600bps 與 115200bps,可配置,有連續(xù),詢問輸出兩種方式,可掉電保存設(shè)置??蛇m應(yīng)不同的工作環(huán)境,與單片機(jī)及電腦連接。
- 模塊另外可以設(shè)置單獨(dú)傳感器芯片工作模式,作為簡(jiǎn)單傳感器模塊,MCU 不參與數(shù)據(jù)處理工作。
-
參考資料網(wǎng)站 https://www.gysensor.cn/air-gy39/
技術(shù)參數(shù)(傳感器精度請(qǐng)參考芯片手冊(cè))
模塊引腳聲明
Pin1 | VCC | 電源+ (3v-5v) |
---|---|---|
Pin2 | CT | 串口UART_TX / IIC_SCL |
Pin3 | DR | 串口UART_RX / IIC_SDA |
Pin4 | GND | 電源地 |
Pin5 | NC | 保留,不要連接 |
Pin6 | INT | max44009光強(qiáng)芯片中斷 S1=0(接GND時(shí)啟用) |
Pin7 | SDA | 芯片數(shù)據(jù)線S1=0(接GND時(shí)啟用) |
Pin8 | SCL | 芯片時(shí)鐘線S1=0(接GND時(shí)啟用) |
PinA | S0 | 串口/MCU_IIC模式選擇,接地為MCU_IIC模式 |
PinB | S1 | 僅使用傳感器芯片選擇 |
模塊通信協(xié)議描述
-
串口通信
(1) 串口通信參數(shù)(默認(rèn)波特率值 9600bps,可通過軟件設(shè)定)
波特率:9600 bps 校驗(yàn)位:N 數(shù)據(jù)位:8 停止位:1
波特率:115200 bps 校驗(yàn)位:N 數(shù)據(jù)位:8 停止位:1
(2) 模塊輸出格式,每幀包含 8-13 個(gè)字節(jié)(十六進(jìn)制):
① .Byte0: 0x5A 幀頭標(biāo)志
②. Byte1: 0x5A 幀頭標(biāo)志
③. Byte2: 0x15 本幀數(shù)據(jù)類型(參考含義說明)
④. Byte3: 0x04 數(shù)據(jù)量
⑤. Byte4: 0x00~0xFF 數(shù)據(jù)前高 8 位
⑤. Byte5: 0x00~0xFF 數(shù)據(jù)前低 8 位
⑥. Byte6: 0x00~0xFF 數(shù)據(jù)后高 8 位
⑦. Byte7: 0x00~0xFF 數(shù)據(jù)后低 8 位
⑧. Byte8: 0x00~0xFF 校驗(yàn)和(前面數(shù)據(jù)累加和,僅留低 8 位)(3) Byte2 代表的含義說明
Byte2 0x15 0x45 0x55 說明 光照強(qiáng)度 溫度,濕度,氣壓,海拔 IIC地址 (4) 數(shù)據(jù)計(jì)算方法
①光照強(qiáng)度計(jì)算方法(當(dāng) Byte2=0x15 時(shí),數(shù)據(jù):Byte4~Byte7) :
Lux=(前高8位<<24) | (前低8位<<16) | (后高8位<<8) | 后低8位 單位lux
例:一幀數(shù)據(jù)<5A- 5A- 15 -04- 00 -00- FE- 40- 0B >
Lux=(0x00<<24)|(0x00<<16)|(0xFE<<8)|0x40
Lux=Lux/100 =650.88 (lux)
②溫度、氣壓、濕度、海拔,計(jì)算方法(當(dāng) Byte2=0x45 時(shí)):
溫度: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
例:一幀數(shù)據(jù)< 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) 命令字節(jié),由外部控制器發(fā)送至 GY-39 模塊(十六進(jìn)制)
2. IIC通信
硬件測(cè)試
接線示意圖
文章來源:http://www.zghlxwxcb.cn/news/detail-658590.html
代碼
#include "main.h"
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能與 I2C有關(guān)的時(shí)鐘 */
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)//粗略延時(shí),iic_40K
{
uint8_t i=20;
x=i*x;
while(x--);
}
IIC起始函數(shù)//
/*
IIC起始:當(dāng)SCL處于高電平期間,SDA由高電平變成低電平出現(xiàn)一個(gè)下降沿,然后SCL拉低
*/
uint8_t I2C_Start(void)
{
SDA_H;
delay_1us(5); //延時(shí)保證時(shí)鐘頻率低于40K,以便從機(jī)識(shí)別
SCL_H;
delay_1us(5);//延時(shí)保證時(shí)鐘頻率低于40K,以便從機(jī)識(shí)別
if(!SDA_read) return 0;//SDA線為低電平則總線忙,退出
SDA_L; //SCL處于高電平的時(shí)候,SDA拉低
delay_1us(5);
if(SDA_read) return 0;//SDA線為高電平則總線出錯(cuò),退出
SCL_L;
delay_1us(5);
return 1;
}
//**************************************
//IIC停止信號(hào)
/*
IIC停止:當(dāng)SCL處于高電平期間,SDA由低電平變成高電平出現(xiàn)一個(gè)上升沿
*/
//**************************************
void I2C_Stop(void)
{
SDA_L;
SCL_L;
delay_1us(5);
SCL_H;
delay_1us(5);
SDA_H;//當(dāng)SCL處于高電平期間,SDA由低電平變成高電平 //延時(shí)
}
//**************************************
//IIC發(fā)送應(yīng)答信號(hào)
//入口參數(shù):ack (0:ACK 1:NAK)
/*
應(yīng)答:當(dāng)從機(jī)接收到數(shù)據(jù)后,向主機(jī)發(fā)送一個(gè)低電平信號(hào)
先準(zhǔn)備好SDA電平狀態(tài),在SCL高電平時(shí),主機(jī)采樣SDA
*/
//**************************************
void I2C_SendACK(uint8_t i)
{
if(1==i)
SDA_H; //準(zhǔn)備好SDA電平狀態(tài),不應(yīng)答
else
SDA_L; //準(zhǔn)備好SDA電平狀態(tài),應(yīng)答
SCL_H; //拉高時(shí)鐘線
delay_1us(5); //延時(shí)
SCL_L ; //拉低時(shí)鐘線
delay_1us(5);
}
///等待從機(jī)應(yīng)答
/*
當(dāng)本機(jī)(主機(jī))發(fā)送了一個(gè)數(shù)據(jù)后,等待從機(jī)應(yīng)答
先釋放SDA,讓從機(jī)使用,然后采集SDA狀態(tài)
*/
/
uint8_t I2C_WaitAck(void) //返回為:=1有ACK,=0無ACK
{
uint16_t i=0;
SDA_H; //釋放SDA
SCL_H; //SCL拉高進(jìn)行采樣
while(SDA_read)//等待SDA拉低
{
i++; //等待計(jì)數(shù)
if(i==500)//超時(shí)跳出循環(huán)
break;
}
if(SDA_read)//再次判斷SDA是否拉低
{
SCL_L;
return RESET;//從機(jī)應(yīng)答失敗,返回0
}
delay_1us(5);//延時(shí)保證時(shí)鐘頻率低于40K,
SCL_L;
delay_1us(5); //延時(shí)保證時(shí)鐘頻率低于40K,
return SET;//從機(jī)應(yīng)答成功,返回1
}
//**************************************
//向IIC總線發(fā)送一個(gè)字節(jié)數(shù)據(jù)
/*
一個(gè)字節(jié)8bit,當(dāng)SCL低電平時(shí),準(zhǔn)備好SDA,SCL高電平時(shí),從機(jī)采樣SDA
*/
//**************************************
void I2C_SendByte(uint8_t dat)
{
uint8_t i;
SCL_L;//SCL拉低,給SDA準(zhǔn)備
for (i=0; i<8; i++) //8位計(jì)數(shù)器
{
if(dat&0x80)//SDA準(zhǔn)備
SDA_H;
else
SDA_L;
SCL_H; //拉高時(shí)鐘,給從機(jī)采樣
delay_1us(5); //延時(shí)保持IIC時(shí)鐘頻率,也是給從機(jī)采樣有充足時(shí)間
SCL_L; //拉低時(shí)鐘,給SDA準(zhǔn)備
delay_1us(5); //延時(shí)保持IIC時(shí)鐘頻率
dat <<= 1; //移出數(shù)據(jù)的最高位
}
}
//**************************************
//從IIC總線接收一個(gè)字節(jié)數(shù)據(jù)
//**************************************
uint8_t I2C_RecvByte()
{
uint8_t i;
uint8_t dat = 0;
SDA_H;//釋放SDA,給從機(jī)使用
delay_1us(1); //延時(shí)給從機(jī)準(zhǔn)備SDA時(shí)間
for (i=0; i<8; i++) //8位計(jì)數(shù)器
{
dat <<= 1;
SCL_H; //拉高時(shí)鐘線,采樣從機(jī)SDA
if(SDA_read) //讀數(shù)據(jù)
dat |=0x01;
delay_1us(5); //延時(shí)保持IIC時(shí)鐘頻率
SCL_L; //拉低時(shí)鐘線,處理接收到的數(shù)據(jù)
delay_1us(5); //延時(shí)給從機(jī)準(zhǔn)備SDA時(shí)間
}
return dat;
}
//**************************************
//向IIC設(shè)備寫入一個(gè)字節(jié)數(shù)據(jù)
//**************************************
uint8_t Single_WriteI2C_byte(uint8_t Slave_Address,uint8_t REG_Address,uint8_t data)
{
if(I2C_Start()==0) //起始信號(hào)
{I2C_Stop(); return RESET;}
I2C_SendByte(Slave_Address); //發(fā)送設(shè)備地址+寫信號(hào)
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
I2C_SendByte(REG_Address); //內(nèi)部寄存器地址,
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
I2C_SendByte(data); //內(nèi)部寄存器數(shù)據(jù),
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
I2C_Stop(); //發(fā)送停止信號(hào)
return SET;
}
//**************************************
//從IIC設(shè)備讀取一個(gè)字節(jié)數(shù)據(jù)
//**************************************
uint8_t Single_ReadI2C(uint8_t Slave_Address,uint8_t REG_Address,uint8_t *REG_data,uint8_t length)
{
if(I2C_Start()==0) //起始信號(hào)
{I2C_Stop(); return RESET;}
I2C_SendByte(Slave_Address); //發(fā)送設(shè)備地址+寫信號(hào)
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
I2C_SendByte(REG_Address); //發(fā)送存儲(chǔ)單元地址
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
if(I2C_Start()==0) //起始信號(hào)
{I2C_Stop(); return RESET;}
I2C_SendByte(Slave_Address+1); //發(fā)送設(shè)備地址+讀信號(hào)
if(!I2C_WaitAck()){I2C_Stop(); return RESET;}
while(length-1)
{
*REG_data++=I2C_RecvByte(); //讀出寄存器數(shù)據(jù)
I2C_SendACK(0); //應(yīng)答
length--;
}
*REG_data=I2C_RecvByte();
I2C_SendACK(1); //發(fā)送停止傳輸信號(hào)
I2C_Stop(); //停止信號(hào)
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 不要使用這兩個(gè)端口
*/
//--------------------------------------------------------------------------------------------------
// 包含頭文件 | 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;//溫濕度
//==================================================================================================
// 實(shí)現(xiàn)功能: 硬件初始化配置
// 函數(shù)說明: Hareware_Iint
// 函數(shù)備注:
//--------------------------------------------------------------------------------------------------
// | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
void Hareware_Iint(void)
{
delay_init();//延時(shí)函數(shù)初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//設(shè)置中斷優(yōu)先級(jí)分組為組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
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);//定時(shí)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");
}
//==================================================================================================
// 實(shí)現(xiàn)功能: 傳感器數(shù)據(jù)采集
// 函數(shù)說明: SensorGet_Data
// 函數(shù)備注:
//--------------------------------------------------------------------------------------------------
// | - | - | 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};
//==================================================================================================
// 實(shí)現(xiàn)功能: 主函數(shù)
// 函數(shù)說明: main
// 函數(shù)備注:
//--------------------------------------------------------------------------------------------------
// | - | - | 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);
}
}
測(cè)試效果
代碼參考鏈接文章來源地址http://www.zghlxwxcb.cn/news/detail-658590.html
到了這里,關(guān)于STM32案例學(xué)習(xí) GY-39環(huán)境監(jiān)測(cè)傳感器模塊的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!