关于51单片机若干的问题,急。。。。。

1.设计一个二进制减1计数器,按一次键,减1,并用4个LED显示计数结果,减至0时,重新从15开始计数。
2.用1个按键控制LED的显示,要求显示3种以上的不同模式。
3. 采用外部中断的方式实现一个二进制减1计数器,按一次键,减1,并用4个LED显示计数结果,减至0时,重新从15开始计数。
4. 采用外部中断的方式实现用1个按键控制LED的显示,要求显示3种以上的不同模式。
5.设计1个秒计数器,每秒计1次数,在LED上显示出来,计至16清零后重新计数。
6.在上题基础上用按键控制秒计数器的启停,按一次键开始计数,按2次停止计数,按3次又开始计数…。
马上要考试了,求高手一一解答啊!小弟只有这么多分,望高手们海涵!

第1个回答  2012-06-12
//实际晶振为11.0592MHz
//为方便计算,假设为12MHz
#include<reg52.h> //包含52单片机头文件
#define uchar unsigned char //宏定义
#define uint unsigned int //红定义
//#include<24c02.h>
sbit dula=P2^6; //定义锁存器锁存端
sbit wela=P2^7;
sbit rs=P3^5; //定义1602液晶RS端
sbit lcden=P3^4; //定义1602液晶LCDEN端
sbit s1=P3^0; //定义按键——功能键
sbit s2=P3^1; //定义按键——增大键
sbit s3=P3^2; //定义按键——减小键
//sbit s4=P3^6; //闹钟查看器
sbit rd=P3^7;
sbit beep=P2^3; //蜂鸣器
sbit dscs=P1^4;
sbit dsas=P1^5;
sbit dsrw=P1^6;
sbit dsds=P1^7;
sbit dsirq=P3^3;
bit flag1,flag_ri; //定义两个位变量
uchar count,s1num,flag,t0_num; //其他变量定义
char miao,fen,shi,day,month,year,week,amiao,afen,ashi;
uchar code table[]=" 20 - - "; //定义初始上电时液晶默认显示状态
//uchar code table1[]=" : : ";
void write_ds(uchar,uchar); //函数声明
uchar read_ds(uchar);
void set_time();

void delay(uint z) //延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}

void di() //蜂鸣器报警声音
{
beep=0;
delay(100);
beep=1;
}

void write_com(uchar com) //写液晶命令函数
{
rs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}

void write_date(uchar date) //写液晶数据函数
{
rs=1;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_sfm(uchar add,uchar date) //写时分秒函数
{
uchar shi,ge;
shi=date/10; //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+0x40+add); //设置显示位置
write_date(0x30+shi); //送去液晶显示十位
write_date(0x30+ge); //送去液晶显示个位
}

void write_nyr(uchar add,uchar date) //写年月日函数
{
uchar shi,ge;
shi=date/10; //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+add); //设置显示位置
write_date(0x30+shi); //送去液晶显示十位
write_date(0x30+ge); //送去液晶显示个位
}
void write_week(char we)
{ //写液晶星期显示函数
write_com(0x80+12);
switch(we)
{
case 1: write_date('M');
delay(5);
write_date('O');
delay(5);
write_date('N');
break;
case 2: write_date('T');
delay(5);
write_date('U');
delay(5);
write_date('E');
break;
case 3: write_date('W');
delay(5);
write_date('E');
delay(5);
write_date('D');
break;
case 4: write_date('T');
delay(5);
write_date('H');
delay(5);
write_date('U');
break;
case 5: write_date('F');
delay(5);
write_date('R');
delay(5);
write_date('I');
break;
case 6: write_date('S');
delay(5);
write_date('A');
delay(5);
write_date('T');
break;
case 7: write_date('S');
delay(5);
write_date('U');
delay(5);
write_date('N');
break;
}
}

void init() //初始化函数
{
uchar num;
rd=0; //软件将矩阵按键第四列一端置低用以分解出独立按键
dula=0; //关闭两锁存器锁存端,防止操作液晶时数码管出现乱码
wela=0;
lcden=0;
fen=0; //初始化分钟变量值
miao=0;
shi=0;
day=1;
month=1;
year=12;
week=1;
count=0;
s1num=0;
// init_24c02();
//一下几行在首次设置DS12C887时使用,以后不必在写入
// write_ds(0x0A,0x20); //打开振荡器
// write_ds(0x0B,0x26); //设置24小时模式,数据二进制格式 ,开启闹铃中断
set_time(); //设置上电默认时间

write_com(0x38); //初始化1602液晶
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80); //设置显示初始坐标
for(num=0;num<15;num++) //显示年月日星期
{
write_date(table[num]);
delay(5);
}
/* for(num=0;num<12;num++)
{
write_date(table1[num]);
delay(5);
}
*/
write_com(0x80+0x40+6); //写出时间显示部分的两个冒号
write_date(':');
delay(5);
write_com(0x80+0x40+9);
write_date(':');
delay(5);
// miao=read_add(1);
// fen=read_add(2);
// shi=read_add(3);
write_sfm(10,miao);
write_sfm(7,fen);
write_sfm(4,shi);
write_nyr(9,day);
write_nyr(6,month);
write_nyr(3,year);
write_week(week);

TMOD=0x01; //设置定时器0工作模式1
TH0=(65536-50000)/256; //定时器装初值
TL0=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
}

