湖南大学基于IAP15F2K61S2设计交通信号灯

发布于 22 天前  100 次阅读


任务及设计要求

  • 了解实际交通灯的变化规律(以十字路口为例);
  • 要求用LCD显示字符“红、黄、绿”(或字母r、y、g)代替相应的信号灯;此处使用字母r、y、g;
  • 要求有东西、南北四组信号灯显示,并显示对应的时间;
  • 时间要求倒计时显示,计时时间到,对应的信号准确切换;
  • 信号灯按一定的规律闪烁,实现简单的交通管理;
  • 能实现紧急事件处理(例如救护车的通行等),可用蜂鸣器报警和特殊数字显示;
  • 可根据交通流量智能调整各路段的通行时间;
  • 显示北京时间,可调整;
  • 扩展功能:
  • 1)可利用开发板上其他硬件模块资源增加功能;
  • 2)可利用主板芯片的增强性功能进行开发和设计;
  • 3)可外接扩展模块增加功能(模块可采用实验室已有模块,也可自备)
  • 4)自定义其他功能,要求具有一定难度、创新性和综合性。

设计实际所实现的功能

概要说明

  此次共设计三个基本功能,分别是:简单交通信号灯功能包括“红(R)、黄(Y)、绿(G)”字符显示、“东西、南北”信号灯显示以及倒计时)、LCD显示北京时间功能(可调整)和紧急事件处理功能(蜂鸣器报警)。最终通过一个按键来实现三个功能的模式转换,下面是各功能的具体设计介绍。

详细说明

  • 简单交通信号灯功能

  此功能可使LCD屏显示基础交通信号灯运行模式。LCD显示屏一共分为两列,第一列第一排为“DX”字样,指示下排为东西方向信号灯,第二排为东西方向的信号灯倒计时;第二列第一排为“NB”字样,指示下排为南北方向信号灯,第二排为南北方向的信号灯倒计时。

  两栏信号灯同时倒计时,初始设置“R(红灯)”时长为10s,“G(绿灯)”时长为7s,“Y(黄灯)”时长为3s,红灯倒计时到0s时即切换为绿灯,绿灯倒计时到0s时即切换为黄灯,黄灯倒计时到0s时即切换为红灯。

  若需根据路况来调整各灯倒计时时长,则可通过其中两个按键来实现对红灯和绿灯的同时加1s/减1s调整,当达到上限/下限时又恢复为初始数值,且根据实际情况,黄灯为固定时长3s,无需调整。

  • LCD显示北京时间

  此功能可使LCD显示北京时间(年、月、日及时、分、秒)并自动计时,系统上电后的初始显示为“Date:21-05-12,Time:14:30:00”(此初始时间可更改),此后无论系统处于何种模式,只要保持供电,时钟功能均会保持计时。若系统掉电后重新上电,则时钟从初始设置时间开始计时。

  如需调整当前时间,则可通过按“暂停键”使时钟计时功能暂停,并通过另外四个键分别实现对“月”、“时”、“分”、“秒”的调整,直至调整为目标时间,再按“暂停键”使时钟恢复计时。

  • 紧急事件处理功能

  通过切换键切换到此模式,即可使系统进入紧急状态,LCD显示屏显示“Emergency!!!”和“Ambulance!!!”字样,代表的是进入紧急状态与救护车模式,同时蜂鸣器发出响声,如需停止该状态,通过切换键切换为其他模式即可。

按键功能

按键编号 按键功能
S6 实现三个模式的切换
S7 在时钟计时模式下实现对“秒”位的加1调整;在交通信号灯模式下实现对红绿灯时长的加1s调整
S8 在时钟计时模式下实现对“分”位的加1调整;在交通信号灯模式下实现对红绿灯时长的减1s调整
S9 在时钟计时模式下实现对“时”位的加1调整
S10 在时钟计时模式下实现对“月”位的加1调整
S11 在时钟计时模式下实现计时暂停及恢复计时功能

系统原理框图及模块的作用

原理框图



模块作用

1、单片机:系统的核心控制单元;
2、矩阵按键

(1)切换功能模块;
(2)调整实时时钟的时间
(3)设置交通灯倒计时秒数;
(4)暂停与启动时钟。

3、LCD1602液晶显示屏:

(1)显示南北与东西方向交通信号灯灯状态及倒计时;
(2)显示北京时间;
(3)显示紧急情况下的字符提醒。

4、DS1302时钟:实时时钟;
5、蜂鸣器:紧急情况报警。

硬件设计及说明

学生设计所实际使用到的具体元器件清单

  • (1)IAP15F2K61S2单片机
  • (2)矩阵按键
  • (3)LCD1602液晶显示屏
  • (4)DS1302时钟
  • (5)蜂鸣器

硬件电路图及功能说明

  • 1、单片机:完成各方面的运算集成



宏晶公司最新STC15系列IAP15F2K61S2芯片,可系统编程或应用编程:

(1)增强型8051CPU,1T,单时钟/机器周期,速度比普通8051快8~12倍;

(2)61K字节片内Flash程序存储器,擦写次数10万次以上;

(3)拥有片内大容量2048字节的SRAM;

(4)共有8个通道的10位高速ADC,速度可达30万次/秒,3路PWM可用作D/A转换;

(5)共有3通道捕获/比较单元(CCP/PWM/PCA);

(6)内部高可靠复位,8级可选复位门槛电压,可省去外部复位电路;

(7)内部高精度R/C时钟,时钟从5MHz~35MHz可选;

程序流程图设计及程序模块功能描述

(8)两组高速异步串行通信端口可同时使用,并且可在5组管脚之间进行转换;

(9)一组高速异步串行通信端口SPI;

(10)各种接口扩展齐全。

  • 2、矩形按键:通过按键的输入完成按键对应的功能



行列按键和独立按键

  其中S12、S13、S14为独立按键(启动与关闭不受其余按键影响),当按键按下并分别由P3^2、P3^3、P3^4送出高电平信号时,表示开关启动。其余按键为2×3组合按键。

  • 3、LCD1602:2*16总共32个显示位置显示需要显示的字符



LCD1602管脚图





LCD1602控制字及读写指令说明

  • 4、DS1302时钟:生成年、月、日、星期、时、分、秒,亦可对其进行写操作



  DS1302是DALLAS公司推出的涓流充电时钟芯片,内含一个实时时钟/日历和31字节静态RAM,可以通过串行接口与单片机进行通信。其工作时功耗很低,保持数据和时钟信息时,功耗小于1mW。



  控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302。在8位控制字指令输入后的下一个SCLK时钟下降沿,读出DS1302中的数据。

  • 5、蜂鸣器:在需要的时候发出声音,作警示作用


  根据电路图可知,当IAP15F2K61S2芯片的P1^6发出一个低电平时,蜂鸣器会发声。蜂鸣器发出不同音调的原理是,接通和关断时间长度不同,就会发出不同的声调,即脉宽调制,PWM

程序流程图

