STM32模拟IIC与IIC四种实现数字光强采集模块GY30(标准库与HAL库)

news2025/1/20 13:16:59

目录

代码实现是的IIC通信,数据采集后在串口显示,方便大家实现二次开发

原件选择

GY-30 数字光强度介绍

BH1750芯片参数

引脚说明

 BH1750指令集

接线表设计

通过四种方式实现GY-30数据采集

1.标准库模拟IIC实现GY-30采集并串口1显示

 2.标准库IIC实现GY-30采集并串口1显示

3.HAL库模拟IIC实现GY-30采集并串口1显示

4.HAL库IIC实现GY-30采集并串口1显示

源码下载链接


代码实现是的IIC通信,数据采集后在串口显示,方便大家实现二次开发

原件选择

1.STM32F103

2.GY-30 数字光强度 光照传感器 BH1750FVI 

GY-30 数字光强度介绍

GY30简介
GY-30是一款内置ROHM-BH1750FLV芯片的数字光照强度模块,用于光照强度采集。
BH1750FVl是一种用于RC总线接口的数字环境光传感器LC。该芯片最适合于获取移动电话液晶显示器和按键背光功率的环境光数据。在高分辨率(1~65535 l×)范围内检测是可行的。

特性
IIC总线接口
光强数字转换器
16位分辩率(1~65535)
直接数字输出,省略复杂的计算,省略标定
不区分环境光源,接近于视觉灵敏度的分光特性
应用
手机、数码相机、车载导航,PDA、LCD显示等。


GY-30模块是一款基于IIC通信的16bit的数字型传感器。模块主要是以BH1750数字型光强感应芯片为核心及一些外围驱动电路。模块整体电路如图:

其中C1、C2 为电源滤波电容,R1、R3 为 I2C 上拉电阻,ADDR 是 I2C 通讯时设备地址的选择,即接电源或接地时,读操作、写操作的指令有所区别,如下图。一般为接地,即写操作指令为0x46,读操作指令为0x47。

BH1750芯片参数

BH1750是一款内部集成了光电转换、ADC转换、IIC信号转换等电路的芯片,省去了复杂信号处理电路,即能保持良好的稳定型又节省空间。BH1750内部简要框图如图:

该芯片内部电路主要分为4部分:其中

  1. 光敏二极管,导通电流随着光强的变化而变化;
  2. I/V转换电路:主要是将电流信号转换为电压信号;
  3. ADC转换电路:将电压信号转换为数字信号,分辨率为16bit;
  4. IIC逻辑电路:主要是将光强数据打包成I标准的IIC通信信号;

引脚说明

 BH1750指令集

#define BHAddWrite     0x46      //写地址
#define BHAddRead      0x47      //读地址
#define BHPowDown      0x00      //关闭模块
#define BHPowOn        0x01      //打开模块等待指令 
#define BHReset        0x07      //重置数据寄存器仅在BHpowOn模式下有效
#define BHModeH1       0x10      //高分辨率 模式1 单位 11X 测量时间 120ms 
#define BHModeH2       0x11      //高分辨率 模式2 单位 11X 测量时间 120ms 
#define BHModeL        0x13      //低分辨率 单位4lx 测量时间16ms  
#define BHSigModeH     0x20      //一次测量高分辨率模式1,然后转到powerdown模式
#define BHSigModeH2    0x21      //同上类似
#define BHSigModeL     0x23      //同上类似  

接线表设计

序号GY-30单片机STM32
1VCC3.3V/5V
2SCLPB6
3SDAPB7
4GNDGND
5-PA9(USART1_ TX)
6-PA10(USART1_RX)

通过四种方式实现GY-30数据采集

1.标准库模拟IIC实现GY-30采集并串口1显示

核心代码gy30.c

