Arduino-----GY39传感器(串口模式)

发布于:2025-06-18 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录


前言

最近项目有用到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);
}


网站公告

今日签到

点亮在社区的每一天
去签到