ds12c887数码管显示.docx
《ds12c887数码管显示.docx》由会员分享,可在线阅读,更多相关《ds12c887数码管显示.docx(23页珍藏版)》请在冰豆网上搜索。
ds12c887数码管显示
单片机数码管动态扫描程序DS12C887红外遥控ds18b20
/DS12C887+8位数码管定时器中断动态扫描遥控时钟单片机程序模块
[功能] 0:
8位数码管定时器中断动态扫描显示
1:
通过单片机解码红外遥控编码并按上图方式显示出来
2:
可通过遥控器调整时间,日期以及闹钟
3:
时钟芯片采用DS12C887+,内部集成电池与晶体,不怕掉电丢时间信息
4:
在调整时间过程中会有动态效果(正在调试中!
!
!
以经搞好了)
5:
在下一版本中会增计算器功能,也是用遥控器操作值得大家期待!
6:
ds18b20温度显示(正在弄这个ds18b20)
7:
数码管扫描数据在P0口通过锁存器(74HC573)输出,ds12c887的双向数据则直接接P0口
//以下是C源文件==============================================================================
#include//80C51头文件
#defineuintunsignedint//16bit无符整型0~465536
#defineulintunsignedlongint//32bit无符长整0~4294967295
#defineucharunsignedchar//8bit宏定义无符字符型0-256
#definec(x)(x*120000/120000)//(x*216000/120000)//定义时钟频率便于红外遥控解码
//单片机硬件设置
sbitduan=P2^0;//数码管段选定义
sbitwei =P2^1;//数码管位选定义
sbitIr_Pin=P3^3;//红外接收端口
sbitbeep=P2^7;//蜂鸣器
//时钟芯片ds12c887控制引脚与单片机连接
sbitdscs=P2^6;//时钟片选
sbitdsas=P2^5;//地址选取通
sbitdsrw=P2^4;//读写输入
sbitdsds=P2^3;//数据选通或输入
sbitdsirq=P2^2;//中断请求输出
sbitDQ=P2^2;//定义温度传感器(18b20)通信端口
//字符码表
ucharcodeLed_Tab[]={//共阳数码管字符码
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,//0---f,ff全灭,
0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xfe,0xbf,0xf7,0xc6,0x9c};//上,中,下3短横线
ucharcodeLed_Sel[]={//位码
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//定义各个变量
ucharshan_xia=0,zuo_you=8,Ir_Buf[4],ds_temp=0,i;//上下变量,左右变量,遥控数字,红外结果
bitok=0,power=0,mute,ds=0,i_k=0;//ds为0时才准读时钟芯片,减少频繁读时钟,i_k为5秒延时开关
uintms;//屏闪时基变量,温度传感变量
//以下是动态扫描变量
ucharLed_Buf[8],Led_Buf_temp[8],Led_Index;//显示缓冲区,调时闪动缓冲区,位码索引
//声明子函数
voidinit();//初始化
voidwrite_ds(ucharadd,uchardate);//时钟芯片写函数
ucharread_ds(ucharadd);//时钟芯片读函数
voiddelay(uintz);//延时
voidhyyk();//红外遥控
uintIr_Get_Low();//低电平时间采集
uintIr_Get_High();//高电平时间采集
//遥控调时,数值放入显示缓冲区同步显示,预写时钟
//经数据采集函数(time_set())根据各项格式显示特征识别后
//按mute键写时钟芯片相应地址达到调整时钟信息的目的
voidykm_set();
voidtime_set();//时间调整数据采集分析写调时缓冲区函数
voidykm_out();//遥控码显示
voidled_out(ucharadd_1,ucharadd_2,ucharadd_3,ucharadd_4);//送出地址,读出信息,更新显示缓冲区
voidled_flash(uchark,ucharz);//调时闪烁 K为闪动开关 Z为闪动内容
//温度显示子函数声明
voiddelay_18b20(uinti);//延时
Init_DS18B20(void);//初始化函数
WriteOneChar(uchardat);//写一个字节
ReadOneChar(void);//读一个字节
ReadTemperature(void);//读取温度
voidout_18b20();//显示
//主程序==================================================================================
voidmain()//程序入口
{
init();//初始化
while
(1)//循环等待中断
{
hyyk();//遥控
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x14))//POWER键值翻转并响铃
{
ok=0;zuo_you=8;shan_xia=0;//有遥控power时复位ok与上下,左右值,取消闪屏显示时间
power=(!
power);
if(power==0)
{
delay(10);
beep=0;
delay(20);
beep=1;
}
Ir_Buf[2]=0xff;
}
if(power==1){uchari;mute=1;for(i=0;i<8;i++)Led_Buf_temp[i]=16;}//在power标志为1时关屏关铃
if(power==0)//power标志为0时根据shan_xia键值显示内容
{
ykm_set();//遥控调时,调整好后按mute键写时钟
led_flash(ok,shan_xia);
if(ok==0){ds=0;i_k=0;ds_temp=0;}
if(ds==0)
{
if(shan_xia==0)led_out(4,2,0,19);//时间
elseif(shan_xia==1)led_out(9,8,7,17);//日期
elseif(shan_xia==2)led_out(5,3,1,18);//闹钟
elseif(shan_xia==3)led_out(6,6,6,18);//星期
elseif(shan_xia==4)out_18b20();//温度
else ykm_out();//遥控码
}
ds=1;//关时钟芯片读与显存刷新,在中断扫描时会打开
//只有在需要显示具体内容时才会访问时钟芯片对应的具体地址并更新显示缓冲区
//ok键值翻转
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x15))
{
if((ok==1)&&(zuo_you<8)){zuo_you=8;i_k=1;i=1;}//如果是位闪状态按ok键就进入全闪状态
else{ok=(!
ok);zuo_you=8;}//否则闪<==>不闪 状态翻转一次
//if(ok==0){i_k=0;ds_temp=0;}//不闪时可以刷新数据
Ir_Buf[2]=0xff;
}
//MUTE键值翻转并响铃
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x0c))
{
if(((ok==1)&&(zuo_you>7))&&(ds_temp>0))time_set();//如果从位闪变为全闪并且8秒写时钟窗口打开则写时钟
else mute=(!
mute);//否则此键为静音转换功能
if(mute==0)
{
delay(10);
beep=0;
delay(20);
beep=1;
}
Ir_Buf[2]=0xff;
}
//按遥控器左键加一
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x11))
{
if(ok==0)mute=1;//如果没有闪屏按此键关闭声音
if(ok==1)
{
if(++zuo_you>7)zuo_you=0;//左移,超出苑围转到最右边
while(Led_Buf[zuo_you]>9){if((++zuo_you)>7)zuo_you=0;}//正在如果要闪动的位不是十则一直数还
Ir_Buf[2]=0xff;
}
}
//按遥控器右键减一
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x10))
{
if(ok==0)mute=0;//如果没有闪屏按此键打开声音
if(ok==1)
{
if((--zuo_you)==255)zuo_you=7;//右移,超出苑围转到最左边
while(Led_Buf[zuo_you]>9){if((--zuo_you)==255)zuo_you=7;}//正在闪动的位不是十进制数则一直移动开遥控
Ir_Buf[2]=0xff;
}
}
//按遥控器上键加一
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x12))
{
if((ok==1)&&(zuo_you<8))
{
Led_Buf[zuo_you]++;//位闪状态有上键按下对应位加一
if(Led_Buf[zuo_you]>9)Led_Buf[zuo_you]=0;//超出为0
}
else
{
zuo_you=8;//改变显示内容时位闪变全屏闪
if(++shan_xia>5)shan_xia=0;//超出为0
}
Ir_Buf[2]=0xff;
}
//按遥控器下键减一
if((Ir_Buf[0]==0x02)&&(Ir_Buf[2]==0x13))
{
if((ok==1)&&(zuo_you<8))
{
Led_Buf[zuo_you]--;//位闪状态有上键按下对应位减一
if(Led_Buf[zuo_you]==255)Led_Buf[zuo_you]=9;//超出则为9
}
else
{
zuo_you=8;//改变显示内容时位闪变全屏闪
if((--shan_xia)==255)shan_xia=5;//自减,超出则为4
}
Ir_Buf[2]=0xff;
}
}
}
}
//数码管扫描===============================================================
timer0()interrupt1using1//定时中断发生,运行中断函数
{
ms++;//屏闪时基
if(ms>=500)ms=0;
if(i_k==1)//不闪屏时允许刷新读写信息
{
if(ms==0){if((++i)>8)i=0;}//延时8秒给mute键的写时钟芯片时间窗口,
ds_temp=i;
}
if(ds_temp==0)i_k=0;
if(((ok==1)&&(zuo_you<8))||(ds_temp>0))ds=1;//在全屏闪5秒内和位闪调时时不允许刷新显存
elseds=0;//ds为何0时才允许刷新显存
TL0=0x25;//12M2ms(测试这个晶振误差后的初值)
TH0=0xf8;
//以下9行消隐
dscs=1;//关掉时钟片选让数据接收口(74hc573数码管的位码和段码锁存器)得到纯净的数据信号
duan=0; //关闭段选
wei=0; //关闭位选
P0=0x00; //消陷码
wei=1; //打开位选
wei=0; //关闭位选,锁存消隐码
P0=0xff; //消隐码
duan=1; //打开段选
duan=0; //关闭段选,锁存消隐码
//数字显示 在锁存器的锁存端出现下降沿时锁存数据
P0=Led_Tab[Led_Buf_temp[Led_Index]];//数模段码送P0口
duan=1;//打开段选
duan=0;//关闭段选,锁存段码
P0=Led_Sel[Led_Index];//位码数据送P0口
wei=1;//打开位选
wei=0;//关闭位选,锁存位码
if(++Led_Index>7)Led_Index=0;
}
//初始化=============================================================================
voidinit()
{
//以下9行消隐在开机瞬间消除屏闪
dscs=1;//关掉时钟片选让数据接收口(74hc573为数码管的位码和段码锁存器)得到纯静净的数据信号
duan=0;//关闭段选
wei=0;//关闭位选
P0=0xff;//消隐码
duan=1;//打开段选
duan=0;//关闭段选,锁存消隐码
P0=0x00;//消陷码
wei=1;//打开位选
wei=0;//关闭位选,锁存消隐码
//定时器设置
TMOD=0x11;
TL0=0xc5;//重装初值
TH0=0xf1;//数码管的刷新频率2ms
EA=1;//开定时总中断
ET0=1;//开定时器0中断 用于遥控高低电平时间采集
ET1=1;//开定时器1中断
TR0=1;//启动定时器1 用于数码管定时中断扫描
//以下是初始化时钟芯片的控制寄存器A和B
write_ds(0x0A,47); //写时钟芯片DS12C887+A寄存器,打开振荡器,启动记时 输出2HZ方波
write_ds(0x0B,126);//写时钟芯片B
}
//写时钟芯片DS12C887+时序========(请参考DS12C887芯片手册)
voidwrite_ds(ucharadd,uchardate)
{dscs=0;dsas=0;dsas=1;dsrw=1;dsds=1;P0=add;dsas=0;dsrw=0;P0=date;dsrw=1;dsas=1;dscs=1;}
//读时钟芯片DS12C887+时序========(请参考DS12C887芯片手册)
ucharread_ds(ucharadd)
{uchards_date;dscs=0;dsas=0;dsas=1;dsrw=1;dsds=1;P0=add;dsas=0;
dsds=0;P0=0xff;ds_date=P0;dsds=1;dsas=1;dscs=1;returnds_date;}
//根据具体内容格式化输出函数
voidled_out(ucharadd_1,ucharadd_2,ucharadd_3,ucharadd_4)
{
uchara,b,c,d=add_4,i;
for(i=0;i<4;i++)
{
if(i==0)a=read_ds(add_1);
if(i==1)b=read_ds(add_2);
if(i==2)c=read_ds(add_3);
if(i==3)d=read_ds(add_4);
}
if(add_1==4)d=18;//时钟间隔位
if(add_1==5)d=16;//闹钟间隔位
if(add_1==4||add_1==5)//按不同的内容用不同的格式输出(参数特征决定输出内容)
{
Led_Buf[7]=a/10;//分离小时位数据
Led_Buf[6]=a%10;
Led_Buf[4]=b/10;//分离分钟位数据
Led_Buf[3]=b%10;
Led_Buf[1]=c/10;//分离秒钟位数据
Led_Buf[0]=c%10;
Led_Buf[5]=d; //间隔位
Led_Buf[2]=d;
}
elseif(add_1==9)
{
Led_Buf[7]=2; //分离小时位数据
Led_Buf[6]=0;
Led_Buf[5]=a/10;
Led_Buf[4]=a%10;//分离分钟位数据
Led_Buf[3]=b/10;
Led_Buf[2]=b%10;
Led_Buf[1]=c/10;//分离秒钟位数据
Led_Buf[0]=c%10;
}
else for(i=0;i<8;i++)Led_Buf[i]=a;
}
//遥控码显示========================================================================
voidykm_out()
{
uchary;//由于使用过的键会对用户码全置1操作,所以在此根据用户反码取反操作还原用户码
if(Ir_Buf[0]==0x02)y=(~Ir_Buf[3]);
elsey=Ir_Buf[2];
Led_Buf[0]=Ir_Buf[3]&0xf;//结果装入显示缓冲区
Led_Buf[1]=(Ir_Buf[3]/16)&0xf;//数据反码
Led_Buf[2]=y&0xf;
Led_Buf[3]=(y/16)&0xf;//数据码
Led_Buf[4]=Ir_Buf[1]&0xf;
Led_Buf[5]=(Ir_Buf[1]/16)&0xf;//用户反码
Led_Buf[6]=Ir_Buf[0]&0xf;
Led_Buf[7]=(Ir_Buf[0]/16)&0xf;//用户码
}
//遥控数字键直接预调时==================================================================================
voidykm_set()//从最左第一位开始直接输入一个0--9的数时显示出来后自动右移一位,当到最右边时转到最左边
{
if((ok==1)&&((Ir_Buf[0]==0x02)&&(Ir_Buf[2]<10)))
{
if(zuo_you>7){zuo_you=7;ds=1;}//ds=1;保证此函数结束后不从写Led_Buf[7]
while(Led_Buf[zuo_you]>9){if((--zuo_you)==255)zuo_you=7;}//闪动的第7位不是十进制数则一直移动
if(Ir_Buf[2]<9)Led_Buf[zuo_you]=Ir_Buf[2]+1;//因为我的遥控器按1时数据码是0x00,按2是0x01...,按0是0x09
elseLed_Buf[zuo_you]=0;
if((--zuo_you)==255){zuo_you=8;i_k=1;i=1;}//先右移,如果到最右边一位则转到最左边一位
while(L