搜索
您的当前位置:首页正文

基于51单片机的蓝牙智能光控窗帘

2023-02-18 来源:知库网
基于51单片机的蓝牙智能光控窗帘

一、设计思路

系统选用 STC12C5A60S2 作为主控芯片,用以完成对系统执行机构的控制、信息处理和液晶显示。 单片机控制直流减速电机实现窗帘、窗户的控制。 光照强度、温湿度信号均通过无线蓝牙模块传输至单片机,经处理后实现电机对窗户、窗帘的自动控制。

根据设计方案和要求,可将电路分为 5 部分,分别为无线蓝牙遥控,传感器数据采集,电机驱动控制,单片机主控和电源部分。

二、系统结构

蓝牙模块 光电传感器 51 A/D转换器 单片机 电机驱动 电源模块 温湿度传感器 此方案控制采用51单片机的最小系统来驱动步进电动机控制窗户和窗帘的拉开和关闭。家居推拉窗及窗帘控制系统可以利用蓝牙无线模块根据室外环境亮度实现环境亮度光控。以及光控状态下环境亮度的控制参数的调整等等。该控制设计可谓是一款多功能的推拉窗及窗帘控制系统设计方案。

系统软件设计框图如下:

1

电机驱动 传感器控制 中单央片控机制程序

1. 光强度传感器 BH1750FVI

不区分光源数字型环境光强度传感器BH1750FVI是日本RHOM 株式会社近些年推出的一种两线式串行总线接口的集成电路,可以根据收集的光线强度数据来进行环境监测,其具有1~65535x的高分辨率,可支持较大范围的光照强度变化。BH1750FVI结构框图如图1所示。 图1 BH1750FVI结构框图

从结构框图可容易看出,外部光照被接近人眼反应的 高精度光敏二极管PD探测到后,通过集成运算放大器将 PD电流转换为 PD电压,由模数转换器获取 16位数字数 据,然后被逻辑和IC界面进行数据处理与存储。OSC为 内部的振荡器提供内部逻辑时钟,通过相应的指令操作即 可读取出内部存储的光照数据。数据传输使用标准的 I2 C总线,按照时序要求操作起来也非常方便。

2. 温湿传感器:

2

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。

3. 电机驱动

L298N 的说明及应用

恒压恒流桥式2A 驱动芯片L298NL298 是SGS 公司的产品,比较常见的是15 脚Multiwatt 封装的L298N,内部同样包含4 通道逻辑驱动电路。可以方便的驱动两个直

流电机,或一个两相步进电机。L298N 芯片可以驱动两个二相电机,也可以驱动一个四相电机,输出电压最高可达50V,可以直接通过电源来调节输出电压;可以直接用

单片机的IO 口提供信号;而且电路简单,使用比较方便。L298N 可接受标准TTL 逻辑电平信号VSS,VSS 可接4.5~7 V 电压。4 脚VS 接电源电压,VS 电压范围VIH 为+2.5~46 V。输出电流可达2 A,可驱动电感性负载。1 脚和15 脚下管的发射极分别单独引出以

便接入电流采样电阻,形成电流传感信号。L298 可驱动2 个电动机,OUT1,OUT2 和OUT3,OUT4 之间可分别接电动机,本实验装置我们选用驱动一台电动机。5,7,10,12 脚接输入控制电平,控制电机的正反转。EnA,EnB 接控制使能端,控制电机的停转。表1 是L298N 功能逻辑图。L298N 驱动模块

3

的应用In3,In4 的逻辑图与表1 相同。由表1 可知EnA 为低电平时,输入电平对电机控制起作用,当EnA 为高电平,输入电平为一高一低,电机

正或反转。同为低电平电机停止,同为高电平电机刹停。 L298N 控制器原理如下:

三、控制软件流程图(多个)

1. 传感器控制程序