系统操作说明

  • 1、系统上电后为模式0,即交通信号灯功能。此时LCD显示屏一共分为两栏

  第一排为“DX”字样,指示下排为东西方向信号灯,第一栏第二排为东西方向的信号灯倒计时;

  第二栏第一排为“NB”字样,指示下排为南北方向信号灯,第二排为南北方向的信号灯倒计时。

  默认时长为红灯10s、绿灯7s、黄灯3s(此初始时长可通过更改程序来调整),两栏信号灯同时开始倒计时,此时按S7键即可使红灯和绿灯的倒计时时长同时增加1s,按S8键即可使红灯和绿灯的倒计时时长同时减短1s,设置的新时长从下一倒计时周期开始更新。

D X N B
G : 0 2 - - R : 0 5 -



  • 2、按S6键将模式切换为模式1,即时钟计时功能。

  LCD显示屏的初始显示为“Date:21-05-12,Time:14:30:00”(此初始时间可通过更改程序来调整),系统开始计时。按下S11键,时钟保存当前时间并停止计时,此时按下S7键即可进行“秒”位加1调整,按下S8键即可进行“分”位加1调整,按下S9键即可进行“时”位加1调整,按下S10键即可进行“月”位加1调整;调整完毕后重新按S11键即可从当前时间开始计时,只要系统不断电,无论处于何种模式,此功能都将保持计时。



  • 3、按S6键将模式切换为模式2,即紧急事件处理功能。

  此时LCD显示屏显示“Emergency!!!”和“Ambulance!!!”字样,同时蜂鸣器发出响声(响声时长可通过更改程序来调整)。最后按S6键将模式切换回模式0。



全部源程序及详细注释

主程序main.c

//文件包含
 #include "stc15f2k60s2.h"
 #include "ds1302.h"
 #include "lcd1602.h"

//宏定义
 #define uchar unsigned char
 #define uint  unsigned int

//行列按键所在端口的序号
//例如Line1在端口P35,则对应的序号为5
 #define  Line1     5    //行1的序号
 #define  Line2     6    //行2的序号
 #define  Column1   4    //列1的序号
 #define  Column2   3    //列2的序号
 #define  Column3   2    //列3的序号

//行列按键所在的端口
 #define  KEYPORT   P3

//按键定义 定义值可以任意,六个值不相同就可以
 #define  KEY6      6
 #define  KEY7      7
 #define  KEY8      8
 #define  KEY9      9
 #define  KEY10     10
 #define  KEY11     11






sbit BEEP =P1^6; //蜂鸣器

sbit high =P3^6;
sbit low  =P3^5;



//                                   秒       分     时      日      月     星期    年
//初始化时间                   00    30    14     10      05      01     21
unsigned char Init[7] = {0x00, 0x30, 0x14, 0x012, 0x05, 0x01, 0x21};
//存放当前时间
unsigned char Now[7]={0x00, 0x30, 0x14, 0x12, 0x05, 0x01, 0x21};

//保持当前时间
unsigned char remain[7];

//保存RAM数据
unsigned char RAMData[7];

//时间更新标记
bit UpdateTimeFlag;

//红绿灯时间更新标志
bit UpdateTrafficFlag;


//按键键值
uint Key_value;

//模式选择
uint model=0;

//暂停标志
uint Pause_flag;

//南北、东西红绿黄灯时间
unsigned int NS_time,EW_time;

//南北、东西红绿灯状态
unsigned int traffic_state=0;

//计数时间
uint count=0;

//保存时间
uint m=0;

//红、绿、黄灯时间
uint red_time=11,green_time=8,yellow_time=4;   //初始值
uint Redtime,Greentime;     //更新值




//函数声明
void IO_Init(void);
void Delay_ms(uint ms);
void Timer0_Init(void);

uchar HEX2ASCII(uchar dat);   //字符转换
void DS1302_Init(void);       //DS1302初始化
void LCD1602_Init(void);      //LCD1602初始化
void DS1302_SetTime(unsigned char * pBuf);  //设置初始时间
void DS1302_GetTime(unsigned char *pBuf);   //读取时间
void DS1302_ReadRAM(unsigned char *pBuf);   //读RAM
void DS1302_WriteRAM(unsigned char * pBuf); //写RAM
void LCD1602_Display_Str(uchar* str);       //显示字符串
void LCD1602_Display_Clock(uchar* pointer); //时钟显示函数
void LCD1602_Display_traffic(uint EW_light,uint NS_light,uint state); //交通灯显示函数
void LCD1602_Display_traffic_emergency(void);                         //紧急情况显示函数
void BEEP_toggle(uint BEEPTIME);                                      //蜂鸣器报警
unsigned int Key_Scan(void);                                                  //按键扫描
void model_choose(void);
void model_0(void);  // 显示红绿灯
void model_1(void);  // 显示当前北京时间
void model_2(void);  // 报警并进入紧急状态

//主函数
void main(void)
{
        IO_Init();       //端口初始化
        Delay_ms(10);    //上电延时10ms
        Timer0_Init();   //定时器0初始化

        DS1302_Init();   //DS1302初始化
        LCD1602_Init();  //LCD1602初始化


        Greentime=green_time;
        Redtime=red_time;
        while(1)
        {

                model_choose();
                Key_value=Key_Scan();
                if(Key_value==11)
                        Pause_flag=!Pause_flag;
//       else if(Key_value==11)
//       Pause_flag=0;


                switch(model)
                {
                case 0:
                {
                        model_0(); // 进入模式0
                } break;


                case 1:
                {
                        model_1(); // 进入模式1
                } break;



                case 2:
                {
                        model_2(); // 进入模式2
                } break;

                default: break;
                }
        }
}

/***********************************************
   模式选择器
 ************************************************/

void model_choose(void)
{
        if(Key_value==6)
        {
                if(model==2)
                        model=0;
                else
                        model+=1;
        }
        else
                model=model;
}
/***********************************************
   函数名称:Delay_ms
   功    能:STC 1T单片机1ms延时程序
   入口参数:ms:延时的毫秒数
   返 回 值:无
   备    注:示波器实测1.05ms 时钟11.0592MHz
 ************************************************/
void Delay_ms(unsigned int ms)
{
        unsigned int De_Cnt;
        while( (ms--) != 0)
        {
                for(De_Cnt = 0; De_Cnt < 600; De_Cnt++);
        }
}
/***********************************************
   函数名称:Timer0_Init
   功    能:定时器0初始化函数
   入口参数:无
   返 回 值:无
   备    注:定时初值可以使用stc下载软件中的
          定时初值自动生成功能。
 ************************************************/
void Timer0_Init(void)
{
        AUXR &= 0x7f; //T0时钟12T模式
        TMOD &= 0xf0; //T0工作于十六位定时方式
        TMOD |=0x01;
        //使用位操作,避免对其他定时器产生影响
        TL0=0x00; //定时初值50ms     11.0592MHz
        TH0=0x4c;
        TF0 = 0; //清除TF0标记
        ET0=1;  //使能T0中断
        EA=1;   //使能总中断
        TR0=1;  //运行T0
}
/***********************************************
   函数名称:Timer0_ISR
   功    能:定时器0中断服务函数
   入口参数:无
   返 回 值:无
   备    注:无
 ************************************************/
