PIC单片机驱动BH1750光照传感器,轻松获取环境光照数据

在智慧农业、智能家居、环境监测等物联网应用中,光照强度是一个常见且重要的采集参数。通过实时获取光照数据,系统可以自动调节灯光、控制遮阳设备、调节植物补光等,实现智能化控制。本文将详细介绍如何使PIC12F1822 这款8脚单片机,通过IIC总线读取BH1750 光照传感器的数据,并提供完整的代码实现。

一、 BH1750 传感器简介

BH1750是一款数字型环境光强度传感器,采用IIC接口通信,具备以下特点:

  • 测量范围:1 ~ 65535 Lux
  • 高分辨率:支持0.5 Lux精度
  • 内置ADC,直接输出数字信号
  • 低功耗,适用于电池供电设备
  • 支持多种测量模式(连续/单次、高/低分辨率)

其典型应用电路简洁:

二、硬件连接: PIC12F1822 BH1750

PIC12F1822是一款小巧且功能丰富的8位单片机,本例中我们使用软件模拟IIC方式。

连接方式如下:

  • BH1750 VCC → PIC +3.3V
  • BH1750 GND → PIC GND
  • BH1750 SDA → PIC RA0(模拟SDA)
  • BH1750 SCL → PIC RA1(模拟SCL)

三、软件实现:

PIC12F1822与BH1750例程如下:

#include<pic12f1822.h>

__CONFIG(0x083c);

__CONFIG(0x3612);

#define uint16 unsigned int

#define uint8 unsigned char

#define fint32 float

#define uint32 unsigned long

#define uchar unsigned char

#define uint unsigned int

//引脚定义

#define B_LUX_SCL0_O TRISA1=0

#define B_LUX_SCL0_H RA1=1

#define B_LUX_SCL0_L RA1=0

#define B_LUX_SDA0_O TRISA0=0

#define B_LUX_SDA0_H RA0=1

#define B_LUX_SDA0_L RA0=0

#define B_LUX_SDA0_I TRISA0=1

#define B_LUX_SDA0_DAT RA0

#define B_LUX_SlaveAddress 0x46 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改

/*-----------------------------函数声明-------------------------------*/

void B_LUX_delay_nms(uint16 k);

void B_LUX_Init(void);

void B_LUX_Single_Write(uint8 REG_Address); //单个写入数据

uint8 B_LUX_Single_Read(uint8 REG_Address); //单个读取内部寄存器数据

void B_LUX_Multiple_read(void); //连续的读取内部寄存器数据

//------------------------------------

void B_LUX_Delay5us(void);

void B_LUX_Delay5ms(void);

void B_LUX_Start(void); //起始信号

void B_LUX_Stop(void); //停止信号

void B_LUX_SendACK(uint8 ack); //应答ACK

uint8 B_LUX_RecvACK(void); //读ack

void B_LUX_SendByte(uint8 dat); //IIC单个字节写

uint8 B_LUX_RecvByte(void); //IIC单个字节读

uint16 B_LUX_GetLux(void);

uint8 BUF_0[8]; //接收数据缓存区

uint16 dis_data_0; //变量

/*---------------------------------------------------------------------

功能描述: 延时纳秒 不同的工作环境,需要调整此函数

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_delay_nms(uint16 k)

{

uint16 i,j;

for(i=0;i<k;i++)

{

for(j=0;j<1760;j++)

{

;

}

}

}

/*---------------------------------------------------------------------

功能描述: 延时5微秒 不同的工作环境,需要调整此函数

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Delay5us()

{

uint8 n = 20;

while (--n);

}

/*---------------------------------------------------------------------

功能描述: 延时5毫秒 不同的工作环境,需要调整此函数

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Delay5ms()

{

uint16 n = 10000;

while (--n);

}

/*---------------------------------------------------------------------

功能描述: 起始信号

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Start()

{

B_LUX_SDA0_H; //拉高数据线

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

B_LUX_SDA0_L; //产生下降沿

B_LUX_Delay5us(); //延时

B_LUX_SCL0_L; //拉低时钟线

}

/*---------------------------------------------------------------------

功能描述: 停止信号

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Stop()

{

B_LUX_SDA0_L; //拉低数据线

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

B_LUX_SDA0_H; //产生上升沿

B_LUX_Delay5us(); //延时

B_LUX_SCL0_L;

B_LUX_Delay5us();

}

/*---------------------------------------------------------------------

功能描述: 发送应答信号

参数说明: ack - 应答信号(0:ACK 1:NAK)

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_SendACK(uint8 ack)

{

if (ack&0x01) B_LUX_SDA0_H; //写应答信号

else B_LUX_SDA0_L;

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

B_LUX_SCL0_L; //拉低时钟线

B_LUX_SDA0_H;

B_LUX_Delay5us(); //延时

}

/*---------------------------------------------------------------------

功能描述: 接收应答信号

参数说明: 无

函数返回: 返回应答信号

---------------------------------------------------------------------*/

uint8 B_LUX_RecvACK()

{

uint8 CY = 0x00;

B_LUX_SDA0_H;

B_LUX_SDA0_I;

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

if(B_LUX_SDA0_DAT)

CY |=1 ; //读应答信号

else CY|=0;

B_LUX_Delay5us(); //延时

B_LUX_SCL0_L; //拉低时钟线

B_LUX_SDA0_O;

return CY;

}