凡是利用一定的物性(物理、化学、生物)法则、定理、定律、效应等进行能量转换与信息转换,并且输出与输入严格一一对应的器件和装置均可称为传感器;传感器又被称为变换器、转换器、检测器、敏感元件、换能器和一次仪表等。传感器一般由敏感元件、转换元件和测量电路三部分组成,有时还加上辅助电源。系统中的传感器是感受被测量的大小并输出相对应的可用输出信号的器件或装置。数 据传输环节用来传输数据。当检测系统的几个功能环节独立地分隔开的时候,则必须由一 个地方向另一个地方传输数据,数据传输环节就是完成这种传输功能。

4

2. 中断控制程序

当传感器模块传来的数据并判断正确时,则中断程序对T1口进行初始化,进而接收来自两个模块的新数据,比较判断后传到命令地址进而对电机进行驱动和通过显示器显示出来。

开始是否有数据Y串口中断N初始化T1数据传送到命令置回归标志位中断返回

中断控制程序

3. 电机驱动程序

5

步进电机执行来自控制器的命令,判断其命令是否正确,若不正确则返回,若正确则继续执行命令,比较做出相应的动作,当窗帘及推拉窗到达指定的位置时停止,器流程图如下。

开始接入N是否正确Y命令执行YN比较判断窗帘推拉窗YY比较判断N比较判断N正转反转正转反转停止返回四、主要程序的指令:

附录一:蓝牙无线模块

附录二:DHT11数字温湿度传感器 附录三:光强度传感器BH1750

6

附录一:

蓝牙无线模块:

修改at:

#include // 引用程式庫

SoftwareSerial BT(8, 9); // 接收腳, 傳送腳 char val; // 儲存接收資料的變數 void setup() {

Serial.begin(9600); // 與電腦序列埠連線 Serial.println(\"BT is ready!\"); // 設定藍牙模組的連線速率 BT.begin(9600); }