void Timer0_ISR(void) interrupt 1
{
        static unsigned char T0_Cnt=0;



        //使用静态计数器,每次调用该中断函数时,
        //静态计数器都能保持上一次的计数值。
        //如果不使用静态计数器,每次调用该中断函数时
        //该计数器初值都是0,计数值就无法累加。
        TL0=0x00; //定时初值50ms     11.0592MHz
        TH0=0x4c;


        T0_Cnt++;
        if(T0_Cnt==21) //定时1000ms
        {
                T0_Cnt=0;
                UpdateTimeFlag=1;       //更新时间标记有效


                if(count==2*(Greentime+yellow_time)-4)
                {
                        count=1;
                        traffic_state=0;
                        Greentime=green_time;
                        Redtime=red_time;  //更新红绿灯时间
                        NS_time=Greentime-1;
                        EW_time=Redtime-1;   //红绿灯回到初始状态,并重置红绿灯时间
                        UpdateTrafficFlag=1; //更新交通灯标志有效

                }
                else
                {
                        count+=1;
                        if(count==1)
                        {
                                traffic_state=0;
                                NS_time=Greentime;
                                EW_time=Redtime; //东西红、南北绿
                        }
                        else if(count==Greentime)
                        {
                                traffic_state=1;
                                NS_time=yellow_time;
                                EW_time=yellow_time; //东西红、南北黄
                        }
                        else if(count==yellow_time+Greentime-1)
                        {
                                traffic_state=2;
                                NS_time=Redtime;
                                EW_time=Greentime; //东西绿、南北红
                        }
                        else if(count==2*Greentime+yellow_time-2)
                        {
                                traffic_state=3;
                                NS_time=yellow_time;
                                EW_time=yellow_time; //东西黄、南北红
                        }
                        NS_time--;
                        EW_time--;
                        UpdateTrafficFlag=1; //更新交通灯标志有效
                }
        }
}
/***********************************************
   函数名称:DS1302_Init
   功    能:DS1302初始化函数
   入口参数:无
   返 回 值:无
   备    注:
     DS1302具体命令详见数据手册
 ************************************************/
void DS1302_Init(void)
{
        unsigned char cnt;

        //将P21 P22设置为准双向口
        P2M1 &=~( (1<<1) | (1<<2) );
        P2M0 &=~( (1<<1) | (1<<2) );

        //初始化P44口为准双向口
        P4M1 &=~(1<<4);
        P4M0 &=~(1<<4);

        DS1302_SCE_Clr();
        DS1302_SCK_Clr();
        DS1302_WriteData(0x8e, 0x00); //允许写操作
        //读取振荡器工作状态
        if( (DS1302_ReadData(0x81)&0x80)==0x80)
        {
                //如果振荡器停止,则启动
                DS1302_WriteData(0x80, 0x00); //时钟启动
        }
        DS1302_WriteData(0x90, 0xa6); //一个二极管+4K电阻充电
        DS1302_WriteData(0x8e, 0x80); //写保护

        Delay_ms(10);
        DS1302_ReadRAM(RAMData);  //读取内部RAM数据
        //比较读出和写入的数据
        for(cnt=0; cnt<7; cnt++)
        {
                if(RAMData[cnt]!=Init[cnt]) //如果不同,则认为未初始化
                {
                        DS1302_SetTime(Init); //重新初始化
                        DS1302_WriteRAM(Init); //将数据写入内部RAM,以此判断是否初始化
                }
        }
}
/***********************************************
   函数名称:DS1302_SetTime
   功    能:DS1302时间设置函数
   入口参数:pBuf:指向设置值数据的指针
   返 回 值:无
   备    注:详见数据手册时间格式。
 ************************************************/
void DS1302_SetTime(unsigned char * pBuf)
{
        unsigned char addr = 0x80; //写时间寄存器开始地址
        unsigned char n = 7;    //连续写7个字节数据

        DS1302_WriteData(0x8e, 0x00); //允许写操作
        while (n--)     //连续写7个时间寄存器,地址增2.
        {
                DS1302_WriteData(addr, *pBuf++);
                addr += 2; //按数据手册定义,地址以2递增
        }
        DS1302_WriteData(0x8e, 0x80); //写保护
}
/***********************************************
   函数名称:DS1302_GetTime
   功    能:DS1302读取时钟函数
   入口参数:pBuf:指向保存时间数据的指针
   返 回 值:无
   备    注:读取到的时钟数据格式为BCD格式。
 ************************************************/
void DS1302_GetTime(unsigned char *pBuf)
{
        unsigned char addr = 0x81; //读时间寄存器开始地址
        unsigned char n = 7;     //连续读7个字节数据
        //读数据不需要执行允许写的操作
        while (n--)
        {
                *pBuf++ = DS1302_ReadData(addr);
                addr += 2; //按数据手册定义,地址以2递增
        }
}
/***********************************************
   函数名称:DS1302_WriteRAM
   功    能:向DS1302的RAM中写入数据函数
   入口参数:pBuf:指向设置值数据的指针
   返 回 值:无
   备    注:详见数据手册时间格式。
 ************************************************/
void DS1302_WriteRAM(unsigned char * pBuf)
{
        unsigned char addr = 0xc0; //写ram开始地址
        unsigned char n = 7;    //使用7个字节的ram

        DS1302_WriteData(0x8e, 0x00); //允许写操作
        while (n--)     //连续写7个RAM寄存器,地址增2.
        {
                DS1302_WriteData(addr, *pBuf++);
                addr += 2; //按数据手册定义,地址以2递增
        }
        DS1302_WriteData(0x8e, 0x80); //写保护
}
/***********************************************
   函数名称:DS1302_ReadRAM
   功    能:从DS1302的RAM中读出数据函数
   入口参数:pBuf:指向保存时间数据的指针
   返 回 值:无
   备    注:无
 ************************************************/
void DS1302_ReadRAM(unsigned char *pBuf)
{
        unsigned char addr = 0xc1; //读ram开始地址
        unsigned char n = 7;     //使用7个字节的ram

        while (n--)              //连续读7个RAM寄存器,地址增2.
        {
                *pBuf++ = DS1302_ReadData(addr);
                addr += 2;
        }
}
/***********************************************
   函数名称:LCD1602_Init
   功    能:LCD1602初始化
   入口参数:无
   返 回 值:无
   备    注:详见数据手册定义。
 ************************************************/
