文章目录
这里我先简单的介绍一下BH1750光照传感器模块的基本信息(不多废话),我将着重讲解它的使用部分,相信对于屏幕前的你也是更关心它是怎么使用的,OK,gogogo!!!
芯片: BH1750FVI 是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景灯的亮度。利用它的高分辨率可以探测较大范围的光强度变化。
工作原理: BH1750的内部由光敏二极管、运算放大器、ADC采集、晶振等组成。PD二极管通过光生伏特效应将输入光信号转换成电信号,经运算放大电路放大后,由ADC采集电压,然后通过逻辑电路转换成16位二进制数存储在内部的寄存器中(光照越强,光电流越大,电压就越大)。
物理电路图:

PCB原理图:

实物图:

可见,该模块有5个引脚,接下来再看看引脚介绍是啥模样
引脚定义:

模块指令:

使用步骤:

产品特点:
IIC是一种串行通信总线,IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。可以理解为 其通过SDA和CLK俩根线完成通信传输,
由于该模块是通过IIC协议进行通信的,所以接下来我再来介绍介绍IIC的相关驱动。
IIC驱动部分都是通用的,其各个模块是根据自身的设备地址及其配置、命令等寄存器操作不同来完成各自的通信。
IIC 驱动部分我划分为了6个部分,分为:
首先先来看时序图:

时序没看明白,别着急,听我一 一道来。
首先,请记住 : SDA和CLK只有“0和1”俩种状态;其次,主机在发送信号时CLK引脚要定义输出模式,在接收信号时CLK引脚要定义输入模式。
1. 开始信号:
对于开始信号,你可以这样理解,SDA是在CLK置高电平的情况下 由高电平->低电平,这就是开始信号,只不过为了通信稳定,一般在跳变中途延时5us。
接下来看看程序是怎么设计的:
void IIC_Start(void)
{
SDA_OUT(); //sda线输出模式
IIC_SDA=1;
IIC_SCL=1;
delay_us(5);
IIC_SDA=0; //产生下降沿
delay_us(5);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
2. 停止信号:
同开始信号,SDA在CLK为高电平时 由低电平->高电平,完成停止信号。
void IIC_Stop(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=0; //产生上升沿
delay_us(5);
IIC_SCL=1;
IIC_SDA=1; //发送I2C总线结束信号
delay_us(5);
}
3. 发送应答信号:
在SDA为低电平时 CLK由高电平->低电平 ,完成应答;
在SDA为高电平时 CLK由高电平->低电平 ,拒绝应答;
所以在程序中 需设置一个变量进行判断是否接受应答:
void SendACK(int ack)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //定义输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = sda;
GPIO_Init(bh1750_PORT, &GPIO_InitStruct);
if(ack == 1) //写应答信号
SDA=1;
else if(ack == 0)
SDA=0;
else
return;
SCL=1; //拉高时钟线
delay_us(5); //延时
SCL=0; //拉低时钟线
delay_us(5); //延时
}
4. 接收应答信号:
在CLK由低电平->高电平->低电平 期间SDA保持低电平
u8 IIC_waitAck()
{
u8 ack =0;
IIC_setSDAMode_In();
IIC_SCL_OUT(0); //准备时序
delay_us(5);
IIC_SCL_OUT(1);
delay_us(5);
if(IIC_SDA_IN)
{
ack =1;
}
else
{
ack =0;
}
IIC_SCL_OUT(0); //拉低,表示应答完成
delay_us(5);
return ack;
}
5. 发送一个字节:
CLK每完成一次 高电平->低电平 跳变,主机发送1bit,1字节发送完成后且需要接收从机发回来的应答信号。
void SendByte(uchar dat)
{
uchar i;
for (i=0; i<8; i++) //8位计数器
{
if( 0X80 & dat )
GPIO_SetBits(bh1750_PORT,sda);
else
GPIO_ResetBits(bh1750_PORT,sda);
dat <<= 1;
SCL=1; //拉高时钟线
delay_us(5); //延时
SCL=0; //拉低时钟线
delay_us(5); //延时
}
RecvACK();
}
6. 接收一个字节:
类似于发送一字节,只是引脚定义不同,具体如下:
u8 IIC_readByte()
{
u8 data = 0;
IIC_setSDAMode_In();
IIC_SCL_OUT(0); //先拉低,为读取数据做准备
delay_us(5);
for(int i=0;i<8;i++)
{
IIC_SCL_OUT(1); // SCL为高期间才可以读取数据
delay_us(5);
if(IIC_SDA_IN)
{
data|=(0x01<<(7-i));
}else{
data &= ~(0x1<<(7-i));
}
IIC_SCL_OUT(0);
delay_us(5);
}
return data;
}
1. 写信号
首先需要对模块进行写操作,然后再初始化, 写操作的过程为:起始信号 -->发送设备地址+写信号 -->发送内部寄存器地址 --> 发送停止信号。
void Single_Write_BH1750(uchar REG_Address)
{
BH1750_Start(); //起始信号
BH1750_SendByte(SlaveAddress); //发送设备地址+写信号
BH1750_SendByte(REG_Address); //内部寄存器地址
BH1750_Stop(); //发送停止信号
}
2. 初始化
对模块进行初始化,初始化SDA和CLK引脚 初步设置为推挽输出,然后对模块进行上电,根据指令表可知 上电指定为0x01,上电后需要延迟180ms左右让模块进行缓冲。
void Init_BH1750()
{
GPIO_InitTypeDef GPIO_InitStruct;
/*开启GPIOB的外设时钟*/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = sda | scl ;
GPIO_Init(bh1750_PORT,&GPIO_InitStruct);
Single_Write_BH1750(0x01);
delay_ms(180); //延时180ms
}
3. 读寄存器内部数据
读数据操作的过程为:起始信号 -->发送设备地址+读信号 -->定义数组存储数据(最后一个数据需要拒绝应答) --> 发送停止信号。
void mread(void)
{
uchar i;
BH1750_Start(); //起始信号
BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号
for (i=0; i<3; i++) //连续读取3个地址数据,存储中BUF
{
BUF[i] = BH1750_RecvByte(); //BUF[0]存储0x32地址中的数据
if (i == 3)
{
BH1750_SendACK(1); //最后一个数据需要回NOACK
}
else
{
BH1750_SendACK(0); //回应ACK
}
}
BH1750_Stop(); //停止信号
delay_ms(5);
}
4. 对数据进行操作、转存
float read_BH1750(void)
{
int dis_data; //变量
float temp1;
float temp2;
Single_Write_BH1750(0x01); // power on
Single_Write_BH1750(0x10); // H- resolution mode
delay_ms(180); //延时180ms
mread(); //连续读出数据,存储在BUF中
dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1]; //合成数据
temp1=dis_data/1.2;
temp2=10*dis_data/1.2;
temp2=(int)temp2%10;
OLED_ShowString(87,2,".",12);
OLED_ShowNum(94,2,temp2,1,12);
return temp1;
}
5. 主函数里调用BH17502并显示在oled上
int main(void)
{
float light;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
Init_BH1750(); //初始化BH1750
OLED_Init(); //初始化OLED
OLED_Clear(); //清屏
while(1)
{
light=read_BH1750(); //读取BH1750的光强数据
OLED_ShowString(0,2,"light:",12); //显示光照强度
OLED_ShowNum(48,2,light,6,12);
OLED_ShowString(110,2,"lx",12);
if(light<100)
{
LED1=0;
OLED_ShowString(38,5,"LED-ON ",12);
}
else
{
LED1=1;
OLED_ShowString(38,5,"LED-OFF",12);
}
}
}
该程序结合oled显示输出,有需要可 留言评论区或私信即可
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
我有以下在Three.js中绘制菱形的代码:varmaterial=newTHREE.MeshPhongMaterial({color:0x55B663,side:THREE.DoubleSide});vargeometry=newTHREE.Geometry();geometry.vertices.push(newTHREE.Vector3(0,1,0));geometry.vertices.push(newTHREE.Vector3(0,-1,0));geometry.vertices.push(newTHREE.Vector3(-1,0,-1));geometry.vertice
我正在向我的本地网络服务发出GET请求,我希望返回302响应并在header中包含一个位置。但是,我得到了一个未定义的响应和一个网络错误,即使我可以在本地看到正在处理请求并且正在创建响应而网络服务中没有任何错误。我在Postman和Chrome中试过,它收到重定向响应并相应地重定向。我不确定这是否是CORS问题,如果是,我该如何解决?我已经在CORS过滤器的响应头中添加了Access-Control-Expose-Headers:Location,[ownheaders]Access-Control-Allow-Origin:'*'Access-Control-Allow-Method
我知道http302响应由浏览器直接处理,因此您无法从源代码访问任何请求属性。但我想知道是否有任何方法可以拦截302重定向响应。让我解释一下:我的前端(Angular)向A发出一个http请求(我拦截传出请求)A响应302Location:B我的前端拦截了带有空字段的302响应,然后转到B这里我想拦截来自B的响应这是我的Angularhttp拦截器代码:@Injectable()exportclassCasInterceptorimplementsHttpInterceptor{intercept(req:HttpRequest,next:HttpHandler):Observable
我想在我的页面上显示连接到Arduino的传感器(湿度)之一的输出。按照脚本,每隔一秒给我一些值(数字)。require'dino'board=Dino::Board.new(Dino::TxRx.new)sensor=Dino::Components::Sensor.new(pin:'A0',board:board)on_data=Proc.newdo|data|putsdatasleep1endsensor.when_data_received(on_data)sleep我想我可以使用Sinatra作为API和Javascript脚本来显示异步输出。所以应该是这样的%w(sinat
有没有一种我没见过的方法可以动态改变方向灯的光强度?甚至环境光?ambientLight=newTHREE.AmbientLight(0xffffff);scene.add(ambientLight);directionalLightL=newTHREE.DirectionalLight(0xffffff,dLight,0);directionalLightL.position.set(dlpX,dlpY,dlpZ);scene.add(directionalLightL);所以最初是为了渲染而完成的,但是我怎样才能在之后只改变一个特定的灯光强度呢?删除/重新添加灯?在dom中找到它并
我对Safari处理CORS请求的方式有疑问。考虑以下场景:DomainA托管一个向DomainB发出XHR请求的页面(源header设置为DomainA)DomainB返回302重定向doDomainC(原始header设置为null,这似乎与RFC没问题)DomainC返回包含实际内容的200响应这在Chrome、FF中有效,但在Safari上失败(在Mozilla/5.0(Macintosh;IntelMacOSX10_10_5)AppleWebKit/600.8.9(KHTML,如Gecko)Version/8.0.8Safari/600.8上测试。9).当我在没有打开xhr.
我在我的应用程序上安装了一个serviceworker,它安装良好,激活良好,缓存也正常。但是当我点击一个302页面时缓存完成,它告诉我:TheFetchEventfor"http://localhost:8000/form/"resultedinanetworkerrorresponse:aredirectedresponsewasusedforarequestwhoseredirectmodeisnot"follow".我已经阅读了很多关于这个主题的文章,我已经查阅了这里的帖子:ServiceWorkerbreaking301redirects,还有https://github.c
现代手机拥有许多传感器,包括地磁、姿态、GPS、光照、温度、气压、摄像、声音、电磁等,完全就是一个高度集成的科学仪器。不夸张的说,一部手机加上一个外围的计算机和控制系统,做一个功能较强的自主移动机器人并不是不可能。但是,很多APP都只是局限于自身的功能,并不喜欢把传感器数据泵出来给其他设备分享。即使有,也是收费的。有没有可能自己做一个小APP,获得所有的手机传感器数据,榨干手机的感知能力呢?实际上实现起来并不困难,甚至连界面都不需要。笔者准备涉足一下从未实操过的App开发,把旧手机的传感器数据分享出来。1.基本思路分享传感器数据,必然需要一个连接。从应用的场景来说,用手机与消费者的网络距离来分
我有一台内置加速度计的平板电脑,Windows7检测设备的方向。是否可以在我的应用程序中使用加速度计数据以及从哪里开始? 最佳答案 我从未使用过它,但您可以查看WindowsSensorandLocationPlatformAPI。 关于Windows7、加速度计和其他传感器,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7127992/