回头看我所写的文章,基本都是软件方面的,是个典型的“欺软怕硬”的人。然而,在最开始的时候,我学习的是硬件。在前面文章《我的2013–一起从心开始》一文中写道,我在大一暑假的时候开始了单片机的学习,在大二、大三期间做过些小东西。刚进入程序员的领域的时候,显然是单片机带我入了门。下面我将写写用单片机做过的一些东西,权当纪念。
本文介绍我大一暑假学完单片机后,在大二上学期为参加学校星火杯而完成的作品(最终没有参加比赛)。这个电子制作是关于用单片机显示时间的作品,其功能就用单片机控制LCD、LED来显示时间和温度。
功能描述
- 显示精确度为0.1摄氏度的温度(低于0摄氏度和高于100摄氏度响铃)
- 液晶时钟,断电后仍然继续走动,每月误差不到一分钟,无电源可工作10年左右,区分平年和闰年;
- 指针式时钟(黄灯为时针,红色为分针,最小误差5分钟,整点报时)与考试计时器(计时2两小时)
电子元器件
- 2个单片机最小系统 (单片机型号为STC89C52)
- 双色发光二级管
- 液晶显示屏
- 按键
- DS12C887时钟芯片
- DS18b20温度传感器
- 蜂鸣器(整点报时)
- LED数码管(显示温度)
作品展示图
- 由于所有电路都是由杜邦线连接,所以存在接触不良,导致有时不能正常显示,于是就没有参赛,下图为双色二极管的显示。
- 下图为用1602液晶显示日期和时间
- 下图为用数码管来显示温度
- 下图为作品的布线,简直是乱成一团,要是用PCB就好了。
原文:http://blog.csdn.net/tengweitw/article/details/45895989
作者:nineheadedbird
附录:代码实现
对于硬件来说,给代码不给管脚图没啥意义,不过由于年代久远,我已经找不到当初设计的电路图了。但仍然给出代码图,希望能起到一点点的参考作用。
//--------------------------------温度显示程序 第一个芯片------------------------------------------------------------------//
#include<reg52.h>
#include<intrins.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit ds=P2^2;
unsigned int te;
unsigned char code tabledu[]=
{
0x3f0x060x5b0x4f
0x660x6d0x7d0x07
0x7f0x6f0x770x7c
0x390x5e0x790x71
};
unsigned char code tabledu1[]=
{
0xbf0x860xdb0xcf
0xe60xed0xfd0x87
0xff0xef0xf70xfc
0x390x5e0x790x71
};
unsigned char code tablewe[]=
{
0xfe0xfd0xfb0xf70xef0xdf
};
void delayxms(unsigned int x)
{
unsigned int ij;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
void delayx2us(unsigned char t)
{
while(--t);
}
void dsreset() // 复位
{
ds=1;
_nop_();
ds=0;
delayx2us(200);//注意时间
ds=1;
delayx2us(20);
}
void writetemp(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
ds = 0;
ds = dat&0x01;
delayx2us(25);
ds = 1;
dat>>=1;
}
delayx2us(25);
}
unsigned char readtemp(void)
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{
ds = 0; // 给脉冲信号
dat>>=1;
ds = 1; // 给脉冲信号
if(ds)
dat|=0x80;
delayx2us(25);
}
return(dat);
}
uint temp()
{
uint ab;
dsreset();
delayxms(1);
writetemp(0xcc);
writetemp(0x44);
delayxms(1);
dsreset();
delayxms(1);
writetemp(0xcc);
writetemp(0xbe);
delayx2us(50);
a=readtemp();
b=readtemp();
a=a*10;
te=b*160+a/16;
return te;
}
void disp(long int num)
{
uchar cde;
c=num/100;
d=num%100/10;
e=num%10;
P0=tabledu[c];
P1=0xfe;
delayxms(6);
P0=tabledu1[d];
P1=0xfd;
delayxms(6);
P0=tabledu[e];
P1=0xfb;
delayxms(6);
P0=0xcc;
P1=0xf7;
delayxms(2);
}
void main()
{
while(1)
{
disp(temp());
if((temp()>=1000)||(temp()<=0))
beep=0;
else
beep=1;
}
//--------------------------------时钟显示程序 第二个芯片------------------------------------------------------------------//
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
//流水灯锁存器
sbit wela1=P2^0;//1
sbit wela2=P2^1;//2
sbit wela3=P2^2;//1
sbit wela4=P2^3;//2
//蜂鸣器
sbit beep=P2^4;
//按键
sbit key1=P2^5;//功能选择键
sbit key2=P2^6;//+(时间、日期加)
sbit key3=P2^7;//-(时间、日期减)
sbit key4=P3^7;//模式键(平时或考试)
//液晶接口
sbit lcden=P3^4;
sbit lcdrs=P3^5;
sbit lcdwr=P3^6;
//ds12c887接口
sbit dscs=P1^6;
sbit dsas=P1^7;
sbit dsrw=P3^0;
sbit dsds=P3^1;
sbit dsirq=P3^3;
//定义变量
uchar hour minseccountriweekyuenianj;
//uchar counthcountmcountycountkloop1;
uchar code table1[]=" - - ";
uchar code table2[]=" : : ";
uchar code table3[]="SUNMONTUEWEDTHUFRISAT";
//延迟函数
void delayxms(unsigned int x)
{
unsigned int ij;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
//--------------------1602液晶函数----------------------------------
//液晶写命令
void write_com(unsigned char com)
{
lcdrs=0;
P0=com;
delayxms(5);
lcden=1;
delayxms(5);
lcden=0;
}
//液晶写数据
void write_data(unsigned char date)
{
lcdrs=1;
P0=date;
delayxms(5);
lcden=1;
delayxms(5);
lcden=0;
}
//液晶初始化
void lcdinit()
{
lcdwr=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
// 液晶显示
void disp()
{
uchar i;
write_com(0x80);
for(i=0;i<15;i++)
{
write_data(table1[i]);
delayxms(5);
}
write_com(0x80+0x40);
for(i=0;i<12;i++)
{
write_data(table2[i]);
delayxms(5);
}
}
//写时间
void write_sfm(uchar addressuchar shu)
{
uchar shige;
shi=shu/10;
ge=shu%10;
write_com(0x80+0x40+address);
write_data(0x30+shi);
write_data(0x30+ge);
}
//写日历
void write_calendar(uchar addressuchar shu)
{
uchar shige;
shi=shu/10;
ge=shu%10;
write_com(0x80+address);
write_data(0x30+shi);
write_data(0x30+ge);
}
//-------------------------DS12C887程序----------------------------
//写时钟
void write_ds(uchar adduchar date)
{
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add;
dsas=0;
dsrw=0;
P0=date;
dsrw=1;
dsas=1;
dscs=1;
}
//读时钟
uchar read_ds(uchar add)
{
uchar ds_date;
dsas=1;
dsds=1;
dsrw=1;
dscs=0;
P0=add;
dsas=0;
dsds=0;
P0=0xff;
ds_date=P0;
dsds=1;
dsas=1;
dscs=1;
return ds_date;
}
//写星期
void write_week(uchar date)
{
write_com(0x80+12);
write_data(table3[3*date]);
write_data(table3[3*date+1]);
write_data(table3[3*date+2]);
}
//键盘检测
void keyscan() //键盘检测 key1 为功能键 key2为加 key3为减 :时间与日期的改变
{
if(key1==0)
{
delayxms(10);
if(key1==0)
{
while(!key1);
count++;
if(count==1)
{
write_com(0x80+0x40+11);
write_com(0x0f);
}
if(count==2)
{
write_com(0x80+0x40+8);
write_com(0x0f);
}
if(count==3)
{
write_com(0x80+0x40+5);
write_com(0x0f);
}
if(count==4)
{
write_com(0x80+13);
write_com(0x0f);
}
if(count==7)
{
write_com(0x80+10);
write_com(0x0f);
}
if(count==6)
{
write_com(0x80+7);
write_com(0x0f);
}
if(count==5)
{
write_com(0x80+4);
write_com(0x0f);
}
if(count==8)
{
count=0;
write_com(0x0c);
write_ds(0sec);
write_ds(2min);
write_ds(4hour);
}
}
}
if(key2==0)
{
delayxms(10);
if(key2==0)
{
while(!key2);
if(count==1)
{
sec++;
if(sec==60)
sec=0;
write_ds(0sec);
write_sfm(10sec);
write_com(0x80+0x40+11);
}
if(count==2)
{
min++;
if(min==60)
min=0;
write_ds(2min);
write_sfm(7min);
write_com(0x80+0x40+8);
}
if(count==3)
{
hour++;
if(hour==24)
hour=0;
write_ds(4hour);
write_sfm(4hour);
write_com(0x80+0x40+5);
}
if(count==4)
{
week++;
if(week==7)
week=0;
write_week(week);
write_ds(6week);
}
if(count==5)
{
nian++;
if(nian==100)
nian=0;
write_ds(9nian);
write_calendar(3nian);
write_com(0x80+4);
}
if(count==6)
{
yue++;
if(yue==13)
yue=1;
write_ds(8yue);
write_calendar(6yue);
write_com(0x80+7);
}
if(count==7) // 判断闰年
{
ri++;
week++;
if(nian%4==0)
{
if((yue==4)||(yue==6)||(yue==9)||(yue==11))
{
if(ri==31)
ri=1;
}
else if(yue==2)
{
if(ri==30)
ri=1;
}
else
{
if(ri==32)
ri=1;
}
}
if(nian%4!=0)
{
if((yue==4)||(yue==6)||(yue==9)||(yue==11))
{
if(ri==31)
ri=1;
}
else if(yue==2)
{
if(ri>=29)
ri=1;
}
else
{
if(ri==32)
ri=1;
}
}
write_ds(7ri);
write_calendar(9ri);
write_com(0x80+10);
delayxms(2);
if(week==7)
week=0;
write_week(week);
write_ds(6week);
}
}
}
if(key3==0)
{
delayxms(10);
if(key3==0)
{
while(!key3);
if(count==1)
{
if(sec==0)
sec=59;
else
sec--;
write_ds(0sec);
write_sfm(10sec);
write_com(0x80+0x40+11);
}
if(count==2)
{
if(min==0)
min=59;
else
min--;
write_ds(2min);
write_sfm(7min);
write_com(0x80+0x40+8);
}
if(count==3)
{
if(hour==0)
hour=23;
else
hour--;
write_ds(4hour);
write_sfm(4hour);
write_com(0x80+0x40+5);
}
if(count==5)
{
if(nian==0)
nian=99;
else
nian--;
write_ds(9nian);
write_calendar(3nian);
write_com(0x80+4);
}
if(count==6)
{
if(yue==1)
yue=12;
else
yue--;
write_ds(8yue);
write_calendar(6yue);
write_com(0x80+7);
}
if(count==7) // 判断闰年
{
ri--;
week--;
if(nian%4==0)
{
if((yue==4)||(yue==6)||(yue==9)||(yue==11))
{
if(ri==0)
ri=30;
}
else if(yue==2)
{
if(ri==0)
ri=29;
}
else
{
if(ri==0)
ri=31;
}
}
if(nian%4!=0)
{
if((yue==4)||(yue==6)||(yue==9)||(yue==11))
{
if(ri==0)
ri=30;
}
else if(yue==2)
{
if(ri==0)
ri=28;
}
else
{
if(ri==0)
ri=31;
}
}
write_ds(7ri);
write_calendar(9ri);
write_com(0x80+10);
delayxms(2);
if(week==-1)
week=7;
write_week(week);
write_ds(6week);
}
}
}
}
//----------------初始化---------------------------------//
void init()
{
lcdinit();
disp();
week=0;
nian=11;
yue=9;
ri=1;
}
//---------------------------流水灯-----------------------------------//
void lampinit()
{
P1=0xff;
wela1=1;
wela2=1;
wela3=1;
wela3=1;
wela1=0;
wela2=0;
wela3=0;
wela4=0;
}
//----------------时钟用黄灯显示程序-------------------------------//
void clock()
{
if((hour==1)&&(hour==13))
{
P1=0xfd;
wela3=1;
wela3=0;
}
if((hour==2)&&(hour==14))
{
P1=0xfb;
wela3=1;
wela3=0;
}
if((hour==3)&&(hour==15))
{
P1=0xf7;
wela3=1;
wela3=0;
}
if((hour==4)&&(hour==16))
{
P1=0xef;
wela3=1;
wela3=0;
}
if((hour==5)&&(hour==17))
{
P1=0xdf;
wela3=1;
wela3=0;
}
if((hour==6)&&(hour==18))
{
P1=0xfe;
wela4=1;
wela4=0;
}
if((hour==7)&&(hour==19))
{
P1=0xfd;
wela4=1;
wela4=0;
}
if((hour==8)&&(hour==20))
{
P1=0xfb;
wela4=1;
wela4=0;
}
if((hour==9)&&(hour=21))
{
P1=0xf7;
wela4=1;
wela4=0;
}
if((hour==10)&&(hour==22))
{
P1=0xef;
wela4=1;
wela4=0;
}
if((hour==11)&&(hour==23))
{
P1=0xdf;
wela4=1;
wela4=0;
}
if((hour==12)&&(hour==0))
{
P1=0xfe;
wela3=1;
wela3=0;
}
if(min<5)
{
if((hour!=12)&&(hour!=24))
{
P1=0xfe;
wela1=1;
wela1=0;
}
}
//----------------分钟用红灯显示------------------------//
if((min>=5)&&(min<10))
{
if((hour!=13)&&(hour!=1))
{
P1=0xfd;
wela1=1;
wela1=0;
}
}
if((min>=10)&&(min<15))
{
if((hour!=14)&&(hour!=2))
{
P1=0xfb;
wela1=1;
wela1=0;
}
}
if((min>=15)&&(min<20))
{
if((hour!=15)&&(hour!=3))
{
P1=0xf7;
wela1=1;
wela1=0;
}
}
if((min>=20)&&(min<25))
{
if((hour!=16)&&(hour!=4))
{
P1=0xef;
wela1=1;
wela1=0;
}
}
if((min>=25)&&(min<30))
{
if((hour!=17)&&(hour!=5))
{
P1=0xdf;
wela1=1;
wela1=0;
}
}
if((min>=30)&&(min<35))
{
if((hour!=18)&&(hour!=6))
{
P1=0xfe;
wela2=1;
wela2=0;
}
}
if((min>=35)&&(min<40))
{
if((hour!=19)&&(hour!=7))
{
P1=0xfd;
wela2=1;
wela2=0;
}
}
if((min>=40)&&(min<45))
{
if((hour!=20)&&(hour!=8))
{
P1=0xfb;
wela2=1;
wela2=0;
}
}
if((min>=45)&&(min<50))
{
if((hour!=21)&&(hour!=9))
{
P1=0xf7;
wela2=1;
wela2=0;
}
}
if((min>=50)&&(min<55))
{
if((hour!=22)&&(hour!=10))
{
P1=0xef;
wela2=1;
wela2=0;
}
}
if(min>=55)
{
if((hour!=23)&&(hour!=11))
{
P1=0xdf;
wela2=1;
wela2=0;
}
}
}
//---------------考试倒计时模式-----------------------//
void test()
{
uchar hour1min1min2shi;
hour1=hour+2;
if(hour==24)
hour1=0;
if(hour==25)
hour1=1;
min1=min+20;
if(min1>=60)
{
min1=min1-60;
hour1=hour1+1;
if(hour1==24)
hour1=0;
}
shi=min1/10;
min1=shi*10;
if((min==min1)&&(sec==0))
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xfe;
wela3=1;
wela3=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xfc;
wela1=1;
wela1=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xf8;
wela1=1;
wela1=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xf0;
wela1=1;
wela1=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xe0;
wela1=1;
wela1=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xc0;
wela1=1;
wela1=0;
}
//-------------------------------------------------//
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xfe;
wela2=1;
wela2=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xfc;
wela2=1;
wela2=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xf8;
wela2=1;
wela2=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xf0;
wela2=1;
wela2=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xe0;
wela2=1;
wela2=0;
}
if(min==min2)
{
min2=min+5;
if(min2==60)
min2=0;
P1=0xc0;
wela2=1;
wela2=0;
}
//----------------------时间到后开始响铃------------------------------------------//
if(min==min2)
{
P1=0;
wela1=1;
wela1=0;
beep=0;
delayxms(1000);
beep=1;
delayxms(1000);
beep=0;
delayxms(1000);
beep=1;
beep=0;
delayxms(1000);
beep=1;
delayxms(1000);
beep=0;
delayxms(6000);
delayxms(6000);
beep=1;
lampinit();
}
}
//-----------------主函数--------------------------------------//
void main()
{
init();
while(1)
{
keyscan();
if(count==0)
{
sec=read_ds(0);
min=read_ds(2);
hour=read_ds(4);
week=read_ds(6);
nian=read_ds(9);
yue=read_ds(8);
ri=read_ds(7);
write_sfm(10sec);
write_sfm(7min);
write_sfm(4hour);
write_week(week);
write_calendar(3nian);
write_calendar(6yue);
write_calendar(9ri);
write_calendar(120);
}
}
}