BH1750.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "BH1750.h"
/* SDA引脚状态控制函数 */
void BH1750_W_SDA(uint8_t BitVal)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)BitVal);
Delay_us(10);
}
/* SCL引脚状态控制函数 */
void BH1750_W_SCL(uint8_t BitVal)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_13, (BitAction)BitVal);
Delay_us(10);
}
/* SDA引脚状态读取函数 */
uint8_t BH1750_R_SDA(void)
{
Delay_us(10);
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
}
/* 初始化BH1750相关引脚 */
void BH1750_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB12(SDA)和PB13(SCL)引脚初始化为开漏输出
/*设置SDA与SCL初始化后的默认电平,均为释放状态*/
BH1750_W_SDA(1);
BH1750_W_SCL(1);
BH1750_SendCommand(BHPowOn); //BH1750上电
BH1750_SendCommand(BHReset); //BH1750复位
BH1750_SendCommand(BHModeH1); //连续高分辨率模式1
}
/***************** 通信协议层 *******************/
/* 起始条件 */
void BH1750_Start(void)
{
BH1750_W_SDA(1);
BH1750_W_SCL(1);
BH1750_W_SDA(0);
BH1750_W_SCL(0);
}
/* 终止条件 */
void BH1750_Stop(void)
{
//BH1750_W_SCL(0); //每个时序基本单元最后会拉低SCL因此此处可以不用拉低SCL
BH1750_W_SDA(0);
BH1750_W_SCL(1);
BH1750_W_SDA(1);
}
/* 主机发送一个字节 */
void BH1750_SendByte(uint8_t Data)
{
for(uint8_t i = 0; i < 8; i++)
{
BH1750_W_SDA(Data & (0x80 >> i));
BH1750_W_SCL(1); //从机读取数据
BH1750_W_SCL(0); //主机改变SDA引脚状态
}
}
/* 主机接收一个字节 */
uint8_t BH1750_ReceiveByte(void)
{
uint8_t Data = 0x00;
BH1750_W_SDA(1); //接收前主机需要先释放SDA线
for(uint8_t i = 0; i < 8; i++)
{
BH1750_W_SCL(1);
if(BH1750_R_SDA())
Data |= (0x80 >> i);
BH1750_W_SCL(0); //从机改变SDA引脚状态
}
return Data;
}
/* 接收应答 */
uint8_t BH1750_ReceiveAck(void)
{
uint8_t Ack = 0;
BH1750_W_SDA(1); //主机释放SDA线,此时从机会改变SDA引脚状态
BH1750_W_SCL(1);
Ack = BH1750_R_SDA();
BH1750_W_SCL(0);
return Ack;
}
/* 发送应答 */
void BH1750_SendAck(uint8_t SendAck)
{
BH1750_W_SDA(SendAck);
BH1750_W_SCL(1); //从机会读取SDA引脚状态,判断主机是否应答
BH1750_W_SCL(0);
}
/***************** 主机与从机通信层 *******************/
/* 主机给从机发送指令 */
void BH1750_SendCommand(uint8_t Command)
{
uint32_t TimeOut = 0;
BH1750_Start();
BH1750_SendByte(BHAddWrite); //发送从机地址与读写位,写命令
while(BH1750_ReceiveAck()) //等待从机应答
{
TimeOut ++;
if(TimeOut > 100000)
break; //从此处退出表示从机超时未应答
}
BH1750_SendByte(Command);
while(BH1750_ReceiveAck()) //等待从机应答
{
TimeOut ++;
if(TimeOut > 100000)
break; //从此处退出表示从机超时未应答
}
BH1750_Stop();
}
/* 主机接收从机传来的信息 */
uint16_t BH1750_ReceiveData(void)
{
Delay_ms(120);
uint32_t TimeOut = 0;
uint16_t Data = 0x0000;
BH1750_Start();
BH1750_SendByte(BHAddRead); //发送从机地址与读写位,读命令
while(BH1750_ReceiveAck()) //等待从机应答
{
TimeOut ++;
if(TimeOut > 100000)
break; //从此处退出表示从机超时未应答
}
Data = BH1750_ReceiveByte();
BH1750_SendAck(0); //主机接收到信息应答,还需要从机发送的信息
Data <<= 8;
Data |= BH1750_ReceiveByte();
BH1750_SendAck(1); //主机接收到信息非应答,不需要从机发送的信息
BH1750_Stop();
return Data;
}
/* 将从 从机接收到的原始数据转化为光照强度 */
float BH1750_Light(void)
{
uint16_t Light = 0;
uint16_t result = 1, Data = BH1750_ReceiveData();
for(uint8_t i = 0; i < 16; i++)
{
if(Data & (0x8000 >> i))
{
for(uint8_t j = 0; j < (15 - i); j ++)
{
result *= 2;
}
Light += result;
result = 1;
}
}
return (float)Light / 1.2;
}
BH1750.h
#ifndef __BH1750_H
#define __BH1750_H
void BH1750_Init(void);
/********************* 指令集 **********************/
#define BHAddWrite 0x46 //从机地址“0100011”+最后写方向位
#define BHAddRead 0x47 //从机地址“0100011”+最后读方向位
#define BHPowDown 0x00 //关闭模块
#define BHPowOn 0x01 //打开模块等待测量指令
#define BHReset 0x07 //重置数据寄存器值在PowerOn模式下有效
#define BHModeH1 0x10 //高分辨率 单位1lx 测量时间120ms
#define BHModeH2 0x11 //高分辨率模式2 单位0.5lx 测量时间120ms
#define BHModeL 0x13 //低分辨率 单位4lx 测量时间16ms
#define BHSigModeH 0x20 //一次高分辨率 测量 测量后模块转到 PowerDown模式
#define BHSigModeH2 0x21 //同上类似
#define BHSigModeL 0x23 // 上类似
/***************** 通信协议层 *******************/
void BH1750_Start(void);
void BH1750_Stop(void);
void BH1750_SendByte(uint8_t Data);
uint8_t BH1750_ReceiveByte(void);
uint8_t BH1750_ReceiveAck(void);
void BH1750_SendAck(uint8_t SendAck);
/***************** 通信层 *******************/
void BH1750_SendCommand(uint8_t Command);
uint16_t BH1750_ReceiveData(void);
float BH1750_Light(void);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "BH1750.h"
#include <stdio.h>
float Light;
char buff[7];
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
BH1750_Init();
while (1)
{
Light = BH1750_Light();
sprintf(buff, "%7.2f", Light);
OLED_ShowString(1, 1, buff);
Delay_ms(500);
}
}
大致实现如上,可自主加入超时退出提醒机制,OLED显示优化等......