如果不想看原理和流程,可以直接下拉找代码。都是测试过的,很稳定,有的,也有的,基于STM32F103系列和STM32F4系列实现,基于标准库,组织清晰。
2.软硬件准备
(1) Kile 5.27
(2) 串口助手
(3) STM32F103与STM32F4系列单片机
(4) CH340 串口转 TTL 工具
这是基于标准的官方数据手册的驱动说明I2C传感器的设计,即它的支撑(实测确实没问题);这个流程图大概说的是程序设计:
VCC | 5V~3.3V |
---|---|
GND | GND |
SCL | PB6 |
SDA | PB7 |
ADDR | VCC/GND |
首先,这个模块更友好,,其次,特别注意ADDR引脚接线:
高电平硬件地址与低电平硬件地址不同:
接硬件地址: ()
接硬件地址: ()
3.3驱动时序
3.3.指令集说明
功能 | 寄存器地址指令 | 注释说明 |
---|---|---|
断电 | 0000_0000 | 没有活动。 |
接通电源 | 0000_0001 | 等待测量命令。 |
重置 | 0000_0111 | 重置数据寄存器值。重置命令不能在关机模式下接受。 |
连续H分辨率模式 | 0001_0000 | 以1lx开始测量分辨率。测量时间通常为120ms。 |
连续h分辨率模式2 | 0001_0001 | 在0.5lx开始测量分辨率。测量时间通常为120ms。 |
连续L分辨率模式 | 0001_0011 | 以4lx开始测量分辨率。测量时间通常为16ms。 |
一次H分辨率模式 | 0010_0000 | 以1lx开始测量分辨率。测量时间通常为120ms。测量后自动设置为关机模式。 |
一次H分辨率模式2 | 0010_0001 | 在0.5lx开始测量分辨率。测量时间通常为120ms。测量后自动设置为关机模式。 |
一次性L分辨率模式 | 0010_0011 | 以4lx开始测量分辨率。测量时间通常为16ms。测量后自动设置为关机模式。 |
改变测量时间(高位) | 01000_MT[7,6,5] | 改变测量时间。※请参考调整测量结果对光学窗口的影响。 |
改变测量时间(低位) | 011_MT[4,3,2,1,0] | 改变测量时间。※请参考调整测量结果对光学窗口的影响。 |
3.4数据转换
(uint16_t)Data_LX = (uint16_t)(H_data << 8) (uint8_t)L_data
无符号短 8 位整形接收,移位对齐数据再加;
4.上代码
4.1硬件IIC驱动
特别说明硬件驱动刚开始的时候出了一个小问题:完全按照手册的顺序写,就是会卡在接收高 8 位数据的 EV7事件上;
解决方案:发送阅读指令并收到回应后(EV6 事件)主机向光照模块发送 ACK 信号相当于告诉它我们准备好接受数据,然后等待光模块发送数据(EV7事件),然后就没问题了。
4.1.1 适用STM32F103系列的硬件IIC驱动
BH1750.c
#include "BH1750.h"/****************************************************************************** 函数名称:I2C_Configuration()** 函数功能:显示用到的引脚初始化与 IIC初始化** 参数说明:**** 返回值:无** IIC_InitTypeDef 说明: I2C_ClockSpeed; //设置SCL时钟频率,此值最高 400 000 I2C_Mode; //指定工作模式,可选IIC模式及SMBUS模式 I2C_DutyCycle; //时钟占空比,可选low/high = 2:0或16:9 I2C_OwnAddress1; //自身的IIC设备地址 I2C_Ack; //使能或者关闭响应,一般是使能 I2C_AcknowledgedAddress;//指定地址长度,可为7或10****************************************************************************** STM32F103C8T6
芯片的硬件: IIC_1: PB6 -- SCL; PB7 -- SDA IIC_1(重映射):PB8 -- SCL; PB9 -- SDA IIC_2:*****************************************************************************/void I2C_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; /* 重映射开启AFIO时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE); //重映射 IIC /* 重映射引脚 使用IIC_1 PB8 -- SCL; PB9 -- SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //I2C必须开漏输出 GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_InitTypeDef I2C_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); I2C_DeInit(I2C1); //使用I2C1 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //选择IIC模式 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //占空比 1/2 I2C_InitStructure.I2C_OwnAddress1 = 0x30; //主机的I2C地址 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答信号使能 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //IIC 7 位寻址 I2C_InitStructure.I2C_ClockSpeed = 100000; //设置最大400K I2C_Cmd(I2C1, ENABLE); //使能IIC1 I2C_Init(I2C1, &I2C_InitStructure); //初始化 IIC_1 相关}/****************************************************************************** 函数名称:BH1750_WriteByte()** 函数功能:BH1750 写数据** 参数说明:** uint8_t addr: 寄存器地址**** 返回值:无** IIC函数说明:** I2C_GetFlagStatus(IIC_x, IIC_Flag_x)-- 检查标志位是否置 1*******************************************************************************/void BH1750_WriteByte(uint8_t addr){ /* 先判断总线是否忙 */ while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); /* 发送Start信号,切换到主模式(M/SL 位置 1) */ I2C_GenerateSTART(I2C1, ENABLE); /* 等待EV5事件,IIC开始信号已经发出 */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* 发送器件地址,发送方向: I2C_Direction_Transmitter */ I2C_Send7bitAddress(I2C1, (BH1750_Addr_GND_REG<<1|0), I2C_Direction_Transmitter); /* 等待EV6事件:表示地址已经发送 */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* 发送操作的寄存器地址 */ I2C_SendData(I2C1, addr); /* 等待EV8事件:数据寄存器DR为空,地址数据已经发送 */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); /* 产生应答信号 */ I2C_AcknowledgeConfig(I2C1, ENABLE); I2C_GenerateSTOP(I2C1, ENABLE);//产生停止信号,关闭I2C1总线}/****************************************************************************** 函数名称:BH1750_Read_Data()** 函数功能:BH1750 读取数据** 参数说明:** uint8_t addr :寄存器地址**** 返回值:RX_Data** IIC函数说明:** I2C_GetFlagStatus(IIC_x, IIC_Flag_x)-- 检查标志位是否置 1*******************************************************************************/uint16_t BH1750_Read_Data(void){ uint8_t H_Data; //高 8 位数据 uint8_t L_Data; //低 8 位 数据 uint16_t Rx_Data; //完整 16 位数据 while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); /* 先判断总线是否忙 */ I2C_GenerateSTART(I2C1, ENABLE); /* 发送Start信号,切换到主模式 */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* 等待EV5事件,IIC开始信号已经发出 */ /* 发送读地址指令,发送方向: I2C_Direction_Receiver */ I2C_Send7bitAddress(I2C1, BH1750_Addr_GND_REG<<1|1, I2C_Direction_Receiver); /* 等待EV6事件:地址已发送 (接收类型) */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); I2C_AcknowledgeConfig(I2C1, ENABLE); /* 产生应答信号 */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* 等待EV7事件 */ H_Data = I2C_ReceiveData(I2C1); /* 读取高8位数据 */ I2C_AcknowledgeConfig(I2C1, ENABLE); /* 产生应答信号 */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* 等待EV7事件 */ /* 与高8位合成16位完整数据 */ L_Data = I2C_ReceiveData(I2C1); /* 读取低8位 */ I2C_AcknowledgeConfig(I2C1, DISABLE); /* 产生非应答信号 */ I2C_GenerateSTOP(I2C1, ENABLE); /** 发送停止信号 **/ Rx_Data = ((uint16_t)H_Data << 8) + L_Data; /* 16位数据合成 */ return RX_Data;}/** BH1750上电 **/void BH1750_Power_ON(void){ BH1750_WriteByte(BH1750_Power_ON_REG);}/** BH1750断电 **/void BH1750_Power_OFF(void){ BH1750_WriteByte(BH1750_Power_OFF_REG);}/** BH1750数据寄存器复位 **/void BH1750_RESET(void){ BH1750_WriteByte(BH1750_MODULE_RESET_REG);}/** BH1750初始化 **/void BH1750_Init(void){ I2C_Configuration()