void LCD1602_Init(void)
{
        Delay_ms(15);     //上电延时15ms
        LCD1602_WriteCMD(0x38); //写显示指令(不检测忙信号)
        Delay_ms(5);
        LCD1602_WriteCMD(0x38); //写显示指令(不检测忙信号)
        Delay_ms(5);
        LCD1602_WriteCMD(0x38); //写显示指令(不检测忙信号)
        LCD1602_CheckBusy();
        LCD1602_WriteCMD(0x38); //写显示指令
        LCD1602_CheckBusy();
        LCD1602_WriteCMD(0x08); //显示关闭
        LCD1602_CheckBusy();
        LCD1602_WriteCMD(0x01); //清屏
        LCD1602_CheckBusy();
        LCD1602_WriteCMD(0x06); //显示光标移动设置
        LCD1602_CheckBusy();
        LCD1602_WriteCMD(0x0c); //显示开及光标设置
}
/***********************************************
   函数名称:LCD1602_Display_Str
   功    能:lcd1602显示字符函数
   入口参数:str指针地址
   返 回 值:无
   备    注:无
 ************************************************/
void LCD1602_Display_Str(uchar* str)
{
        while(*str!='\0') //未到字符串末尾
        {
                LCD1602_CheckBusy(); //检测忙信号
                LCD1602_WriteDAT(*str);//发送数据
                str++;    //移动指针
        }
}
/***********************************************
   函数名称:LCD1602_Display_Clock
   功    能:lcd1602显示时钟
   入口参数:pointer指针地址
   返 回 值:无
   备    注:1602LCD显示的为字符,必须将整数转换成
          相应的字符,否则显示乱码。
 ************************************************/
void LCD1602_Display_Clock(uchar* pBuf)
{
        LCD1602_WriteCMD(0x01); //清屏
        LCD1602_CheckBusy();  //检测忙信号
        LCD1602_WriteCMD(LINE1); //写入地址
        LCD1602_Display_Str("Date: ");                  //日期

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*(pBuf+6)&0xf0)>>4)); //年高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(*(pBuf+6)&0x0f)); //年低位

        LCD1602_CheckBusy();
        LCD1602_WriteDAT('-');            //“-”

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*(pBuf+4)&0xf0)>>4)); //月高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(*(pBuf+4)&0x0f)); //月低位

        LCD1602_CheckBusy();
        LCD1602_WriteDAT('-');            //“-”

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*(pBuf+3)&0xf0)>>4)); //日高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(*(pBuf+3)&0x0f)); //日低位



        LCD1602_CheckBusy();  //检测忙信号
        LCD1602_WriteCMD(LINE2); //写入地址
        LCD1602_Display_Str("Time: ");                //时间

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*(pBuf+2)&0xf0)>>4)); //时高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(*(pBuf+2)&0x0f)); //时低位

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(':');            //“:”

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*(pBuf+1)&0xf0)>>4)); //分高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(*(pBuf+1)&0x0f)); //分低位

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(':');            //“:”

        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII(((*pBuf)&0xf0)>>4)); //秒高位
        LCD1602_CheckBusy();
        LCD1602_WriteDAT(HEX2ASCII((*pBuf)&0x0f));  //秒低位


//  LCD1602_CheckBusy();
//  LCD1602_WriteCMD(LINE2+3);
//  LCD1602_Display_Str("TimeDisplay");
}
/***********************************************
   函数名称:HEX2ASCII
   功    能:十六进制转ASCII函数
   入口参数:dat:十六进制数
   返 回 值:转换成的ASCII值。
   备    注:无
 ************************************************/
uchar HEX2ASCII(uchar dat)
{
        dat &= 0x0f;
        if(dat <= 9) return (dat + '0'); //数字0~9
        return (dat - 10 + 'A');    //字母A~F
}
/***********************************************
   函数名称:IO_Init
   功    能:单片机IO端口模式初始化
   入口参数:无
   返 回 值:无
   备    注:无
 ************************************************/
void IO_Init(void)
{
        //初始化P0口为准双向口
        P0M1 =0x00;
        P0M0 =0x00;

        //初始化P41,P42口为准双向口
        P4M1 &=~( (1<<1) | (1<<2) );
        P4M0 &=~( (1<<1) | (1<<2) );

        //初始化P37口为准双向口
        P3M1 &=~(1<<7);
        P3M0 &=~(1<<7);

        //分析
        //  1<<0等价于0x01 即 0000 0001
        //  1<<1等价于0x02 即 0000 0010
        //  1<<2等价于0x04 即 0000 0100
        //  1<<3等价于0x08 即 0000 1000
        //  以此类推1<<n 即第n位为1,其余位是0

        //  x |=(1<<n)  即对x执行按位取或
        //  即x中的第n位置为1,不改变其他位状态

        //  y &=~(1<<n)  即将1<<n按位取反,然后对y按位取与
        //  即y中的第n位置为0,不改变其他位状态
}