//发送起始信号
void IIC_Start(void)
{
	IIC_Sdaout_Mode();//输出模式
	IIC_SCL=1;
	IIC_SDAout=1;
	delay_us(2);
	IIC_SDAout=0;
	
	IIC_SCL=0;//方便后续数据收发
}
//停止信号
void IIC_Stop(void)
{
	IIC_Sdaout_Mode();//输出模式
	IIC_SCL=0;
	IIC_SDAout=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SDAout=1;
}
/***********发送应答信号**************************
**
**形参:u8 ack -- 0应答,1非应答
**
***************************************************/
void IIC_SendAck(u8 ack)
{
	IIC_Sdaout_Mode();//输出模式	
	IIC_SCL=0;//告诉从机,主机开始发送数据
	IIC_SDAout=ack&0x01;
	delay_us(2);
	IIC_SCL=1;//告诉从机,主机数据发送完成
	//方便下一次数据收发
	delay_us(2);
	IIC_SCL=0;
}
//获取应答信号
u8 IIC_Wait_Ack(void)
{
	u8 cnt=0;
	IIC_SdaIn_Mode();//配置为输入模式
	IIC_SDAout=1;	
	IIC_SCL=0;//告诉从机,主机需要获取数据
	delay_us(2);
	IIC_SCL=1;//从机数据发送完成,主机开始读取数据
	while(IIC_SDAin)
	{
		cnt++;
		delay_us(1);
		if(cnt>=100)return 1;
	}
	delay_us(2);
	IIC_SCL=0;//方便下一次数据收发
	return 0;
}
//发送一个字节数据
void IIC_Send_Byte(u8 data)
{
	u8 i=0;
	IIC_Sdaout_Mode();//输出模式
	for(i=0;i<8;i++)
	{
		IIC_SCL=0;//告诉从机,主机开始发送数据
		if(data&0x80)IIC_SDAout=1;
		else IIC_SDAout=0;
		delay_us(2);
		IIC_SCL=1;//主机数据发送完成
		data<<=1;
		delay_us(2);
	}
	IIC_SCL=0;//方便下一次数据收发
}
//读取一个字节数据
u8 IIC_Read_Byte(void)
{
	u8 i=0;
	u8 data=0;
	IIC_SdaIn_Mode();//配置为输入模式
	for(i=0;i<8;i++)
	{
		IIC_SCL=0;//告诉从机,主机需要获取数据
		delay_us(2);
		IIC_SCL=1;//开始读取数据
		data<<=1;//默认收到0
		if(IIC_SDAin)data|=0x01;
		delay_us(2);
	}
	IIC_SCL=0;
	return data;
}

void bh_data_send(u8 command)  
{  
    do{  
    IIC_Start();                      //iic开始
    IIC_Send_Byte(BHAddWrite);       //写地址  
    }while(IIC_Wait_Ack());           //等待响应 
    IIC_Send_Byte(command);          //发送命令  
    IIC_Wait_Ack();                   //等待响应 
    IIC_Stop();                       //iic停止  
}   


u16 bh_data_read(void)  
{  
    u16 buf;  
    IIC_Start();                       //iic开始  
    IIC_Send_Byte(BHAddRead);         //发送读地址
    IIC_Wait_Ack();                     //等待响应  
    buf=IIC_Read_Byte();              //读取数据  
		IIC_SendAck(0);
    buf=buf<<8;                        //读取并保存高八位数据
    buf+=0x00ff&IIC_Read_Byte();      //读取并保存第八位数据
		IIC_SendAck(1);
    IIC_Stop();                        //发送停止信号
    return buf;   
}  

void BH1750init(void)
{
	IIC_Init();//GPIO初始化
	bh_data_send(BHPowOn);    //发送启动信号
	bh_data_send(BHReset);    //清除寄存器  
  bh_data_send(BHModeH1);   //设置为模式1
  delay_ms(180);            //最高延时180ms 
}

实现

 2.标准库IIC实现GY-30采集并串口1显示

gy30.c核心代码

