利用51单片机和3位数码管实现10分钟内的简易计时器

作者&投稿:阴具 (若有异议请与网页底部的电邮联系)
利用AT89C51单片机设计简易电子钟(六位),通过8位LED数码管实现时间显示;系统可以通过三个按键实现时间~

程序设计思路:1.利用单片机内部定时器作为计时器,调用timer函数;2、设计一套按键子程序;(3)设计一套数码显示管子程序。下列提供一套程序供参考。

#include
#include
#define uchar unsigned char
#define uint unsigned int

const uchar table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0-9对应字符
const uchar key_value[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uchar data[4]={0}; //显示初始值为0
uint count=0; //初始计数值为0
uchar keynum;


void port_init() //端口初始化函数
{DDRA=0XFF; //端口A为推挽1输出
PORTA=0XFF;
PORTB=0XFF; //端口B为推挽1输出
DDRB=0XFF;
DDRC=0XFF; //端口C为不带上拉电阻的输入
PORTC=0XFF;
DDRD=0XFF; //端口D低4位为输出
PORTD=0X0F;
}


void delay(uint j) //延时函数
{uint k;
while(j--)
{for(k=1000;k>0;k--) ;}
}


void display(uchar *p) //显示函数
{uchar i,sel=0x01;
for(i=0;i<4;i++)
{PORTA=sel; //选通最右边的数码管
PORTB=table[p[i]]; //送字型码
delay(1);
sel=sel<<1; //左移一位
}
}


uchar get_key(void)
{if((PIND&0X0F)!=0X0F) delay(3);
{
PORTD=0XEF;
switch(PIND&0X0F)
{case 0x0e: keynum=key_value[0];break;
case 0x0d: keynum=key_value[4];break;
case 0x0b: keynum=key_value[8];break;
case 0x07: keynum=key_value[12];break;
default:break;
}
PORTD=0xdf;
switch(PIND&0X0F)
{case 0x0e:keynum=key_value[1];break;
case 0x0d:keynum=key_value[5];break;
case 0x0b:keynum=key_value[9];break;
case 0x07:keynum=key_value[13];break;
default:break;
}

PORTD=0xbf;
switch(PIND&0X0F)
{case 0x0e:keynum=key_value[2];break;
case 0x0d:keynum=key_value[6];break;
case 0x0b:keynum=key_value[10];break;
case 0x07:keynum=key_value[14];break;
default:break;
}

PORTD=0x7f;
switch(PIND&0X0F)
{case 0x0e:keynum=key_value[3];break;
case 0x0d:keynum=key_value[7];break;
case 0x0b:keynum=key_value[11];break;
case 0x07:keynum=key_value[15];break;
default:break;
}
while((PIND&0x0f)!=0x0f);
}

return keynum;
}

void process(uint i,uchar *q) //拆分BCD码函数,显示千、百、十、个位
{ q[0]=i/1000;
i=i%1000;
q[1]=i/100;
i=i%100;
q[2]=i/10;
i=i%10;
q[3]=i;
}

void main(void)
{port_init();
PORTB=0xff;
PORTA=0X00;
delay(50);
PORTA=0xff;

while(1)
{get_key();
count=keynum;
process(count,data);
display(data);
}
}

用c语言编写程序,用于c51单片机四位共阴数码管显示,显示分秒的计时器。

用proteus做的时钟
可以显示年月日时分秒
可调整时间
有图
*/
#includereg52.h

修改如下:
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char 
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
sbit key1=P2^7;
sbit key2=P2^6;
sbit weiH=P3^0;
sbit weiM=P3^1;
sbit weiL=P3^2;
uint num=0,ge=0,shi=0,fen=0,k; //num用来计数,ge为各位显示,shi为十位显示,fen为分钟显示

void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}

