简介
通过STM32实现的智能感应LED,充电、OLED显示、LED照明、光感应于一体的数字屏幕显示的智能家居设计,使用了ADI,STM32,光照传感器芯片。
实现了将太阳能板吸收的太阳能储存到18650电池中,光照传感器和LED灯做到根据环境亮度的4种区间值,分别产生不同的照明,此外还增加了应急闪烁的功能。
使用到的芯片:
MAX757
厂家:美信
用途:用于替换原理图中的U2部分——锂电池升压模块,将4.2V电压转换为5V电压
简介:MAX757是CMOS升压DC-DC开关稳压器,适用于小型、低输入电压或电池供电系统。 MAX756 接受低至 0.7V 的正输入电压,并将其转换为更高的 3.3V 或 5V 引脚可选输出电压。 MAX757 是可调版本,可接受低至 0.7V 的输入电压,并在 2.7V 至 5.5V 的范围内产生更高的可调输出电压。 MAX757 的典型满载效率大于 87%。
- VIN (V) (min) 0.7
- VIN (V) (max) 5.5
- VOUT1 (V) (min) 2.7
- VOUT1 (V) (max) 5.5
- IOUT1 (A) (max) 0.3
ADP151AUJZ-3.3-R7
厂家:ADI
用途:用于替换原理图中的U4部分,将5V输入电压转换为3.3V
- 稳压器拓扑:正,固定式
- 电压 - 输出:3.3V
- 电流 - 输出:200mA
- 电压 - 跌落(典型值):0.15V @ 200mA
- 稳压器数:1
- 电压 - 输入:最高 5.5V
- 电流 - 限制(最小值):220mA
- 工作温度:-40°C ~ 125°C
BH1750FVI,其内部由光敏二极管、运算放大器、ADC采集、晶振等组成。PD二极管通过光生伏特效应将输入光信号转换成电信号,经运算放大电路放大后,由ADC采集电压,然后通过逻辑电路转换成16位二进制数存储在内部的寄存器中
STM32F103C8T6是一款基于ARM Cortex-M 内核STM32系列的32位的微控制器,程序存储器容量是64KB,需要电压2V~3.6V,工作温度为-40°C ~ 85°C。
核心代码
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "string.h"
#include "timer.h"
#include "oled.h"
#include "exti.h"
#include "bh1750.h"
char oledBuf[20];
float Light = 0; //光照度
u8 flaog=0;
u8 flaog_GY=0;
//PWM PB5
//舵机 舵机PWM 的频率设置 TIM3_PWM_Init(1999,71); //不分频。PWM频率=72000000/72/2000=5000hz
//这里把时钟预分频数 设置的比较小,是因为 只有 周期比较短 频率低的时候 灯不会出现闪烁
//角度设置TIM_SetCompare2(TIM3,1970); //灯比较暗,角度设置TIM_SetCompare2(TIM3,500);比较亮
//按键这里使用PB1
// PB5 接 TB6612的PWMB
// PA7接 STBY
int main(void)
{
extern unsigned char LOGO[][16];
u16 t=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
OLED_Init() ;//初始化与LED连接的硬件接口
OLED_Clear();
LED_Init(); //LED端口初始化
BH1750_Init();
KEY_Init(); //初始化与按键连接的硬件接口
EXTIX_Init();
TIM3_PWM_Init(1999,0); //不分频。
while(1)
{
Light = LIght_Intensity();
sprintf(oledBuf,"Light:%.1f Lx",Light);
OLED_ShowString(0,0,(u8*)oledBuf,16);//8*16 “ABC”
LED0_PA7=1;
//
// LED0_PA7=0;
// TIM_SetCompare2(TIM3,500); //
if(flaog==0){
if(Light<=20)
{
LED0_PA7=0;
TIM_SetCompare2(TIM3,1000);
}
else {
LED0_PA7=1;
}
OLED_ShowCHinese16x16(0,2,5,LOGO); //模
OLED_ShowCHinese16x16(16,2,6,LOGO); //式
OLED_ShowCHinese16x16(0,4,7,LOGO); //选
OLED_ShowCHinese16x16(16,4,8,LOGO); //泽
OLED_ShowCHinese16x16(0,6,9,LOGO); //常
OLED_ShowCHinese16x16(16,6,10,LOGO); //亮
OLED_ShowCHinese16x16(32,6,11,LOGO); //照
OLED_ShowCHinese16x16(48,6,12,LOGO); //明
}
if(flaog==1){
if(Light<=20)
{
LED0_PA7=0;
TIM_SetCompare2(TIM3,1500); //舵机零度 栏杆关闭
}
else {
LED0_PA7=1;
}
OLED_ShowCHinese16x16(0,2,5,LOGO); //模
OLED_ShowCHinese16x16(16,2,6,LOGO); //式
OLED_ShowCHinese16x16(0,4,7,LOGO); //选
OLED_ShowCHinese16x16(16,4,8,LOGO); //泽
OLED_ShowCHinese16x16(0,6,13,LOGO); //感
OLED_ShowCHinese16x16(16,6,14,LOGO); //应
OLED_ShowCHinese16x16(32,6,15,LOGO); //微
OLED_ShowCHinese16x16(48,6,16,LOGO); //亮
}
if(flaog==2){
//感应高亮模式
OLED_ShowCHinese16x16(0,2,5,LOGO); //模
OLED_ShowCHinese16x16(16,2,6,LOGO); //式
OLED_ShowCHinese16x16(0,4,7,LOGO); //选
OLED_ShowCHinese16x16(16,4,8,LOGO); //泽
OLED_ShowCHinese16x16(0,6,17,LOGO); //模
OLED_ShowCHinese16x16(16,6,18,LOGO); //式
OLED_ShowCHinese16x16(32,6,19,LOGO); //选
OLED_ShowCHinese16x16(48,6,20,LOGO); //泽
}
if(flaog==3)
{
//救援高亮模式
LED0_PA7=0;
TIM_SetCompare2(TIM3,500); //舵机零度 栏杆关闭
delay_ms(10);
LED0_PA7=1;
delay_ms(10);
LED0_PA7=0;
LED0_PA7=1;
OLED_ShowCHinese16x16(0,2,5,LOGO); //模
OLED_ShowCHinese16x16(16,2,6,LOGO); //式
OLED_ShowCHinese16x16(0,4,7,LOGO); //选
OLED_ShowCHinese16x16(16,4,8,LOGO); //泽
OLED_ShowCHinese16x16(0,6,21,LOGO); //模
OLED_ShowCHinese16x16(16,6,22,LOGO); //式
OLED_ShowCHinese16x16(32,6,23,LOGO); //选
OLED_ShowCHinese16x16(48,6,24,LOGO); //泽
}
if( flaog_GY==1){
for(t=0;t<=200;t++)
{
delay_ms(100);
LED0_PA7=0;
TIM_SetCompare2(TIM3,500); //舵机零度 栏杆关闭
flaog_GY=0;
}
LED0_PA7=1;
}
}
}
Oled代码
# include "stm32f10x.h"
# include "stdlib.h"
# include "oledfont.h"
# include "oled.h"
void Delay(u32 count)
{
u32 i=0;
for(;i<count;i++);
}
/**********************************************
//IIC Start
**********************************************/
void OLED_IIC_Start()
{
OLED_SCLK_Set() ;
OLED_SDIN_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
/**********************************************
//IIC Stop
**********************************************/
void OLED_IIC_Stop()
{
OLED_SCLK_Set() ;
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
void OLED_IIC_Wait_Ack()
{
OLED_SCLK_Set() ;
OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/
void OLED_Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
unsigned char m,da;
da=IIC_Byte;
OLED_SCLK_Clr();
for(i=0;i<8;i++)
{
m=da;
m=m&0x80;
if(m==0x80)
{OLED_SDIN_Set();}
else OLED_SDIN_Clr();
da=da<<1;
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
}
/**********************************************
// IIC Write Command
**********************************************/
void OLED_Write_IIC_Command(unsigned char IIC_Command)
{
OLED_IIC_Start();
OLED_Write_IIC_Byte(0x78); //Slave address,SA0=0
OLED_IIC_Wait_Ack();
OLED_Write_IIC_Byte(0x00); //write command
OLED_IIC_Wait_Ack();
OLED_Write_IIC_Byte(IIC_Command);
OLED_IIC_Wait_Ack();
OLED_IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void OLED_Write_IIC_Data(unsigned char IIC_Data)
{
OLED_IIC_Start();
OLED_Write_IIC_Byte(0x78); //D/C#=0; R/W#=0
OLED_IIC_Wait_Ack();
OLED_Write_IIC_Byte(0x40); //write data
OLED_IIC_Wait_Ack();
OLED_Write_IIC_Byte(IIC_Data);
OLED_IIC_Wait_Ack();
OLED_IIC_Stop();
}
/*
********************************************************************************************************************
* void OLED_WR_Byte(u8 dat,u8 cmd)
*
*Description :向SSD1306写入一个字节。
*Arguments : dat 要写入的数据/命令
cmd 数据/命令标志 0,表示命令;1,表示数据;
*Returns : none
*Notes : none
********************************************************************************************************************
*/
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd)
{
OLED_Write_IIC_Data(dat);
}
else
{
OLED_Write_IIC_Command(dat);
}
}
/********************************************
// fill_Picture
********************************************/
void fill_picture(unsigned char fill_Data)
{
unsigned char m,n;
for(m=0;m<8;m++)
{
OLED_WR_Byte(0xb0+m,0); //page0-page1
OLED_WR_Byte(0x00,0); //low column start address
OLED_WR_Byte(0x10,0); //high column start address
for(n=0;n<128;n++)
{
OLED_WR_Byte(fill_Data,1);
}
}
}
/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
unsigned int m;
for(;Del_50ms>0;Del_50ms--)
for(m=6245;m>0;m--);
}
void Delay_1ms(unsigned int Del_1ms)
{
unsigned char j;
while(Del_1ms--)
{
for(j=0;j<123;j++);
}
}
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{ OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
void OLED_On(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 12/16/24
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else {
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
//m^n函数
u32 oled_pow(uint8_t m,uint8_t n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNumber(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}
//显示一个字符号串
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
{
while (*chr!='\0')
{ OLED_ShowChar(x,y,*chr,Char_Size);
x+=8;
if(x>120){x=0;y+=2;}
chr++;
}
}
//==============================================================
//函数名:LED_ShowCHinese16x16(u8 x,u8 y,u8 num,u8 (*buf)[16]) num为第几个字,buf为中文数组(字体为16*16)
//功能描述:写入一组中文
//参数:显示的位置(x,y),y为页范围0~3,要显示的中文
//返回:无
//==============================================================
void OLED_ShowCHinese16x16(uint8_t x,uint8_t y,uint8_t num,uint8_t (*buf)[16])
{
uint8_t i;
OLED_Set_Pos(x,y);
for(i=0;i<16;i++)
{
OLED_WR_Byte(buf[2*num][i],OLED_DATA);
}
OLED_Set_Pos(x,y+1);
for(i=0;i<16;i++)
{
OLED_WR_Byte(buf[2*num+1][i],OLED_DATA);
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;
if(y1%8==0) y=y1/8;
else y=y1/8+1;
for(y=y0;y<y1;y++)
{
OLED_Set_Pos(x0,y);
for(x=x0;x<x1;x++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
void OLED_Float(unsigned char Y,unsigned char X,double real,unsigned char N)
{
unsigned char i_Count=1;
unsigned char n[12]={0};
long j=1;
int real_int=0;
double decimal=0;
unsigned int real_decimal=0;
if(real<0)
{
real_int=(int)(-real);
}
else
{
real_int=(int)real;
}
decimal=real-real_int;
real_decimal=decimal*1e4;
while(real_int/10/j!=0)
{
j=j*10;i_Count++;
}
n[0]=(real_int/10000)%10;
n[1]=(real_int/1000)%10;
n[2]=(real_int/100)%10;
n[3]=(real_int/10)%10;
n[4]=(real_int/1)%10;
n[5]='.';
n[6]=(real_decimal/1000)%10;
n[7]=(real_decimal/100)%10;
n[8]=(real_decimal/10)%10;
n[9]=real_decimal%10;
n[6+N]='\0';
for(j=0;j<10;j++) n[j]=n[j]+16+32;
if(real<0)
{
i_Count+=1;
n[5-i_Count]='-';
}
n[5]='.';
n[6+N]='\0';
OLED_ShowString(X,Y,&n[5-i_Count],16);
}
void OLED_Float2(unsigned char Y,unsigned char X,double real,unsigned char N1,unsigned char N2)
{
unsigned char i_Count=1;
unsigned char n[12]={0};
long j=1;
unsigned int real_int=0;
double decimal=0;
unsigned int real_decimal=0;
X=X*8;
real_int=(int)real;
//Dis_Num(2,0,real_int,5);
decimal=real-real_int;
real_decimal=decimal*1e4;
//Dis_Num(2,6,real_decimal,4);
while(real_int/10/j!=0)
{
j=j*10;i_Count++;
}
n[0]=(real_int/10000)%10;
n[1]=(real_int/1000)%10;
n[2]=(real_int/100)%10;
n[3]=(real_int/10)%10;
n[5]='.';
n[6]=(real_decimal/1000)%10;
n[7]=(real_decimal/100)%10;
n[8]=(real_decimal/10)%10;
n[9]=real_decimal%10;
n[6+N2]='\0';
for(j=0;j<10;j++) n[j]=n[j]+16+32;
n[5]='.';
n[6+N2]='\0';
OLED_ShowString(X,Y,&n[5-N1],12);
}
void OLED_Num2(unsigned char x,unsigned char y, int number)
{
unsigned char shi,ge;
int num =number;
if(num<0)
{
num=-num;
shi=num%100/10;
ge=num%10;
OLED_fuhao_write(x,y,13);
OLED_Num_write(x+1,y,shi);
OLED_Num_write(x+2,y,ge);
}
else
{
shi=num%100/10;
ge=num%10;
OLED_fuhao_write(x,y,11);
OLED_Num_write(x+1,y,shi);
OLED_Num_write(x+2,y,ge);
}
}
void OLED_Num3(unsigned char x,unsigned char y,int number)
{
unsigned char ge,shi,bai;
int num =number;
if(num<0)
{
num=-num;
OLED_fuhao_write(x,y,13); //显示-号
ge = num %10;
shi = num/10%10;
bai = num/100;
OLED_Num_write(x+3,y,ge);
OLED_Num_write(x+2,y,shi);
OLED_Num_write(x+1,y,bai);
}
else
{
OLED_fuhao_write(x,y,11);
ge = num %10;
shi = num/10 %10;
bai = num/100;
OLED_Num_write(x+3,y,ge);
OLED_Num_write(x+2,y,shi);
OLED_Num_write(x+1,y,bai);
}
}
void OLED_Num4(unsigned char x,unsigned char y, int number)
{
unsigned char qian,bai,shi,ge;
int num =number;
if(num<0)
{
num=-num;
}
qian=num/1000;
bai=num%1000/100;
shi=num%100/10;
ge=num%10;
OLED_Num_write(x,y,qian);
OLED_Num_write(x+1,y,bai);
OLED_Num_write(x+2,y,shi);
OLED_Num_write(x+3,y,ge);
}
void OLED_Num_write(unsigned char x,unsigned char y,unsigned char asc)
{
int i=0;
OLED_Set_Pos(x*6,y);
for(i=0;i<6;i++)
{
OLED_WR_Byte(F6x8[asc+16][i],OLED_DATA);
}
}
void OLED_fuhao_write(unsigned char x,unsigned char y,unsigned char asc)
{
int i=0;
OLED_Set_Pos(x*6,y);
for(i=0;i<6;i++)
{
OLED_WR_Byte(F6x8[asc][i],OLED_DATA);
}
}
void OLED_Num5(unsigned char x,unsigned char y,unsigned int number)
{
unsigned char wan,qian,bai,shi,ge;
wan=number/10000;
qian = number%10000/1000;
bai=number%1000/100;
shi=number%100/10;
ge=number%10;
OLED_Num_write(x,y,wan);
OLED_Num_write(x+1,y,qian);
OLED_Num_write(x+2,y,bai);
OLED_Num_write(x+3,y,shi);
OLED_Num_write(x+4,y,ge);
}
//初始化SSD1306
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能B端口时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOC14,15
GPIO_SetBits(GPIOC,GPIO_Pin_14|GPIO_Pin_15);
Delay(20000);
OLED_WR_Byte(0xAE,OLED_CMD);//--display off
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
OLED_WR_Byte(0x81,OLED_CMD); // contract control
OLED_WR_Byte(0xFF,OLED_CMD);//--128
OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
OLED_WR_Byte(0x00,OLED_CMD);//
OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
OLED_WR_Byte(0x80,OLED_CMD);//
OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
OLED_WR_Byte(0x05,OLED_CMD);//
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
OLED_WR_Byte(0xF1,OLED_CMD);//
OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
OLED_WR_Byte(0x12,OLED_CMD);//
OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
OLED_WR_Byte(0x30,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
OLED_WR_Byte(0x14,OLED_CMD);//
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}
void display(void)
{
// OLED_ShowCHinese16x16(20,0,0,LOGO);//果
// OLED_ShowCHinese16x16(36,0,1,LOGO);//果
// OLED_ShowCHinese16x16(52,0,2,LOGO);//小
// OLED_ShowCHinese16x16(68,0,3,LOGO);//师
// OLED_ShowCHinese16x16(84,0,4,LOGO);//弟
OLED_ShowCHinese16x16(0,2,5,LOGO); //温
OLED_ShowCHinese16x16(16,2,6,LOGO);//度
OLED_ShowCHinese16x16(0,4,9,LOGO); //阈
OLED_ShowCHinese16x16(16,4,10,LOGO);//值
}
传感器代码
#include "bh1750.h"
#include "sys.h"
/*
应用说明:
在访问I2C设备前,请先调用 i2c_CheckDevice() 检测I2C设备是否正常,该函数会配置GPIO
*/
static void I2C_BH1750_GPIOConfig(void);
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟,最快400KHz
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频72MHz ,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
*/
for (i = 0; i < 10; i++);
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
BH1750_I2C_SDA_1();
BH1750_I2C_SCL_1();
i2c_Delay();
BH1750_I2C_SDA_0();
i2c_Delay();
BH1750_I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
BH1750_I2C_SDA_0();
BH1750_I2C_SCL_1();
i2c_Delay();
BH1750_I2C_SDA_1();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参:_ucByte : 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
BH1750_I2C_SDA_1();
}
else
{
BH1750_I2C_SDA_0();
}
i2c_Delay();
BH1750_I2C_SCL_1();
i2c_Delay();
BH1750_I2C_SCL_0();
if (i == 7)
{
BH1750_I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
BH1750_I2C_SCL_1();
i2c_Delay();
if (BH1750_I2C_SDA_READ())
{
value++;
}
BH1750_I2C_SCL_0();
i2c_Delay();
}
return value;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
* 形 参:无
* 返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
BH1750_I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
BH1750_I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (BH1750_I2C_SDA_READ()) /* CPU读取SDA口线状态 */
re = 1;
else
re = 0;
BH1750_I2C_SCL_0();
i2c_Delay();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
BH1750_I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
BH1750_I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
BH1750_I2C_SCL_0();
i2c_Delay();
BH1750_I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
BH1750_I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
BH1750_I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
BH1750_I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: I2C_BH1750_GPIOConfig
* 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void I2C_BH1750_GPIOConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(BH1750_RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin = BH1750_I2C_SCL_PIN | BH1750_I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出 */
GPIO_Init(BH1750_GPIO_PORT_I2C, &GPIO_InitStructure);
/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
i2c_Stop();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_CheckDevice
* 功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
* 形 参:_Address:设备的I2C总线地址
* 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{
uint8_t ucAck;
i2c_Start(); /* 发送启动信号 */
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
i2c_SendByte(_Address | BH1750_I2C_WR);
ucAck = i2c_WaitAck(); /* 检测设备的ACK应答 */
i2c_Stop(); /* 发送停止信号 */
return ucAck;
}
//BH1750写一个字节
//返回值 成功:0 失败:非0
uint8_t BH1750_Byte_Write(uint8_t data)
{
i2c_Start();
//发送写地址
i2c_SendByte(BH1750_Addr|0);
if(i2c_WaitAck()==1)
return 1;
//发送控制命令
i2c_SendByte(data);
if(i2c_WaitAck()==1)
return 2;
i2c_Stop();
return 0;
}
//BH1750读取测量数据
//返回值 成功:返回光照强度 失败:返回0
uint16_t BH1750_Read_Measure(void)
{
uint16_t receive_data=0;
i2c_Start();
//发送读地址
i2c_SendByte(BH1750_Addr|1);
if(i2c_WaitAck()==1)
return 0;
//读取高八位
receive_data=i2c_ReadByte();
i2c_Ack();
//读取低八位
receive_data=(receive_data<<8)+i2c_ReadByte();
i2c_NAck();
i2c_Stop();
return receive_data; //返回读取到的数据
}
//BH1750s上电
void BH1750_Power_ON(void)
{
BH1750_Byte_Write(POWER_ON);
}
//BH1750s断电
void BH1750_Power_OFF(void)
{
BH1750_Byte_Write(POWER_OFF);
}
//BH1750复位 仅在上电时有效
void BH1750_RESET(void)
{
BH1750_Byte_Write(MODULE_RESET);
}
//BH1750初始化
void BH1750_Init(void)
{
I2C_BH1750_GPIOConfig(); /* 配置GPIO */
BH1750_Power_ON(); //BH1750s上电
//BH1750_RESET(); //BH1750复位
BH1750_Byte_Write(Measure_Mode);
//SysTick_Delay_ms(120);
}
//获取光照强度
float LIght_Intensity(void)
{
return (float)(BH1750_Read_Measure()/1.1f*Resolurtion);
}
遇到的问题及后续思路
根据光传感器设定的亮度值 20% 50% 80% 这几个档位是固定的,在实际体验中,亮度不能够实现无极调光显得不够智能,在设计时因根据环境亮度实现无极调光。
心得体会
- 非常感谢这次活动,在实践中锻炼了动手能力。
- 感谢社区里的大佬,在制作中遇到的一些问题,只要问对大佬就直接有答案了
- 希望以后继续参加电子森林的活动