void I2C_GY30_Config(void)
{
	GPIO_InitTypeDef    GPIO_InitStuctrue;
	I2C_InitTypeDef     I2C_InitStuctrue;
	//开启GPIO外设时钟
	GY30_I2C_GPIO_APBxClkCmd(GY30_I2C_SCL_GPIO_CLK|GY30_I2C_SDA_GPIO_CLK,ENABLE);
	//开启IIC外设时钟
	GY30_I2C_APBxClkCmd(GY30_I2C_CLK,ENABLE);
	
	//SCL引脚-复用开漏输出
  GPIO_InitStuctrue.GPIO_Mode=GPIO_Mode_AF_OD;
  GPIO_InitStuctrue.GPIO_Pin=GY30_I2C_SCL_GPIO_PIN;
	GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GY30_I2C_SCL_GPIO_PORT,&GPIO_InitStuctrue);
	//SDA引脚-复用开漏输出
	GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStuctrue.GPIO_Pin = GY30_I2C_SDA_GPIO_PIN;
	GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GY30_I2C_SDA_GPIO_PORT,&GPIO_InitStuctrue);
	
	//IIC结构体成员配置
  I2C_InitStuctrue.I2C_Ack=I2C_Ack_Enable;
	I2C_InitStuctrue.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
	I2C_InitStuctrue.I2C_ClockSpeed=GY30_I2C_BAUDRATE;
	I2C_InitStuctrue.I2C_DutyCycle=I2C_DutyCycle_2;
	I2C_InitStuctrue.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStuctrue.I2C_OwnAddress1=STM32_I2C_OWN_ADDR;
	I2C_Init(GY30_I2C,&I2C_InitStuctrue);
	I2C_Cmd(GY30_I2C,ENABLE);

}

//向EEPROM写入一个字节
void  GY30_Byte_Write(uint8_t addr)
{
	//发送起始信号
	I2C_GenerateSTART(GY30_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
	//发送设备写地址
	I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
	//检测EV6事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
	//发送要操作设备内部的地址
	I2C_SendData(GY30_I2C,addr);
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
//  I2C_SendData(EEPROM_I2C,data);
//	//检测EV8_2事件
//	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
	//发送停止信号
	I2C_GenerateSTOP(GY30_I2C,ENABLE);
	
}

//向EEPROM写入多个字节
uint32_t  GY30_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
{
	
	I2CTimeout = I2CT_LONG_TIMEOUT;
	//判断IIC总线是否忙碌
	while(I2C_GetFlagStatus(GY30_I2C, I2C_FLAG_BUSY))   
	{
		if((I2CTimeout--) == 0) return 1;
	} 
	//重新赋值
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送起始信号
	I2C_GenerateSTART(GY30_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
	{
		 if((I2CTimeout--) == 0) return 2;
	} 
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送设备写地址
	I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
	//检测EV6事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
	{
		 if((I2CTimeout--) == 0) return 3;
	} 

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送要操作设备内部的地址
	I2C_SendData(GY30_I2C,addr);
	//检测EV8事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
	{
		 if((I2CTimeout--) == 0) return 4;
	} 

	while(Num_ByteToWrite)
	{
		I2C_SendData(GY30_I2C,*data);
		I2CTimeout = I2CT_FLAG_TIMEOUT;
		while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
		{
				if((I2CTimeout--) == 0) return  5;
		} 
		 Num_ByteToWrite--;
		 data++;
	}

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//检测EV8_2事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
	{
				if((I2CTimeout--) == 0) return 6;
	 } 
	//发送停止信号
	I2C_GenerateSTOP(GY30_I2C,ENABLE);
	 return 1;
}

//向EEPROM读取多个字节
uint32_t GY30_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead)
{
	 I2CTimeout = I2CT_LONG_TIMEOUT;
  //判断IIC总线是否忙碌
  while(I2C_GetFlagStatus(GY30_I2C, I2C_FLAG_BUSY))   
  {
    if((I2CTimeout--) == 0) return 1;
  } 
	
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送起始信号
	I2C_GenerateSTART(GY30_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
  {
        if((I2CTimeout--) == 0) return 7;
   } 
	
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送设备写地址
	I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
	//检测EV6事件等待从机应答
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR)
 {
        if((I2CTimeout--) == 0) return 8;
  }
  
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送要操作设备内部存储器的地址
	I2C_SendData(GY30_I2C,addr);
	//检测EV8事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
 {
        if((I2CTimeout--) == 0) return 9;
  }
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送起始信号
	I2C_GenerateSTART(GY30_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
	{
        if((I2CTimeout--) == 0) return 10;
   }
	I2CTimeout = I2CT_FLAG_TIMEOUT;	 
	//发送设备读地址
	I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Receiver);
	//检测EV6事件
	while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR)
	{
       if((I2CTimeout--) == 0) return 10;
   }
	 
	while(Num_ByteToRead--)
	{
		//是否是最后一个字节,若是则发送非应答信号
		if( Num_ByteToRead==0)
	 {
		 //发送非应答信号
		 I2C_AcknowledgeConfig(GY30_I2C,DISABLE);
		 //发送停止信号
	   I2C_GenerateSTOP(GY30_I2C,ENABLE);
	 }
	 
	 I2CTimeout = I2CT_FLAG_TIMEOUT;	 
	 //检测EV7事件
   while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR)
   {
       if((I2CTimeout--) == 0) return 10;
   }
	 
    *data=I2C_ReceiveData(GY30_I2C);
	  data++; 
	 
	}
	
	//重新开启应答信号
	I2C_AcknowledgeConfig(GY30_I2C,ENABLE);
  return 1;
}
void I2C_GY30_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite)
{
  u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
  //I2C_PageSize=8
  Addr = WriteAddr % I2C_PageSize;
  count = I2C_PageSize - Addr;
  NumOfPage =  NumByteToWrite / I2C_PageSize;
  NumOfSingle = NumByteToWrite % I2C_PageSize;
 
  /* 写入数据的地址对齐,对齐数为8 */
  if(Addr == 0) 
  {
    /* 如果写入的数据个数小于8 */
    if(NumOfPage == 0) 
    {
      GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle);
      GY30_WaitForWriteEnd();
    }
    /* 如果写入的数据个数大于8 */
    else  
    {
			//按页写入
      while(NumOfPage--)
      {
        GY30_Page_Write(WriteAddr, pBuffer, I2C_PageSize); 
    	  GY30_WaitForWriteEnd();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;
      }
      //不足一页(8个)单独写入
      if(NumOfSingle!=0)
      {
        GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle);
        GY30_WaitForWriteEnd();
      }
    }
  }
  /*写的数据的地址不对齐*/
  else 
  {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;	
      
      if(count != 0)
      {  
        GY30_Page_Write(WriteAddr, pBuffer, count);
        GY30_WaitForWriteEnd();
        WriteAddr += count;
        pBuffer += count;
      } 
      
      while(NumOfPage--)
      {
        GY30_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
        GY30_WaitForWriteEnd();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;  
      }
      if(NumOfSingle != 0)
      {
        GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle); 
        GY30_WaitForWriteEnd();
      }
    } 
}

