1 系统方案设计
1.1 系统整体设计
电子智能补光器的设计思路:首先通过单片机判断特殊天气模式是否启用,如果启用则直接亮黄灯并在手机上显示出来。确定特殊天气模式没有启用时,通过季节模块判断当前月份对应的季节来确定补光模式。通过光照传感器将外界光照强度与对应季节设定光照阈值进行比较,当外界光照强度大于设定阈值时进行补光操作,并通过蓝牙连接在手机上显示当前补光模式以及光照强度。
1.2 设计任务
主要任务简述:以单片机为核心,设计电子智能补光器,以满足各种不同情境下对光照需求的差异。
要求简述:
(1)在外界光照强度大于所设定阈值时补光器保持不工作状态,光照强度小于设定阈值时开始补光;
(2)可选择春、夏、秋、冬四种模式,分别对应四种不同的阈值电压;
(3)设置特殊天气模式,开启特殊天气模式后亮起黄色雾灯;
(4)通过蓝牙连接手机,显示当前的模式和光照强度。
1.3 模块方案选型
1.3.1主控方案选型
STC89C52单片机是宏晶科技推出的高反应速度、低功率消耗、有着很强抵的挡外界干扰能力的单片机,而且该单片机的指令代码非常切合传统的8051单片机,并且与传统51单片机对比而言,该单片机速度更快,是传统51单片机的8~12倍。除此之外,该单片机还有6时钟周期和12时钟周期可以任意选择。
主要特性如下:
(1)新一代8051单片机,6时钟机器周期和12时钟机器周期可以任意选择,指令代码非常契合传统8051单片机。
(2)工作电压:5.5V~3.3V(5V单片机)。
(3)工作频率范围处于0~40MHz之间,相当于普通8051单片机工作频率的0~80MHz范围,而且新一代单片机的实际工作频率可达48MHz。
(4)一共具有3个16位定时器,也就是定时器T0、T1、T2。
(5)外部中断4路,低电平触发或下降沿中断电路,PowerDown模式可通过外部中断低电平触发中断的方式触发。
1.3.2光电转换器的选择
ADC0832是NS(National Semiconductor)公司生产的串行接口8位A/D转换器,通过三线接口与单片机连接,功耗低,性能价格比较高,合适使用在袖珍式的智能仪器仪表中。ADC0832为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。芯片具有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件连接和处理器控制变得更加方便。通过DI 数据输入端,可以轻易的实现通道功能的选择。其主要特点如下:
(1)8位分辨率,其最高分辨可达256级;
(2)双通道A/D转换;
选择该A/D转换芯片,不仅因为其体积小、功耗低,而且可以适应一般的模拟量转换要求,完全满足系统的要求。另外,其内部电源输入与参考电压的复用,使得转换芯片的模拟电压输入在0~5V之间,电源电路供电可以同时满足51单片机和该芯片的共同使用。除此之外该芯片的转换时间极短,仅为32μS,反应非常迅速,另外该芯片具有双数据输出可作为数据校验的工具,以此来减少实验数据误差,转换速度快并且稳定性能出色。单独工作的芯片的使能输入,可以更轻松地对多元件进行连接,同时也可以更加方便地控制处理器。通过DI 数据输入端,使得实现通道功能的选择变的易如反掌。除此之外,价格上的优势同样也是选择它的原因之一。
1.3.3显示器的选择
LCD1602液晶显示器是广泛使用的一种工业字符型液晶显示模块。由字符型液晶显示器(LCD)、控制驱动主电路HD44780及其扩展驱动电路HD44100,以及少量电阻、电容元件和结构件等装配在PCB板上而组成,能够同时显示16x02即32个字符。(16列2行)。但寄存器不止32个,有一些显示效果,如字符一个个显示、字符从左到右或从右到左显示等等,显示效果简单。当然也有其他更好的选择,例如12864液晶显示器,它的显示模块是128×64点阵的汉字图形型液晶显示模块,可显示汉字及图形,具有多种功能:光标显示、画面移位、睡眠模式等。
其实综合来说,二者编程方面的难度差不多,原理方面也差不多,甚至12864液晶显示器更胜一筹,因为该显示器显示更全面,字符也更多,需要进行更多操作的话自然是12864液晶显示器能够胜任。但是对比来说的话,1602液晶显示器也能实现设计的要求,而且相对来说更重要的原因就是1602液晶显示器比较廉价,网上购买也比较便宜,最低五六块钱左右。而12864液晶显示器网上购买最便宜的也要在二三十左右。所以从造价方面以及使用方面考虑,当然是价格低廉而且功能也不欠缺的优先。因此选择1602液晶显示器作为显示器件。
2 硬件设计
2.1 单片机模块
单片机的主要特点有:
(1)有出色的性能单价比,高效能、低电压,易于制作便携式产品。
(2)集成度高,体积小,有较高的稳定性。而且单片机把各功能零件组合在一块芯片上,内部结构使用的是总线结构,不仅减轻了各芯片彼此之间的连线,还大大增加了单片机的安全性和抗干扰能力。
(3)控制功能强。为求满足工业控制的要求,通常单片机的指令系统中均有极多样的转移指令、I/O口的逻辑操作和位处理特性。单片机的逻辑控制功能及运转速度均远高于同一等级的微机。
(4)外部总线增加了I2C(Inter-Integrated Circuit)及SPI(Serial Peripheral Interface)等串行总线方式,逐步缩小了体积,精简了构造。单片机的系统扩展、系统配置较典型、规范,容易构成各种规模的应用系统。
PORT0(P0.0~P0.7):端口0是一个8位宽的开路汲极双向输出入端口,共有8个位,P0.0表示位0,P0.1表示位1,依此类推。其他三个I/O端口(P1、P2、P3)则不具有此电路组态,而是内部有一提升电路,P0在当做I/O用时可以推动8个LS的TTL负载。
PORT1(P1.0~P1.7):端口1也是具有内部提升电路的双向I/O端口,其输出缓冲器可以推动4个LSTTL负载,同样地若将端口1的输出设为高电平,便是由此端口来输入数据。
PORT2(P2.0~P2.7):端口2是具有内部提升电路的双向I/O端口,每一个引脚可以推动4个LS的TTL负载,若将端口2的输出设为高电平时,此端口便能当成输入端口来使用。P2除了当做一般I/O端口使用外,若是在STC89C52扩充外接程序存储器或数据存储器时,也提供地址总线的高字节A8~A15,这个时候P2便不能当做I/O来使用了。
PORT3(P3.0~P3.7):端口3也具有内部提升电路的双向I/O端口,其输出缓冲器可以推动4个TTL负载,同时还多工具有其他的额外特殊功能,包括串行通信、外部中断控制、计时计数控制及外部数据存储器内容的读取或写入控制等功能。单片机的引脚图如图3-1所示。
#include "51Lib_Configure.h"
#include "51Lib_Declaration.h"
#if _CONFIG_FUNC_LCD1602_ == CH_ENABLE
#define _NOP() _nop_()
#define DataPort P0
#define DataPIN P0
#define CLR_RS (lcd1602_RS=0)
#define SET_RS (lcd1602_RS=1)
#define CLR_RW (lcd1602_RW=0)
#define SET_RW (lcd1602_RW=1)
#define CLR_EN (lcd1602_EN=0)
#define SET_EN (lcd1602_EN=1)
/*
LcdReset(); //LCD1602初始化
DelayMs(10);
sprintf(temp,"1111111111111111");//更新显示
DispStr(0,0,(unsigned char *)temp);//打印显示
sprintf(temp,"1111111111111111");//更新显示
DispStr(0,1,(unsigned char *)temp);//打印显示
*/
/***********************************************
函数名称:DispNum
功 能:让液晶从某个位置起连续显示一个数值,前面不会补0
参 数:x--位置的列坐标
y--位置的行坐标
Dis_dat--需要显示的数
Dis_Len--需要显示的宽度
返回值 :无
***********************************************/
void DispNum(uchar x, uchar y, uint Dis_dat, uchar Dis_Len)
{
uchar i;
uint dat = 1;
Disp1Char(x+Dis_Len-1,y,Dis_dat%10+0x30);
if(Dis_Len == 1)
return;
for(i = 1;i < Dis_Len;i++)
dat*=10;
for(i = 1; i < Dis_Len ; i++)
{
//dat = pow(10, Dis_Len-i);
if(Dis_dat >= dat)
Disp1Char(x+i-1,y,Dis_dat/dat%10+0x30);
else
Disp1Char(x+i-1,y,' ');
dat/=10;
}
}
/***********************************************
函数名称:DispStr
功 能:让液晶从某个位置起连续显示一个字符串
参 数:x--位置的列坐标
y--位置的行坐标
ptr--指向字符串存放位置的指针
返回值 :无
***********************************************/
void DispStr(uchar x,uchar y,uchar *ptr)
{
uchar *temp;
uchar i,n = 0;
temp = ptr;
while(*ptr++ != '�') n++; //计算字符串有效字符的个数
for (i=0;i<n;i++)
{
Disp1Char(x++,y,temp[i]);
if (x == 0x10)
{
break;
}
}
}
/*******************************************
函数名称:DispNchar
功 能:让液晶从某个位置起连续显示N个字符
参 数:x--位置的列坐标
y--位置的行坐标
n--字符个数
ptr--指向字符存放位置的指针
返回值 :无
*******************************************
void DispNChar(uchar x,uchar y, uchar n,uchar *ptr)
{
uchar i;
for (i=0;i<n;i++)
{
Disp1Char(x++,y,ptr[i]);
if (x == 0x10)
{
x = 0;
y ^= 1;
}
}
}
*/
/*******************************************
函数名称:LocateXY
功 能:向液晶输入显示字符位置的坐标信息
参 数:x--位置的列坐标
y--位置的行坐标
返回值 :无
********************************************/
void LocateXY(uchar x,uchar y)
{
uchar temp;
temp = x&0x0f;
y &= 0x01;
if(y) temp |= 0x40; //如果在第2行
temp |= 0x80;
LcdWriteCommand(temp,1);
}
/*******************************************
函数名称:Disp1Char
功 能:在某个位置显示一个字符
参 数:x--位置的列坐标
y--位置的行坐标
data--显示的字符数据
返回值 :无
********************************************/
void Disp1Char(uchar x,uchar y,uchar data1)
{
LocateXY( x, y );
LcdWriteData( data1 );
}
/*******************************************
函数名称:LcdReset
功 能:对1602液晶模块进行复位操作
参 数:无
返回值 :无
********************************************/
void LcdReset(void)
{
// DataDir = 0xFF; //数据端口设为输出状态
LcdWriteCommand(0x38, 0); //规定的复位操作
DelayMs(5);
LcdWriteCommand(0x38, 0);
DelayMs(5);
LcdWriteCommand(0x38, 0);
DelayMs(5);
LcdWriteCommand(0x38, 1); //显示模式设置
LcdWriteCommand(0x08, 1); //显示关闭
LcdWriteCommand(0x01, 1); //显示清屏
LcdWriteCommand(0x06, 1); //写字符时整体不移动
LcdWriteCommand(0x0c, 1); //显示开,不开游标,不闪烁
}
/*------------------------------------------------
清屏函数
------------------------------------------------*/
void LcdClear(void)
{
LcdWriteCommand(0x01,1);
DelayMs(5);
}
/*******************************************
函数名称:LcdWriteCommand
功 能:向液晶模块写入命令
参 数:cmd--命令,
chk--是否判忙的标志,1:判忙,0:不判
返回值 :无
********************************************/
void LcdWriteCommand(uchar cmd,uchar chk)
{
if (chk) WaitForEnable(); // 检测忙信号?
CLR_RS;
CLR_RW;
_NOP();
DataPort = cmd; //将命令字写入数据端口
_NOP();
SET_EN; //产生使能脉冲信号
_NOP();
_NOP();
CLR_EN;
}
/*******************************************
函数名称:LcdWriteData
功 能:向液晶显示的当前地址写入显示数据
参 数:data--显示字符数据
返回值 :无
********************************************/
void LcdWriteData( uchar data1 )
{
WaitForEnable(); //等待液晶不忙
SET_RS;
CLR_RW;
SET_EN;
_NOP();
DataPort = data1; //将显示数据写入数据端口
_NOP();
//产生使能脉冲信号
_NOP();
_NOP();
CLR_EN;
}
/*******************************************
函数名称:WaitForEnable
功 能:等待1602液晶完成内部操作
参 数:无
返回值 :无
********************************************/
void WaitForEnable(void)
{
unsigned int later=0;
DataPort=0xff;
CLR_RS;
SET_RW;
_NOP();
SET_EN;
_NOP();
_NOP();
// while((DataPIN&Busy)!=0);
while(((DataPIN&0x80)!=0)&&(later<1000)) //检测忙标志
{
DelayUs2x(2);
later++;
}
CLR_EN;
// DataDir|=0xFF; //将P4口切换为输出状态
}
#endif