模块1--BH1750的应用(IIC)

1.BH1750基本原理讲解

BH1750作为一款数字化的光照传感器,采用的是IIC接口,本篇文章主要是侧重BH1750的应用,关于IIC总线的时序原理,请大家自行学习。
数字化的传感器,简单点理解即只要通信接口配置正确,即可读出数据,内部集成的有AD转换,但是得到的数据只是为数字量,还需要进行转换
模块1--BH1750的应用(IIC)_第1张图片
本篇文章使用的指令只有两个:
等待测量–0X01
连续高分辨率模式–0x10
模块1--BH1750的应用(IIC)_第2张图片
引脚的连接方式按照上图即可,初学者可能对ADDR引脚有疑问,其实简单点理解就是有两个地址:
ADDR连接GND时,地址为:0x46
ADDR连接VCC时,地址为:0xB8
本篇文章后续代码使用的地址是:0x46;

2.代码篇

函数部分:

#include "bh1750.h"
#include "delay.h"
void bh1750_Config(uint8_t mode)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    if(mode==1)
		{
		  GPIO_StructInit(&GPIO_InitStructure);
          GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_2|GPIO_Pin_3;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
          GPIO_Init(GPIOA, &GPIO_InitStructure);
		}
		Single_Write_BH1750(0x01);
		delay_ms(200);
}

void bh1750_Start(void)
{
	SCK_STA(1);
	SDA_OUT(1);
	delay_us(5);
	SDA_OUT(0);
	delay_us(5);
	SCK_STA(0);
}


void bh1750_Stop(void)
{
	
	SDA_OUT(0);
	SCK_STA(0);
	delay_us(5);
	SCK_STA(1);
	delay_us(5);
	SDA_OUT(1);
	delay_us(5);
	/*
	这样写也可以
	SDA_OUT(0);
	SCK_STA(1);
	delay_us(5);
	SDA_OUT(1);
	delay_us(5);
	*/
	
}

//发送应答信号
//ack--0  应答
void bh1750_SendAck(u8 ack)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	SCK_STA(0);//时钟线拉低
	delay_us(5);
	if(ack==1)
	{
		SDA_OUT(1);
	}
	else if(ack==0)
	{
		SDA_OUT(0);
	}
	else return;
	SCK_STA(1);
	delay_us(5);
	SCK_STA(0);
	delay_us(5);
}
uint8_t bh1750_RevAck(void)
{
	uint8_t revack=0xff;
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	SCK_STA(1);
	delay_us(5);
	if(SDA_IN==1)
	{
		revack=1;
	}
	else if(SDA_IN==0)
	{
		revack=0;
	}
	SCK_STA(0);
	delay_us(5);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	return revack;
}

void bh1750_SendData(uint8_t data)
{
	uint8_t i=0;
	 SCK_STA(0);
	for(i=0;i<8;i++)
	{
		if((data& 0x80))
	  {
		  SDA_OUT(1);
	  }
	  else SDA_OUT(0);
		data<<=1;
		SCK_STA(1);
	  delay_us(5);
	  SCK_STA(0);
	  delay_us(5);	
	}
	bh1750_RevAck();
}
uint8_t bh1750_RevData(void)
{
	u8 i=0;
	u8 revdata=0;
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	//SDA_OUT(1);
	for(i=0;i<8;i++)
	{
		revdata<<=1;
		SCK_STA(1);
		delay_us(5);
		if(SDA_IN)
		{
			revdata |=0X01;
		}
		SCK_STA(0);
		delay_us(5);
	}
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
	return revdata;
}
//数据接收函数
void Single_Write_BH1750(u8 REG_Address)//REG_Address是要写入的指令
{
  bh1750_Start();                  //起始信号
  bh1750_SendData(SLAVEADDR);   //发送设备地址+写信号
  bh1750_SendData(REG_Address);    //写入指令
  bh1750_Stop();                   //发送停止信号
}

