1.介绍
相信电子时钟大家都非常熟悉,而且电子专业的一定也接触过电子时钟,电子时钟的设计其实非常简单,一些数码管,一些按键就可以制作一个电子时钟了,自己设计的电子时钟会拿三极管等来驱动数码管,而今天我们不一样,采用8155来驱动电子时钟,那么我们就来尝试一下吧!
2.设计
首先需要了解一下8155的工作原理才能进行设计,先介绍一下引脚功能:
RESET:复位信号输入端,高电平有效。复位后,3个I/O口均为输入方式。
AD0~AD7:三态的地址/数据总线。与单片机的低8位地址/数据总线(P0口)相连。单片机与8155之间的地址、数据、命令与状态信息都是通过这个总线口传送的。
RD:读选通信号,控制对8155的读操作,低电平有效。
WR:写选通信号,控制对8155的写操作,低电平有效。
CE:片选信号线,低电平有效。
IO/M :8155的RAM存储器或I/O口选择线。当IO/M =0时,则选择8155的片内RAM,AD0~AD7上地址为8155中RAM单元的地址(00H~FFH);当IO/M =1时,选择 8155的I/O口,AD0~AD7上的地址为8155 I/O口的地址。
ALE:地址锁存信号。8155内部设有地址锁存器,在ALE的下降沿将单片机P0口输出的低8位地址信息及 ,IO/ 的状态都锁存到8155内部锁存器。因此,P0口输出的低8位地址信号不需外接锁存器。
PA0~PA7:8位通用I/O口,其输入、输出的流向可由程序控制。
PB0~PB7:8位通用I/O口,功能同A口。
PC0~PC5:有两个作用,既可作为通用的I/O口,也可作为PA口和PB口的控制信号线,这些可通过程序控制。
TIMER IN:定时/计数器脉冲输入端。
TIMER OUT:定时/计数器输出端。
VCC:+5V电源。



然后就是地址编码及工作方式,在单片机应用系统中,8155是按外部数据存储器统一编址的,为16位地址,其高8位由片选线 提供, CE=0,选中该片。
当 CE=0,IO/M =0时,选中8155片内RAM,这时8155只能作片外RAM使用,其RAM的低8位编址为00H~FFH;当 CE=0,IO/M =1时,选中8155的I/O口,其端口地址的低8位由AD7~AD0确定,如表6-6所示。这时,A、B、C口的口地址低8位分别为01H、02H、03H(设地址无关位为0)。
下图1为8155芯片的I/O口地址:
1.png

图1

8155的A口、B口可工作于基本I/O方式或选通I/O方式。C口可工作于基本I/O方式,也可作为A口、B口在选通工作方式时的状态控制信号线。当C口作为状态控制信号时,其每位线的作用如下:
PC0:AINTR(A口中断请求线)
PC1:ABF(A口缓冲器满信号)
PC2:(A口选通信号)
PC3:BINTR(B口中断请求线)
PC4:BBF(B口缓冲器满信号)
PC5: (B口选通信号)
8155的I/O工作方式选择是通过对8155内部命令寄存器设定控制字实现的。命令寄存器只能写入,不能读出,命令寄存器的格式如图6-16所示。
在ALT1~ALT4的不同方式下,A口、B口及C口的各位工作方式如下:
ALT1:A口,B口为基本输入/输出,C口为输入方式。
ALT2:A口,B口为基本输入/输出,C口为输出方式。
ALT3:A口为选通输入/输出,B口为基本输入/输出。PC0为AINTR,PC1为ABF,PC2为 ,PC3~PC5为输出。
ALT4:A口、B口为选通输入/输出。PC0为AINTR,PC1为ABF,PC2为 ,PC3为BINTR,PC4为BBF,PC5为 。
下图2为8155命令寄存器格式:
2.png

图2