void keyscan() //按键扫描函数
{
// rd=0; //前面已定义
if(s1==0)
{
delay(5);
if(s1==0) //确认功能键被按下
{ s1num++; //功能键按下次数记录
while(!s1); //释放确认
di(); //每当有按键释放蜂鸣器发出滴声
if(s1num==1) //第一次被按下时
{
TR0=0; //关闭定时器
write_com(0x80+0x40+10); //光标定位到秒位置
write_com(0x0f); //光标开始闪烁
}

if(s1num==2) //第二次按下光标闪烁定位到分钟位置
{
write_com(0x80+0x40+7);
}
if(s1num==3) //第三次按下光标闪烁定位到小时位置
{
write_com(0x80+0x40+4);
}
if(s1num==4) //第四次按下光标闪烁定位到日期位置
{
write_com(0x80+9);
}
if(s1num==5) //第五次按下光标闪烁定位到月份位置
{
write_com(0x80+6);
}
if(s1num==6) //第六次按下光标闪烁定位到年份位置
{
write_com(0x80+3);
}
if(s1num==7) //第七次按下光标闪烁定位到年份位置
{
write_com(0x80+12);
}

if(s1num==8) //第八次按下
{
s1num=0; //记录按键数清0
write_com(0x0c); //取消光标闪烁
TR0=1; //启动定时器使时钟走
}
flag=0;
write_ds(0,miao);
write_ds(2,fen);
write_ds(4,shi);
write_ds(6,week);
write_ds(7,day);
write_ds(8,month);
write_ds(9,year);
// break;
}

}
if(s1num!=0) //只有功能键被按下后,增大和减小键才有效
{
if(s2==0)
{
delay(5);
if(s2==0) //增大键确认被按下
{
while(!s2); //按键释放
di(); //每当有按键释放蜂鸣器发出滴声

if(s1num==1) //若功能键第一次按下
{
miao++; //则调整秒加1
if(miao==60) //若满60后将清0
miao=0;
write_sfm(10,miao); //每调节一次送液晶显示一下
write_com(0x80+0x40+10); //显示位置重新回到调节处
// write_add(1,miao); //数据改变立即存入24C02

}
if(s1num==2) //若功能键第二次按下
{
fen++; //则调整分钟加1
if(fen==60) //若满60后将清0
fen=0;
write_sfm(7,fen); //每调节一次送液晶显示一下
write_com(0x80+0x40+7); //显示位置重新回到调节处
// write_add(2,fen);
}
if(s1num==3) //若功能键第三次按下
{
shi++; //则调整小时加1
if(shi==24) //若满24后将清0
shi=0;
write_sfm(4,shi);//每调节一次送液晶显示一下
write_com(0x80+0x40+4); //显示位置重新回到调节处
// write_add(3,shi); //数据改变立即存入24C02
}
if(s1num==4) //若功能键第四次按下
{
day++; //则调整日期加1
if(day==32) //若满31后将清0
day=1;
write_nyr(9,day);//每调节一次送液晶显示一下
write_com(0x80+9); //显示位置重新回到调节处
// write_add(9,day); //数据改变立即存入24C02
}
if(s1num==5) //若功能键第五次按下
{
month++; //则调整月份加1
if(month==13) //若满12后将清0
month=1;
write_nyr(6,month);//每调节一次送液晶显示一下
write_com(0x80+6); //显示位置重新回到调节处
// write_add(6,month); //数据改变立即存入24C02
}
if(s1num==6) //若功能键第六次按下
{
year++; //则调整年份加1
if(year==33) //若满32后将返回初始年份
year=12;
write_nyr(3,year);//每调节一次送液晶显示一下
write_com(0x80+3); //显示位置重新回到调节处
// write_add(3,year); //数据改变立即存入24C02
}
if(s1num==7) //若功能键第七次按下
{
week++; //则调整年份加1
if(week==8) //若满32后将返回初始年份
week=1;
write_week(week);//每调节一次送液晶显示一下
write_com(0x80+12); //显示位置重新回到调节处
// write_add(week); //数据改变立即存入24C02
}

}
}
if(s3==0)
{
delay(5);
if(s3==0) //确认减小按键按下
{
while(!s3); //按键释放
di(); //每当有按键释放蜂鸣器发出滴声
if(s1num==1) //若功能键第一次按下
{

miao--; //则调整秒减1
if(miao==-1) //若减到负数则将其重新设置为59
miao=59;
write_sfm(10,miao); //每调节一次送液晶显示一下
write_com(0x80+0x40+10); //显示位置重新回到调节处
// write_add(1,miao); //数据改变立即存入24C02
}
if(s1num==2) //若功能键第二次按下
{
fen--; //则调整分钟减1
if(fen==-1) //若减到负数则将其重新设置为59
fen=59;
write_sfm(7,fen); //每调节一次送液晶显示一下
write_com(0x80+0x40+7); //显示位置重新回到调节处
// write_add(2,fen); //数据改变立即存入24C02
}
if(s1num==3) //若功能键第三次按下
{
shi--; //则调整小时减1
if(shi==-1) //若减到负数则将其重新设置为23
shi=23;
write_sfm(4,shi); //每调节一次送液晶显示一下
write_com(0x80+0x40+4); //显示位置重新回到调节处
// write_add(3,shi); //数据改变立即存入24C02
}
if(s1num==4) //若功能键第四次按下
{
day--; //则调整日期减1
if(day==0) //若减到0则将其重新设置为31
day=31;
write_nyr(9,day); //每调节一次送液晶显示一下
write_com(0x80+9); //显示位置重新回到调节处
// write_add(9,day); //数据改变立即存入24C02
}
if(s1num==5) //若功能键第五次按下
{
month--; //则调整月份减1
if(month==0) //若减到0则将其重新设置为12
month=12;
write_nyr(6,month); //每调节一次送液晶显示一下
write_com(0x80+6); //显示位置重新回到调节处
// write_add(6,month); //数据改变立即存入24C02
}
if(s1num==6) //若功能键第六次按下
{
year--; //则调整月份减1
if(year==11) //若减到初始值则将其重新设置为32
year=32;
write_nyr(3,year); //每调节一次送液晶显示一下
write_com(0x80+3); //显示位置重新回到调节处
// write_add(3,year); //数据改变立即存入24C02
}
if(s1num==7) //若功能键第七次按下
{
week--; //则调整月份减1
if(week==0) //若减到初始值则将其重新设置为32
week=7;
write_week(week); //每调节一次送液晶显示一下
write_com(0x80+12); //显示位置重新回到调节处
// write_add(week); //数据改变立即存入24C02
}

}
}
}
}