效果如下: 

3.HAL库模拟IIC实现GY-30采集并串口1显示

#include "gy30.h" 

uint8_t mcy=0;
uint8_t BUF[3];
/***开始信号**/
void BH1750_Start()
{
    HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);                    //拉高数据线
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);                   //拉高时钟线
    delay_us(5);                 
    HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);                    //产生下降沿
    delay_us(5);                
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);                    //拉低时钟线
}

/*****停止信号******/
void BH1750_Stop()
{
    HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);                   //拉低数据线
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);                      //拉高时钟线
    delay_us(5);                 
    HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);                    //产生上升沿
    delay_us(5);                 
}
/*****初始化BH1750******/
void Init_BH1750()
{
		BH1750_Start();                                                 //起始信号
		BH1750_SendByte(SlaveAddress);                                  //发送设备地址+写信号
		BH1750_SendByte(0x01);                                  //内部寄存器地址
		BH1750_Stop();                                                  //停止信号
	
}

//连续读出BH1750内部数据
void mread(void)
{   
	  uint8_t i;	
    BH1750_Start();                          //起始信号
    BH1750_SendByte(SlaveAddress+1);         //发送设备地址·+读信号
	
	  for (i=0; i<3; i++)                      //连续读取6个地址数据到BUF
    {
        BUF[i] = BH1750_RecvByte();         
        if (i == 3)
        {
           BH1750_SendACK(1);                //最后一个数据需要回NOACK
        }
        else
        {		
          BH1750_SendACK(0);                //回应ACK
        }
   }
 
    BH1750_Stop();                          //停止信号
    Delay_mms(5);

}

uint32_t Value_GY30(void)
{
		uint16_t dis_data;
	  uint16_t Value_GY_30;
    Single_Write_BH1750(0x01);   // power on
    Single_Write_BH1750(0x10);   // H- resolution mode   
    HAL_Delay(180);            //延时180ms                    
    mread();       //连续读出数据,存储在BUF中
    dis_data=BUF[0];
    dis_data=(dis_data<<8)+BUF[1];//字节合成数据
    Value_GY_30=dis_data;
    return Value_GY_30;
}
//系统主频72MHZ
void delay_us(uint16_t us)
{
	while(us--)
	{
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();
	}
}
void Delay_mms(uint16_t tmp)
{
	  uint16_t i=0;
	  while(tmp--)
	  {
		i=12000;
		while(i--);
    }
}

