• 作者:老汪软件技巧
  • 发表时间:2024-12-21 21:07
  • 浏览量:

· 靠自媒体连续年入百万,靠自己买房买车。

我本科及硕士都是学机械,通过自学成功进入世界500强外企。我已经将自己的学习经验写成了一本电子书,超千人通过此书学习并转行成功。现在将这本电子书免费分享给大家,希望对你们有帮助:

电子书链接:

2. GY-302光感模块介绍

本文将带你具体了解 GY-302 光感模块。

GY-302 光感模块的芯片是 BH1750FVI,BH1750FVI 的内部是由光敏二极管、运算放大器、ADC 采集、晶振等组成的,它的通信协议是 I2C。BH1750FVI 的工作原理是 PD 二极管通过光生伏特效应将输入光信号转换成电信号,经运算放大电路放大后,由 ADC 采集电压,然后通过逻辑电路转换成 16 位二进制数存储在内部的寄存器中(光照越强,光电流越大,电压就越大)。

这是一款我们最常见的 GY-302 光感模块,它长这样:

引脚说明:

VCC:电源引脚,接正电(3V~5V);

GND:电源引脚,接负电;

SCL:时钟引脚,要接在单片机有 I2C-SCL 功能的引脚上;

SDA:数据引脚,要接在单片机有 I2C-SDA 功能的引脚上;

ADDR:接在 GND 或者 VCC 上(接在 GND 和 VCC 上的硬件地址不相同)。

设备参数:

参数额定值

电源电压

4.5V

运行温度

-40 ~ 85℃

储存温度

-40 ~ 100℃

反向电流

7mA

功率损耗

260mW

运行条件:

参数最小值时间最大值单位

VCC电压

2.4

3.0

3.6

I2C参考电压

1.65

VCC

特点:

采用 ROHM 原装 BH1750FVI 芯片;数据范围:0-65535lx;供电电源:3-5V;尺寸:13.9mm×18.5mm;传感器内置 16bitAD 转换器;直接数字输出,省略复杂的计算;不区分环境光源,接近于视觉灵敏度的分光特性;可对广泛的亮度进行高精度测定;模块内部包含通信电平转换。3. IIC通信

GY-302 光感模块的通信协议是 I2C。

I2C 通信协议是一种串行通信总线,使用多主从架构,是由飞利浦(Philips)公司在 1980 年代初设计的一种串行、半双工的通信,主要用于近距离、低速的芯片之间的通信。I2C 总线有两根双向的信号线,一根数据线 SDA 用于收发数据,一根时钟线 SCL 用于通信双方时钟的同步。

不太懂 I2C 通信协议的小伙伴可以去看一下 0.96 寸 OLED 屏幕模块的文章,那里面有详细的教程。

【OLED链接】

4. GY-302指令集

GY-302 指令集是一种用于控制和操作工业自动化设备的编程语言。它由一系列指令组成,可以控制各种设备,如机器人、PLC(可编程逻辑控制器)、CNC(计算机数控)系统等。

GY-302 指令集的特点:

易于理解和使用:采用了一种简单易懂的语法,使得开发人员能够轻松地学习和使用它。强大的功能:提供了一系列功能强大的指令,可以完成各种复杂的任务,如运动控制、逻辑控制、数据处理等。可扩展性:具有良好的可扩展性,可以通过添加新的指令和功能来满足不断发展的工业自动化需求。兼容性:与多种硬件设备和软件平台兼容,使得用户可以在不同的设备和平台上使用相同的指令集。安全性:采用了一系列安全机制,以确保工业自动化系统的安全和稳定运行。

GY-302指令集:

功能十六进制指令说明

断电

0x00

无激活状态

通电

0x01

等待测量指令

重置

0x07

重置数字寄存器值(重置指令在断电模式下不起作用)

连续 H 分辨率模式

0x10

在 11x 分辨率下开始测量(测量时间一般为 120ms)

连续 H 分辨率模式2

0x11

在 0.51x 分辨率下开始测量(测量时间一般为 120ms)

连续 L 分辨率模式

0x13

在 411x 分辨率下开始测量(测量时间一般为 16ms)

一次 H 分辨率模式

0x20

在 11x 分辨率下开始测量(测量时间一般为 120ms,测量后自动设置为断电模式)

一次 H 分辨率模式2

0x21

在 0.51x 分辨率下开始测量(测量时间一般为 120ms,测量后自动设置为断电模式)

一次 L 分辨率模式

0x23

在 411x 分辨率下开始测量(测量时间一般为 16ms,测量后自动设置为断电模式)

改变测量时间(高位)

01000_MT[7,6,5]

改变测量时间(要参考“根据光学扇窗的影响调整测量结果”)

改变测量时间(低位)

011_MT[4,3,2,1,0]

改变测量时间(要参考“根据光学扇窗的影响调整测量结果”)

5. GY-302驱动代码

接着我们来学习如何使用 GY-302 光感模块。

本教程使用的硬件如下:

接线如下:

GY-302STM32C8T60.96寸OLED屏幕模块

VCC

VCC

VCC

GND

GND

GND

B8

SCL

B9

SDA

SCL

B10

SDA

B11

ADDR

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法】。

ST-Link V2STM32

SWCLK

SWCLK

SWDIO

SWDIO

GND

GND

3.3V

3V3

接好如下图。开发板使用的是我们自绘的板子。大家也可以用自己的板子,只要是 STM32F103C8T6 主控芯片就行。

GY-302 同样是用 I2C 通信协议的,首先我们打开工程,新建一个 gy302.c 和 gy302.h。

先写一个引脚初始化的代码(本文使用 PB10 和 PB11),代码如下:

void gy302_IO_Init(void)
{
    GPIO_InitTypeDef GY302;
    GY302_I2C_SCL_SDA_CLK();                        //开启时钟
    GY302.Pin=GY302_I2C_SCL_PIN;                    //配置SCL引脚
    GY302.Mode=GPIO_MODE_OUTPUT_OD;                 //开漏输出
    GY302.Speed=GPIO_SPEED_FREQ_HIGH;               //高速
    HAL_GPIO_Init(GY302_I2C_SCL_SDA_GPIO, &GY302);
    GY302.Pin=GY302_I2C_SDA_PIN;                    //配置SDA引脚
    HAL_GPIO_Init(GY302_I2C_SCL_SDA_GPIO, &GY302);
}

接着我们需要写一个 I2C 的模拟信号,代码如下:

void GY302_Start(void)
{
    GY302_SDA_SET();                    //拉高数据线
    GY302_SCL_SET();                    //拉高时钟线
    delay_us(5);                 
    GY302_SDA_RESET();                  //产生下降沿
    delay_us(5);                
    GY302_SCL_RESET();                  //拉低时钟线
}
void GY302_Stop(void)
{
    GY302_SDA_RESET();                  //拉低数据线
    GY302_SCL_SET();                    //拉高时钟线
    delay_us(5);                 
    GY302_SDA_SET();                    //产生上升沿
    delay_us(5);
}  
void GY302_SendACK(int ack)
{
    if(ack == 1)                //写应答信号
            GY302_SDA_SET();
        else if(ack == 0)
            GY302_SDA_RESET();
        else
            return;
            
    GY302_SCL_SET();
    delay_us(5);
    GY302_SCL_RESET();
    delay_us(5);
}
uint32_t GY302_RecvACK(void)
{
    uint8_t mcy = 0;
    GY302_SCL_SET();                                //拉高时钟线
    delay_us(5);
    if(HAL_GPIO_ReadPin( GY302_I2C_SCL_SDA_GPIO, GY302_I2C_SDA_PIN ) == 1 )   //读应答信号
        mcy = 1 ;
    else
        mcy = 0 ;
    GY302_SCL_RESET();                              //拉低时钟线
    delay_us(5);
    return mcy;
}

I2C 通信准备完成之后,我们可以开始写指令操作了,首先需要定义一个写入数据的函数。我们对GY302发送命令时,要先发送器件地址+写入位,然后发送指令,代码如下:

void GY302_SendByte(uint8_t dat)
{
    uint8_t i;
 
    for (i=0; i<8; i++)                 //8位计数器
      {
        if( 0X80 & dat )
          GY302_SDA_SET();
        else
          GY302_SDA_RESET();
        dat <<= 1;

_模块教程_模块介绍

GY302_SCL_SET(); //拉高时钟线 delay_us(5); GY302_SCL_RESET(); //拉低时钟线 delay_us(5); } GY302_RecvACK(); } void GY302_Write_Cmd(uint8_t REG_Address)//REG_Address是要写入的指令 { GY302_Start(); //起始信号 GY302_SendByte(SlaveAddress); //发送器件地址+写信号 GY302_SendByte(REG_Address); //写入指令,内部寄存器地址 GY302_Stop(); //结束信号 }

这样我们就可以将我们的指令通过 I2C 通信协议写入到 GY-302 光感模块当中了,接下来我们需要读取 GY-302 光感模块采集的数据。读取数据的时候,需要先发送器件地址+读入位,然后读取两字节数据,代码如下:

uint8_t GY302_RecvByte(void)
{
    uint8_t i, bit, dat = 0;
    GY302_SDA_SET();                        //准备读取数据
    for (i=0; i<8; i++)                     //8位计数器
    {
        dat <<= 1;
        GY302_SCL_SET();                    //拉高时钟线
        delay_us(5);
       if( SET == HAL_GPIO_ReadPin( GY302_I2C_SCL_SDA_GPIO, GY302_I2C_SDA_PIN ) )
            bit = 0x01;
       else
            bit = 0x00;
            
        dat |= bit;                         //读数据 
            
        GY302_SCL_RESET();                  //拉低时钟线
        delay_us(5);
    }
    return dat;
}
uint32_t GY30_Value(void)
{
    uint8_t i, BUF[3];
    uint16_t dis_data, Value_GY_30 = 0;
    GY302_Write_Cmd(0x01);               //上电
    GY302_Write_Cmd(0x10);               //设置为连续 H 分辨率模式
    delay_ms(100);                          //延时,很重要,为读取数据做准备
    GY302_Start();                          //起始信号
    GY302_SendByte(SlaveAddress+1);         //发送设备地址+读信号
     for (i=0; i<3; i++)                    //连续读取6个地址数据到BUF
    {
        BUF[i] = GY302_RecvByte();
        if (i == 3)
        {
            GY302_SendACK(1);               //最后一个数据需要回NOACK
        }
        else
        {
            GY302_SendACK(0);               //回应ACK
        }
    }
 
    GY302_Stop();                           //停止信号
    delay_us(5);
    dis_data = BUF[0];
    dis_data = ( dis_data<<8 ) + BUF[1];    //字节合成数据
    Value_GY_30 = (float)dis_data;
    return Value_GY_30;
}

完成数据的读取,剩下的就是初始化 GY-302 光感模块了,根据上文的指令集我们可以得出代码如下:

void GY302_Init(void)
{
    gy302_IO_Init();
    GY302_Start();                       //起始信号
    GY302_SendByte(SlaveAddress);        //发送设备地址+写信号
    GY302_SendByte(0x01);                //上电
    GY302_Stop();                        //停止信号
}

gy302.h 的代码如下:

#ifndef __GY302_H
#define __GY302_H
#include "stm32f1xx_hal.h"
#define GY302_I2C_SCL_SDA_CLK()     __HAL_RCC_GPIOB_CLK_ENABLE()
#define GY302_I2C_SCL_SDA_GPIO      GPIOB
#define GY302_I2C_SCL_PIN           GPIO_PIN_10
#define GY302_I2C_SDA_PIN           GPIO_PIN_11
#define GY302_SCL_RESET()       HAL_GPIO_WritePin(GY302_I2C_SCL_SDA_GPIO,GY302_I2C_SCL_PIN,GPIO_PIN_RESET)  //SCL
#define GY302_SCL_SET()         HAL_GPIO_WritePin(GY302_I2C_SCL_SDA_GPIO,GY302_I2C_SCL_PIN,GPIO_PIN_SET)
#define GY302_SDA_RESET()       HAL_GPIO_WritePin(GY302_I2C_SCL_SDA_GPIO,GY302_I2C_SDA_PIN,GPIO_PIN_RESET)  //SDA
#define GY302_SDA_SET()         HAL_GPIO_WritePin(GY302_I2C_SCL_SDA_GPIO,GY302_I2C_SDA_PIN,GPIO_PIN_SET)
#define SlaveAddress       0x46  //ADDR接GND时的器件地址
void GY302_Start(void);
void GY302_Stop(void);
void GY302_Init(void);
void GY302_SendACK(int ack);
uint32_t GY302_RecvACK(void);
void GY302_SendByte(uint8_t dat);
void GY302_Write_Cmd(uint8_t REG_Address);
uint8_t GY302_RecvByte(void);
uint32_t GY30_Value(void);
#endif

main.c 代码如下:

#include "sys.h"
#include "delay.h"
#include "oled.h"
#include "gy302.h"
int main(void)
{
    uint16_t Light = 0;
    uint8_t a,b,c,d,e;
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    OLED_Init();                        /* oled初始化 */
    GY302_Init();                       /* GY-302初始化 */
    OLED_Fill(0x00);                    /* 清屏 */
    while(1)
    {
        Light = GY30_Value();                  //获取光照强度
        a = Light / 10000;
        b = (Light % 10000) / 1000;
        c = (Light % 1000) / 100;
        d = (Light % 100) / 10;
        e = Light % 10;
        OLED_Show_ChineseFont(0,0,0,16);
        OLED_Show_ChineseFont(16,0,1,16);
        OLED_Show_ChineseFont(32,0,2,16);
        OLED_Show_ChineseFont(48,0,3,16);
        OLED_ShowStr(64,0,":",16);
        OLED_Show_Char(0,2,a + '0',16);
        OLED_Show_Char(12,2,b + '0',16);
        OLED_Show_Char(24,2,c + '0',16);
        OLED_Show_Char(36,2,d + '0',16);
        OLED_Show_Char(48,2,e + '0',16);
        OLED_Show_Char(67,2,'l',16);
        OLED_Show_Char(75,2,'x',16);
        delay_ms(500);
    }
}

最终效果如下,这是正常状态:

打光状态下光照强度增加:

到这里我们就完成了 GY-302 光感模块的使用了,感谢各位看官的陪伴!

6. 小结今天我们学习了 GY-302 光感模块,不仅为我们的技术锦上添花,还复习了有关于 I2C 通信的知识,真是一石二鸟!希望本文章能够为各位看官枯燥的项目学习中带来几分兴趣,感谢各位看官,peace and love!

另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。

刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章


上一条查看详情 +鸿蒙Next之包体积极限优化
下一条 查看详情 +没有了