void loop() {

// 若收到「序列埠監控視窗」的資料,則送到藍牙模組 if (Serial.available()) { val = Serial.read(); BT.print(val); }

// 若收到藍牙模組的資料,則送到「序列埠監控視窗」 if (BT.available()) { val = BT.read(); Serial.print(val); } }

7

从机:

void setup() {

Serial.begin(9600); }

void loop() {

while(Serial.available()) {

char c=Serial.read(); if(c=='A') {

Serial.println(\"Hello I am amarino\"); } } }

主机:

void setup(){

Serial.begin(9600); }

void loop(){

Serial.println('A'); // 发送A

while(1); }

8

附录二:

DHT11数字温湿度传感器:

U8 code table2[]=\" wendu shidu \"; U8 code table3[]=\" . . \";

sbit RS=P2^6; sbit RW=P2^5; sbit E=P2^7;

void write_com(U8 com) { E=0; RS=0; RW=0; Delay(5); E=1; P0=com; E=0; }

void write_date(U8 date) { E=0; RS=1; RW=0; Delay(5); E=1; P0=date; E=0; P0=0; }

void init() { U8 num; Delay(15); write_com(0x38); write_com(0x38); write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); for(num=0;num<15;num++)

9

{ write_date(table2[num]); Delay(1); } write_com(0x80+0x40); for(num=0;num<15;num++) { write_date(table3[num]); Delay(1); } }

void write_dht11(U8 add,U8 date) { U8 shi,ge; shi=date/10; ge=date%10; write_com(0x80+0x40+add); write_date(0x30+shi); write_date(0x30+ge); }

/***********************dht11.h***************************/ typedef unsigned char U8; typedef unsigned int U16;

sbit P1_0 = P2^0 ;

U8 U8FLAG,k; U8 U8temp;

U8 U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata; U8

U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp; U8 U8comdata;

void Delay(U16 z) {

U8 x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--); }

void delay_10us() {

10

U8 i; i--; i--; i--; i--; i--; i--; }

void COM(void) //数据0 1确认 {

U8 i;

for(i=0;i<8;i++) {

U8FLAG=2;

while((!P1_0)&&U8FLAG++); //1bit是否结束 delay_10us(); delay_10us(); delay_10us();

U8temp=0;// 26us~28us 表示为0

if(P1_0)U8temp=1; // 超过28us依然为高电平 表示为1 U8FLAG=2;

while((P1_0)&&U8FLAG++);

if(U8FLAG==1)break;//U8FLAG溢出超时则跳出for循环 //判断数据位是0还是1

// 如果高电平高过预定0高电平值则数据位为 1

U8comdata<<=1;

U8comdata|=U8temp; } }

void RH(void) //-----湿温度读取子程序 ------------ {

P1_0=0;

Delay(34); //主机拉低高于18ms P1_0=1;

//总线由上拉电阻拉高 主机延时20us delay_10us(); delay_10us();

11

delay_10us(); delay_10us();

P1_0=1;//主机设为输入 判断从机响应信号

if(!P1_0)//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行 {

U8FLAG=2;

while((!P1_0)&&U8FLAG++);//判断从机是否发出 80us 的低电平响应信号是否结束 U8FLAG=2;

while((P1_0)&&U8FLAG++);//判断从机是否发出 80us 的高电平, 如发出则进入数据接收状态 COM();//数据接收状态

U8RH_data_H_temp=U8comdata; //湿度整数8位 COM(); U8RH_data_L_temp=U8comdata; //湿度小数8位 COM();

U8T_data_H_temp=U8comdata; //温度整数8位 COM();

U8T_data_L_temp=U8comdata; //温度小数8位 COM();

U8checkdata_temp=U8comdata; //校验位 P1_0=1;

U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);

if(U8temp==U8checkdata_temp) //数据校验 正确执行 { U8RH_data_H=U8RH_data_H_temp; U8RH_data_L=U8RH_data_L_temp; U8T_data_H=U8T_data_H_temp; U8T_data_L=U8T_data_L_temp; U8checkdata=U8checkdata_temp; } } }

/***********************main.c***************************/ #include

#include

12

U16 a,b,t; U8 flag,i; void main() { RW=1; t=0; flag=0; TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1; ET0=1; TR0=1; init(); P1_0=1; P2=0xff; Delay(40); while(1) { RH(); write_dht11(0,U8T_data_H); write_dht11(3,U8T_data_L); write_dht11(9,U8RH_data_H); write_dht11(12,U8RH_data_L); if(flag==2)//100后flag为2,进行比较 { if(a==U8T_data_H&&b==U8RH_data_H) Buzzer=0; while(a==U8T_data_H&&b==U8RH_data_H); flag=0; } test(); } }

void timer0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; t++; if(t==2000)//100秒检测一次 { t=0;

13

}

flag=2;//100秒后flag为2 }

if(flag==0)//最开始 flag为0 赋值 { a=U8T_data_H; b=U8RH_data_H; flag=1;//flag变化 }

14

附录三:

光强度传感器BH1750:

//使用时,用户只需更改GPIO_Pin_14、GPIO_Pin_15这两个引脚,并在主函数里面调用此函数即可。void BH1750_Get_Guang( float *Zhaodu)

#include \"stm32f10x_lib.h\"

#define uchar unsigned char #define uint unsigned int

#define DataPort P0 //LCD1602数据端口

#define SlaveAddress 0x46 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改

//ALT ADDRESS引脚接地时地址为0x46,接电源时地址为0xB8

#define BH1750_SCL GPIO_Pin_14 #define BH1750_SDA GPIO_Pin_15 //#define GPIO_I2C GPIOB

#define BH1750_SCL_0() GPIOF->BRR=BH1750_SCL #define BH1750_SCL_1() GPIOF->BSRR=BH1750_SCL #define BH1750_SDA_0() GPIOF->BRR=BH1750_SDA #define BH1750_SDA_1() GPIOF->BSRR=BH1750_SDA

#define BH1750_SDA_STATE() (GPIOF->IDR&BH1750_SDA) //{ return (GPIOB->IDR & PIN_SDA) != 0; }

typedef unsigned char BYTE; typedef unsigned short WORD;

BYTE BUF[8]; //接收数据缓存区 uchar ge,shi,bai,qian,wan; //显示变量 int dis_data; //变量

15

void Init_BH1750(void);

void conversion(uint temp_data);

void Single_Write_BH1750(uchar REG_Address); //单个写入数据 uchar Single_Read_BH1750(uchar REG_Address); //单个读取内部寄存器数据

void Multiple_Read_BH1750(void); //连续的读取内部寄存器数据

//------------------------------------

u8 BH1750_Start(void); void BH1750_Stop(void);

u8 BH1750_SendByte(u8 Data); u8 BH1750_ReceiveByte(void); void BH1750_SendACK(void); void BH1750_SendNACK(void); void BH1750_Nop(void );

void BH1750_Delay(unsigned int k) ;

//-----------------------------------

u8 BH1750_ACK =0; u8 BH1750_READY =0; u8 BH1750_NACK =1;

u8 BH1750_BUS_BUSY =2; u8 BH1750_BUS_ERROR =3;

u8 BH1750_RETRY_COUNT = 3; //重试次数

void BH1750_Nop(void) {

u8 i=50;

16

while(i) i--; }

void BH1750_Delay(unsigned int k) { unsigned int i,j; for(i=0;i/*******************************************************************************

* 函数名称:IIC_START * 描 述:发送启动 * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:

* 修改日期:2010年6月8日

*******************************************************************************/

u8 BH1750_Start(void) {

BH1750_SDA_1(); BH1750_Nop();

BH1750_SCL_1(); BH1750_Nop();

if(!BH1750_SDA_STATE()) {

////DebugPrint(\"TWI_START:BUSY\\n\"); return BH1750_BUS_BUSY; }

BH1750_SDA_0();

17

BH1750_Nop();

BH1750_SCL_0(); BH1750_Nop();

if(BH1750_SDA_STATE()) {

////DebugPrint(\"TWI_START:BUS ERROR\\n\"); return BH1750_BUS_ERROR; }

return BH1750_READY; } /*

--------------------------------------------------------------------------*/ /**

* @Brief: IIC_STOP */ /*

--------------------------------------------------------------------------*/

void BH1750_Stop(void) {

BH1750_SDA_0(); BH1750_Nop();

BH1750_SCL_1(); BH1750_Nop();

BH1750_SDA_1(); BH1750_Nop();

//////DebugPrint(\"TWI_STOP\\n\"); } /*

--------------------------------------------------------------------------*/ /**

* @Brief: IIC_SendACK

18

*/ /*

--------------------------------------------------------------------------*/

void BH1750_SendACK(void) {

BH1750_SDA_0(); BH1750_Nop(); BH1750_SCL_1(); BH1750_Nop(); BH1750_SCL_0(); BH1750_Nop(); BH1750_SDA_1();

//////DebugPrint(\"TWI_SendACK\\n\"); } /*

--------------------------------------------------------------------------*/ /**

* @Brief: IIC_SendNACK */ /*

--------------------------------------------------------------------------*/

void BH1750_SendNACK(void) {

BH1750_SDA_1(); BH1750_Nop(); BH1750_SCL_1(); BH1750_Nop(); BH1750_SCL_0(); BH1750_Nop();

//////DebugPrint(\"TWI_SendNACK\\n\"); } /*

--------------------------------------------------------------------------*/ /**

* @Brief: TWI_SendByte *

* @Param: Data *

19

* @Returns: */ /*

--------------------------------------------------------------------------*/

u8 BH1750_SendByte(u8 Data) {

u8 i;

BH1750_SCL_0(); for(i=0;i<8;i++) {

//---------数据建立---------- if(Data&0x80) {

BH1750_SDA_1(); } else {

BH1750_SDA_0(); }

Data<<=1;

BH1750_Nop();

//---数据建立保持一定延时----

//----产生一个上升沿[正脉冲] BH1750_SCL_1(); BH1750_Nop(); BH1750_SCL_0();

BH1750_Nop();//延时,防止SCL还没变成低时改变SDA,从而产生START/STOP信号 //--------------------------- }

//接收从机的应答 BH1750_SDA_1(); BH1750_Nop(); BH1750_SCL_1(); BH1750_Nop();

if(BH1750_SDA_STATE()) {

BH1750_SCL_0(); BH1750_SDA_1();

//////DebugPrint(\"TWI_NACK!\\n\"); return BH1750_NACK; } else

20

{

BH1750_SCL_0(); BH1750_SDA_1();

//////DebugPrint(\"TWI_ACK!\\n\"); return BH1750_ACK; } } /*

--------------------------------------------------------------------------*/ /**

* @Brief: IIC_ReceiveByte *

* @Returns: */ /*

--------------------------------------------------------------------------*/

u8 BH1750_ReceiveByte(void) {

u8 i,Dat;

BH1750_SDA_1(); BH1750_SCL_0(); Dat=0;

for(i=0;i<8;i++) {

BH1750_SCL_1();//产生时钟上升沿[正脉冲],让从机准备好数据 BH1750_Nop(); Dat<<=1;

if(BH1750_SDA_STATE()) //读引脚状态 {

Dat|=0x01; }

BH1750_SCL_0();//准备好再次接收数据 BH1750_Nop();//等待数据准备好 }

//////DebugPrint(\"TWI_Dat:%x\\n\ return Dat; }

21

//*********************************************************

//void conversion(uint temp_data) // 数据转换出 个,十,百,千,万 //{

// wan=temp_data/10000+0x30 ;

// temp_data=temp_data%10000; //取余运算 // qian=temp_data/1000+0x30 ;

// temp_data=temp_data%1000; //取余运算 // bai=temp_data/100+0x30 ;

// temp_data=temp_data%100; //取余运算 // shi=temp_data/10+0x30 ;

// temp_data=temp_data%10; //取余运算 // ge=temp_data+0x30; //}

//*********************************

void Single_Write_BH1750(uchar REG_Address) {

BH1750_Start(); //起始信号

BH1750_SendByte(SlaveAddress); //发送设备地址+写信号 BH1750_SendByte(REG_Address); //内部寄存器地址, // BH1750_SendByte(REG_data); //内部寄存器数据, BH1750_Stop(); //发送停止信号 }

//********单字节读取***************************************** /*

uchar Single_Read_BH1750(uchar REG_Address) { uchar REG_data;

BH1750_Start(); //起始信号

BH1750_SendByte(SlaveAddress); //发送设备地址+写信号

BH1750_SendByte(REG_Address); //发送存储单元地址,从0开始

BH1750_Start(); //起始信号

BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号 REG_data=BH1750_RecvByte(); //读出寄存器数据 BH1750_SendACK(1); BH1750_Stop(); //停止信号 return REG_data; }

22

*/

//********************************************************* //

//连续读出BH1750内部数据 //

//********************************************************* void Multiple_Read_BH1750(void) { uchar i;

BH1750_Start(); //起始信号

BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号 for (i=0; i<3; i++) //连续读取2个地址数据,存储中BUF {

BUF[i] = BH1750_ReceiveByte(); //BUF[0]存储0x32地址中的数据

if (i == 3) {

BH1750_SendNACK(); //最后一个数据需要回NOACK } else {

BH1750_SendACK(); //回应ACK } }

BH1750_Stop(); //停止信号 //Delay5ms(); BH1750_Delay(500) ; }

//初始化BH1750,根据需要请参考pdf进行修改**** void Init_BH1750() {

Single_Write_BH1750(0x01); }

//********************************************************* //在主程序内调用本函数********

//********************************************************* void BH1750_Get_Guang( float *Zhaodu) {

23

BH1750_Delay(100) ; //延时100ms

Init_BH1750(); //初始化BH1750

Single_Write_BH1750(0x01); // power on

Single_Write_BH1750(0x10); // H- resolution mode

BH1750_Delay(200) ; //延时180ms

Multiple_Read_BH1750(); //连续读出数据,存储在BUF中

dis_data=BUF[0];

dis_data=(dis_data<<8)+BUF[1];//合成数据,即光照数据

*Zhaodu=(float)dis_data/1.2; }

24

因篇幅问题不能全部显示,请点此查看更多更全内容

Top