/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void BH1750_SendACK(int ack)
{
			GPIO_InitTypeDef GPIO_InitStruct;
	
  GPIO_InitStruct.Pin = scl|sda;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 
    if(ack == 1)   //写应答信号
			HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET); 
		else if(ack == 0)
			HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);
		else
			return;
			
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);     
    delay_us(5);               
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);      
    delay_us(5);               
}

/**************************************
接收应答信号
**************************************/
int BH1750_RecvACK()
{		
		
	  GPIO_InitTypeDef GPIO_InitStruct;
	
	  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;  /*输入上拉*/
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Pin = sda;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 	
	
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);            //拉高时钟线
    delay_us(5);                
	
	  if(HAL_GPIO_ReadPin( GPIOB, sda ) == 1 )//读应答信号
        mcy = 1 ;  
    else
        mcy = 0 ;			
	
    HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);                    //拉低时钟线
    delay_us(5);               
  
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
	
    return mcy;
}

/**************************************
向iic总线发送一个字节数据
**************************************/
void BH1750_SendByte(uint8_t dat)
{
    uint8_t i;
 
    for (i=0; i<8; i++)         //8位计数器
      {
				if( 0X80 & dat )
          HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);
        else
          HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);
			 
				dat <<= 1;
        HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);               //拉高时钟线
        delay_us(5);             
        HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);                //拉低时钟线
        delay_us(5);            
      }
    BH1750_RecvACK();
}

//我们对BH1750发送命令时,要先发送器件地址+写入位,然后发送指令
//读取数据的时候,需要先发送器件地址+读入位,然后读取两字节数据

//写入指令
void Single_Write_BH1750(uint8_t REG_Address)//REG_Address是要写入的指令
{
	BH1750_Start();                  //起始信号
	BH1750_SendByte(SlaveAddress);  //发送器件地址+写信号
	BH1750_SendByte(REG_Address);   //写入指令,内部寄存器地址
	BH1750_Stop();                   //结束信号
}
/**************************************
从iic总线读取一个字节地址
**************************************/
uint8_t BH1750_RecvByte()
{
    uint8_t i;
    uint8_t dat = 0;
	  uint8_t bit;
	  
	 GPIO_InitTypeDef GPIO_InitStruct;
	
	 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;   /*上拉输入*/
   GPIO_InitStruct.Pin = sda;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
   HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
	
    HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);          //准备读取数据
    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);               //拉高时钟线
        delay_us(5);            
			
			  if( SET == HAL_GPIO_ReadPin( GPIOB, sda ) )
             bit = 0X01;
       else
             bit = 0x00;  
			
        dat |= bit;             //读数据 
			
        HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);                //拉低时钟线
        delay_us(5);           
    }
		
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
    return dat;
}

 

4.HAL库IIC实现GY-30采集并串口1显示