/*---------------------------------------------------------------------

功能描述: 向IIC总线发送一个字节数据

参数说明: dat - 写字节

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_SendByte(uint8 dat)

{

uint8 i;

for (i=0; i<8; i++) //8位计数器

{

if (dat&0x80) B_LUX_SDA0_H;

else B_LUX_SDA0_L; //送数据口

B_LUX_Delay5us(); //延时

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

B_LUX_SCL0_L; //拉低时钟线

B_LUX_Delay5us(); //延时

dat <<= 1; //移出数据的最高位

}

B_LUX_RecvACK();

}

/*---------------------------------------------------------------------

功能描述: 从IIC总线接收一个字节数据

参数说明: 无

函数返回: 接收字节

---------------------------------------------------------------------*/

uint8 B_LUX_RecvByte()

{

uint8 i;

uint8 dat = 0;

B_LUX_SDA0_I;

// B_LUX_SDA0_H; //使能内部上拉,准备读取数据,

for (i=0; i<8; i++) //8位计数器

{

B_LUX_SCL0_H; //拉高时钟线

B_LUX_Delay5us(); //延时

if(B_LUX_SDA0_DAT)

dat|=1 ;

else dat|=0;

B_LUX_SCL0_L; //拉低时钟线

B_LUX_Delay5us(); //延时

dat <<= 1;

}

B_LUX_SDA0_O;

return dat;

}

/*---------------------------------------------------------------------

功能描述: 写BH1750

参数说明: REG_Address - 寄存器地址

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Single_Write(uint8 REG_Address)

{

B_LUX_Start(); //起始信号

B_LUX_SendByte(B_LUX_SlaveAddress); //发送设备地址+写信号

B_LUX_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页

// BH1750_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页

B_LUX_Stop(); //发送停止信号

}

/*---------------------------------------------------------------------

功能描述: 连续读出BH1750内部数据

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Multiple_read(void)

{

uint8 i;

B_LUX_Start(); //起始信号

B_LUX_SendByte(B_LUX_SlaveAddress+1); //发送设备地址+读信号

for (i=0; i<3; i++) //连续读取6个地址数据,存储中BUF

{

BUF_0[i] = B_LUX_RecvByte(); //BUF[0]存储0x32地址中的数据

if (i == 3)

{

B_LUX_SendACK(1); //最后一个数据需要回NOACK

}

else

{

B_LUX_SendACK(0); //回应ACK

}

}

B_LUX_Stop(); //停止信号

B_LUX_Delay5ms();

}

/*---------------------------------------------------------------------

功能描述: 初始化光照传感器

参数说明: 无

函数返回: 无

---------------------------------------------------------------------*/

void B_LUX_Init()

{

// P1SEL &= ~(0x48);

B_LUX_SCL0_O;

B_LUX_SDA0_O;

B_LUX_delay_nms(100); //延时100ms

B_LUX_Single_Write(0x01);

}

/*---------------------------------------------------------------------

功能描述: 光照读取函数

参数说明: 无

函数返回: 返回光照值

---------------------------------------------------------------------*/

uint16 B_LUX_GetLux()

{

uint32 temp;

B_LUX_Single_Write(0x01); // power on

B_LUX_Single_Write(0x10); // H- resolution mode

B_LUX_delay_nms(50); //延时180ms

B_LUX_Multiple_read(); //连续读出数据,存储在BUF中

B_LUX_Single_Write(0x00); // power off

dis_data_0=BUF_0[0];

dis_data_0=(dis_data_0<<8)+BUF_0[1];//合成数据,即光照数据

// temp=dis_data_0*10;

// dis_data_0=temp/12;

// return (uint32)(temp);

return dis_data_0;

}

四、扩展建议:更高范围的传感器选择

一般场景65535LX的光照强度就够用了,若项目需要检测更强光照(如室外直射阳光),可选用MAX44009 (1 ~ 188,000 Lux),电路和程序稍做调整就可以,但MAX44009价格很高,差不多是BH1750的10倍多,性价比要差一些,适用于对范围有严格要求的场景。

附:《 PIC 单片机入门实战》 8 篇文章内容来源于我自己画的电路原理图及程序, 若你对 PIC 单片机感兴趣,或正在入门嵌入式开发, 关注我,免费赠送资料(包括原理图、数据手册、各种例程等)。

此外,我也设计了对应的多功能开发板,集成MP1584与HT7333电源方案,适合学习与项目原型开发。欢迎交流合作,共同进步。

相关推荐
雾削木5 小时前
使用 ESPHome 的核心指令
java·前端·javascript·单片机·嵌入式硬件
Acrelhuang5 小时前
工厂配电升级优选 安科瑞智能断路器安全提效又节能-安科瑞黄安南
大数据·运维·开发语言·人工智能·物联网
柱子jason5 小时前
使用IOT-Tree Server和InfluxDB对采集数据进行记录
物联网
DLGXY6 小时前
STM32——输入捕获、编码器接口(十一)
stm32·单片机·嵌入式硬件
余生皆假期-13 小时前
永磁同步电机二次起步处理
单片机·嵌入式硬件
DLGXY15 小时前
STM32——TIM定时器、定时中断、RCC时序(八)
stm32·单片机·嵌入式硬件
CQ_YM15 小时前
ARM之I2C
arm开发·单片机·嵌入式硬件·嵌入式
让世界再也没有bug15 小时前
测试工具之一 ------示波器
单片机·嵌入式硬件·硬件测试·嵌入式软件测试
CircuitWizard15 小时前
STM32 + 淘晶驰T1串口屏波形显示
stm32·单片机·嵌入式硬件