/*****************************************/
void LCD1602_Display_traffic(uint EW_light,uint NS_light,uint state)
{


        LCD1602_WriteCMD(0x01); //清屏
        LCD1602_CheckBusy2(); //检测忙信号
        switch(state)
        {
        case 0: {
                LCD1602_WriteCMD(LINE2);
                LCD1602_Display_Str("R:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light%10)+0x30));
                LCD1602_WriteCMD(LINE2+8);
                LCD1602_Display_Str("G:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light%10)+0x30));  //东西红、南北绿


        } break;
        case 1: {
                LCD1602_WriteCMD(LINE2);
                LCD1602_Display_Str("R:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light%10)+0x30));
                LCD1602_WriteCMD(LINE2+8);
                LCD1602_Display_Str("Y:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light%10)+0x30));  //东西红、南北黄


        } break;
        case 2: {
                LCD1602_WriteCMD(LINE2);
                LCD1602_Display_Str("G:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light%10)+0x30));
                LCD1602_WriteCMD(LINE2+8);
                LCD1602_Display_Str("R:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light%10)+0x30));    //东西绿、南北红


        } break;
        case 3: {
                LCD1602_WriteCMD(LINE2);
                LCD1602_Display_Str("Y:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((EW_light%10)+0x30));
                LCD1602_WriteCMD(LINE2+8);
                LCD1602_Display_Str("R:");
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light/10)+0x30));
                LCD1602_CheckBusy2();
                LCD1602_WriteDAT(HEX2ASCII((NS_light%10)+0x30));   //东西黄、南北绿


        } break;
        }
        LCD1602_WriteCMD(LINE1);
        LCD1602_Display_Str("DX");
        LCD1602_WriteCMD(LINE1+8);
        LCD1602_Display_Str("NB");

}



void LCD1602_Display_traffic_emergency(void)
{
        LCD1602_WriteCMD(0x01); //清屏
        LCD1602_CheckBusy();   //检测忙信号

        LCD1602_WriteCMD(LINE1+2);
        LCD1602_Display_Str("Emergency!!!");

        LCD1602_WriteCMD(LINE2+2);
        LCD1602_Display_Str("Ambulance!!!");
}

void BEEP_toggle(uint BEEPTIME)
{
        BEEP=0;
        Delay_ms(BEEPTIME);
        BEEP=1;
}

unsigned int Key_Scan(void)
{
        unsigned char KeyTemp1,KeyTemp2;
        unsigned char KeyValue;

        //所有列置低
        KEYPORT &=(~((1<<Column1)|(1<<Column2)|(1<<Column3))); //    4    3    2
        //读入端口先置高
        //1<<Line1相当于1<<5 = (0010 0000) 即Line1所在的P35口置高
        KEYPORT |= (1<<Line1) | (1<<Line2);
        //读取按键,将读入端口不用的位屏蔽掉
        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2)));
        if(KeyTemp1!=0xff) //如果有键按下
        {
                Delay_ms(10); //延时,防抖动
                KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2))); //再次读取
                if(KeyTemp1!=0xff) //确实有按键按下
                {
                        //将第一列拉低,其他列置高,扫描第一列
                        KEYPORT &=(~(1<<Column1));
                        KEYPORT |= (1<<Column2)|(1<<Column3);
                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2)));
                        if(KeyTemp1!=0xff) //第一列有键按下
                        {
                                while(KeyTemp1!=0xff) //等待按键释放
                                {
                                        KeyTemp2=KeyTemp1;
                                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2))); //重新读取
                                }
                                switch(KeyTemp2)
                                {
                                case ~(1<<Line1): //S6按下
                                {
                                        KeyValue=KEY6;

                                } break;
                                case ~(1<<Line2): //S9按下
                                {
                                        KeyValue=KEY9;

                                } break;
                                }
                        }

                        //将第二列拉低,其他列置高,扫描第二列
                        KEYPORT &=(~(1<<Column2));
                        KEYPORT |= (1<<Column1)|(1<<Column3);
                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2))); //读取行
                        if(KeyTemp1!=0xff) //第二列有键按下
                        {
                                while(KeyTemp1!=0xff) //等待按键释放
                                {
                                        KeyTemp2=KeyTemp1;
                                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2))); //重新读取
                                }
                                switch(KeyTemp2)
                                {
                                case ~(1<<Line1): //S7按下
                                {
                                        KeyValue=KEY7;

                                } break;
                                case ~(1<<Line2): //S10按下
                                {
                                        KeyValue=KEY10;

                                } break;
                                }
                        }

                        //将第三列拉低,其他列置高,扫描第三列
                        KEYPORT &=(~(1<<Column3));
                        KEYPORT |= (1<<Column1)|(1<<Column2);
                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2))); //读取行
                        if(KeyTemp1!=0xff) //第三列有键按下
                        {
                                while(KeyTemp1!=0xff) //等待按键释放
                                {
                                        KeyTemp2=KeyTemp1;
                                        KeyTemp1=KEYPORT | (~((1<<Line1)|(1<<Line2)));//重新读取
                                }
                                switch(KeyTemp2)
                                {
                                case ~(1<<Line1): //S8按下
                                {
                                        KeyValue=KEY8;

                                } break;
                                case ~(1<<Line2): //S11按下
                                {
                                        KeyValue=KEY11;

                                } break;
                                }
                        }
                        return KeyValue;
                }
                else
                {
                        return 0;         //无按键按下
                }
        }
        else
        {
                return 0;                //无按键按下
        }
}

// 进入模式0
void model_0(void){
        BEEP=1;
        if(UpdateTrafficFlag==1)
        {
                UpdateTrafficFlag=0;
                switch(Key_value)
                {
                case 7: {
                        if(red_time<21)                //红灯时间最长20s
                        {
                                red_time=red_time+1;
                                green_time=green_time+1;

                        }
                        else
                        {
                                red_time=11;
                                green_time=8;
                                yellow_time=4;
                        }                     //+红灯时间2s
                } break;
                case 8: {
                        if(red_time>7)                 //红灯时间最短6s
                        {
                                red_time=red_time-1;
                                green_time=green_time-1;

                        }
                        else
                        {
                                red_time=11;
                                green_time=8;
                                yellow_time=4;
                        }                    //-红灯时间2s
                } break;
                default: break;

                }

            1602_Display_traffic(EW_time,NS_time,traffic_state); //显示交通灯时间
        }

}
// 进入模式1
void model_1(void){

        BEEP=1;

        if(!Pause_flag)                                          //正常显示实时时间
        {
                if( UpdateTimeFlag==1 ) //定时1s更新时间
                {
                        UpdateTimeFlag=0;
                        DS1302_GetTime(Now); //读取时钟
                        LCD1602_Display_Clock(Now);//显示时钟
                }
        }

        else                                              //时钟调时
        {
                LCD1602_Display_Clock(Now);//显示时钟,但不更新时钟
                for(m=0; m<7; m++)
                {
                        Init[m]=Now[m]; //保存下现在的时间
                }
                switch(Key_value)
                {
                case 7:
                {

                        if(Init[0]==0x59)
                                Init[0]= 0x00;
                        else if((Init[0]&0x0f)<0x09)
                                Init[0]= Init[0]+0x01;
                        else
                        {
                                Init[0]&=0xf0;
                                Init[0]+=0x10;
                        }                     //加秒操作     S7按下

                        DS1302_Init();
                        DS1302_GetTime(Now);
                } break;
                case 8:
                {
                        if(Init[1]==0x59)
                                Init[1]= 0x00;
                        else if((Init[1]&0x0f)<0x09)
                                Init[1]= Init[1]+0x01;
                        else
                        {
                                Init[1]&=0xf0;
                                Init[1]+=0x10;
                        }                     //加分操作     S8按下
                        DS1302_Init();
                        DS1302_GetTime(Now);

                } break;
                case 9:
                {
                        if(Init[2]==0x23)
                                Init[2]= 0x00;
                        else if((Init[2]&0x0f)<0x09)
                                Init[2]= Init[2]+0x01;
                        else
                        {
                                Init[2]&=0xf0;
                                Init[2]+=0x10;
                        }                     //加时操作     S9按下
                        DS1302_Init();
                        DS1302_GetTime(Now);

                } break;
                case 10:
                {
                        if(Init[4]==0x12)
                                Init[4]= 0x00;
                        else if((Init[4]&0x0f)<0x09)
                                Init[4]= Init[4]+0x01;
                        else
                        {
                                Init[4]&=0xf0;
                                Init[4]+=0x10;
                        }                     //加月操作     s10按下
                        DS1302_Init();
                        DS1302_GetTime(Now);

                } break;
                default: break;
                }
                LCD1602_Display_Clock(Now);
        }

}
//进入模式2
void model_2(void){
        BEEP_toggle(200);
        LCD1602_Display_traffic_emergency();     //显示紧急状态
}

LCD1602.c

#include "lcd1602.h"
//包含该函数可以使用_nop_()函数
#include <intrins.h>
/***********************************************
   函数名称:LCD1602_Delay1us
   功    能:STC 1T单片机1us延时程序
   入口参数:us:延时的微秒数
   返 回 值:无
   备    注:外部时钟11.0592MHz
 ************************************************/