8155内还有一个状态寄存器,这里这节没用到,就不多说明了。
介绍完基础知识了之后,就是真正的设计部分了,对8155的端口的输出和输入设计,用到PA和PB口,用PA做输出,PB做输入,PA作为数码管的位选,PB作为按键的输入先晒出仿真图3:
3.png

图3

接下来就是程序了,也比较简单,就是开个定时器,让它自己跑时间,这里需要注意的是,COMMAND、PA和PB的地址,地址是根据连接线来进行设置的,这里的连接线得到的地址是0x1F00开始的,根据不同的连接方式可以修改相应的地址,这个地址可以去查询51单片机的手册,接下来就是配置了,根据上面的图进行PA和PB的输入输出设置,最后编写出如下代码:
<font size="3">#include "reg52.H"
  • #include "absacc.h"
  • #define uchar unsigned char
  • #define uint unsigned int
  • #define COMMAND XBYTE[0xF700]  //控制位地址
  • #define PA XBYTE[0xF701]           //PA地址
  • #define PB XBYTE[0xF702]           //PB地址
  • sbit cs = P2^3;        //片选
  • sbit om = P2^4;        //IO选择线
  • uchar shi=12,fen=50,miao=30,set_cnt;        //set_cnt 0正常显示,1设置时,2设置分,3设置秒
  • uchar time0_cnt=0; //用于定时器统计进入几次
  • uchar shanshuo=0;  //闪烁统计
  • uchar code table[]={  //共阴数码管段码
  • 0x3f,0x06,0x5b,0x4f,
  • 0x66,0x6d,0x7d,0x07,
  • 0x7f,0x6f,0x77,0x7c,
  • 0x39,0x5e,0x79,0x71};
  • void delayms(uint xms);
  • void display1(uchar shi,uchar ge,uchar shi1,uchar ge1);
  • void djs(uchar shi, uchar fen, uchar miao);
  • void init(void);
  • void keyscan(void);
  • void main()
  • {
  •         init();        //开启定时器,用于增加时间
  •        
  •         cs=0;        //片选拉低
  •         om=1;        //IO使能
  •         COMMAND=0X02;        //设置PB为输出,PA为输入
  •        
  •         PB=0XFF;
  •         while(1)
  •         {       
  •                 keyscan();        //按键扫描
  •                 djs(shi, fen, miao);  //显示
  •         }
  • }
  • //按键扫描
  • void keyscan(void)
  • {
  •         static key_value=0;
  •         if(PA==0x02)
  •         {
  •                 key_value=0x02;        //设置按键按下
  •         }
  •         else if(PA==0x01)
  •         {
  •                 key_value=0x01;        //调整按键按下
  •         }
  •         else        //没有按键被按下
  •         {
  •                 if(key_value==0x02)
  •                 {
  •                         set_cnt++;         //切换模式
  •                         shanshuo=0;         //闪烁清除
  •                         time0_cnt=0; //定时器进入统计清除
  •                         if(set_cnt>3) //设置结束
  •                                 set_cnt=0;//正常显示
  •                 }
  •                 else if(key_value==0x01)
  •                 {
  •                         if(set_cnt==1) //设置时
  •                         {
  •                                 shi++;        //时调整
  •                                 if(shi>=24) //大于置0
  •                                         shi=0;
  •                         }
  •                         else if(set_cnt==2)        //设置分
  •                         {
  •                                 fen++;        //分调整
  •                                 if(fen>=60) //大于置0
  •                                         fen=0;
  •                         }
  •                         else if(set_cnt==3)        //设置秒
  •                         {
  •                                 miao++;        //秒调整
  •                                 if(miao>=60) //大于置0
  •                                         miao=0;
  •                         }
  •                 }
  •                 key_value = 0;
  •         }
  • }
  • //延时程序,用于扫描
  • void delayms(uint xms)
  • {
  •         uint i,j;
  •         for(i=xms;i>0;i--)
  •                 for(j=110;j>0;j--);
  • }
  • //显示程序
  • void display(uchar shi, uchar ge, uchar shi1, uchar ge1, uchar shi2, uchar ge2)
  • {
  •         if(set_cnt!=1 || shanshuo%2==1)
  •         {
  •                 PB=0xfe;        //位选,显示时的十位
  •                 P1=0x00;        //消影
  •                 P1=table[shi];        //段选,显示内容
  •                 delayms(5);         //延时显示
  •                 PB=0xfd;   //位选,显示时的个位
  •                 P1=0x00;   //消影
  •                 P1=table[ge];  //段选,显示内容
  •                 delayms(5);         //延时显示
  •         }
  •         if(set_cnt!=2 || shanshuo%2==1)
  •         {       
  •                 PB=0xfb;        //位选,显示分的十位
  •                 P1=0x00;        //消影
  •                 P1=table[shi1];        //段选,显示内容
  •                 delayms(5);         //延时显示
  •                 PB=0xf7;        //位选,显示分的个位
  •                 P1=0x00;        //消影
  •                 P1=table[ge1]; //段选,显示内容
  •                 delayms(5);        //延时显示
  •         }
  •         if(set_cnt!=3 || shanshuo%2==1)
  •         {
  •                 PB=0xef;   //位选,显示秒的十位
  •                 P1=0x00;   //消影
  •                 P1=table[shi2];        //段选,显示内容
  •                 delayms(5);         //延时显示
  •                 PB=0xdf;   //位选,显示秒的个位
  •                 P1=0x00;   //消影
  •                 P1=table[ge2];        //段选,显示内容
  •                 delayms(5);        //延时显示
  •         }
  • }
  • //显示拆除程序
  • void djs(uchar shi, uchar fen, uchar miao)
  • {
  •         uchar shi_h,shi_l ,fen_h,fen_l, miao_h, miao_l;        //定义时分秒的个位和十位
  •         shi_h=(shi)/10;         //时的十位
  •         shi_l=(shi)%10;         //时的个位
  •         fen_h=(fen)/10;         //分的十位
  •         fen_l=(fen)%10;         //分的个位
  •         miao_h=(miao)/10; //秒的十位
  •         miao_l=(miao)%10; //秒的个位
  •         display(shi_h,shi_l,fen_h,fen_l,miao_h,miao_l);                //显示时分秒
  • }
  • //初始化定时器
  • void init(void)
  • {
  •         TMOD=0x11;         //定时器模式
  •         TH0=(65536-50000)/256;         //初始值,50ms
  •         TL0=(65536-50000)%256;
  •         EA=1;        //中断总开关
  •         ET0=1;        //定时器中断开启
  •         TR0=1;        //定时器开启
  • }
  • //定时器0执行函数
  • void T0_time()interrupt 1
  • {
  •         TH0=(65536-50000)/256;        //初始值,50ms
  •         TL0=(65536-50000)%256;
  •        
  •         time0_cnt++;   //定时器进入一次
  •                
  •         if(set_cnt==0)//正常走时状态
  •         {
  •                 if(time0_cnt>=20)  //50ms*20 = 1S,所以1S进入一次
  •                 {
  •                         time0_cnt=0;//重新计数
  •                         miao++;        //秒加1
  •                         if(miao>=60)
  •                         {
  •                                 miao=0;         //清除秒
  •                                 fen++;         //分加一
  •                                 if(fen>=60)
  •                                 {
  •                                         fen=0; //清除分
  •                                         shi++; //时加一
  •                                         if(shi>=24)
  •                                         {
  •                                                 shi=0; //清除时
  •                                         }
  •                                 }
  •                         }
  •                 }
  •         }
  •         else
  •         {
  •                 if(time0_cnt>=10)  //50ms*10 = 0.5S,所以0.5S进入一次
  •                 {
  •                         time0_cnt=0;//重新计数
  •                         shanshuo++;
  •                 }
  •         }
  • }</font>
  • 复制代码
    3.总结
    可以说这个8155和别的驱动不太一样,大家可以好好理解一下!