/*******************************************************************************
* @文件名 : main
* @描述 : 光强传感器实验
* @作者 : 物联网项目组
* @日期 : 2020/01/15
* @版本 : V2.0.0
--------------------------------------------------------------------------------
功能介绍:
1. 检测BH1750光强
1、显示屏实时显示光强:xxlx
2、串口输出光强Illumination:xxlx
*******************************************************************************/
#include "main.h"
#include "usart_api.h"
#include "stm32l4xx_hal.h"
#include "gpio_api.h"
#include "handle.h"
/*****************************内部函数定义**************************************/
void SystemClock_Config(void);
/********************************************************************************
* 名 称:main
* 功 能:主函数
* 参数说明:无
* 返 回 值:无
* 说 明:无
* 调用技巧:内部调用
********************************************************************************/
int main(void)
{
HAL_Init();
SystemClock_Config();
LCD_Display_Init(); //屏幕初始化显示
gpio_module_open(LEDS);
uart_open(uart2, 115200);
printf("\r\n 光强检测实验 \r\n");
printf("------------------------------\r\n");
printf("开始本实验:\r\n\r\n");
/*****************************code start 1*************************************/
Init_BH1750();
/*****************************code end 1*************************************/
printf("** 光强传感器初始化\r\n");
while(1)
{
Light_Intensity_Handle(); //检测光强值并显示
}
}
/********************************************************************************
* 名 称:SystemClock_Config
* 功 能:系统时钟初始化
* 参数说明:无
* 返 回 值:无
* 说 明:无
* 调用手段:内部函数
********************************************************************************/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3;
PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
Gui_Printf_Display("An error message detected");
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*------------------------------------------------------------------------------
* @文件名 : handle
* @描述 : 用户处理函数
* @作者 : 物联网项目组
* @日期 : 2023/04/01
* @版本 : V0.0.2
*******************************************************************************
功能介绍:
1、显示屏初始化显示;
2、检测光强值并显示
******************************************************************************/
#include "handle.h"
#include "gpio_api.h"
#include "lcd.h"
#include "stdio.h"
#include "string.h"
#include "guangxian.h"
/********************************************************************************
* 名 称:LCD_Display_Init
* 功 能:显示屏上电初始化表明
* 入口参数:无
* 返 回 值:无
* 说 明:无
* 调用方法:外部函数
********************************************************************************/
void LCD_Display_Init(void)
{
/*显示屏初始化界面*/
LCD_Init();
LCD_Fill(0,lcddev.height-20,lcddev.width,lcddev.height,BLUE);
LCD_Fill(0,0,lcddev.width,20,BLUE);
Gui_StrCenter(0,2,BLUE,BLUE," ",16,0);
Gui_StrCenter(0,40,BLUE,WHITE,"光强检测实验",24,1);
Gui_StrCenter(0,lcddev.height-18,BLUE,BLUE," ",16,0);
LCD_draw_bmp(96,120,48,gImage_guangxian); //光强图标表现
}
/********************************************************************************
* 名 称:Light_Intensity_Handle
* 功 能:光强检测处理函数
* 入口参数:无
* 返 回 值:无
* 说 明:无
* 调用方法:外部函数
********************************************************************************/
void Light_Intensity_Handle(void)
{
uint16_t light_value = 0; //光强值
char str[20]; //显示屏显示缓冲数组
static uint32_t tickstart;
if((HAL_GetTick() - tickstart) >= 1000) //1000ms检测一次
{
tickstart = HAL_GetTick();
memset(str,0,sizeof(str));
/*****************************code start 2*************************************/
light_value=BH1750_Handle();
/*****************************code end 2*************************************/
if(light_value > 0 && (light_value < 54612))
{
sprintf(str,"光强: %d lx",light_value);
printf("** 读取光强传感器材料\r\n");
printf("** Illumination:%d lx\r\n\r\n", light_value);
}
else
{
sprintf(str,"光强:---");
}
LCD_Fill(90,182,230,198,WHITE); //刷新表现
Show_Str(90,182,BLUE,WHITE,(uint8_t *)str,16,1); //显示光强值
led_toggle(LED1_PORT);
}
}
/*-----------------------------------------------------------------------------
* @文件名 : bh1750
* @描述 : 光照强度检测驱动档案
* @作者 : 物联网项目组
* @日期 : 2023/04/01
* @版本 : V0.0.2
*******************************************************************************
本驱动函数使用指导流程:
1、添加本驱动的.c和.h文件
2、在main.c中调用Init_BH1750函数进行GPIO初始化
3、通过调用BH1750_Handle的返回值读取光照强度
4、用户要根据程序环境时钟修改SYSCLOCK的值,要不会影响延时精度
******************************************************************************/
#include "bh1750.h"
/********************************内部引脚定义***********************************/
#define BH1750_SCL_Pin GPIO_PIN_13
#define BH1750_SCL_GPIO_Port GPIOB
#define BH1750_SDA_Pin GPIO_PIN_14
#define BH1750_SDA_GPIO_Port GPIOB
/********************************IO模式设置*************************************/
#define BH1750_SDA_IN() {GPIOB->MODER&=~(3<<(14*2));GPIOB->MODER|=0<<14*2;} // PB14输入模式
#define BH1750_SDA_OUT() {GPIOB->MODER&=~(3<<(14*2));GPIOB->MODER|=1<<14*2;} // PB14输出模式
/********************************IO口函数操作***********************************/
#define BH1750_SCLK_Clr() HAL_GPIO_WritePin(BH1750_SCL_GPIO_Port, BH1750_SCL_Pin, GPIO_PIN_RESET)
#define BH1750_SCLK_Set() HAL_GPIO_WritePin(BH1750_SCL_GPIO_Port, BH1750_SCL_Pin, GPIO_PIN_SET)
#define BH1750_SDA_Clr() HAL_GPIO_WritePin(BH1750_SDA_GPIO_Port, BH1750_SDA_Pin, GPIO_PIN_RESET)
#define BH1750_SDA_Set() HAL_GPIO_WritePin(BH1750_SDA_GPIO_Port, BH1750_SDA_Pin, GPIO_PIN_SET)
#define BH1750_READ_SDA() HAL_GPIO_ReadPin(BH1750_SDA_GPIO_Port, BH1750_SDA_Pin)
/********************************BH1750宏定义***********************************/
#define BH1750_ADD_WRITE 0x46 // 写数据
#define BH1750_ADD_READ 0x47 // 读数据
#define BH1750_RSET 0x07 // 复位
#define BH1750_POWER_ON 0x01 // 打开模块
#define BH1750_POWER_DOWN 0x00 // 关闭模块
#define BH1750_MODE_H1 0x10 // 高分辨率1 单位1lx
#define BH1750_MODE_H2 0x11 // 高分辨率2 单位0.51lx
#define BH1750_MODE_L 0x13 // 低分辨率 单位4lx
/********************************内部宏定义*************************************/
#define SYSCLOCK 80 // 系统时钟,用于延时,需要用户根据平台时钟进行修改,要不会影响精确延时,单位Mhz
#define ACK 1
#define NOACK 0
#define TURE 0
#define ERROR 1
//******************************内部函数定义************************************/
static void delay_us(uint16_t Nus);
static void delay_ms(uint16_t Nms);
static void BH1750_GPIO_Init(void);
static void BH1750_IIC_Start(void);
static void BH1750_IIC_Stop(void);
static uint8_t BH1750_IIC_Wait_Ack(void);
static void BH1750_IIC_Ack(void);
static void BH1750_IIC_No_Ack(void);
static void BH1750_Write_Byte(uint8_t date);
static uint8_t BH1750_Read_Byte(uint8_t ack);
static void BH1750_Write_Command(uint8_t cmd);
static void Start_BH1750(void);
static uint16_t Read_BH1750(void);
/********************************************************************************
* 名 称:delay_us
* 功 能:微秒级延时
* 参数说明:Nus:延时的时间,单位us
* 返 回 值:无
* 说 明:根据系统时钟,进行延时
* 调用途径:内部函数
********************************************************************************/
static void delay_us(uint16_t Nus)
{
uint32_t i;
i = Nus * (SYSCLOCK/3);
while(i--);
}
/********************************************************************************
* 名 称:delay_ms
* 功 能:微秒级延时
* 参数说明:nus:延时的时间,单位us
* 返 回 值:无
* 说 明:根据平台时钟,进行延时
********************************************************************************/
static void delay_ms(uint16_t Nms)
{
uint32_t i;
i = Nms * (SYSCLOCK/3) * 1000;
while(i--);
}
/********************************************************************************
* 名 称:BH1750_GPIO_Init
* 功 能:初始化BH1750引脚
* 参数说明:无
* 返 回 值:无
* 说 明:用于配置BH1750引脚工作模式
********************************************************************************/
static void BH1750_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = BH1750_SCL_Pin | BH1750_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(BH1750_SCL_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12,GPIO_PIN_SET);
}
/********************************************************************************
* 名 称:BH1750_IIC_Start
* 功 能:产生IIC开始信号
* 参数说明:无
* 返 回 值:无
* 说 明:SDA高电平要延时 > 4.7us,SDA变为低电平之后
还要延时 > 4us
* 调用方法:内部函数
********************************************************************************/
static void BH1750_IIC_Start(void)
{
BH1750_SDA_OUT();
BH1750_SDA_Set();
BH1750_SCLK_Set();
delay_us(5);
BH1750_SDA_Clr();
delay_us(5);
BH1750_SCLK_Clr();
}
/********************************************************************************
* 名 称:BH1750_IIC_Start
* 功 能:产生IIC停止信号
* 参数说明:无
* 返 回 值:无
* 说 明:内部函数,SDA高电平要延时 > 4.7us,SDA变为低电平之后
还要延时 > 4us
* 调用方法:内部函数
********************************************************************************/
static void BH1750_IIC_Stop(void)
{
BH1750_SDA_OUT();
BH1750_SCLK_Clr();
BH1750_SDA_Clr();
delay_us(5);
BH1750_SCLK_Set();
BH1750_SDA_Set();
delay_us(5);
}
/********************************************************************************
* 名 称:BH1750_IIC_Wait_Ack
* 功 能:等待IIC应答信号
* 参数说明:无
* 返 回 值:TURE:接收成功
ERROR:接受失败
* 说 明:无
* 调用技巧:内部函数
********************************************************************************/
static uint8_t BH1750_IIC_Wait_Ack(void)
{
uint8_t ack_time=0;
BH1750_SDA_IN();
BH1750_SDA_Set();
delay_us(2);
BH1750_SCLK_Set();
delay_us(2);
while(BH1750_READ_SDA())
{
ack_time++;
delay_us(10);
if(ack_time>250)
{
BH1750_IIC_Stop();
return ERROR;
}
}
BH1750_SDA_Clr();//时钟输出0
return TURE;
}
/********************************************************************************
* 名 称:BH1750_IIC_Ack
* 功 能:产生ACK应答
* 参数说明:无
* 返 回 值:无
* 说 明:无
* 调用办法:内部函数
********************************************************************************/
static void BH1750_IIC_Ack(void)
{
BH1750_SCLK_Clr();
BH1750_SDA_OUT();
BH1750_SDA_Clr();
delay_us(2);
BH1750_SCLK_Set() ;
delay_us(2);
BH1750_SCLK_Clr();
}
/********************************************************************************
* 名 称:BH1750_IIC_No_Ack
* 功 能:不产生ACK应答
* 参数说明:无
* 返 回 值:无
* 说 明:无
* 调用方法:内部函数
********************************************************************************/
static void BH1750_IIC_No_Ack(void)
{
BH1750_SCLK_Clr();
BH1750_SDA_OUT();
BH1750_SDA_Set();
delay_us(2);
BH1750_SCLK_Set();
delay_us(2);
BH1750_SCLK_Clr();
}
/********************************************************************************
* 名 称:BH1750_Write_Byte
* 功 能:IIC发送一个数据
* 参数说明:date: 要发送的数据
* 返 回 值:无
* 说 明:无
* 调用办法:内部函数
********************************************************************************/
static void BH1750_Write_Byte(uint8_t date)
{
uint8_t i;
BH1750_SDA_OUT();
BH1750_SCLK_Clr();
for(i=0; i<8; i++)
{
if((date&0x80) == 0x80)
{
BH1750_SDA_Set();
}
else
{
BH1750_SDA_Clr();
}
date = date << 1;
delay_us(2);
BH1750_SCLK_Set();
delay_us(2);
BH1750_SCLK_Clr();
delay_us(2);
}
}
/********************************************************************************
* 名 称:BH1750_Read_Byte
* 功 能:IIC发送一个数据
* 参数说明:ack: 1 发送ACK
0 发送nACK
* 返 回 值:无
* 说 明:无
* 调用方法:内部函数
********************************************************************************/
static uint8_t BH1750_Read_Byte(uint8_t ack)
{
uint8_t i,receive = 0;
BH1750_SDA_IN();
for(i=0;i<8;i++ )
{
BH1750_SCLK_Clr();
delay_us(2);
BH1750_SCLK_Set();
receive <<= 1;
if(BH1750_READ_SDA())
receive++;
delay_us(2);
}
if (!ack)
BH1750_IIC_No_Ack();
else
BH1750_IIC_Ack();
return receive;
}
/********************************************************************************
* 名 称:BH1750_Write_Command
* 功 能:写指令到BH1750中
* 参数说明:cmd: 指令
* 返 回 值:无
* 说 明:能力函数
* 调用方法:内部函数
********************************************************************************/
static void BH1750_Write_Command(uint8_t cmd)
{
BH1750_IIC_Start();
BH1750_Write_Byte(BH1750_ADD_WRITE);
BH1750_IIC_Wait_Ack();
BH1750_Write_Byte(cmd);
BH1750_IIC_Wait_Ack();
BH1750_IIC_Stop();
}
/********************************************************************************
* 名 称:Init_BH1750
* 功 能:初始化BH1750
* 参数说明:无
* 返 回 值:无
* 说 明:用于初始化BH1750
* 调用方式:外部函数
********************************************************************************/
void Init_BH1750(void)
{
BH1750_GPIO_Init();
}
/********************************************************************************
* 名 称:Start_BH1750
* 功 能:开始测量光的强度
* 参数说明:无
* 返 回 值:无
* 说 明:无
* 调用方法:内部函数
********************************************************************************/
static void Start_BH1750(void)
{
BH1750_Write_Command(BH1750_POWER_ON);
BH1750_Write_Command(BH1750_MODE_H1);
}
/********************************************************************************
* 名 称:Read_BH1750
* 功 能:读取光强度
* 参数说明:无
* 返 回 值:light_buf:读取到的光强值
* 说 明:得到的内容不是最终值需要处理
* 调用技巧:内部函数
********************************************************************************/
static uint16_t Read_BH1750(void)
{
uint16_t light_buf = 0;
BH1750_IIC_Start();
BH1750_Write_Byte(BH1750_ADD_READ); // 发送读数据信号
BH1750_IIC_Wait_Ack();
light_buf = BH1750_Read_Byte(ACK); // 读数据的高八位
light_buf <<= 8;
light_buf |= BH1750_Read_Byte(NOACK); // 读数据的低八位
BH1750_IIC_Stop();
return light_buf;
}
/********************************************************************************
* 名 称:BH1750_Handle
* 功 能:读取光强度
* 参数说明:无
* 返 回 值:result_lx:得到单位为lx光值
* 说 明:机制函数
* 调用方法:外部函数
********************************************************************************/
uint16_t BH1750_Handle(void)
{
uint16_t result_lx = 0;
Start_BH1750();
delay_ms(180);
result_lx = Read_BH1750();
result_lx = (float)(result_lx / 1.2);
return result_lx;
}