void write_ds(uchar add,uchar date)
{ //写12C887函数
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)
{ //读12C887函数
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 set_time()
{ //首次上电初始化时间函数
write_ds(0,0);
write_ds(1,0);
write_ds(2,0);
write_ds(3,0);
write_ds(4,0);
write_ds(5,0);
write_ds(6,0);
write_ds(7,0);
write_ds(8,0);
write_ds(9,0);
}

void main() //主函数
{
init(); //首先初始化各函数
while(1) //进入主程序大循环
{
keyscan(); //不停地检测按键是否被按下
if(flag==0&&flag1==0) //正常工作时进入这里
{
keyscan(); //按键扫描
year=read_ds(9); //读取12C887数据
month=read_ds(8);
day=read_ds(7);
week=read_ds(6);
shi=read_ds(4);
fen=read_ds(2);
miao=read_ds(0);
write_sfm(10,miao); //送液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
write_week(week);
write_nyr(3,year);
write_nyr(6,month);
write_nyr(9,day);
}
}
// while(1);
}

void timer0() interrupt 1 //定时器0中断服务程序
{
TH0=(65536-50000)/256; //再次装定时器初值
TL0=(65536-50000)%256;
count++; //中断次数累加
if(count==20) //20次50毫秒为1秒
{
count=0;
miao++;
if(miao==60) //秒加到60则进位分钟
{
miao=0; //同时秒数清0
fen++;
if(fen==60) //分钟加到60则进位小时
{
fen=0; //同时分钟数清0
shi++;
if(shi==24) //小时加到24则进位日期
{
shi=0; //同时小时数清0
day++;
if(day==31) //日期加到31则进位月份
{
day=0; //同时日期数清0
month++;
if(month==12) //月份加到12则进位年份
{
month=0; //同时月份数清0
year++;
if(year==99) //年份加到32则将年份返回初始值
{
year=0;
}
write_nyr(3,year);
// write_add(3,year); //数据改变立即存入24C02
}
write_nyr(6,month);
// write_add(6,month); //数据改变立即存入24C02
}
write_nyr(9,day);
// write_add(9,day); //数据改变立即存入24C02
}
write_sfm(4,shi); //小时若变化则重新写入
// write_add(3,shi); //数据改变立即存入24C02
}
write_sfm(7,fen); //分钟若变化则重新写入
// write_add(2,fen); //数据改变立即存入24C02
}
write_sfm(10,miao); //秒若变化则重新写入
// write_add(1,miao); //数据改变立即存入24C02

}
}

这都是我调试好用过的程序,不知道硬件连接的是不是一样,希望对你有帮助。本回答被提问者和网友采纳
第2个回答  2012-06-12
QQ 2606454510