- 作者:老汪软件技巧
- 发表时间: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;
![_模块教程_模块介绍](/uploads/allimg/20241221/1734786440911_3.jpg)
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 随你挑!
有收获?希望老铁们来个三连击,给更多的人看到这篇文章