void LCD1602_Delay1us(unsigned int us)
{
        while( us--)
        {
                _nop_();
        }
}
/*************************************
 * 函 数 名: LCD1602_WriteCMD
 * 函数功能: 向lcd1602写指令
 * 入口参数: cmd:指令
 * 返    回: 无
 * 备    注:无
 **************************************/
void LCD1602_WriteCMD(unsigned char cmd)
{
        EN_Clr();
        RS_Clr();
        RW_Clr();
        LCD1602_Delay1us(10);
        EN_Set();
        LCD1602_Delay1us(10);
        DataPort=cmd;
        LCD1602_Delay1us(10);
        EN_Clr();
}
/***********************************************
   函数名称:LCD1602_WriteDAT
   功    能:向lcd1602写数据
   入口参数:dat:数据
   返 回 值:无
   备    注:无
 ************************************************/
void LCD1602_WriteDAT(unsigned char dat)
{
        EN_Clr();
        RS_Set();
        RW_Clr();
        LCD1602_Delay1us(10);
        EN_Set();
        LCD1602_Delay1us(10);
        DataPort=dat;
        LCD1602_Delay1us(10);
        EN_Clr();
}
/***********************************************
   函数名称:LCD1602_CheckBusy
   功    能:检测lcd1602忙信号
   入口参数:无
   返 回 值:无
   备    注:无
 ************************************************/
void LCD1602_CheckBusy(void)
{
        unsigned char temp;
        DataPort=0xff; //做输入先置高,51系列单片机读之前需要置高
        while(1)
        {
                EN_Clr();
                RS_Clr();
                RW_Set();
                LCD1602_Delay1us(10);
                EN_Set();
                LCD1602_Delay1us(10);
                temp=DataPort; //读取忙通道数据
                LCD1602_Delay1us(10);
                EN_Clr();
                if((temp&0x80)!=0x80)
                {
                        break;
                }
        }
}



void LCD1602_CheckBusy2(void)
{
        unsigned char temp;
        DataPort=0xff; //做输入先置高,51系列单片机读之前需要置高
        while(1)
        {
                EN_Clr();
                RS_Clr();
                RW_Set();
                LCD1602_Delay1us(70);
                EN_Set();
                LCD1602_Delay1us(70);
                temp=DataPort; //读取忙通道数据
                LCD1602_Delay1us(70);
                EN_Clr();
                if((temp&0x80)!=0x80)
                {
                        break;
                }
        }
}

lcd1602.h

# ifndef __LCD1602_H__
# define __LCD1602_H__

#include "stc15f2k60s2.h"

//LCD1602操作位定义
#define   DataPort    P0
sbit RS      = P4^2;        //寄存器选择 0:指令寄存器 1:数据寄存器
sbit RW      = P4^1;        //读写控制 0:写  1:读
sbit EN      = P3^7;        //读写数据使能   0:停止 1:启动

//定义端口操作
#define SET       1   //置高
#define CLR       0   //置低

#define RS_Set()    {RS=SET;}   //端口置高
#define RS_Clr()    {RS=CLR;}   //端口置低

#define RW_Set()    {RW=SET;}   //端口置高
#define RW_Clr()    {RW=CLR;}   //端口置低

#define EN_Set()    {EN=SET;}   //端口置高
#define EN_Clr()    {EN=CLR;}   //端口置低

//1602屏地址定义
#define LINE1 0x80           //第一行地址
#define LINE2 0xc0           //第二行地址

void LCD1602_WriteCMD(unsigned char cmd);
void LCD1602_WriteDAT(unsigned char dat);
void LCD1602_CheckBusy(void);
void LCD1602_CheckBusy2(void);


# endif

ds1302.h

# ifndef __DS1302_H__
# define __DS1302_H__

#include "stc15f2k60s2.h"

//DS1302接口定义
sbit SCE     = P4^4;                        //DS1302选择端
sbit SIO     = P2^2;                        //DS1302数据口
sbit SCK     = P2^1;                        //DS1302时钟口

//定义端口操作
 #define  DS1302_SCE_Clr()    {SCE=0;}
 #define  DS1302_SCE_Set()    {SCE=1;}

 #define  DS1302_SIO_Clr()    {SIO=0;}
 #define  DS1302_SIO_Set()    {SIO=1;}

 #define  DS1302_SCK_Clr()    {SCK=0;}
 #define  DS1302_SCK_Set()    {SCK=1;}


unsigned char DS1302_ReadData(unsigned char addr);
void DS1302_WriteData(unsigned char addr, unsigned char dat);

# endif

ds1302.c

#include "ds1302.h"
#include <intrins.h>

/***********************************************
   函数名称:Delay_us
   功    能:STC 1T单片机1us延时程序
   入口参数:us:延时的微秒数
   返 回 值:无
   备    注:外部时钟11.0592MHz
 ************************************************/
void Delay_us(unsigned int us)
{
        while( us--)
        {
                _nop_();
        }
}
/***********************************************
   函数名称:DS1302_ReadByte
   功    能:从DS1302读一个字节数据
   入口参数:无
   返 回 值:unsigned char:读出的数据
   备    注:无
 ************************************************/
unsigned char DS1302_ReadByte(void)
{
        unsigned char i;
        unsigned char dat = 0;
        for (i=0; i<8; i++)     //8位计数器
        {
                DS1302_SCK_Clr(); //时钟线拉低
                Delay_us(1);    //延时等待
                dat >>= 1;      //数据右移一位
                if (SIO)
                {
                        dat |= 0x80; //读取数据
                }
                DS1302_SCK_Set(); //时钟线拉高
                Delay_us(1);    //延时等待
        }
        return dat;
}
/***********************************************
   函数名称:DS1302_WriteByte
   功    能:向DS1302写一个字节数据
   入口参数:dat:写入的数据
   返 回 值:无
   备    注:无
 ************************************************/
void DS1302_WriteByte(unsigned char dat)
{
        unsigned char i;
        unsigned char temp;
        for (i=0; i<8; i++)     //8位计数器
        {
                temp=dat;
                DS1302_SCK_Clr(); //时钟线拉低
                Delay_us(1);    //延时等待
                if( (temp&0x01)==0x01 ) //先发送低字节
                {
                        DS1302_SIO_Set();
                }
                else
                {
                        DS1302_SIO_Clr();
                }
                DS1302_SCK_Set(); //时钟线拉高
                dat >>= 1;      //移出数据
                Delay_us(1);    //延时等待
        }
}
/***********************************************
   函数名称:DS1302_ReadData
   功    能:读DS1302某地址的的数据
   入口参数:addr:地址。
   返 回 值:读出的数据。
   备    注:无
 ************************************************/
