• STM32模拟IIC与IIC四种实现数字光强采集模块GY30(标准库与HAL库)


    目录

    代码实现是的IIC通信,数据采集后在串口显示,方便大家实现二次开发

    原件选择

    GY-30 数字光强度介绍

    BH1750芯片参数

    引脚说明

     BH1750指令集

    接线表设计

    通过四种方式实现GY-30数据采集

    1.标准库模拟IIC实现GY-30采集并串口1显示

     2.标准库IIC实现GY-30采集并串口1显示

    3.HAL库模拟IIC实现GY-30采集并串口1显示

    4.HAL库IIC实现GY-30采集并串口1显示

    源码下载链接


    代码实现是的IIC通信,数据采集后在串口显示,方便大家实现二次开发

    原件选择

    1.STM32F103

    2.GY-30 数字光强度 光照传感器 BH1750FVI 

    GY-30 数字光强度介绍

    GY30简介
    GY-30是一款内置ROHM-BH1750FLV芯片的数字光照强度模块,用于光照强度采集。
    BH1750FVl是一种用于RC总线接口的数字环境光传感器LC。该芯片最适合于获取移动电话液晶显示器和按键背光功率的环境光数据。在高分辨率(1~65535 l×)范围内检测是可行的。

    特性
    IIC总线接口
    光强数字转换器
    16位分辩率(1~65535)
    直接数字输出,省略复杂的计算,省略标定
    不区分环境光源,接近于视觉灵敏度的分光特性
    应用
    手机、数码相机、车载导航,PDA、LCD显示等。


    GY-30模块是一款基于IIC通信的16bit的数字型传感器。模块主要是以BH1750数字型光强感应芯片为核心及一些外围驱动电路。模块整体电路如图:

    其中C1、C2 为电源滤波电容,R1、R3 为 I2C 上拉电阻,ADDR 是 I2C 通讯时设备地址的选择,即接电源或接地时,读操作、写操作的指令有所区别,如下图。一般为接地,即写操作指令为0x46,读操作指令为0x47。

    BH1750芯片参数

    BH1750是一款内部集成了光电转换、ADC转换、IIC信号转换等电路的芯片,省去了复杂信号处理电路,即能保持良好的稳定型又节省空间。BH1750内部简要框图如图:

    该芯片内部电路主要分为4部分:其中

    1. 光敏二极管,导通电流随着光强的变化而变化;
    2. I/V转换电路:主要是将电流信号转换为电压信号;
    3. ADC转换电路:将电压信号转换为数字信号,分辨率为16bit;
    4. IIC逻辑电路:主要是将光强数据打包成I标准的IIC通信信号;

    引脚说明

     BH1750指令集

    1. #define BHAddWrite 0x46 //写地址
    2. #define BHAddRead 0x47 //读地址
    3. #define BHPowDown 0x00 //关闭模块
    4. #define BHPowOn 0x01 //打开模块等待指令
    5. #define BHReset 0x07 //重置数据寄存器仅在BHpowOn模式下有效
    6. #define BHModeH1 0x10 //高分辨率 模式1 单位 11X 测量时间 120ms
    7. #define BHModeH2 0x11 //高分辨率 模式2 单位 11X 测量时间 120ms
    8. #define BHModeL 0x13 //低分辨率 单位4lx 测量时间16ms
    9. #define BHSigModeH 0x20 //一次测量高分辨率模式1,然后转到powerdown模式
    10. #define BHSigModeH2 0x21 //同上类似
    11. #define BHSigModeL 0x23 //同上类似

    接线表设计

    序号GY-30单片机STM32
    1VCC3.3V/5V
    2SCLPB6
    3SDAPB7
    4GNDGND
    5-PA9(USART1_ TX)
    6-PA10(USART1_RX)

    通过四种方式实现GY-30数据采集

    1.标准库模拟IIC实现GY-30采集并串口1显示

    核心代码gy30.c

    1. //发送起始信号
    2. void IIC_Start(void)
    3. {
    4. IIC_Sdaout_Mode();//输出模式
    5. IIC_SCL=1;
    6. IIC_SDAout=1;
    7. delay_us(2);
    8. IIC_SDAout=0;
    9. IIC_SCL=0;//方便后续数据收发
    10. }
    11. //停止信号
    12. void IIC_Stop(void)
    13. {
    14. IIC_Sdaout_Mode();//输出模式
    15. IIC_SCL=0;
    16. IIC_SDAout=0;
    17. delay_us(2);
    18. IIC_SCL=1;
    19. delay_us(2);
    20. IIC_SDAout=1;
    21. }
    22. /***********发送应答信号**************************
    23. **
    24. **形参:u8 ack -- 0应答,1非应答
    25. **
    26. ***************************************************/
    27. void IIC_SendAck(u8 ack)
    28. {
    29. IIC_Sdaout_Mode();//输出模式
    30. IIC_SCL=0;//告诉从机,主机开始发送数据
    31. IIC_SDAout=ack&0x01;
    32. delay_us(2);
    33. IIC_SCL=1;//告诉从机,主机数据发送完成
    34. //方便下一次数据收发
    35. delay_us(2);
    36. IIC_SCL=0;
    37. }
    38. //获取应答信号
    39. u8 IIC_Wait_Ack(void)
    40. {
    41. u8 cnt=0;
    42. IIC_SdaIn_Mode();//配置为输入模式
    43. IIC_SDAout=1;
    44. IIC_SCL=0;//告诉从机,主机需要获取数据
    45. delay_us(2);
    46. IIC_SCL=1;//从机数据发送完成,主机开始读取数据
    47. while(IIC_SDAin)
    48. {
    49. cnt++;
    50. delay_us(1);
    51. if(cnt>=100)return 1;
    52. }
    53. delay_us(2);
    54. IIC_SCL=0;//方便下一次数据收发
    55. return 0;
    56. }
    57. //发送一个字节数据
    58. void IIC_Send_Byte(u8 data)
    59. {
    60. u8 i=0;
    61. IIC_Sdaout_Mode();//输出模式
    62. for(i=0;i<8;i++)
    63. {
    64. IIC_SCL=0;//告诉从机,主机开始发送数据
    65. if(data&0x80)IIC_SDAout=1;
    66. else IIC_SDAout=0;
    67. delay_us(2);
    68. IIC_SCL=1;//主机数据发送完成
    69. data<<=1;
    70. delay_us(2);
    71. }
    72. IIC_SCL=0;//方便下一次数据收发
    73. }
    74. //读取一个字节数据
    75. u8 IIC_Read_Byte(void)
    76. {
    77. u8 i=0;
    78. u8 data=0;
    79. IIC_SdaIn_Mode();//配置为输入模式
    80. for(i=0;i<8;i++)
    81. {
    82. IIC_SCL=0;//告诉从机,主机需要获取数据
    83. delay_us(2);
    84. IIC_SCL=1;//开始读取数据
    85. data<<=1;//默认收到0
    86. if(IIC_SDAin)data|=0x01;
    87. delay_us(2);
    88. }
    89. IIC_SCL=0;
    90. return data;
    91. }
    92. void bh_data_send(u8 command)
    93. {
    94. do{
    95. IIC_Start(); //iic开始
    96. IIC_Send_Byte(BHAddWrite); //写地址
    97. }while(IIC_Wait_Ack()); //等待响应
    98. IIC_Send_Byte(command); //发送命令
    99. IIC_Wait_Ack(); //等待响应
    100. IIC_Stop(); //iic停止
    101. }
    102. u16 bh_data_read(void)
    103. {
    104. u16 buf;
    105. IIC_Start(); //iic开始
    106. IIC_Send_Byte(BHAddRead); //发送读地址
    107. IIC_Wait_Ack(); //等待响应
    108. buf=IIC_Read_Byte(); //读取数据
    109. IIC_SendAck(0);
    110. buf=buf<<8; //读取并保存高八位数据
    111. buf+=0x00ff&IIC_Read_Byte(); //读取并保存第八位数据
    112. IIC_SendAck(1);
    113. IIC_Stop(); //发送停止信号
    114. return buf;
    115. }
    116. void BH1750init(void)
    117. {
    118. IIC_Init();//GPIO初始化
    119. bh_data_send(BHPowOn); //发送启动信号
    120. bh_data_send(BHReset); //清除寄存器
    121. bh_data_send(BHModeH1); //设置为模式1
    122. delay_ms(180); //最高延时180ms
    123. }

    实现

     2.标准库IIC实现GY-30采集并串口1显示

    gy30.c核心代码

    1. void I2C_GY30_Config(void)
    2. {
    3. GPIO_InitTypeDef GPIO_InitStuctrue;
    4. I2C_InitTypeDef I2C_InitStuctrue;
    5. //开启GPIO外设时钟
    6. GY30_I2C_GPIO_APBxClkCmd(GY30_I2C_SCL_GPIO_CLK|GY30_I2C_SDA_GPIO_CLK,ENABLE);
    7. //开启IIC外设时钟
    8. GY30_I2C_APBxClkCmd(GY30_I2C_CLK,ENABLE);
    9. //SCL引脚-复用开漏输出
    10. GPIO_InitStuctrue.GPIO_Mode=GPIO_Mode_AF_OD;
    11. GPIO_InitStuctrue.GPIO_Pin=GY30_I2C_SCL_GPIO_PIN;
    12. GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
    13. GPIO_Init(GY30_I2C_SCL_GPIO_PORT,&GPIO_InitStuctrue);
    14. //SDA引脚-复用开漏输出
    15. GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
    16. GPIO_InitStuctrue.GPIO_Pin = GY30_I2C_SDA_GPIO_PIN;
    17. GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
    18. GPIO_Init(GY30_I2C_SDA_GPIO_PORT,&GPIO_InitStuctrue);
    19. //IIC结构体成员配置
    20. I2C_InitStuctrue.I2C_Ack=I2C_Ack_Enable;
    21. I2C_InitStuctrue.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
    22. I2C_InitStuctrue.I2C_ClockSpeed=GY30_I2C_BAUDRATE;
    23. I2C_InitStuctrue.I2C_DutyCycle=I2C_DutyCycle_2;
    24. I2C_InitStuctrue.I2C_Mode=I2C_Mode_I2C;
    25. I2C_InitStuctrue.I2C_OwnAddress1=STM32_I2C_OWN_ADDR;
    26. I2C_Init(GY30_I2C,&I2C_InitStuctrue);
    27. I2C_Cmd(GY30_I2C,ENABLE);
    28. }
    29. //向EEPROM写入一个字节
    30. void GY30_Byte_Write(uint8_t addr)
    31. {
    32. //发送起始信号
    33. I2C_GenerateSTART(GY30_I2C,ENABLE);
    34. //检测EV5事件
    35. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
    36. //发送设备写地址
    37. I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
    38. //检测EV6事件
    39. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
    40. //发送要操作设备内部的地址
    41. I2C_SendData(GY30_I2C,addr);
    42. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
    43. // I2C_SendData(EEPROM_I2C,data);
    44. // //检测EV8_2事件
    45. // while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
    46. //发送停止信号
    47. I2C_GenerateSTOP(GY30_I2C,ENABLE);
    48. }
    49. //向EEPROM写入多个字节
    50. uint32_t GY30_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
    51. {
    52. I2CTimeout = I2CT_LONG_TIMEOUT;
    53. //判断IIC总线是否忙碌
    54. while(I2C_GetFlagStatus(GY30_I2C, I2C_FLAG_BUSY))
    55. {
    56. if((I2CTimeout--) == 0) return 1;
    57. }
    58. //重新赋值
    59. I2CTimeout = I2CT_FLAG_TIMEOUT;
    60. //发送起始信号
    61. I2C_GenerateSTART(GY30_I2C,ENABLE);
    62. //检测EV5事件
    63. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
    64. {
    65. if((I2CTimeout--) == 0) return 2;
    66. }
    67. I2CTimeout = I2CT_FLAG_TIMEOUT;
    68. //发送设备写地址
    69. I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
    70. //检测EV6事件
    71. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
    72. {
    73. if((I2CTimeout--) == 0) return 3;
    74. }
    75. I2CTimeout = I2CT_FLAG_TIMEOUT;
    76. //发送要操作设备内部的地址
    77. I2C_SendData(GY30_I2C,addr);
    78. //检测EV8事件
    79. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    80. {
    81. if((I2CTimeout--) == 0) return 4;
    82. }
    83. while(Num_ByteToWrite)
    84. {
    85. I2C_SendData(GY30_I2C,*data);
    86. I2CTimeout = I2CT_FLAG_TIMEOUT;
    87. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    88. {
    89. if((I2CTimeout--) == 0) return 5;
    90. }
    91. Num_ByteToWrite--;
    92. data++;
    93. }
    94. I2CTimeout = I2CT_FLAG_TIMEOUT;
    95. //检测EV8_2事件
    96. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
    97. {
    98. if((I2CTimeout--) == 0) return 6;
    99. }
    100. //发送停止信号
    101. I2C_GenerateSTOP(GY30_I2C,ENABLE);
    102. return 1;
    103. }
    104. //向EEPROM读取多个字节
    105. uint32_t GY30_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead)
    106. {
    107. I2CTimeout = I2CT_LONG_TIMEOUT;
    108. //判断IIC总线是否忙碌
    109. while(I2C_GetFlagStatus(GY30_I2C, I2C_FLAG_BUSY))
    110. {
    111. if((I2CTimeout--) == 0) return 1;
    112. }
    113. I2CTimeout = I2CT_FLAG_TIMEOUT;
    114. //发送起始信号
    115. I2C_GenerateSTART(GY30_I2C,ENABLE);
    116. //检测EV5事件
    117. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
    118. {
    119. if((I2CTimeout--) == 0) return 7;
    120. }
    121. I2CTimeout = I2CT_FLAG_TIMEOUT;
    122. //发送设备写地址
    123. I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Transmitter);
    124. //检测EV6事件等待从机应答
    125. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR)
    126. {
    127. if((I2CTimeout--) == 0) return 8;
    128. }
    129. I2CTimeout = I2CT_FLAG_TIMEOUT;
    130. //发送要操作设备内部存储器的地址
    131. I2C_SendData(GY30_I2C,addr);
    132. //检测EV8事件
    133. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    134. {
    135. if((I2CTimeout--) == 0) return 9;
    136. }
    137. I2CTimeout = I2CT_FLAG_TIMEOUT;
    138. //发送起始信号
    139. I2C_GenerateSTART(GY30_I2C,ENABLE);
    140. //检测EV5事件
    141. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
    142. {
    143. if((I2CTimeout--) == 0) return 10;
    144. }
    145. I2CTimeout = I2CT_FLAG_TIMEOUT;
    146. //发送设备读地址
    147. I2C_Send7bitAddress(GY30_I2C,GY30_I2C_Address,I2C_Direction_Receiver);
    148. //检测EV6事件
    149. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR)
    150. {
    151. if((I2CTimeout--) == 0) return 10;
    152. }
    153. while(Num_ByteToRead--)
    154. {
    155. //是否是最后一个字节,若是则发送非应答信号
    156. if( Num_ByteToRead==0)
    157. {
    158. //发送非应答信号
    159. I2C_AcknowledgeConfig(GY30_I2C,DISABLE);
    160. //发送停止信号
    161. I2C_GenerateSTOP(GY30_I2C,ENABLE);
    162. }
    163. I2CTimeout = I2CT_FLAG_TIMEOUT;
    164. //检测EV7事件
    165. while( I2C_CheckEvent(GY30_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR)
    166. {
    167. if((I2CTimeout--) == 0) return 10;
    168. }
    169. *data=I2C_ReceiveData(GY30_I2C);
    170. data++;
    171. }
    172. //重新开启应答信号
    173. I2C_AcknowledgeConfig(GY30_I2C,ENABLE);
    174. return 1;
    175. }
    176. void I2C_GY30_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite)
    177. {
    178. u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
    179. //I2C_PageSize=8
    180. Addr = WriteAddr % I2C_PageSize;
    181. count = I2C_PageSize - Addr;
    182. NumOfPage = NumByteToWrite / I2C_PageSize;
    183. NumOfSingle = NumByteToWrite % I2C_PageSize;
    184. /* 写入数据的地址对齐,对齐数为8 */
    185. if(Addr == 0)
    186. {
    187. /* 如果写入的数据个数小于8 */
    188. if(NumOfPage == 0)
    189. {
    190. GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle);
    191. GY30_WaitForWriteEnd();
    192. }
    193. /* 如果写入的数据个数大于8 */
    194. else
    195. {
    196. //按页写入
    197. while(NumOfPage--)
    198. {
    199. GY30_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
    200. GY30_WaitForWriteEnd();
    201. WriteAddr += I2C_PageSize;
    202. pBuffer += I2C_PageSize;
    203. }
    204. //不足一页(8个)单独写入
    205. if(NumOfSingle!=0)
    206. {
    207. GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle);
    208. GY30_WaitForWriteEnd();
    209. }
    210. }
    211. }
    212. /*写的数据的地址不对齐*/
    213. else
    214. {
    215. NumByteToWrite -= count;
    216. NumOfPage = NumByteToWrite / I2C_PageSize;
    217. NumOfSingle = NumByteToWrite % I2C_PageSize;
    218. if(count != 0)
    219. {
    220. GY30_Page_Write(WriteAddr, pBuffer, count);
    221. GY30_WaitForWriteEnd();
    222. WriteAddr += count;
    223. pBuffer += count;
    224. }
    225. while(NumOfPage--)
    226. {
    227. GY30_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
    228. GY30_WaitForWriteEnd();
    229. WriteAddr += I2C_PageSize;
    230. pBuffer += I2C_PageSize;
    231. }
    232. if(NumOfSingle != 0)
    233. {
    234. GY30_Page_Write(WriteAddr, pBuffer, NumOfSingle);
    235. GY30_WaitForWriteEnd();
    236. }
    237. }
    238. }

    效果如下: 

    3.HAL库模拟IIC实现GY-30采集并串口1显示

    1. #include "gy30.h"
    2. uint8_t mcy=0;
    3. uint8_t BUF[3];
    4. /***开始信号**/
    5. void BH1750_Start()
    6. {
    7. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET); //拉高数据线
    8. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET); //拉高时钟线
    9. delay_us(5);
    10. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET); //产生下降沿
    11. delay_us(5);
    12. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET); //拉低时钟线
    13. }
    14. /*****停止信号******/
    15. void BH1750_Stop()
    16. {
    17. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET); //拉低数据线
    18. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET); //拉高时钟线
    19. delay_us(5);
    20. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET); //产生上升沿
    21. delay_us(5);
    22. }
    23. /*****初始化BH1750******/
    24. void Init_BH1750()
    25. {
    26. BH1750_Start(); //起始信号
    27. BH1750_SendByte(SlaveAddress); //发送设备地址+写信号
    28. BH1750_SendByte(0x01); //内部寄存器地址
    29. BH1750_Stop(); //停止信号
    30. }
    31. //连续读出BH1750内部数据
    32. void mread(void)
    33. {
    34. uint8_t i;
    35. BH1750_Start(); //起始信号
    36. BH1750_SendByte(SlaveAddress+1); //发送设备地址·+读信号
    37. for (i=0; i<3; i++) //连续读取6个地址数据到BUF
    38. {
    39. BUF[i] = BH1750_RecvByte();
    40. if (i == 3)
    41. {
    42. BH1750_SendACK(1); //最后一个数据需要回NOACK
    43. }
    44. else
    45. {
    46. BH1750_SendACK(0); //回应ACK
    47. }
    48. }
    49. BH1750_Stop(); //停止信号
    50. Delay_mms(5);
    51. }
    52. uint32_t Value_GY30(void)
    53. {
    54. uint16_t dis_data;
    55. uint16_t Value_GY_30;
    56. Single_Write_BH1750(0x01); // power on
    57. Single_Write_BH1750(0x10); // H- resolution mode
    58. HAL_Delay(180); //延时180ms
    59. mread(); //连续读出数据,存储在BUF中
    60. dis_data=BUF[0];
    61. dis_data=(dis_data<<8)+BUF[1];//字节合成数据
    62. Value_GY_30=dis_data;
    63. return Value_GY_30;
    64. }
    65. //系统主频72MHZ
    66. void delay_us(uint16_t us)
    67. {
    68. while(us--)
    69. {
    70. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    71. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    72. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    73. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    74. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    75. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    76. __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    77. __nop();__nop();
    78. }
    79. }
    80. void Delay_mms(uint16_t tmp)
    81. {
    82. uint16_t i=0;
    83. while(tmp--)
    84. {
    85. i=12000;
    86. while(i--);
    87. }
    88. }
    89. /**************************************
    90. 发送应答信号
    91. 入口参数:ack (0:ACK 1:NAK)
    92. **************************************/
    93. void BH1750_SendACK(int ack)
    94. {
    95. GPIO_InitTypeDef GPIO_InitStruct;
    96. GPIO_InitStruct.Pin = scl|sda;
    97. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    98. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    99. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    100. if(ack == 1) //写应答信号
    101. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);
    102. else if(ack == 0)
    103. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);
    104. else
    105. return;
    106. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET);
    107. delay_us(5);
    108. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET);
    109. delay_us(5);
    110. }
    111. /**************************************
    112. 接收应答信号
    113. **************************************/
    114. int BH1750_RecvACK()
    115. {
    116. GPIO_InitTypeDef GPIO_InitStruct;
    117. GPIO_InitStruct.Mode = GPIO_MODE_INPUT; /*输入上拉*/
    118. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    119. GPIO_InitStruct.Pin = sda;
    120. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    121. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET); //拉高时钟线
    122. delay_us(5);
    123. if(HAL_GPIO_ReadPin( GPIOB, sda ) == 1 )//读应答信号
    124. mcy = 1 ;
    125. else
    126. mcy = 0 ;
    127. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET); //拉低时钟线
    128. delay_us(5);
    129. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    130. HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
    131. return mcy;
    132. }
    133. /**************************************
    134. 向iic总线发送一个字节数据
    135. **************************************/
    136. void BH1750_SendByte(uint8_t dat)
    137. {
    138. uint8_t i;
    139. for (i=0; i<8; i++) //8位计数器
    140. {
    141. if( 0X80 & dat )
    142. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET);
    143. else
    144. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_RESET);
    145. dat <<= 1;
    146. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET); //拉高时钟线
    147. delay_us(5);
    148. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET); //拉低时钟线
    149. delay_us(5);
    150. }
    151. BH1750_RecvACK();
    152. }
    153. //我们对BH1750发送命令时,要先发送器件地址+写入位,然后发送指令
    154. //读取数据的时候,需要先发送器件地址+读入位,然后读取两字节数据
    155. //写入指令
    156. void Single_Write_BH1750(uint8_t REG_Address)//REG_Address是要写入的指令
    157. {
    158. BH1750_Start(); //起始信号
    159. BH1750_SendByte(SlaveAddress); //发送器件地址+写信号
    160. BH1750_SendByte(REG_Address); //写入指令,内部寄存器地址
    161. BH1750_Stop(); //结束信号
    162. }
    163. /**************************************
    164. 从iic总线读取一个字节地址
    165. **************************************/
    166. uint8_t BH1750_RecvByte()
    167. {
    168. uint8_t i;
    169. uint8_t dat = 0;
    170. uint8_t bit;
    171. GPIO_InitTypeDef GPIO_InitStruct;
    172. GPIO_InitStruct.Mode = GPIO_MODE_INPUT; /*上拉输入*/
    173. GPIO_InitStruct.Pin = sda;
    174. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    175. HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
    176. HAL_GPIO_WritePin(GPIOB, sda,GPIO_PIN_SET); //准备读取数据
    177. for (i=0; i<8; i++) //8位计数器
    178. {
    179. dat <<= 1;
    180. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_SET); //拉高时钟线
    181. delay_us(5);
    182. if( SET == HAL_GPIO_ReadPin( GPIOB, sda ) )
    183. bit = 0X01;
    184. else
    185. bit = 0x00;
    186. dat |= bit; //读数据
    187. HAL_GPIO_WritePin(GPIOB, scl,GPIO_PIN_RESET); //拉低时钟线
    188. delay_us(5);
    189. }
    190. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    191. HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
    192. return dat;
    193. }

     

    4.HAL库IIC实现GY-30采集并串口1显示

    1. //写命令
    2. void GY30_WR_CMD(uint8_t cmd)
    3. {
    4. HAL_I2C_Master_Transmit(&hi2c1, 0x46, &cmd,1, 0x100);
    5. //HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
    6. //HAL_I2C_Mem_Write(&hi2c1 ,0x46,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
    7. }
    8. /**
    9. @brief BH1750初始化函数
    10. @param 无
    11. @return
    12. */
    13. void BH1750_Init(void)
    14. {
    15. GY30_WR_CMD(0x01);
    16. GY30_WR_CMD(0x10);
    17. GY30_WR_CMD(0x47);
    18. }
    19. //读数据
    20. void GY30_READ_DATA(uint8_t data[])
    21. {
    22. // uint8_t temp = 0X47;
    23. //
    24. // HAL_I2C_Mem_Write(&hi2c1 ,0x47,0x00,I2C_MEMADD_SIZE_8BIT,&temp,1,0x100);
    25. BH1750_Init();
    26. HAL_I2C_Master_Receive(&hi2c1, 0x46, data, 2, 0x100);
    27. //HAL_I2C_Mem_Read_IT(&hi2c1, 0x46, 0X00,I2C_MEMADD_SIZE_8BIT, data, 2);
    28. //HAL_I2C_Mem_Read(&hi2c1 ,0x46,0x47,I2C_MEMADD_SIZE_8BIT,data,2,0x100);
    29. }
    30. /**
    31. @brief BH1750获取光强度
    32. @param 无
    33. @return 光强度
    34. */
    35. uint32_t BH1750_ReadLightIntensity(void)
    36. {
    37. uint32_t lux = 0;
    38. uint8_t sensorData[2] = {0};
    39. GY30_READ_DATA(sensorData);
    40. lux = (sensorData[0] << 8 | sensorData[1]);
    41. return lux;
    42. }

    四种实现效果一样,硬件IIC比模拟IIC的确要简单一些,看各人的喜好,花了一天时间特意研究整理,实现效果一定没有问题的。

    创作不易

    源码下载链接

    (2条消息) STM32模拟IIC与IIC四种实现实现数字光强采集模块GY30(标准库与HAL库)-C文档类资源-CSDN文库

    吾芯电子工作室

  • 相关阅读:
    程序员都看不懂的代码
    Nuscenes数据集总结
    如何保证MySQL和Redis数据一致性?
    setter与getter访问器属性——数据驱动显示
    如何正确使用多线程和锁机制来构建可靠的程序
    【MySQL系列】- SELECT语句执行顺序
    Java Double isInfinite(double v)方法具有什么功能呢?
    【重铸Java根基】J集合相关知识点
    在混合云中优化边缘计算的三种方法
    01 概率论的基本概念
  • 原文地址:https://blog.csdn.net/XiaoCaiDaYong/article/details/128070764