云社区 博客 博客详情
云社区 博客 博客详情

基于小熊派光强传感器BH1750实践(multi_timer+状态机工程应用)

Engineer-Bruce_Yang 发表于 2020-05-02 08:55:09 05-02 08:55
Engineer-Bruce_Yang 发表于 2020-05-02 08:55:09 2020-05-02
0
0

【摘要】 本实践案例基于小熊派开发板:实践光强传感器的开发,我们需要带上一个扩展模块:E53_SC1,如下图所示,最终连接的效果:再来看看这个拓展板以及主板上对应的硬件接口,后面我们才能够去配置相应的硬件管脚,达到驱动使用的目的:转接板E53_SC1在主板上的电路原理图:BH1750光强传感器简介BH1750是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数...

本实践案例基于小熊派开发板:

blob.png

实践光强传感器的开发,我们需要带上一个扩展模块:E53_SC1,如下图所示,最终连接的效果:

blob.png

再来看看这个拓展板以及主板上对应的硬件接口,后面我们才能够去配置相应的硬件管脚,达到驱动使用的目的:

blob.png

转接板E53_SC1在主板上的电路原理图:

blob.png

blob.png

BH1750光强传感器简介

BH1750是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景的的亮度,利用它的高分辨率可以探测较大范围的光强度变化。(1lx-65535lx)

blob.png

要控制这个传感器,当然要了解传感器支持的协议,以及一些指令,这是一个基于I2C接口的传感器。

I2C是(Inter-Integrated Circuit)的英文缩写,是Philips公司开发的一个通信协议,只有两根线(SDA/SCL)是用来通信的。

blob.png

BH1750支持的命令:

blob.png

BH1750从机地址计算:

blob.png

根据文档提示,我们了解到光强传感器的从机地址是0100011

当主机向从机发送写命令时为:

0100011(从机地址:7位) 0(写数据位:1位) ===> 0x46

当主机向从机发送读命令时为:

0100011(从机地址:7位) 1(写数据位:1位) ===> 0x47

工程实践:stm32cubMx

1、芯片选型,这里选择stm32l431rctx

blob.png

blob.png

2、配置rcc时钟以及串行调试接口

blob.png

blob.png


blob.png


3、配置调试LED

blob.png

4、配置串口调试

方便根据调试信息查看程序执行流程(默认即可)。

blob.png


5、配置I2C1(PC6/PC7位于I2C1)

默认即可

blob.png

6、生成Keil5基础工程

blob.png

实际开发建议硬件外设分模块,这样看起来不要把所有的生成全部都挤到main.c里面去了,这点让我非常讨厌,所以生成工程时候习惯点击设置以下这一项:blob.png

接下来点击生成代码:

blob.png

blob.png

blob.png

工程实践:编写代码

1、将multi_timer添加到keil5工程

blob.png

2、创建一个Package目录,将multi_timer的程序文件添加进来

blob.png


3、编写代码

由于篇幅限制,只看我自己代码添加的位置:

usart.h

添加重定向打印

/* USER CODE BEGIN 1 */
int fputc(int ch, FILE *file)
{
   return HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
}
/* USER CODE END 1 */

stm32l4xx_it.c

添加multi_timer计数

/**
 * @brief This function handles System tick timer.
 */
void SysTick_Handler(void)
{
 /* USER CODE BEGIN SysTick_IRQn 0 */
   timer_ticks();
 /* USER CODE END SysTick_IRQn 0 */
 HAL_IncTick();
 /* USER CODE BEGIN SysTick_IRQn 1 */

 /* USER CODE END SysTick_IRQn 1 */
}

main.h

添加相应的头文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "multi_timer.h"
/* USER CODE END Includes */

main.c

在程序中宏定义相应的值

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/*接收光强超时值*/
#define TIMEOUT 200
/*光强值检测阈值*/
#define LIGHT_SENSOR_THREHOLD 30

/*mode:模式选择*/
//连续高分辨率模式精度 1 lux
#define LUX_1_MODE   0x10
//连续高分辨率模式2精度 0.5 lux
#define LUX_0_5_MODE 0x11
//低分辨率模式
#define LUX_LOW_MODE 0x13

#define WRITE_ADDRESS 0x46 //0100 011  0
#define READ_ADDRESS  0x47 //0100 011  1
/* USER CODE END PD */

光强采集结构体

typedef struct light_sensor
{
   /*光强值*/
   int Lux ;
   /*multi_timer定时器句柄*/
   Timer timer1 ;
   /*定时器计数值*/
   uint16_t Timer_Count ;
   /*是否采集完成标志*/
   uint8_t   Conver_completed ;
   /*定时回调*/
   void (*timeout_cb)(void);
} light_sensor_TypeDef;
light_sensor_TypeDef lsensor ;

定时回调函数以及结构体初始化

/*定时器回调函数*/
void timer1_callback(void)
{
   ++lsensor.Timer_Count;
}


