目录
前言
最近项目有用到GY39这款传感器,这款传感器是集温湿度、气压、海拔、光强度于一体的,功能非常强大,这款传感器的通讯模式分为串口模式(默认)和IIC模式,在这里和大家分享一下串口模式的
一、硬件连接
VCC | 5V |
GND | GND |
CT | IO12(RX) |
DR | IO13(TX) |
二、串口通信协议
模块通信协议描述
串口通信
(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)
三、代码
#include <SoftwareSerial.h>
// 定义软串口引脚 (RX, TX)
SoftwareSerial gy39Serial(12, 13); // GY39_TX -> Arduino pin 10, GY39_RX -> Arduino pin 11
// 数据解析状态机变量
#define MAX_FRAME_LEN 20
uint8_t Re_buf[MAX_FRAME_LEN];
uint8_t state = 0; // 0:等待帧头1 1:等待帧头2 2:等待长度 3:读取数据
uint8_t len = 0; // 数据包长度
uint8_t dataIndex = 0; // 数据索引
uint8_t dataCount = 0; // 已接收数据计数
void setup() {
Serial.begin(9600); // 初始化硬件串口(用于调试输出)
gy39Serial.begin(9600); // 初始化GY39软串口
gy39Serial.write(0xA5);
gy39Serial.write(0x02);
gy39Serial.write(0xA7);
Serial.println("GY39 Sensor Demo Started");
}
void loop() {
gy39SerialStateMachine();
}
void gy39SerialStateMachine() {
uint8_t data = 0;
uint8_t datelen = 0;
uint8_t datatype = 0;
uint8_t dataIndex = 0;
uint8_t dataCount = 0;
uint8_t state = 0;
while (gy39Serial.available()) {
data = gy39Serial.read();
switch (state) {
case 0: //校验帧头1
if (data == 0x5A) {
Re_buf[0] = data;
state = 1;
}
break;
case 1: //校验帧头2
if (data == 0x5A) {
Re_buf[1] = data;
state = 2;
}
else {
state = 0;
}
break;
case 2: //校验数据类型:0x15为光照强度,0x45为温湿度、气压、海拔
datatype = data;
if(datatype == 0x45 || datatype == 0x15) {
Re_buf[2] = data;
state = 3;
}
else {
state = 0;
}
break;
case 3:
datelen = data;
if (datelen > 0 && datelen < MAX_FRAME_LEN - 2) {
Re_buf[3] = data;
dataIndex = 4;
dataCount = 0;
state = 4;
}
else {
state = 0;
}
break;
case 4:
Re_buf[dataIndex] = data;
dataIndex++;
dataCount++;
// 检查是否接收完所有数据
if (dataCount >= datelen) {
processData();
state = 0;
}
break;
}
}
}
// 处理接收到的完整数据包
void processData() {
//气象传感器
uint16_t Temp = (Re_buf[4] << 8) | Re_buf[5];
uint32_t P = ((uint32_t)Re_buf[6] << 24) | ((uint32_t)Re_buf[7] << 16) |
((uint32_t)Re_buf[8] << 8) | Re_buf[9];
uint16_t Hum = (Re_buf[10] << 8) | Re_buf[11];
uint16_t Alt = (Re_buf[12] << 8) | Re_buf[13];
Serial.print("Ambient temperature: ");
Serial.println((float)Temp / 100);
Serial.print("P: ");
Serial.println((float)P / 100);
Serial.print("Humidity: ");
Serial.println((float)Hum / 100);
Serial.print("Alt: ");
Serial.println((float)Alt);
}