1. 实验:Stm32f103 驱动 bh1750采集光照强度,串口打印采集到的数据。
2. 实验准备器材
? ? ? ? 开发版:stm32f103c8t6
? ? ? ? 器件:bh1750 GY-302
? ? ? ? 开发环境:win10,KILE4
? ? ? ? ? ? ? ? 下载程序的软件:FlyMcu.exe
? ? ? ? ? ? ? ? 串口调试助手:ComAssistant.exe
3. BH1750 的接线
????????VCC:5V或3.3V
????????GND:接地
????????SCL:IIC时钟总线,接stm32的引脚PB6
????????SDA:IIC数据总线,接stm32的引脚PB7
????????AD0:地址线,不接时默认为低电平,在本程序中不接
4. BH1750光照强度计算
????????光照强度 =(寄存器值[15:0] * 分辨率) / 1.2 (单位:勒克斯lx)
? ? ? ? 解释:接收完两个字节还不算完成,因为这个数据还不是测量出来的光照强度值,我们还需要进行计算,计算公式是:光照强度 =(寄存器值[15:0] * 分辨率) / 1.2 (单位:勒克斯lx)因为我们从BH1750寄存器读出来的是2个字节的数据,先接收的是高8位[15:8],后接收的是低8位[7:0],所以我们需要先把这2个字节合成一个数,然后乘上分辨率,再除以1.2即可得到光照值。例如:我们读出来的第1个字节是0x12(0001 0010),第2个字节是0x53(0101 0011),那么合并之后就是0x1253(0001 0010 0101 0011),换算成十进制也就是4691,乘上分辨率(我用的分辨率是1),再除以1.2,最后等于3909.17 lx。
5. 本项目实现参考
? ? ? ? 杜洋老师学的开发版知识
? ? ? ? csdn参考1:BH1750光照传感器超详细攻略(从原理到代码讲解,看完你就懂了)_ShenZhen_zixian的博客-CSDN博客_bh1750
? ? ? ? csdn参考2:BH1750FVI光强度传感器及其STM32驱动程序_小学生8的博客-CSDN博客_bh1750fvi
6. 自己进行了驱动的整合,整个代码工程的调试,完整代码如下
bh1750.h
#ifndef __BH1750_H #define __BH1750_H #include "sys.h"
//IO方向设置 #define SDA_IN() ?{GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}? ? ? ? #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
#define IIC_SCL ? ?PBout(6) //SCL #define IIC_SDA ? ?PBout(7) //SDA?? ?? #define READ_SDA ? PBin(7) ?//输入SDA? #define ADDR 0x23//0100011 #define uchar unsigned char?
#define BHAddWrite ? ? 0x46 ? ? ?//从机地址+最后写方向位 #define BHAddRead ? ? ?0x47 ? ? ?//从机地址+最后读方向位 #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 ? ? ?// 上类似
//BH1750 功能函数 void BH1750_Config_Init(void); void bh_data_send(u8 command); u16 bh_data_read(void);
//IIC所有操作函数?? ?这些是必须要声明的,因为在c文件内部实现,顺序问题,在使用之前,必须对IIC函数声明,,? ? ? ? ? ? void IIC_Start(void);?? ??? ??? ??? ?//发送IIC开始信号 void IIC_Stop(void);?? ? ??? ??? ??? ?//发送IIC停止信号 void IIC_Send_Byte(u8 txd);?? ??? ??? ?//IIC发送一个字节 u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节 u8 IIC_Wait_Ack(void); ?? ??? ??? ??? ?//IIC等待ACK信号 void IIC_Ack(void);?? ??? ??? ??? ??? ?//IIC发送ACK信号 void IIC_NAck(void);?? ??? ??? ??? ?//IIC不发送ACK信号 #endif
/****************************************************************************/
bh1750.c
#include "delay.h" #include "bh1750.h"
typedef ? unsigned char BYTE;
void Single_Write_BH1750(uchar REG_Address) { ? ?IIC_Start(); ? ? ? ? ? ? ? ? ?//起始信号 ? ?IIC_Send_Byte(BHAddWrite); ? //发送设备地址+写信号 ? ?IIC_Send_Byte(REG_Address); ? ?//内部寄存器地址, ? ?IIC_Stop(); ? ? ? ? ? ? ? ? ? //发送停止信号 }
void BH1750_GPIO_Init(void)?? ? ? //BH1750 GPIO的初始化 { ?? ?GPIO_InitTypeDef ?GPIO_InitStructure;
?? ?RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);?? ? //使能端口时钟 ?? ?GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;?? ?? ??? ?GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; ?? ??? ? //推挽输出 ?? ?GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz ??? ?GPIO_Init(GPIOB, &GPIO_InitStructure);? ? ?? ??? ?GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);?? ? }
void BH1750_Config_Init(void)? ? ? ? ? ? ??//BH1750配置初始化 { ?? ?BH1750_GPIO_Init();?? ??? ??? ?//GPIO引脚配置 ?? ?Single_Write_BH1750(0x01);?? ?//是一个信号,打开设备的信号 我的理解,,没看原理 }
void bh_data_send(u8 command)?? ? ? ?? ? { ? ? do{ ? ? IIC_Start(); ? ? ? ? ? ? ? ? ? ? ?//iic起始信号 ? ? IIC_Send_Byte(BHAddWrite); ? ? ? //发送器件地址 ? ? }while(IIC_Wait_Ack()); ? ? ? ? ? //等待从机应答 ? ? IIC_Send_Byte(command); ? ? ? ? ?//发送指令 ? ? IIC_Wait_Ack(); ? ? ? ? ? ? ? ? ? //等待从机应答 ? ? IIC_Stop(); ? ? ? ? ? ? ? ? ? ? ? //iic停止信号 }
u16 bh_data_read(void) { ?? ?u16 buf; ?? ?IIC_Start(); ? ? ? ? ? ? ? ? ? ? ? //iic起始信号 ?? ?IIC_Send_Byte(BHAddRead); ? ? ? ? //发送器件地址+读标志位 ?? ?IIC_Wait_Ack(); ? ? ? ? ? ? ? ? ? ? //等待从机应答 ?? ?buf=IIC_Read_Byte(1); ? ? ? ? ? ? ?//读取数据 ?? ?buf=buf<<8; ? ? ? ? ? ? ? ? ? ? ? ?//读取并保存高八位数据 ?? ?buf+=0x00ff&IIC_Read_Byte(0); ? ? ?//读取并保存低八位数据 ?? ?IIC_Stop(); ? ? ? ? ? ? ? ? ? ? ? ?//发送停止信号? ?? ?return buf;? }
/******************************* 下面的都是 IIC 的一些操作 ?1113lc ***********************************/ //产生IIC起始信号 void IIC_Start(void) { ?? ?SDA_OUT(); ? ? //sda线输出 ?? ?IIC_SDA=1;?? ? ??? ? ? ?? ?IIC_SCL=1; ?? ?delay_us(4); ??? ?IIC_SDA=0;//START:when CLK is high,DATA change form high to low? ?? ?delay_us(4); ?? ?IIC_SCL=0;//钳住I2C总线,准备发送或接收数据? }?? ? ? //产生IIC停止信号 void IIC_Stop(void) { ?? ?SDA_OUT();//sda线输出 ?? ?IIC_SCL=0; ?? ?IIC_SDA=0;//STOP:when CLK is high DATA change form low to high ??? ?delay_us(4); ?? ?IIC_SCL=1;? ?? ?IIC_SDA=1;//发送I2C总线结束信号 ?? ?delay_us(4);?? ??? ??? ??? ??? ??? ??? ? ? ?? ? } //等待应答信号到来 //返回值:1,接收应答失败 // ? ? ? ?0,接收应答成功 u8 IIC_Wait_Ack(void) { ?? ?u8 ucErrTime=0; ?? ?SDA_IN(); ? ? ?//SDA设置为输入 ? ?? ?IIC_SDA=1;delay_us(1);?? ? ?? ?? ?IIC_SCL=1;delay_us(1);?? ?? ?? ?while(READ_SDA) ?? ?{ ?? ??? ?ucErrTime++; ?? ??? ?if(ucErrTime>250) ?? ??? ?{ ?? ??? ??? ?IIC_Stop(); ?? ??? ??? ?return 1; ?? ??? ?} ?? ?} ?? ?IIC_SCL=0;//时钟输出0 ?? ? ?? ?? ?return 0; ? }? //产生ACK应答 void IIC_Ack(void) { ?? ?IIC_SCL=0; ?? ?SDA_OUT(); ?? ?IIC_SDA=0; ?? ?delay_us(2); ?? ?IIC_SCL=1; ?? ?delay_us(2); ?? ?IIC_SCL=0; } //不产生ACK应答?? ??? ? ? ? void IIC_NAck(void) { ?? ?IIC_SCL=0; ?? ?SDA_OUT(); ?? ?IIC_SDA=1; ?? ?delay_us(2); ?? ?IIC_SCL=1; ?? ?delay_us(2); ?? ?IIC_SCL=0; }?? ??? ??? ??? ??? ? ?? ??? ??? ??? ? ? ?? //IIC发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答?? ??? ??? ? ? void IIC_Send_Byte(u8 txd) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? u8 t; ?? ?? ?SDA_OUT(); ?? ? ? ? ? ? IIC_SCL=0;//拉低时钟开始数据传输 ? ? for(t=0;t<8;t++) ? ? { ? ? ? ? ? ? ? ? ? ? ? //IIC_SDA=(txd&0x80)>>7; ?? ??? ?if((txd&0x80)>>7) ?? ??? ??? ?IIC_SDA=1; ?? ??? ?else ?? ??? ??? ?IIC_SDA=0; ?? ??? ?txd<<=1; ?? ? ? ?? ??? ?delay_us(2); ? //对TEA5767这三个延时都是必须的 ?? ??? ?IIC_SCL=1; ?? ??? ?delay_us(2);? ?? ??? ?IIC_SCL=0;?? ? ?? ??? ?delay_us(2); ? ? }?? ?? } ?? ? ? ? //读1个字节,ack=1时,发送ACK,ack=0,发送nACK ?? u8 IIC_Read_Byte(unsigned char ack) { ?? ?unsigned char i,receive=0; ?? ?SDA_IN();//SDA设置为输入 ? ? for(i=0;i<8;i++ ) ?? ?{ ? ? ? ? IIC_SCL=0;? ? ? ? ? delay_us(2); ?? ??? ?IIC_SCL=1; ? ? ? ? receive<<=1; ? ? ? ? if(READ_SDA)receive++; ?? ?? ??? ?delay_us(1);? ? ? }?? ??? ??? ??? ??? ?? ? ? if (!ack) ? ? ? ? IIC_NAck();//发送nACK ? ? else ? ? ? ? IIC_Ack(); //发送ACK ?? ? ? return receive; }
/****************************************************************************/
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "bh1750.h" #include "usart.h" int main (void){????????????????? ? ?//主程序
?? ?u16 value;? ?? ?USART1_Init(115200);?? ? //串口初始化为115200 ?? ?BH1750_Config_Init();?? ? //BH1750的初始化
?? ?bh_data_send(BHPowOn); ? //打开模块等待测量命令 ?? ?bh_data_send(BHReset);?? ? //重置数据寄存器值在PowerOn模式下有效 ?? ?bh_data_send(BHModeL); ?? ? //低分辨率 单位4lx ?测量时间16ms? ?? ? ?? ?delay_ms(180); ?? ??? ??? ?//等待测量结束延时180ms,保证通讯?? ??? ? ?? ??? ??? ? ?? ?while(1){ ?? ??? ?value = bh_data_read()*4/1.2; ?//光照强度的计算公式 = 寄存器值*分辨率/1.2? ?? ??? ?printf("%d\r\n",value); ?? ??? ?delay_ms(1000); ?? ?}
}
/****************************************************************************/
7. 结束语
? ? ? ? 实验代码,我测试ok的,如有错误,欢迎指正。
?
?
|