ALE/PROG:
端口3的管脚设置:
P3.0:
RXD,串行通信输入。
P3.1:
TXD,串行通信输出。
P3.2:
INT0,外部中断0输入。
P3.3:
INT1,外部中断1输入。
P3.4:
T0,计时计数器0输入。
P3.5:
T1,计时计数器1输入。
P3.6:
WR:
外部数据存储器的写入信号。
P3.7:
RD,外部数据存储器的读取信号。
2、复位电路
MCS-51单片机的复位是由外部的复位电路来实现的。
复位引脚RST通过一个斯密特触发器与复位电路相连,斯密特触发器用来抑制噪声,在每个机器周期的S5P2,斯密特触发器的输出电平由复位电路采样一次,然后才能得到内部复位操作所需要的信号。
上电复位:
上电复位电路是—种简单的复位电路,只要在RST复位引脚接一个电容到VCC,接一个电阻到地就可以了。
上电复位是指在给系统上电时,复位电路通过电容加到RST复位引脚一个短暂的高电平信号,这个复位信号随着VCC对电容的充电过程而回落,所以RST引脚复位的高电平维持时间取决于电容的充电时间。
为了保证系统安全可靠的复位,RST引脚的高电平信号必须维持足够长的时间。
电路图如下:
上电自动复位是通过外部复位电路的电容充电来实现的。
只要Vcc的上升时间不超过1ms,就可以实现自动上电复位。
3、时钟电路
时钟是单片机的心脏,单片机各功能部件的运行都是以时钟频率为基准,有条不紊的一拍一拍地工作。
因此,时钟频率直接影响单片机的速度,时钟电路的质量也直接影响单片机系统的稳定性。
常用的时钟电路有两种方式:
一种是内部时钟方式,另一种为外部时钟方式。
本文用的是内部时钟方式。
电路图如下:
MCS-51单片机内部有一个用于构成振荡器的高增益反相放大器,该高增益反向放大器的输入端为芯片引脚XTAL1,输出端为引脚XTAL2。
这两个引脚跨接石英晶体振荡器和微调电容,就构成一个稳定的自激振荡器。
4、显示电路
采用LCD显示,LCD显示具有丰富多样性,灵活性,电路简单、易于控制而且功耗小,对于信息量多的系统,是比较适合的,LCD液晶显示模块采用LCD1602型号,具有很低的功耗,正常工作室电流仅2.0mA/5.0V。
通过编程实现总动关闭屏幕能够更有效地降低功耗。
LCD1602分两行显示,每行可现实多达16个字符,其内部的字符发生器已经存储了160个不同的点阵字符图形,通过内部指令可实现对其显示多样的控制。
5、按键电路
按键的开关状态通过一定的电路转换为高、低电平状态。
按键闭合过程在相应的I/O端口形成一个负脉冲。
闭合和释放过程都要经过一定的过程才能达到稳定,这一过程是处于高、低电平之间的一种不稳定状态,称为抖动。
抖动持续时间的常长短与开关的机械特性有关,一般在5-10ms之间。
为了避免CPU多次处理按键的一次闭合,应采用措施消除抖动。
本文采用的是独立式按键,直接用I/O口线构成单个按键电路,每个按键占用一条I/O口线,每个按键的工作状态不会产生互相影响。
电路图如下:
P1.0口表示功能移位键,按键选择要调整的时十位、时个位、分十位或分个位。
P1.1口表示数字“+“键,按一下则对应的数字加1。
P1.2口表示数字“-”键,按一下则对应的数字减1。
P1.3口表示时间表的切换,程序默认为日常时间表,当按下该开关,使输入为低电平时,表示当前执行的是考试时间表,并有绿发光二极管显示。
再按键,使键抬起,输入维高电平时,表示当前执行的是日常作息时间表,用红发光二级管显示。
6、温度采集部分
此部分选用DS18B20传感器,主要由四部分组成:
64位ROM、温度传感器、非挥
发的温度报警触发器TH和TL、配置寄存器。
有三个管脚:
DQ为数字信号输入/输出端;GND为电源地;VDD为外接供电电源输入端。
电源有两种接法:
1)远端因入;2)寄生电源方式。
它是支持“一线总线”接口的温度传感器,测量温度范围为-55°C~+125°C,在-10~+85°C范围内,可编程为9位—12位A/D转换精度,工作电压在3V—5V之间。
现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。
###软件设计:
#include
#include
//#include"LCD1602.h"
//#include"DS1302.h"
#defineuintunsignedint
#defineucharunsignedchar
sbitDS1302_CLK=P1^7。
//实时时钟时钟线引脚
sbitDS1302_IO=P1^6。
//实时时钟数据线引脚
sbitDS1302_RST=P1^5。
//实时时钟复位线引脚
sbitwireless_1=P3^0。
sbitwireless_2=P3^1。
sbitwireless_3=P3^2。
sbitwireless_4=P3^3。
sbitACC0=ACC^0。
sbitACC7=ACC^7。
charhide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year。
//秒,分,时到日,月,年位闪的计数
sbitSet=P2^0。
//模式切换键
sbitUp=P2^1。
//加法按钮
sbitDown=P2^2。
//减法按钮
sbitout=P2^3。
//立刻跳出调整模式按钮
sbitDQ=P1^0。
//温度传送数据IO口
chardone,count,temp,flag,up_flag,down_flag。
uchartemp_value。
//温度值
ucharTempBuffer[5],week_value[2]。
voidshow_time(>。
//液晶显示程序
/***********1602液晶显示部分子程序****************/
//PortDefinitions**********************************************************
sbitLcdRs=P2^5。
sbitLcdRw=P2^6。
sbitLcdEn=P2^7。
sfrDBPort=0x80。
//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
//内部等待函数**************************************************************************
unsignedcharLCD_Wait(void>
{
LcdRs=0。
LcdRw=1。
_nop_(>。
LcdEn=1。
_nop_(>。
LcdEn=0。
returnDBPort。
}
//向LCD写入命令或数据************************************************************
#defineLCD_COMMAND0//Command
#defineLCD_DATA1//Data
#defineLCD_CLEAR_SCREEN0x01//清屏
#defineLCD_HOMING0x02//光标返回原点
voidLCD_Write(bitstyle,unsignedcharinput>
{
LcdEn=0。
LcdRs=style。
LcdRw=0。
_nop_(>。
DBPort=input。
_nop_(>。
//注意顺序
LcdEn=1。
_nop_(>。
//注意顺序
LcdEn=0。
_nop_(>。
LCD_Wait(>。
}
//设置显示模式************************************************************
#defineLCD_SHOW0x04//显示开
#defineLCD_HIDE0x00//显示关
#defineLCD_CURSOR0x02//显示光标
#defineLCD_NO_CURSOR0x00//无光标
#defineLCD_FLASH0x01//光标闪动
#defineLCD_NO_FLASH0x00//光标不闪动
voidLCD_SetDisplay(unsignedcharDisplayMode>
{
LCD_Write(LCD_COMMAND,0x08|DisplayMode>。
}
//设置输入模式************************************************************
#defineLCD_AC_UP0x02
#defineLCD_AC_DOWN0x00//default
#defineLCD_MOVE0x01//画面可平移
#defineLCD_NO_MOVE0x00//default
voidLCD_SetInput(unsignedcharInputMode>
{
LCD_Write(LCD_COMMAND,0x04|InputMode>。
}
//初始化LCD************************************************************
voidLCD_Initial(>
{
LcdEn=0。
LCD_Write(LCD_COMMAND,0x38>。
//8位数据端口,2行显示,5*7点阵
LCD_Write(LCD_COMMAND,0x38>。
LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR>。
//开启显示,无光标
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN>。
//清屏
LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE>。
//AC递增,画面不动
}
//液晶字符输入的位置************************
voidGotoXY(unsignedcharx,unsignedchary>
{
if(y==0>
LCD_Write(LCD_COMMAND,0x80|x>。
if(y==1>
LCD_Write(LCD_COMMAND,0x80|(x-0x40>>。
}
//将字符输出到液晶显示
voidPrint(unsignedchar*str>
{
while(*str!
='\0'>
{
LCD_Write(LCD_DATA,*str>。
str++。
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/***********DS1302时钟部分子程序******************/
typedefstruct__SYSTEMTIME__
{
unsignedcharSecond。
unsignedcharMinute。
unsignedcharHour。
unsignedcharWeek。
unsignedcharDay。
unsignedcharMonth。
unsignedcharYear。
unsignedcharDateString[11]。
unsignedcharTimeString[9]。
}SYSTEMTIME。
//定义的时间类型
SYSTEMTIMECurrentTime。
#defineAM(X>X
#definePM(X>(X+12>//转成24小时制
#defineDS1302_SECOND0x80//时钟芯片的寄存器位置,存放时间
#defineDS1302_MINUTE0x82
#defineDS1302_HOUR0x84
#defineDS1302_WEEK0x8A
#defineDS1302_DAY0x86
#defineDS1302_MONTH0x88
#defineDS1302_YEAR0x8C
voidDS1302InputByte(unsignedchard>//实时时钟写入一字节(内部函数>
{
unsignedchari。
ACC=d。
for(i=8。
i>0。
i-->
{
DS1302_IO=ACC0。
//相当于汇编中的RRC
DS1302_CLK=1。
DS1302_CLK=0。
ACC=ACC>>1。
}
}
unsignedcharDS1302OutputByte(void>//实时时钟读取一字节(内部函数>
{
unsignedchari。
for(i=8。
i>0。
i-->
{
ACC=ACC>>1。
//相当于汇编中的RRC
ACC7=DS1302_IO。
DS1302_CLK=1。
DS1302_CLK=0。
}
return(ACC>。
}
voidWrite1302(unsignedcharucAddr,unsignedcharucDa>//ucAddr:
DS1302地址,ucData:
要写的数据
{
DS1302_RST=0。
//Write1302(0x8e,0x00>。
DS1302_CLK=0。
DS1302_RST=1。
DS1302InputByte(ucAddr>。
//地址,命令
DS1302InputByte(ucDa>。
//写1Byte数据
DS1302_CLK=1。
DS1302_RST=0。
}
unsignedcharRead1302(unsignedcharucAddr>//读取DS1302某地址的数据
{
unsignedcharucData。
DS1302_RST=0。
DS1302_CLK=0。
DS1302_RST=1。
DS1302InputByte(ucAddr|0x01>。
//地址,命令
ucData=DS1302OutputByte(>。
//读1Byte数据
DS1302_CLK=1。
DS1302_RST=0。
return(ucData>。
}
voidDS1302_GetTime(SYSTEMTIME*Time>//获取时钟芯片的时钟数据到自定义的结构型数组
{
unsignedcharReadValue。
ReadValue=Read1302(DS1302_SECOND>。
Time->Second=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
//高三位取出读出乘⑩
ReadValue=Read1302(DS1302_MINUTE>。
Time->Minute=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
ReadValue=Read1302(DS1302_HOUR>。
Time->Hour=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
ReadValue=Read1302(DS1302_DAY>。
Time->Day=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
ReadValue=Read1302(DS1302_WEEK>。
Time->Week=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
ReadValue=Read1302(DS1302_MONTH>。
Time->Month=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
ReadValue=Read1302(DS1302_YEAR>。
Time->Year=((ReadValue&0x70>>>4>*10+(ReadValue&0x0F>。
}
voidDateToStr(SYSTEMTIME*Time>//将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{
if(hide_year<2>//这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为2007/07/22
{
Time->DateString[0]='2'。
Time->DateString[1]='0'。
Time->DateString[2]=Time->Year/10+'0'。
Time->DateString[3]=Time->Year%10+'0'。
}
else
{
Time->DateString[0]=''。
Time->DateString[1]=''。
Time->DateString[2]=''。
Time->DateString[3]=''。
}
Time->DateString[4]='/'。
if(hide_month<2>
{
Time->DateString[5]=Time->Month/10+'0'。
Time->DateString[6]=Time->Month%10+'0'。
}
else
{
Time->DateString[5]=''。
Time->DateString[6]=''。
}
Time->DateString[7]='/'。
if(hide_day<2>
{
Time->DateString[8]=Time->Day/10+'0'。
Time->DateString[9]=Time->Day%10+'0'。
}
else
{
Time->DateString[8]=''。
Time->DateString[9]=''。
}
if(hide_week<2>
{
week_value[0]=Time->Week%10+'0'。
//星期的数据另外放到week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0]=''。
}
week_value[1]='\0'。
Time->DateString[10]='\0'。
//字符串末尾加'\0',判断结束字符
}
voidTimeToStr(SYSTEMTIME*Time>//将时,分,秒数据转换成液晶显示字符放到数组TimeString[]。
{
if(hide_hour<2>
{
Time->TimeString[0]=Time->Hour/10+'0'。
Time->TimeString[1]=Time->Hour%10+'0'。
}
else
{
Time->TimeString[0]=''。
Time->TimeString[1]=''。
}
Time->TimeString[2]=':
'。
if(hide_min<2>
{
Time->TimeString[3]=Time->Minute/10+'0'。
Time->TimeString[4]=Time->Minute%10+'0'。
}
else
{
Time->TimeString[3]=''。
Time->TimeString[4]=''。