uint8_t rev_buf[2]={0};
void read_BH1750(void)
{
	
	uint8_t i;
	bh1750_Start();  
	bh1750_SendData(SLAVEADDR+1); 
	for(i=0;i<2;i++)
	{
		rev_buf[i]=bh1750_RevData();
		if(i==2)
		{
			bh1750_SendAck(1);//非应答
		}
		else bh1750_SendAck(0);//应答
	}
	bh1750_Stop();  
  delay_ms(5);  
}
//整理数据
float get_BH1750Data(void)
{
	int data=0;
	float tmp1=0;
	float tmp2=0;
	Single_Write_BH1750(REG_CMD);//上电
	Single_Write_BH1750(HIGH_MEASUCMD);//高分辨率测量
	delay_ms(200);
	read_BH1750();//读取数据
	data=rev_buf[0];
	data=(data<<8)|rev_buf[1];
	tmp1=data/1.
	return tmp1;
	
}

声明部分:

#ifndef __BH1750_H__
#define __BH1750_H__
#define SLAVEADDR 0x46
#define REG_CMD 0x01   //通电   开始写入
#define HIGH_MEASUCMD 0x10 //高分辨率模式,此模式下通电后需要等待180ms左右设备才可以工作

#define INPUT_MODE 0
#define OUTPUT_MODE 1

#define SCK_STA(x) x?(GPIO_SetBits(GPIOA,GPIO_Pin_2)):(GPIO_ResetBits(GPIOA,GPIO_Pin_2))
#define SDA_OUT(x) x?(GPIO_SetBits(GPIOA,GPIO_Pin_3)):(GPIO_ResetBits(GPIOA,GPIO_Pin_3))

#define SDA_IN   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)

void bh1750_Config(uint8_t mode);
void bh1750_Start(void);
void bh1750_Stop(void);
void bh1750_SendAck(u8 ack);
uint8_t bh1750_RevAck(void);
void bh1750_SendData(uint8_t data);
uint8_t bh1750_RevData(void);
void Single_Write_BH1750(u8 REG_Address);
void read_BH1750(void);
float get_BH1750Data(void);

#endif

/*
BH1750代码中的重点,当然了也是IIC通信中的重点(是我个人感觉这个是重点)
响应部分的时序分析:
1.先说发送应答部分,意味着是主机发送应答,重点在于是否还要接受数据,因此我们需要整理,应答信号,也就是想好此时
我们是需要发送0还是1,这个时候一定要注意,时钟线是需要设置为低电平的,因为只有时钟为低电平的时候,我们才可以改变SDA线路上的电平状态,设置好应答信号之后,紧接着拉高时钟电平,这个时候就是发送数据到从机。
2.再说接收应答部分,意味着我们的MCU只要接收应答即可,说明应答信号在模块内部已经整好了,那么我们只需要将时钟线拉高,等待接收即可,接收完毕之后,再把时钟线拉低,进行延时,等待模块处理数据
以上两点,是我在看了好多IIC时序中得到的一点经验,大佬们也许会感觉这个东西没什么,但是我把这个点着重说出来了,希望初学者可以少走弯路。大家可以自习的想一下IIC的时序,这个时序其实不难,但是为什么在写的过程中总是出现问题,模拟IIC对
延时和状态的切换要求是比较严格的。

最后想说的就是,在IIC的接收和发送函数中是和应答这一块是一个道理,大家可以自习比较下,先按照标准的IIC时序就行配置理解关于IIC其实好多模块在应用的过程中都会有些不一样,这个就需要大家区查看相应的模块手册。
关于IIC的使用,我会在后续再找两个模块进行讲解比较,关于这些基础类的之后还是需要大家多去使用,多去思考,才能灵活运用
*/

模块1--BH1750的应用(IIC)_第3张图片
关于结果我只是在串口上面进行打印了,时间紧迫,就先记录了下关于此模块的运用,后续时间充足我会把IIC的时序讲解,写出来和大家一起探讨。
关于以上代码的格式,有些没有对齐,我现在实在是修改不了,电脑这会卡的不能行,就跟便秘一样,凑合着看吧,兄弟们。

你可能感兴趣的:(嵌入式常用技术及外设,单片机,stm32,物联网)