unsigned char DS1302_ReadData(unsigned char addr)
{
        unsigned char dat;

        DS1302_SCE_Clr(); //片选线拉低
        Delay_us(1);
        DS1302_SCK_Clr(); //时钟线拉低
        Delay_us(1);
        DS1302_SCE_Set(); //片选线拉高
        Delay_us(1);
        DS1302_WriteByte(addr); //写地址
        dat = DS1302_ReadByte();//读数据
        DS1302_SCK_Set(); //时钟线拉高
        DS1302_SCE_Clr(); //片选线拉低

        return dat;
}
/***********************************************
   函数名称:DS1302_WriteData
   功    能:往DS1302的某个地址写入数据
   入口参数:addr:地址。dat:写入的数据。
   返 回 值:无
   备    注:无
 ************************************************/
void DS1302_WriteData(unsigned char addr, unsigned char dat)
{
        DS1302_SCE_Clr(); //片选线拉低
        Delay_us(1);
        DS1302_SCK_Clr(); //时钟线拉低
        Delay_us(1);
        DS1302_SCE_Set(); //时钟线拉高
        Delay_us(1);
        DS1302_WriteByte(addr); //写地址
        DS1302_WriteByte(dat); //写数据
        DS1302_SCK_Set(); //时钟线拉高
        DS1302_SCE_Clr(); //片选线拉低
}

STC15F2K60S2.H

#ifndef   __STC15F2K60S2_H__
#define   __STC15F2K60S2_H__


//内核特殊功能寄存器        // 复位值   描述
sfr ACC         =   0xE0;   //0000,0000 累加器Accumulator
sfr B           =   0xF0;   //0000,0000 B寄存器
sfr PSW         =   0xD0;   //0000,0000 程序状态字
sbit CY         =   PSW^7;
sbit AC         =   PSW^6;
sbit F0         =   PSW^5;
sbit RS1        =   PSW^4;
sbit RS0        =   PSW^3;
sbit OV         =   PSW^2;
sbit P          =   PSW^0;
sfr SP          =   0x81;   //0000,0111 堆栈指针
sfr DPL         =   0x82;   //0000,0000 数据指针低字节
sfr DPH         =   0x83;   //0000,0000 数据指针高字节

//I/O 口特殊功能寄存器
sfr P0          =   0x80;   //1111,1111 端口0
sbit P00        =   P0^0;
sbit P01        =   P0^1;
sbit P02        =   P0^2;
sbit P03        =   P0^3;
sbit P04        =   P0^4;
sbit P05        =   P0^5;
sbit P06        =   P0^6;
sbit P07        =   P0^7;
sfr P1          =   0x90;   //1111,1111 端口1
sbit P10        =   P1^0;
sbit P11        =   P1^1;
sbit P12        =   P1^2;
sbit P13        =   P1^3;
sbit P14        =   P1^4;
sbit P15        =   P1^5;
sbit P16        =   P1^6;
sbit P17        =   P1^7;
sfr P2          =   0xA0;   //1111,1111 端口2
sbit P20        =   P2^0;
sbit P21        =   P2^1;
sbit P22        =   P2^2;
sbit P23        =   P2^3;
sbit P24        =   P2^4;
sbit P25        =   P2^5;
sbit P26        =   P2^6;
sbit P27        =   P2^7;
sfr P3          =   0xB0;   //1111,1111 端口3
sbit P30        =   P3^0;
sbit P31        =   P3^1;
sbit P32        =   P3^2;
sbit P33        =   P3^3;
sbit P34        =   P3^4;
sbit P35        =   P3^5;
sbit P36        =   P3^6;
sbit P37        =   P3^7;
sfr P4          =   0xC0;   //1111,1111 端口4
sbit P40        =   P4^0;
sbit P41        =   P4^1;
sbit P42        =   P4^2;
sbit P43        =   P4^3;
sbit P44        =   P4^4;
sbit P45        =   P4^5;
sbit P46        =   P4^6;
sbit P47        =   P4^7;
sfr P5          =   0xC8;   //xxxx,1111 端口5
sbit P50        =   P5^0;
sbit P51        =   P5^1;
sbit P52        =   P5^2;
sbit P53        =   P5^3;
sbit P54        =   P5^4;
sbit P55        =   P5^5;
sbit P56        =   P5^6;
sbit P57        =   P5^7;
sfr P6          =   0xE8;   //0000,0000 端口6
sbit P60        =   P6^0;
sbit P61        =   P6^1;
sbit P62        =   P6^2;
sbit P63        =   P6^3;
sbit P64        =   P6^4;
sbit P65        =   P6^5;
sbit P66        =   P6^6;
sbit P67        =   P6^7;
sfr P7          =   0xF8;   //0000,0000 端口7
sbit P70        =   P7^0;
sbit P71        =   P7^1;
sbit P72        =   P7^2;
sbit P73        =   P7^3;
sbit P74        =   P7^4;
sbit P75        =   P7^5;
sbit P76        =   P7^6;
sbit P77        =   P7^7;
sfr P0M0        =   0x94;   //0000,0000 端口0模式寄存器0
sfr P0M1        =   0x93;   //0000,0000 端口0模式寄存器1
sfr P1M0        =   0x92;   //0000,0000 端口1模式寄存器0
sfr P1M1        =   0x91;   //0000,0000 端口1模式寄存器1
sfr P2M0        =   0x96;   //0000,0000 端口2模式寄存器0
sfr P2M1        =   0x95;   //0000,0000 端口2模式寄存器1
sfr P3M0        =   0xB2;   //0000,0000 端口3模式寄存器0
sfr P3M1        =   0xB1;   //0000,0000 端口3模式寄存器1
sfr P4M0        =   0xB4;   //0000,0000 端口4模式寄存器0
sfr P4M1        =   0xB3;   //0000,0000 端口4模式寄存器1
sfr P5M0        =   0xCA;   //0000,0000 端口5模式寄存器0
sfr P5M1        =   0xC9;   //0000,0000 端口5模式寄存器1
sfr P6M0        =   0xCC;   //0000,0000 端口6模式寄存器0
sfr P6M1        =   0xCB;   //0000,0000 端口6模式寄存器1
sfr P7M0        =   0xE2;   //0000,0000 端口7模式寄存器0
sfr P7M1        =   0xE1;   //0000,0000 端口7模式寄存器1

//系统管理特殊功能寄存器
sfr PCON        =   0x87;   //0001,0000 电源控制寄存器
sfr AUXR        =   0x8E;   //0000,0000 辅助寄存器
sfr AUXR1       =   0xA2;   //0000,0000 辅助寄存器1
sfr P_SW1       =   0xA2;   //0000,0000 外设端口切换寄存器1
sfr CLK_DIV     =   0x97;   //0000,0000 时钟分频控制寄存器
sfr BUS_SPEED   =   0xA1;   //xx10,x011 总线速度控制寄存器
sfr P1ASF       =   0x9D;   //0000,0000 端口1模拟功能配置寄存器
sfr P_SW2       =   0xBA;   //xxxx,x000 外设端口切换寄存器

