单片机 数码管时钟程序 高手来个。

2025-02-25 10:00:00
推荐回答(4个)
回答1:

我也是新手但研究ds1302加ds18b20已经半年了,写了很多程序,大体上有两种方案,一种是IO口直接驱动数码管,这种方式程序简单,但缺点很明显,占IO口资源太多,而且最关键的一点就是必须采用单片机动态扫描数码管,在简单还行,复杂一点的如加按键闹钟温度什么的,在调时或有时数码管会出现不可避免的闪烁,自己玩玩还行,做成实用的产品就不行了。第二种是采用驱动芯片,如MAX7219,这样扫描电路由芯片完成,单片机只把数据送给芯片就行,完全不必担心闪烁的困扰。
你的电路是IO口驱动,我先给你个IO口的吧,我开发板上段选和位选分别接了两个D触发器,你根据你的电路在改一下就行,ds1302的三个口也得改一下,不过这个电路在扫描时温度会有抖动,是因为中断扫描打断了ds1302和ds18b20的时序,他们都是非常严格的时序器件,网上有人提出的解决办法是在进入时序函数之前关中断,但延时效果更差,如果去掉一个ds18b20就没问题了。程序给你自己研究吧,我还有一个用max7219驱动带按键的,比这个好的多,接近产品了,想要给你。

#include
#include

sbit SCLK=P2^2; //ds1302时钟信号
sbit DIO=P2^1; //ds1302数据信号
sbit CE=P2^0; //ds1302片选信号
sbit ACC_7=ACC^7;
sbit DQ=P2^4; //ds18b20总线
sbit P0_0=P0^0;
sbit P0_1=P0^1;

unsigned char code a[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};

unsigned char shi,ge,i=0;
char hour,minute,second;

void startT0()
{
TMOD=0x01;
TH0=(65536-500)/256;
TL0=(65536-500)%256;
ET0=1;
EA=1;
TR0=1;
}

//************ds1302操作子程序********************************************

void write(unsigned char addr,dat)//写一个字节子函数
{
unsigned char i,n;
CE=0;
SCLK=0;
CE=1;
for(i=0;i<8;i++)//发送地址
{
SCLK=0;
n=addr;
DIO=n&0x01;
addr>>=1;
SCLK=1;
}

for(i=0;i<8;i++)//发送数据
{
SCLK=0;
n=dat;
DIO=n&0x01;
dat>>=1;
SCLK=1;
}

CE=0;
}

unsigned char read( unsigned char addr)//读一个字节
{
unsigned char i,m,dat1;
CE=0;
SCLK=0;
CE=1;
for(i=0;i<8;i++)//发送地址
{
SCLK=0;
m=addr;
DIO=m&0x01;

addr>>=1;
SCLK=1;
}

for(i=0;i<8;i++)
{
ACC_7=DIO;
SCLK=1;
ACC>>=1;
SCLK=0;
}
CE=0;
dat1=ACC;
return dat1;
}

//*****************ds18b20操作子程序***********************************

void delay1( unsigned int a)// 延时
{
while(--a);
}

void write18(unsigned char dat)//写数据
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
delay1(5);
DQ=1;
dat>>=1;
}
}

unsigned char read18()//读数据
{
unsigned char i,dat=0;
DQ=1;
_nop_();
for(i=0;i<8;i++)
{
DQ=0;
_nop_();
_nop_();
dat>>=1;
DQ=1;
_nop_();
_nop_();
if(DQ)
dat|=0x80;
delay1(30);
DQ=1;
}
return dat;
}

void start18()//**********ds18b20初始化**************
{
DQ=1;
delay1(8);
DQ=0;
delay1(90);
DQ=1;
_nop_();
_nop_();

delay1(100);
DQ=1;
}

//*******************初始化************************************
void start()
{

write(0x8e,0x00); //去掉写保护
write(0x80,0x00); //秒初始化
write(0x82,0x00); //分初始化
write(0x84,0x00); //时初始化
write(0x8e,0x80); //写保护开启
}

void du()
{
unsigned char w,b,c;
unsigned int a,bb ;
EA=1;
w=read(0x81);
b=w&0x0f;
c=(w&0x70)>>4;
second=c*10+b;
w=read(0x83);
b=w&0x0f;
c=(w&0x70)>>4;
minute=c*10+b;
w=read(0x85);
b=w&0x0f;
c=(w&0x30)>>4;
hour=c*10+b;

start18();
write18(0xcc);
write18(0x44);
start18();
write18(0xcc);
write18(0xbe);
a=read18();
bb=read18();
EA=1;
bb=((bb&0x03)<<4)+((a&0xf0)>>4);

shi=bb/10;
ge=bb%10;

}

int main()
{
start();
startT0();
while(1){du();

}

return 0;
}

void t0() interrupt 1
{
TH0=(65536-500)/256;
TL0=(65536-500)%256;

switch(i)
{case 0:{P1=a[hour/10];P0_0=1;P0_0=0;P1=~0x01;P0_1=1;P0_1=0;}break;
case 1:{P1=a[hour%10];P0_0=1;P0_0=0;P1=~0x02;P0_1=1;P0_1=0;}break;
case 2:{P1=a[minute/10];P0_0=1;P0_0=0;P1=~0x04;P0_1=1;P0_1=0;}break;
case 3:{P1=a[minute%10];P0_0=1;P0_0=0;P1=~0x08;P0_1=1;P0_1=0;}break;
case 4:{P1=a[second/10];P0_0=1;P0_0=0;P1=~0x10;P0_1=1;P0_1=0;}break;
case 5:{P1=a[second%10];P0_0=1;P0_0=0;P1=~0x20;P0_1=1;P0_1=0;}break;
case 6:{P1=a[shi];P0_0=1;P0_0=0;P1=~0x40;P0_1=1;P0_1=0;}break;
case 7:{P1=a[ge];P0_0=1;P0_0=0;P1=~0x80;P0_1=1;P0_1=0;}break;

}
i++;
if(i==8)i=0;

}

回答2:

//只需将流水灯的延时等待,改成数码管的扫描刷新就可以了。 延时程序对啊,输送字符进led前给阳极来个0 000 000极或阴极来个1 111 111,扫描

回答3:

这个很简单的啊 你到网上随便搜一个程序 然后修改一下就会有你要的效果了!

回答4:

411173277