/*初始化参数*/
void Init_BH750(void)
{
   lsensor.Lux = 0 ;
   lsensor.Timer_Count = 0 ;
   lsensor.Conver_completed = 0 ;
   lsensor.timeout_cb = timer1_callback ;
}

这里的读光强没有用小熊派例程里直接延时然后读取的方法,小熊派的读光强函数是这么写的:

blob.png

而我是这么写的:

/*读取光强*/
void ReadBH1750(uint8_t mode)
{
   float lux = 0;
   uint8_t ReadData[2] = {0};
   static uint8_t Sensor_Status = 0 ;

   /*读取光强流程*/
   switch(Sensor_Status)
   {
       /*1、发送检测光强模式的指令*/
       case 0:
           if(HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, WRITE_ADDRESS, (uint8_t *)&mode, 1, 0xff))
               return  ;
            /*切换为读地址状态*/
           Sensor_Status = 1 ;
           lsensor.Timer_Count = 0 ;
           lsensor.Conver_completed = 0 ;
           break ;

       case 1:

           /*
            2、发送命令后延时200ms等待读取
            定时200ms,判断是否已经到了
            这里相当于取代了延时等待,不占用CPU
           */
           if(TIMEOUT == lsensor.Timer_Count)
           {
               lsensor.Timer_Count = 0 ;

               //3、开始读取光强,发送读光强指令
               if(HAL_OK == HAL_I2C_Master_Receive(&hi2c1, READ_ADDRESS, ReadData, 2, 0xff))
               {
                   lux=(float)((ReadData[0]<<8)|ReadData[1]);
   lux=(double)lux/1.2;
                   lsensor.Lux = (int)lux ;
                   /*4、转换完成*/
                   lsensor.Conver_completed = 1 ;
   Sensor_Status = 0 ; /*切换为写地址状态*/
               }
           }

           break ;

       default:
           break;
   }
}

这里利用了switch case+multi_timer产生一个200ms的定时计数,通过状态1流程判断计数器是否到达设定值,从而达到延时的效果,这段程序在主程序的while循环中几乎不会占用CPU,非常高效!


主程序逻辑:

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
   /* USER CODE BEGIN 1 */

   /* USER CODE END 1 */

   /* MCU Configuration--------------------------------------------------------*/

   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
   HAL_Init();

   /* USER CODE BEGIN Init */

   /* USER CODE END Init */

   /* Configure the system clock */
   SystemClock_Config();

   /* USER CODE BEGIN SysInit */

   /* USER CODE END SysInit */

   /* Initialize all configured peripherals */
   MX_GPIO_Init();
   MX_I2C1_Init();
   MX_USART1_UART_Init();
   /* USER CODE BEGIN 2 */
   /*串口初始化后加这个延时,防止后面的printf打印乱码*/
   HAL_Delay(200);
   printf("光强读取测试实验\n");
   Init_BH750();
   timer_init(&lsensor.timer1, lsensor.timeout_cb, 1, 1);
   timer_start(&lsensor.timer1);
   /* USER CODE END 2 */

   /* Infinite loop */
   /* USER CODE BEGIN WHILE */
   while (1)
   {
       /* USER CODE END WHILE */

       /* USER CODE BEGIN 3 */
       //采用连续高分辨率模式精度 1 lux
       ReadBH1750(LUX_1_MODE);
       if(1 == lsensor.Conver_completed) /*如果转换完了才会执行*/
       {
           printf("当前光强值:%d\n", lsensor.Lux);
           //当光强值大于设定的光强值阈值,则关灯,否则开灯
           if(lsensor.Lux > LIGHT_SENSOR_THREHOLD)
           {
               HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
           }
           else
           {
               HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
           }
       }

       timer_loop();

   }
   /* USER CODE END 3 */
}

运行结果:

blob.png

blob.png

状态机思想前变万化,学会灵活应用则一定能够写出非常高效,简单易维护的程序。

实际例程下载:

链接:https://pan.baidu.com/s/1GA29ua5yVfvGFfRCcS52LA
提取码:afe5
复制这段内容后打开百度网盘手机App,操作更方便哦

若觉得本次分享的文章对您有帮助,关注"嵌入式云IOT技术圈"并转发分享,也是对我的支持。


blob.png

登录后可下载附件,请登录或者注册

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:huaweicloud.bbs@huawei.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
评论文章 //点赞 收藏 0
点赞
分享文章到微博
分享文章到朋友圈

评论 (0)


0/1000
评论

登录后可评论,请 登录注册

评论

您没有权限执行当前操作

温馨提示

您确认删除评论吗?

确定
取消
温馨提示

您确认删除评论吗?

删除操作无法恢复,请谨慎操作。

确定
取消
温馨提示

您确认删除博客吗?

确定
取消

确认删除

您确认删除博客吗?

确认删除

您确认删除评论吗?

温馨提示

登录超时或用户已下线,请重新登录!!!

确定
取消