//写命令
void GY30_WR_CMD(uint8_t cmd)
{
	HAL_I2C_Master_Transmit(&hi2c1, 0x46, &cmd,1, 0x100);
	//HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
	//HAL_I2C_Mem_Write(&hi2c1 ,0x46,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}


/**
 @brief BH1750初始化函数
 @param 无
 @return 无
*/
void BH1750_Init(void)
{
	GY30_WR_CMD(0x01);
	GY30_WR_CMD(0x10);
	GY30_WR_CMD(0x47);
	
}

//读数据
void GY30_READ_DATA(uint8_t data[])
{
//	uint8_t temp = 0X47;
//	
//	HAL_I2C_Mem_Write(&hi2c1 ,0x47,0x00,I2C_MEMADD_SIZE_8BIT,&temp,1,0x100);
	BH1750_Init();
	HAL_I2C_Master_Receive(&hi2c1, 0x46, data, 2, 0x100);
	//HAL_I2C_Mem_Read_IT(&hi2c1, 0x46, 0X00,I2C_MEMADD_SIZE_8BIT, data, 2);
	//HAL_I2C_Mem_Read(&hi2c1 ,0x46,0x47,I2C_MEMADD_SIZE_8BIT,data,2,0x100);
}

/**
 @brief BH1750获取光强度
 @param 无
 @return 光强度
*/
uint32_t BH1750_ReadLightIntensity(void)
{
    uint32_t lux = 0;
    uint8_t sensorData[2] = {0};
    GY30_READ_DATA(sensorData);
    lux = (sensorData[0] << 8 | sensorData[1]);
    return lux;
}

四种实现效果一样,硬件IIC比模拟IIC的确要简单一些,看各人的喜好,花了一天时间特意研究整理,实现效果一定没有问题的。

创作不易

源码下载链接

(2条消息) STM32模拟IIC与IIC四种实现实现数字光强采集模块GY30(标准库与HAL库)-C文档类资源-CSDN文库

吾芯电子工作室

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40952.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

重构uniapp uni-ui coloerUI项目

重构uniapp uni-ui coloerUI项目这里写自定义目录标题重构uniappuni-uicoloerUI项目起源流程重构uniappuni-uicoloerUI项目 起源 从网上复制了若依移动端的代码,但是对里面的文件夹布局方式和第三方组件库引入方式不甚了解,就想着从头创建一个空白项目&#xff0c;然后一步一…

Linux中设置开机启动执行命令和普通用户配置环境变量开机启动生效

记录&#xff1a;343 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;开机启动就执行自定义的命令&#xff0c;配置rc.local文件达到需求&#xff1b;在普通用户中配置环境变量开机启动生效&#xff0c;使用profile实现。 版本&#xff1a; 操作系统&#xff1a;CentOS…

01、Docker入门

目录 1、Docker是什么 2、Docker与虚拟化 3、Docker虚拟化的好处 好处一&#xff1a;应用部署方便 好处二&#xff1a;服务器同等配置&#xff0c;性能更优&#xff0c;利用率更高 4、核心概念 5、CentOS7 安装docker(在线方式) 6、镜像 7、Docker容器 8、查看Docker容…

typescript 八叉树的简单实现

查了一些文章&#xff0c;准备自己用typescript写一个简单的八叉树场景管理。 所谓的简单&#xff0c;就是所有元素都是边长为1的立方体。 元素类和树节点类 //元素类&#xff0c;因为都是边长为1的立方体&#xff0c;所以就用cube命名 export class CubeData {public reado…

由于没有远程桌面授权服务器可以提供许可证,远程会话连接已断开

一、问题描述 在使用Windows的远程桌面工具连接WindowsServer2016服务器时&#xff0c;无法连接到服务器&#xff0c;并且提示【由于没有远程桌面授权服务器可以提供许可证&#xff0c;远程回来连接已经断开。请跟服务器管理员联系】。 二、解决办法 2.0、前提 Windows Serv…

黑胶歌曲没权限,看我python大展神通,一分钟一个歌单

前言 大家早好、午好、晚好吖 ❤ ~ 人之初&#xff0c;喜白嫖。 大家都喜欢白嫖&#xff0c;我也喜欢&#xff0c;那么今天就来试试怎么白嫖抑云~ 一、需要的准备 1、环境 Python3.6以上 pycharm2019以上 2、模块 requests # 发送请求模块 第三方模块 exec js # 调用JS的…

CocosCreater 教程(下)

1.物理系统 1.1 2D刚体 刚体是组成物理世界的基本对象。 1.2 2D 碰撞组件 目前引擎支持三种不同的碰撞组件&#xff1a; 盒碰撞组件&#xff08;BoxCollider2D&#xff09;、圆形碰撞组件&#xff08;CircleCollider2D&#xff09; 和 多边形碰撞组件&#xff08;PolygonCo…

Java中的抽象类和接口

java中的抽象类和接口抽象类什么是抽象类&#xff1f;抽象的使用场景抽象类的案例抽象类的特征、注意事项小结抽象类的应用知识&#xff1a;模版方法模式接口接口概述、特点接口的基本使用&#xff1a;被实现接口与接口的关系&#xff1a;多继承JDK8开始接口新增方法接口的注意…

AtCoder Beginner Contest 277 F. Sorting a Matrix(拓扑排序+虚点)

题目 n*m(2<n,m<1e6,n*m<1e6)的矩阵&#xff0c; 第i行第j列元素a[i][j](0<a[i][j]<n*m) 对于值为0的元素&#xff0c;你可以将其赋值为任意正整数&#xff0c; 不同位置的0元素&#xff0c;可以被赋值成不同的正整数 然后&#xff0c;你可以执行以下操作若…

firefly3399 移植linux5.15.80 - 2022-11-27

需要注意的是&#xff0c;虚拟机需要足够的硬盘空间&#xff0c;不小于15GB&#xff01;&#xff01; 一、内核源码下载 国内镜像地址 git clone https://kernel.source.codeaurora.cn/pub/scm/linux/kernel/git/stable/linux.git/ 基本达到了带宽的最大值。 国外地址&#…

Android使用AudioTrack播放WAV音频文件

目录 1、wav文件格式 2、wav文件解析 3、wav文件播放 QA&#xff1a; 开始播放wav的时候使用了系统的播放器mediaplayer进行播放&#xff0c;但是无奈mediaplayer支持的实在不好。 好些年前自己做过pcm播放使用的是audiotrack&#xff0c;参考&#xff1a;CSDN 其实两者之…

php 进程池设计与实现,phper必学!

php 进程池设计与实现phper 为什么要学习进程池池的概念为什么要有进程池?动态创建进程缺点进程池的优点选择子进程为新任务服务的方式进程池模型服务端客户端结语phper 为什么要学习进程池 在php开发过程中经常使用的 php-fpm 使用的进程模型就是进程池&#xff0c;学习进程…

如何基于FSM有限状态机实现Enemies AI

文章目录&#x1f35f; Preface&#x1f355; 巡逻状态&#x1f37f; 寻路状态&#x1f32d; 攻击状态&#x1f357; 完整代码&#x1f35f; Preface 本文简单介绍如何基于FSM有限状态机实现Enemies AI&#xff0c;首先定义敌人的AI逻辑&#xff1a;默认状态下Enemy为巡逻状态…

刷爆力扣之等价多米诺骨牌对的数量

刷爆力扣之等价多米诺骨牌对的数量 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&…

使用 nlohmann 解析 json 文件

使用 nlohmann 解析 json 文件nlohmann/json的配置json基本数据结构json文件的读取、构造与输出C对象与nlohmann::json对象的转换C对象转换成nlohmann::json对象nlohmann::json对象转换成C对象序列化反序列化序列化nlohmann 是德国工程师&#xff0c;以其名字为工程名的 nlohm…

springboot项目的打包发布部署,jar和war的区别

简介&#xff1a; 1.Spring Boot使用了内嵌容器&#xff0c;因此它的部署方式也变得非常简单灵活&#xff0c;可以将Spring Boot项目打包成JAR包来独立运行&#xff0c;也可以打包成WAR包部署到Tomcat容器中运行&#xff0c;如果涉及大规模的部署&#xff0c;Jenkins成为最佳选…

【HCIP-Datacom】 IS-IS基础 ISIS动态路由协议配置(ISIS思维导图在底部)

目录 ISIS配置方法&#xff1a; 路由计算&#xff1a; ATT置位条件&#xff1a; 路由渗透&#xff1a; ISIS的认证&#xff1a; ISIS配置命令&#xff1a; ISIS的开销类型&#xff1a; ISIS配置方法&#xff1a; 进入ISIS进程 isis 1 //创建isis进程 设置实体名 network-entit…

.NET 升级发布后,IIS出现了System.IO.DirectoryNotFoundException

最近计划升级项目到.NET6, 在使用Release发布后发现IIS不能发现wwwroot目录,什么错误? 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:无尽的折腾后,终于又回到了起点,工控,我来了 !1 发布的一…

《统计学习方法》 第十六章 主成分分析PCA

主成分分析(PCA) 假设xxx为mmm 维随机变量&#xff0c;其均值为μ\muμ&#xff0c;协方差矩阵为Σ\SigmaΣ 考虑由mmm维随机变量xxx到mmm维随机变量yyy的线性变换 yiαiTx∑k1mαkixk,i1,2,⋯,my _ { i } \alpha _ { i } ^ { T } x \sum _ { k 1 } ^ { m } \alpha _ { k …

计算点在线上的投影坐标

如题 计算点到线上的垂点&#xff0c;首先明确&#xff1a; 该线段必须给出确切的起始点和终点&#xff0c; 而不是一个向量&#xff0c;因为一个向量并不能代表一个线段。 所以参数列表如下&#xff1a; Vector3 VerticalPoint(Vector3 point, Vector3 lStart, Vector3 lEnd…