STM32+BH1750+LED+OLED 灯光自动调节系统
本系统基于BH1750数字光强传感器采集环境照度数据,通过动态调整PWM(脉冲宽度调制)占空比实现LED亮度的闭环控制,并同步在OLED显示屏上实时显示当前光照强度值(单位:lux)及亮度调节百分比。该系统实现了环境光照强度的实时监测、智能调光和可视化反馈功能。
·
整体电路图
整体实现思路
本系统基于BH1750数字光强传感器采集环境照度数据,通过动态调整PWM(脉冲宽度调制)占空比实现LED亮度的闭环控制,并同步在OLED显示屏上实时显示当前光照强度值(单位:lux)及亮度调节百分比。该系统实现了环境光照强度的实时监测、智能调光和可视化反馈功能。
OLED模块
OLED模块主要实现光感数据的实时显示
SCL引脚连接PB1,SDA引脚连接PB0,其余接地或接电源
Display_Init方法和Refresh_Data方法实现光感数据的实时显示
主要实现代码:
//这一部分主要实现文本显示,还不涉及数据实时显示
void Display_Init(void)
{
OLED_Clear();
OLED_ShowCHinese(0,3,9);//光
OLED_ShowCHinese(18,3,10);//强
OLED_ShowCHinese(40,3,0);//:
OLED_ShowString(80, 3, "lx", 16);//lx
}
uint8_t light_int; //初始化光感变量
// 光照强度的计算公式 bh_data_read()方法是BH1750采集光感数据的函数
light_int = bh_data_read() * 4 / 1.2;
void Refresh_Data(void)
{
char data[3];
sprintf(data,"%3d",light_int);
OLED_ShowString(50,3,data,16); //将BH1750采集到的数据显示到OLED屏幕上
}
BH1750模块

SCL引脚接PB6 SDA引脚接PB7 其余接地和电源
主要实现代码
#include "Delay.h"
#include "bh1750.h"
#include "stdint.h"
#include "stm32f10x.h" // Device header
typedef unsigned char BYTE;
void Single_Write_BH1750(uchar REG_Address)
{
IIC_Start_1750(); //起始信号
IIC_Send_Byte(BHAddWrite); //发送设备地址+写信号
IIC_Send_Byte(REG_Address); //内部寄存器地址,
IIC_Stop_1750(); //发送停止信号
}
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_1750(); //iic起始信号
IIC_Send_Byte(BHAddWrite); //发送器件地址
}while(IIC_Wait_Ack_1750()); //等待从机应答
IIC_Send_Byte(command); //发送指令
IIC_Wait_Ack_1750(); //等待从机应答
IIC_Stop_1750(); //iic停止信号
}
u16 bh_data_read(void)
{
u16 buf;
IIC_Start_1750(); //iic起始信号
IIC_Send_Byte(BHAddRead); //发送器件地址+读标志位
IIC_Wait_Ack_1750(); //等待从机应答
buf=IIC_Read_Byte(1); //读取数据
buf=buf<<8; //读取并保存高八位数据
buf+=0x00ff&IIC_Read_Byte(0); //读取并保存低八位数据
IIC_Stop_1750(); //发送停止信号
return buf;
}
/*******************************
下面的都是 IIC 的一些操作 1113lc
***********************************/
//产生IIC起始信号
void IIC_Start_1750(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_1750(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_1750(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_1750();
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;
}
PWM控制
根据光强数据实时调节PA0引脚的占空比
#include "stm32f10x.h" // Device header
/**
* 函 数:PWM初始化
* 参 数:无
* 返 回 值:无
*/
void PWM_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出
//受外设控制的引脚,均需要配置为复用模式
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
//则最好执行此函数,给结构体所有成员都赋一个默认值
//避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
/**
* 函 数:PWM设置CCR
* 参 数:Compare 要写入的CCR的值,范围:0~100
* 返 回 值:无
* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
* 占空比Duty = CCR / (ARR + 1)
*/
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
更多推荐




所有评论(0)