//=============================================================================
//74HC595与74LS138联合使用显示技术(可用于项目,proteus仿真通过,硬件没测)
//本程序为原创.
//功能,节约CPU的IO口,使原来需要16个IO口的8个LED8,现在只需要6个IO口
//P10-P12驱动74HC138输出扫描字(数组法),P13_P15驱动74HC595使用输出段码
//-----------------------------------------------------------------------------
//显示错乱分析:595是在上升沿触发,输出段码.如果先输出扫描字,
//因595有锁存功能,LED上显示就是上一次段码,时间等于串口传送的时间(这个时间较长)
//等传送完毕,595锁存,LED显示本次段码.在一个很短时间出现本次段码和上次段码交叉显示
//视觉效果就是显示错乱.
//解决方法:先把段码传送好,再把扫描字放好,然后打开段码开关,即595门控位置1产生上升沿
//这样段码与扫描字不同步的时间就很短,视觉上就不会产生错乱感.
//程序员:舒杰刚 2009年9月17日
//=============================================================================
#include "reg51.h" //文件包含命令
#include "intrins.h" //包含_nop_()
#define uchar unsigned char //定义一下方便输入
#define uint unsigned int //定义一下方便输入
//-----------------------------------------------------------------------------
void senddata(uchar senddat);
//-----------------------------------------------------------------------------
sbit DAT=P1^3; //定义串行数据输入端
sbit CLK=P1^4; //定义时钟端
sbit CNT=P1^5; //定义门控位
//-----------------------------------------------------------------------------
uchar code disp_dm[]={ //定义段码共阴
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
//定义扫描字
uchar code disp_smz[]={0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};
//-----------------------------------------------------------------------------
uchar dispbuf[8]={1,2,3,4,5,6,7,8}; //显示缓存
//=============================================================================
//数据传送指令(本程序核心函数)
//=============================================================================
void senddata(uchar senddat)
{ uchar i;
for(i=0;i<8;i++)
{ if((senddat&0x01)==0){DAT=0;}
else{DAT=1;}
_nop_();CLK=0; //595是上升沿触发方式
_nop_();CLK=1; //时钟产生一个上升沿
senddat=senddat>>1;
}
}
//=============================================================================
//定时器0中断程序
//=============================================================================
void t0() interrupt 1
{
uchar tmp,c;
static uchar disp_count;
TH0=0x06;TL0=0x06; //定时器赋初值
//动态扫描显示,传送段码----------------------------------------------------
CNT=0; //关闭存储寄存器输入
c=dispbuf[disp_count]; //取出待显示字符
senddata(disp_dm[c]); //送出字形码数据
//显示扫描字---------------------------------------------------------------
tmp=disp_smz[disp_count]; //根据当前的计数值取位值
P1=P1|0x07; //P1或00000111B相或,将低3位置1
P1=P1&tmp; //低三位输出扫描字
CNT=1; //开启存储器的输入
//-------------------------------------------------------------------------
disp_count++;
if(disp_count>7){disp_count=0;}
}
//=============================================================================
//主函数
//=============================================================================
void main(void)
{
TMOD=0x02; //定时器工作方式2
TH0=0x06;TL0=0x06; //定时器赋初值
TR0=1;ET0=1;EA=1; //R0开始运行,开T0中断,总中断
dispbuf[4]=4;dispbuf[6]=1; //测试用
while(1)
{;}
} |