硬件连接
用到的引脚宏定义
#define I2C_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()//时钟
#define I2C_GPIO_PORT GPIOG
#define I2C_SCL_PIN GPIO_PIN_15//时钟线引脚
#define I2C_SDA_PIN GPIO_PIN_14//双向数据线引脚
模块引脚号 | 名称 | 说明 |
1 | VCC | 供电电压源正极 |
2 | SCL | IIC时钟线,时钟输入引脚,由MCU输出时钟 |
3 | SDA | IIC数据线,双向IO口,用来传输数据 |
4 | ADDR | IIC地址线,接GND时器件地址为0100011 ,接VCC时器件地址为1011100 |
5 | GND | 供电电压源负极 |
BH1750的通讯过程
根据手册写出我流BH1750FVI通讯协议,步骤如下:
在访问I2C设备前,先打开时钟配置GPIO开漏输出,调用 I2C_CheckDevice() 检测I2C设备是否正常or存在。
bh1750fvi初始化,过程包括发送上电+连续检测命令。
BH1750 读取数据,过程包括发送ST+0x47+等待模块ack信号+读取高位数据(8bit)+发送ack+读取低位数据(8bit)+发送nack+SP(注:因为我将IIC地址线接GND,所以器件地址为0100011 ,所以读数据发送0x47)
最后调用函数并将结果打印出。
补:写指令流程
1.发送起始信号AT
2.发送写指令地址+接收ACK信号
3.发送操作指令+接收ACK信号
4.发送停止信号SP
补:读指令流程:
1.发送起始信号AT
2.发送读指令地址+接收ACK信号
3.接收高 8 位数据+发送ACK信号)
4.接收低 8 位数据+发送NACK
5.发送结束信号SP
BH1750的命令
功能 | 寄存器地址指令 | 注释说明 |
断电 | 0000_0000 | 没有活动状态。 |
接通电源 | 0000_0001 | 正在等待测量命令。 |
重置 | 0000_0111 | 重置数据寄存器值。在关机模式下,不能接受重置命令。 |
连续H分辨率模式 | 0001_0000 | 以1lx的分辨率开始测量。测量时间通常为120ms。 |
连续h分辨率模式2 | 0001_0001 | 在0.5lx的分辨率下开始测量。测量时间通常为120ms。 |
连续L分辨率模式 | 0001_0011 | 以4lx的分辨率开始测量。测量时间通常为16ms。 |
一次H分辨率模式 | 0010_0000 | 以1lx的分辨率开始测量。测量时间通常为120ms。测量后自动设置为关机模式。 |
一次H分辨率模式2 | 0010_0001 | 在0.5lx的分辨率下开始测量。测量时间通常为120ms。测量后自动设置为关机模式。 |
一次性L分辨率模式 | 0010_0011 | 以4lx的分辨率开始测量。测量时间通常为16ms。测量后自动设置为关机模式。 |
更改测量时间(高位) | 01000_MT[7,6,5] | 改变测量时间。※请参考“调整测量结果对光学窗口的影响”。 |
更改测量时间(低位) | 011_MT[4,3,2,1,0] | 更改测量时间。※请参考“调整测量结果对光学窗口的影响”。 |
驱动代码
IIC底层封装就不写了,用到了这些基础函数
/* 函数声明 ------------------------------------------------------------------*/
void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(uint8_t _ucByte);
uint8_t I2C_ReadByte(void);
uint8_t I2C_WaitAck(void);
void I2C_Ack(void);
void I2C_NAck(void);
void I2C_InitGPIO(void);
BH1750封装函数bsp_bh1750fvi.c
/* 需要包含头文件 --------------------------------------------------------------*/
#include "BH1750FVI/bsp_bh1750fvi.h"
#include "IIC/bsp_iic.h"
/* 函数体 --------------------------------------------------------------------*/
uint8_t BUF[3]={0};
/**
* @brief I2C_CheckDevice,检测I2C设备是否正常
* @param 无
* @retval 无
*/
uint8_t I2C_CheckDevice(void)
{
uint8_t ucAck;
I2C_Start(); /* 发送启动信号 */
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7*/
I2C_SendByte(0x46);
ucAck = I2C_WaitAck(); /* 检测设备的ACK应答 */
I2C_Stop(); /* 发送停止信号 */
return ucAck;
}
/**
* @brief bh1750fvi_Init,初始化向bh1750fvi发送上电+连续检测命令
* @param 无
* @retval 无
*/
void bh1750fvi_Init(void)
{
BH1750_WriteCommand(BH1750_Power_ON_REG); // 1.发送通电命令0x01
BH1750_WriteCommand(BH1750_CONTINUE_H_MODE); // 2.发送7位地址+读写位(0x10)
HAL_Delay(120);
}
/**
* @brief BH1750_WriteByte,BH1750 写数据
* @param uint8_t addr: 寄存器地址
* @retval 无
*/
uint8_t BH1750_WriteCommand(uint8_t addr)
{
I2C_Start(); // 1.发送起始信号
I2C_SendByte(Lux_ADDR); // 2.发送7位地址+读写位(0:写)
if(I2C_WaitAck()==1) //0表示正确应答,1表示无器件响应
return 1;
I2C_SendByte(addr); // 3.发送8位操作指令
if(I2C_WaitAck()==1)
return 2;
I2C_Stop(); // 4.发送停止信号
return 0;
}
/**
* @brief BH1750_ReadData, 一次完整的数据传输为16bit,BH1750 读取数据
* @param *BH1750_Data1: BH1750结构体
* @retval ERROR: 读取出错
* SUCCESS:读取成功
*/
uint16_t BH1750_ReadData(BH1750_Data_TypeDef *BH1750_Data1)
{
I2C_Start(); // 1.发送起始信号
I2C_SendByte(Read_ADDR); // 2.发送7位地址与读写位(0x47)
if(I2C_WaitAck()==1) // 3.等待从机应答信号
return 0;
BUF[0] = I2C_ReadByte(); //读取高八位数据
I2C_Ack(); //回应ACK
BUF[1] = I2C_ReadByte(); //读取低八位数据
I2C_NAck(); //最后一个数据需要回NOACK
I2C_Stop(); // 6.发送停止信号
BH1750_Data1->lux_high8bit = BUF[0];
BH1750_Data1->lux_low8bit = BUF[1];
BH1750_Data1->AllData = BH1750_Data1->lux_high8bit*256 + BH1750_Data1->lux_low8bit;
BH1750_Data1->illumination = (float)(BH1750_Data1->AllData/1.2);//计算实际光照值
if(BH1750_Data1->illumination != 0)
{
return SUCCESS;
}
else
return ERROR;
}
对应头文件bsp_bh1750fvi.h
#ifndef __BSP_BH1750FVI_H__
#define __BSP_BH1750FVI_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/************************ BH1750 数据类型定义******************************/
typedef struct
{
uint8_t lux_high8bit; //原始数据:光照高8位
uint8_t lux_low8bit; //原始数据:光照低8位
uint16_t AllData; //完整 16 位数据
float illumination; //实际光照
}BH1750_Data_TypeDef;
/* 宏定义 --------------------------------------------------------------------*/
#define Lux_ADDR 0x46 //接GND的写操作从地址
#define Read_ADDR 0x47 //接GND的读操作从地址
#define BH1750_Power_OFF_REG 0x00 //断电指令
#define BH1750_Power_ON_REG 0x01 //通电,等待测量命令
/*************************************************
不同模式下分辨率不同(也即精度不同)
高分辨率模式2:分辨率是0.5lx
高分辨率模式:分辨率1lx
低分辨率模式:分辨率4lx
不同模式只是精度不一样,对于计算没有区别
***************************************************/
/** 工作模式指令集 **/
#define BH1750_CONTINUE_H_MODE 0x10 //连续H分辨率模式
#define BH1750_CONTINUE_H_MODE2 0x11 //连续H分辨率模式2
#define BH1750_CONTINUE_L_MODE 0x13 //连续L分辨率模式
#define BH1750_ONE_TIME_H_MODE 0x20 //一次H分辨率模式
#define BH1750_ONE_TIME_H_MODE2 0x21 //一次H分辨率模式2
#define BH1750_ONE_TIME_L_MODE 0x23 //一次性L分辨率模式
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void bh1750fvi_Init(void);
uint8_t BH1750_WriteCommand(uint8_t addr);
uint16_t BH1750_ReadData(BH1750_Data_TypeDef *BH1750_Data1);
uint8_t I2C_CheckDevice(void);
#endif
bsp_iic.h
#ifndef __BSP_IIC_H__// 防止bsp_iic.h被重复引用
#define __BSP_IIC_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
#define I2C_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
#define I2C_GPIO_PORT GPIOG
#define I2C_SCL_PIN GPIO_PIN_15
#define I2C_SDA_PIN GPIO_PIN_14
#define I2C_SCL_HIGH() HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SCL_PIN,GPIO_PIN_SET) // 输出高电平
#define I2C_SCL_LOW() HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SCL_PIN,GPIO_PIN_RESET) // 输出低电平
#define I2C_SDA_HIGH() HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SDA_PIN,GPIO_PIN_SET) // 输出高电平
#define I2C_SDA_LOW() HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SDA_PIN,GPIO_PIN_RESET) // 输出低电平
#define I2C_SDA_READ() HAL_GPIO_ReadPin(I2C_GPIO_PORT,I2C_SDA_PIN)
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(uint8_t _ucByte);
uint8_t I2C_ReadByte(void);
uint8_t I2C_WaitAck(void);
void I2C_Ack(void);
void I2C_NAck(void);
void I2C_InitGPIO(void);
#endif /* __BSP_IIC_H__ */
main函数加入
#include "BH1750FVI/bsp_bh1750fvi.h"
#include "IIC/bsp_iic.h"
//光照传感器的结构体
BH1750_Data_TypeDef BH1750_Data1;
/* 模块初始化 */
I2C_InitGPIO();
if(I2C_CheckDevice()==0)
printf("BH1750设备检测成功\r\n");
else
printf("BH1750设备检测失败\r\n");
bh1750fvi_Init();
int main(void)
{
/* 初始化外设 */
InitPeri(); //所有外设初始化
while (1)
{
if(timecount==1000) //每秒打印一次
{
if(BH1750_ReadData(&BH1750_Data1)==SUCCESS)
{
printf("读取BH1750 %7.2f Lux \r\n",BH1750_Data1.illumination);//调试串口
}
else
{
printf("读取BH1750信息失败\n");
}
timecount=0;
}
}
}