//中断特殊功能寄存器
sfr IE          =   0xA8;   //0000,0000 中断控制寄存器
sbit EA         =   IE^7;
sbit ELVD       =   IE^6;
sbit EADC       =   IE^5;
sbit ES         =   IE^4;
sbit ET1        =   IE^3;
sbit EX1        =   IE^2;
sbit ET0        =   IE^1;
sbit EX0        =   IE^0;
sfr IP          =   0xB8;   //0000,0000 中断优先级寄存器
sbit PPCA       =   IP^7;
sbit PLVD       =   IP^6;
sbit PADC       =   IP^5;
sbit PS         =   IP^4;
sbit PT1        =   IP^3;
sbit PX1        =   IP^2;
sbit PT0        =   IP^1;
sbit PX0        =   IP^0;
sfr IE2         =   0xAF;   //0000,0000 中断控制寄存器2
sfr IP2         =   0xB5;   //xxxx,xx00 中断优先级寄存器2
sfr INT_CLKO    =   0x8F;   //0000,0000 外部中断与时钟输出控制寄存器

//定时器特殊功能寄存器
sfr TCON        =   0x88;   //0000,0000 T0/T1控制寄存器
sbit TF1        =   TCON^7;
sbit TR1        =   TCON^6;
sbit TF0        =   TCON^5;
sbit TR0        =   TCON^4;
sbit IE1        =   TCON^3;
sbit IT1        =   TCON^2;
sbit IE0        =   TCON^1;
sbit IT0        =   TCON^0;
sfr TMOD        =   0x89;   //0000,0000 T0/T1模式寄存器
sfr TL0         =   0x8A;   //0000,0000 T0低字节
sfr TL1         =   0x8B;   //0000,0000 T1低字节
sfr TH0         =   0x8C;   //0000,0000 T0高字节
sfr TH1         =   0x8D;   //0000,0000 T1高字节
sfr T4T3M       =   0xD1;   //0000,0000 T3/T4模式寄存器
sfr T3T4M       =   0xD1;   //0000,0000 T3/T4模式寄存器
sfr T4H         =   0xD2;   //0000,0000 T4高字节
sfr T4L         =   0xD3;   //0000,0000 T4低字节
sfr T3H         =   0xD4;   //0000,0000 T3高字节
sfr T3L         =   0xD5;   //0000,0000 T3低字节
sfr T2H         =   0xD6;   //0000,0000 T2高字节
sfr T2L         =   0xD7;   //0000,0000 T2低字节
sfr WKTCL       =   0xAA;   //0000,0000 掉电唤醒定时器低字节
sfr WKTCH       =   0xAB;   //0000,0000 掉电唤醒定时器高字节
sfr WDT_CONTR   =   0xC1;   //0000,0000 看门狗控制寄存器

//串行口特殊功能寄存器
sfr SCON        =   0x98;   //0000,0000 串口1控制寄存器
sbit SM0        =   SCON^7;
sbit SM1        =   SCON^6;
sbit SM2        =   SCON^5;
sbit REN        =   SCON^4;
sbit TB8        =   SCON^3;
sbit RB8        =   SCON^2;
sbit TI         =   SCON^1;
sbit RI         =   SCON^0;
sfr SBUF        =   0x99;   //xxxx,xxxx 串口1数据寄存器
sfr S2CON       =   0x9A;   //0000,0000 串口2控制寄存器
sfr S2BUF       =   0x9B;   //xxxx,xxxx 串口2数据寄存器
sfr S3CON       =   0xAC;   //0000,0000 串口3控制寄存器
sfr S3BUF       =   0xAD;   //xxxx,xxxx 串口3数据寄存器
sfr S4CON       =   0x84;   //0000,0000 串口4控制寄存器
sfr S4BUF       =   0x85;   //xxxx,xxxx 串口4数据寄存器
sfr SADDR       =   0xA9;   //0000,0000 从机地址寄存器
sfr SADEN       =   0xB9;   //0000,0000 从机地址屏蔽寄存器

//ADC 特殊功能寄存器
sfr ADC_CONTR   =   0xBC;   //0000,0000 A/D转换控制寄存器
sfr ADC_RES     =   0xBD;   //0000,0000 A/D转换结果高8位
sfr ADC_RESL    =   0xBE;   //0000,0000 A/D转换结果低2位

//SPI 特殊功能寄存器
sfr SPSTAT      =   0xCD;   //00xx,xxxx SPI状态寄存器
sfr SPCTL       =   0xCE;   //0000,0100 SPI控制寄存器
sfr SPDAT       =   0xCF;   //0000,0000 SPI数据寄存器

//IAP/ISP 特殊功能寄存器
sfr IAP_DATA    =   0xC2;   //0000,0000 EEPROM数据寄存器
sfr IAP_ADDRH   =   0xC3;   //0000,0000 EEPROM地址高字节
sfr IAP_ADDRL   =   0xC4;   //0000,0000 EEPROM地址第字节
sfr IAP_CMD     =   0xC5;   //xxxx,xx00 EEPROM命令寄存器
sfr IAP_TRIG    =   0xC6;   //0000,0000 EEPRPM命令触发寄存器
sfr IAP_CONTR   =   0xC7;   //0000,x000 EEPROM控制寄存器

//PCA/PWM 特殊功能寄存器
sfr CCON        =   0xD8;   //00xx,xx00 PCA控制寄存器
sbit CF         =   CCON^7;
sbit CR         =   CCON^6;
sbit CCF2       =   CCON^2;
sbit CCF1       =   CCON^1;
sbit CCF0       =   CCON^0;
sfr CMOD        =   0xD9;   //0xxx,x000 PCA 工作模式寄存器
sfr CL          =   0xE9;   //0000,0000 PCA计数器低字节
sfr CH          =   0xF9;   //0000,0000 PCA计数器高字节
sfr CCAPM0      =   0xDA;   //0000,0000 PCA模块0的PWM寄存器
sfr CCAPM1      =   0xDB;   //0000,0000 PCA模块1的PWM寄存器
sfr CCAPM2      =   0xDC;   //0000,0000 PCA模块2的PWM 寄存器
sfr CCAP0L      =   0xEA;   //0000,0000 PCA模块0的捕捉/比较寄存器低字节
sfr CCAP1L      =   0xEB;   //0000,0000 PCA模块1的捕捉/比较寄存器低字节
sfr CCAP2L      =   0xEC;   //0000,0000 PCA模块2的捕捉/比较寄存器低字节
sfr PCA_PWM0    =   0xF2;   //xxxx,xx00 PCA模块0的PWM寄存器
sfr PCA_PWM1    =   0xF3;   //xxxx,xx00 PCA模块1的PWM寄存器
sfr PCA_PWM2    =   0xF4;   //xxxx,xx00 PCA模块1的PWM寄存器
sfr CCAP0H      =   0xFA;   //0000,0000 PCA模块0的捕捉/比较寄存器高字节
sfr CCAP1H      =   0xFB;   //0000,0000 PCA模块1的捕捉/比较寄存器高字节
sfr CCAP2H      =   0xFC;   //0000,0000 PCA模块2的捕捉/比较寄存器高字节

#endif

你知道雪为什么是白色的吗?因为她忘记了原来的颜色