uchar key1scan(void)
{if(key1==0)
{delayms(10);
if(key1==0)
{while(!key1);
return 1;
}
return 0;
}

uchar key2scan(void)
{if(key2==0)
{delayms(10);
if(key2==0)
{while(!key2);
return 1;
}
}
return 0;
}

void showtime() interrupt 1//时间显示
{
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
num++;
num%=3;
switch(num)
{
case 0:
weiL=1; //显示秒的个位
P1=0xff;
P1=table[ge];
delayms(5);
weiL=0;
break;
case 1:
weiM=1; //显示秒的十位
P1=0xff;
P1=table[shi];
delayms(5);
weiM=0;
break;
case 2:
weiH=1; //显示分钟,只显示0-9
P1=0xff;
P1=table[fen];
delayms(5);
weiH=0;
break;
}

void main()
{
TMOD=0x01;
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
TR0=1;
ET0=1;
EA=1;
num=0;
while(1)
    {
if((key1scan()==1)&&(key2scan()!=1))break; //按键1按下,按键2未按下开始计时
    }
while(1)
    {
    delay(1000);
    ge++;
    if(ge>9)
        {
        ge=0;
        shi++
        if(shi>5)
            {
            fen++;
            if(fen>9)fen=0;
            }
         }
    showtime();
    }
}


因为楼主说,(不要太大面积修改)。
所以,就没有敢进行大面积的修改。

只简单的改改,未必能好用,仅供参考:

#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

sbit key1=P2^7;
sbit key2=P2^6;
sbit weiH=P3^0;
sbit weiM=P3^1;
sbit weiL=P3^2;

uint num=0,ge=0,shi=0,fen=0,k;
//num用来计数,ge为各位显示,shi为十位显示,fen为分钟显示

void delayms(uint xms) //i=xms即延时约xms毫秒
{
uint i,j;
for(i=xms;i>0;i--) for(j=110;j>0;j--);
}

uchar key1scan()
{
if(key1==0) {
delayms(10);
if(key1==0) {
while(!key1) showtime();//等待释放期间,也进行显示
return 1;
}
}
return 0;//添上了返回值
}

uchar key2scan()
{
if(key2==0) {
delayms(10);
if(key2==0) {
while(!key2) showtime();
return 1;
}
}
return 0;//添上了返回值
}

void showtime() //时间显示
{

//这里去掉了while(1) ,避免了死循环

P1=0xff; weiL=1; P1=table[ge]; delayms(5); weiL=0;//显示秒的个位
P1=0xff; weiM=1; P1=table[shi]; delayms(5); weiM=0;//显示秒的十位
P1=0xff; weiH=1; P1=table[fen]; delayms(5); weiH=0;//显示分钟,只显示0-9
}

void main()
{
num=0;
while(1) {
if(key1scan() && !key2scan()) { //按键1按下,按键2未按下开始计时
++num;
if(num<10) {ge=num;}
if(num=10) {
num = num - 10; //个位到10清零
if(shi == 6) { //十位到6清零
shi=0;
++fen;
}
++shi;
ge=num;
}
showtime();
}
}
}

你的循环函数用错地方了,应该用在main函数里,而不是子函数里,现在的情况是一直在显示showtime函数里循环不能跳出来,而你的即使部分呢又不是定时中断,这样就导致数码管不会变了。
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
sbit key1=P2^7;
sbit key2=P2^6;
sbit weiH=P3^0;
sbit weiM=P3^1;
sbit weiL=P3^2;
uint num=0,ge=0,shi=0,fen=0,k; //num用来计数,ge为各位显示,shi为十位显示,fen为分钟显示

void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}

key1scan()
{if(key1==0)
{delayms(10);
if(key1==0)
{while(!key1);
TR0 = 1;
}
}
}

key2scan()
{if(key2==0)
{delayms(10);
if(key2==0)
{while(!key2);
TR0 =0;
}
}
}

void showtime() //时间显示
{
//weiL=1; //显示秒的个位
P1=0xff;
weiL=0;
P1=table[ge];
delayms(10);
weiL=1;

//weiM=1; //显示秒的十位
P1=0xff;
P1=table[shi];
weiM=0;
delayms(10);
weiM=1;

//weiH=1; //显示分钟,只显示0-9
P1=0xff;
P1=table[fen];
weiH=0;
delayms(10);
weiH=1;
}

void time_0() interrupt 1
{
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
num++;
if(num ==20) //1秒则个位+1;
{
num = 0;
ge++;
if(ge == 10)
{
ge = 0; //个位到10清零
shi++;
if(shi==6) //十位到6清零
{shi=0;
fen++;
}
}
}
}

void main()
{
TMOD = 0X01; //觉得不用定时器中断简直就是浪费时间。
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256; //50ms*20=1s
ET0 = 1; // 打开定时中断
EA = 1; //打开总中断。
while(1)
{
key1scan(); //扫描按键1,如果按下,则打开定时中断TR0开始计时
key2scan(); //扫描按键2,如果按下,则关闭定时中断TR0停止计时。
showtime();
}
}

主函数里面要加while(1)


51单片机的串口接收一帧数据有几位?
发送的位数跟工作方式有关。51单片机的发送和接受,只有10位和11位两种。先说单片机串口的工作方式:单片机串口的工作方式共4种,方式0--方式3.方式0:用移位脉冲。RXD做输入\/输出,TXD进行移位。收发的数据为八位。方式1:传送一帧信息为10位,即1位起始位(0),8位数据位(低位在先)和1位停止...

51单片机psw各个标志位的定义?
3. F0:F0 标志位由用户自行定义,用于满足特定的程序需求,其值由用户程序设定。4. RS1 和 RS0:这两个标志位用于选择当前的工作寄存器组。8051 单片机有八个8位通用寄存器 R0 到 R7,RS1 和 RS0 的组合决定了当前使用的寄存器组地址。5. OV (Overflow):OV 标志位用于指示算术运算是否发生...

急!!51单片机P3。3口输入,P1。1口输出,将灯左移问题
如果我写的不对或者有疑问可以给我留言 http:\/\/hi.baidu.com\/xiaozhishmily 呵呵。ORG 0810H J100: MOV A,#01H ;累加器的初值写为1,最低位的灯亮 J101: JB P3.3,J101 MOV R2,#20H LCALL DELY JB P3.3,J101 ;P3.3电平为低吗?J102: JNB P3.3,J102 MOV R2,#20H LCALL...

51单片机c程序用定时器控制两个数码管显示0到59,一直没弄懂段位和位选...
每个数字 有 八个段 为 a b c d e f g h,(h 为小数点)数码管 有 两位一体的、三位一体的,四位一体的等,如四位一体的数码管有12个脚,分为 a b c d e f g h 八个 段码脚,四个 位码脚(四个数字位)数码管 的 显示 方法 需要 扫描显示,就是...

利用51单片机设计一个单片机3*4键盘输入系统
然后把处理完的值在数码管上显示出来,这里需要对应你的单片机电路图,写一个自己的数码管驱动。你后面说的每按一下,向左移动一位?不明白什么意思,但是你把上面的弄完了,实现这些东西肯定没问题。郭天祥的十天学会单片机 你看看3和4讲,应该是讲矩阵键盘和数码管的,一看就会。。。

51单片机的三总线分别是什么?
单片机控制系统的三总线是指数据总线、地址总线、控制总线。1、数据总线 51 单片机的数据总线为P0 口,CPU 从P0 口送出和读回数据。2、地址总线 51 系列单片机的地址总线为16 位。高8位地址则通过P2 口送出。3、控制总线 51 系列单片机的控制总线包括(RD)读控制信号P3.7 和(WR)写控制信号P3.6...

51单片机的地址问题(位地址和字节地址)
1. 8051的内部RAM能作为用户RAM区的只有00~7FH,可以用直接寻址或寄存器间接寻址;80H~FFH是SFR,放了些特殊功能寄存器,只能用直接寻址;2. 位地址00~7FH和片内RAM字节地址00~7FH只是地址的称呼一样,代表的含义不同,位地址只能用位寻址;3. 具体的地址是只能通过指令来区分。其实楼主的理解还是...

三个按钮+一片51单片机+三个74HC595+15个数码管,实现3段五位数码管分别...
可以实现,没有问题,我是用三片595做的三个4位的.一片74HC595可以利用单片机的三个引脚得到8个输出引脚,如果是两片74HC595串联,则可以扩展得到16个输出引脚,如果是三片,则可以得到24个输出引脚.大概的设计思路是:假设,三个74HC595,按照串联的顺序,分别编号叫A,B,C,即A->B->C 15个数码管,一共...

MCS-51单片机4个I\/O口的作用是什么?三总线是如何分配的?为什么说能作为...
4个I\/O口的作用是:第一功能是普通I\/O口,其中P0口需外接上拉电阻;第二功能各不相同,分别为:P0口:作外部三总线的地址总线(低8位)\/数据总线;P1口:作扩展型芯片的外部引脚,例如52的C\/T2外部信号输入,S52之WDT的报警输出等;P2口:作外部三总线的地址总线(高8位);P3口:作串口、...

51单片机怎样用按键实现数码管位切换
用一个变量计数,每按一次键加1,一共切换多少位,就计数到多少。计到最大再回到第一位计数。例,四位数码管,计数为0,1,2,3,超过3就回0。好了,按键解决了,再解决显示的,计数值对的数码管,让它显示出小数点,就是要调整的位。按键切换数码管,就是显示小数点的位在切换。最后是,变量...

长沙市13485137515: 51单片机做一个10秒倒计时的程序 -
梅隶盐酸: C语言 #include<reg51.h> #define uint unsigned int #define uchar unsigned char sbit p27=P2^7;//数码管位选端定义 uchar c,i; //数码管译码表 unsigned char code NumDecode[] = { 0XC0,//;0 0XF9,//;1 0XA4,//;2 0XB0,//;3 0X99,//;4 0X92,//;5 0X...

长沙市13485137515: 51单片机用c语言编写一个程序,数码管显示从10到30,再从30到10. -
梅隶盐酸: 大概理解你的意思,是在数码管一次排列好这一句话,首先第一步需要做的是数码管的取模工作.#include//这边为了让你看的更容易,用的是单独操作,没有用总线sbitled1=P1^0;sbitled2=P1^1;sbitled3=P1^2;sbitled4=P1^3;sbitled5=P1^4;sbitled6=P1^5;sbitled7=P1^6;//看清楚自己的管脚,不一定对应,这里采用P0对应段选codeunsignedcharled_paly[5]={0x76,0x79,0x38,0x38,0x5c};//HELLOvoiddelay(unsignedintum)//延时函数{inti,j;for(i=0;i

长沙市13485137515: 51单片机动态数码管扫描 -
梅隶盐酸: 问题在 P0=tab[(x%100)]; 改成 P0=tab[(x%10)];

长沙市13485137515: 51单片机控制数码管显示矩阵键盘输入的十进制数,有什么好一点的实现方式?求原理 -
梅隶盐酸: 数码管会不?矩阵键盘会不?这就是原理啦.程序的话,不使用 Delay()函数,采用定时器替代.不使用 while(K==0),使用 状态记录替代.那么你就搞定了!!

长沙市13485137515: 一个只有一路ad的芯片,利用51单片机,如何在硬件上搭建实现10路检测?
梅隶盐酸: 有一路ad的芯片,利用51单片机,加模拟开关,CD4067是16选1模拟开关.用51单片机的I/O口,控制CD4067的选择通道A,B,C,D.CD4067的公共端接ad芯片的输入,10路模拟量,接16路通道中的10路.CD4067禁止端接地.

长沙市13485137515: 利用单片机实现十个楼层控制,用数码管显示电梯所在的楼层 -
梅隶盐酸: 电梯控制很难的,需要很强的逻辑.比如,你需要的按键是每层10个,就是100个按键,这样的程序,编写起来有挑战性

长沙市13485137515: 51单片机编程 -
梅隶盐酸: 51编程得看外部电路的连接情况.没有电路图,木有办法写...1. 数码管和单片机之间的电路有很多种,你这种就用译码器,74138就行.假设单片机p1口用作数码管输出. 2. 滑槽电路也不清楚,假设一个电机,用的是P2^0,P2^1(顺时针...

长沙市13485137515: 急~51单片机10毫秒秒表制作~在线等! -
梅隶盐酸: #includeunsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};unsigned char second;unsigned char keycnt;unsigned int cnt;void main(void){unsigned char i,j;TMOD=0...

长沙市13485137515: 单片机C51编程(C语言):实现学号的显示(学号是10位数字) -
梅隶盐酸: 你用什么驱动数码管呢?不同的驱动,程序写法不同.如果直接用I/O口驱动,8位数码管就这样写: wei=位选 duan=段选//断码表uchar code shuzi[12]={0xc0,0xf9,0xa4,0xb0,0x99,//0,1,2,3,4,0x92,0x82,0xf8,0x80,0x90,//5,6,7,8,9,0x00,0xff}; ...

长沙市13485137515: 求用51单片机接两个数码管,0 - 99动态显示程序(用C语言) -
梅隶盐酸: #include #define uchar unsigned char #define uint unsigned int uchar DSY_CODE[]= { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f }; void delay(uint x) { uchar i; while(x--)for(i=0;i<120;i++); } void main() { uchar i; P0 = 0x00; P2 = 0x00; while(1)...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网