找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4431|回复: 29
收起左侧

求助:写了个数码管闹钟程序,有几个地方调不出来。

[复制链接]
ID:121267 发表于 2016-5-16 20:33 | 显示全部楼层 |阅读模式
8位LED数码管可调闹钟。



8个LED数码管88-88-88这样。
采用 2个锁存器输出 段选,位选。
采用3个独立按键:
1、SET(按一下调整秒钟,在按一下调整分钟,按三下调整小时,按4下完成调整。)

2、加减按键,按一下,就加减一个数字。先由SET选择调试 小时 还是分钟, 然后按加减键 调节数字。

问题:
1、SET键那里我采用的是记录键值思路。

    按一下SET ,  keynumber=1,  TR0=0 暂停计时,
  按下加按键,  如果键值=1、2或者3,   秒、分钟或者小时的计数变量加一。

但是问题就来了, 按下SET 键后 有的时候是  调节小时,有的时候是调节分钟,有的时候没变化。
下面是原理图 和 程序。


电路原理图

电路原理图
回复

使用道具 举报

ID:121267 发表于 2016-5-16 20:49 | 显示全部楼层
#include<reg51.h>
#define uchar unsigned char
uchar code led[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x040,0x80};
sbit duEN=P3^6;
sbit weiEN=P3^7;
sbit k0=P2^0;
sbit k1=P2^1;
sbit k2=P2^2;
char countsec,countmin,counthou;
uchar flag;
char key;
延时程序略过。

键盘扫描。
void keyboard()
{
                if(k0==0)
                                {
                                       键盘消抖。
                                        ys(50);
                                        if(k0==0)
                                        {
                                                松手检测。
                                                while(!k0)
                                                {
                                                        key++;                                                       
                                                        TR0=0;
                                                        if(key==4)
                                                        {
                                                                key=0;
                                                                TR0=1;
                                                        }
                                                }
                                        }
                                }
               

                                if(k1==0)
                                {
                                        ys(50);
                                        if(k1==0)
                                        {
                                       
                                                 while(!k1);
                                                        if(key==1)
                                                        {
                                                        countsec++;
                                                        if(countsec==60)
                                                        countsec=0;
                                                        }
                                                        if(key==2)
                                                        {
                                                        countmin++;
                                                        if(countmin==60)
                                                        countmin=0;
                                                        }
                                                        if(key==3)
                                                        {
                                                        counthou++;
                                                        if(counthou==24)
                                                        counthou=0;
                                                        }
                                        }
                                }


                                if(k2==0)
                                {
                                        ys(50);
                                        if(k2==0)
                                        {
                                                while(!k2);
                                                        if(key==1)
                                                        {
                                                        countsec--;
                                                        if(countsec==-1)
                                                        countsec=59;
                                                        }
                                                        if(key==2)
                                                        {
                                                        countmin--;
                                                        if(countmin==-1)
                                                        countmin=59;
                                                        }
                                                        if(key==3)
                                                        {
                                                        counthou--;
                                                        if(counthou==-1)
                                                        counthou=23;
                                                }
                                        }
                                }

}
一共8位,有点长,就发一段吧,其他都是一样的。
void ledxs()
{  
        P0=led[counthou/10];
        duEN=1;       
        duEN=0;
        P0=wei[0];       
        weiEN=1;       
        weiEN=0;
        ys(5);
以下为消隐,求教 为什么这样可以消隐。按我理解 先给P0赋值,然后开锁存器使能,瞬间值就付给锁存,然后关使能。应该不会出现鬼影的。事           实是不加下面几句,仿真中时钟乱显示。
        P0=0xff;           
        duEN=1;                              
        duEN=0;

}

主程序: T0初始化,最后不断扫描键盘和显示,等待中断发生,从而刷新显示。

void main()
{
        TMOD=0X01;
        TH0=(65536-45872)/256;
        TL0=(65536-45872)%256;
        EA=1;
        ET0=1;
        TR0=1;
        while(1)
        {
               
        keyboard();                       
        ledxs();

        }                                          
}


中断子程序:秒计数。

void timer0() interrupt 1 using 0
{
        flag++;       
        if(flag==20)
                {
                        flag=0;
                        countsec++;}
        if(countsec==60)
        {
                countsec=0;
                countmin++;        }
        if(countmin==60)
        {
                countmin=0;
                counthou++;        }
        if(counthou==24)
        {
                counthou=0;
        }
        TH0=(65536-45872)/256;
        TL0=(65536-45872)%256;
}


回复

使用道具 举报

ID:121267 发表于 2016-5-16 20:55 | 显示全部楼层
oh, fvck。 整理排版的时候发现,我SET键(K0) 的松手检测写错了。 写成下面这个:
                                                while(!k0)
                                                {
                                                        key++;                                                        
                                                        TR0=0;
                                                        if(key==4)
                                                        {
                                                                key=0;
                                                                TR0=1;
                                                        }
                                                } MD 怪不得  按了这个键是调整小时还是分钟,是无规律的,等待松手的时候不知道KEY加了多少次。
修改之后 。仿真没有问题了。
                                               while(!k0);
                                                        key++;                                                        
                                                        TR0=0;
                                                        if(key==4)
                                                        {
                                                                key=0;
                                                                TR0=1;
                                                        }
                                                
回复

使用道具 举报

ID:121267 发表于 2016-5-16 21:14 | 显示全部楼层
还有几个问题。

我采用的是共阳极数码管, 使用锁存器作为驱动。1、位选 是不是  为1的时候  允许该位显示?
如果采用9012 PNP三极管作为驱动,是不是  某个位控制I0口输出为0的时候允许该位点亮。
看网上程序的时候 没注意每个人的驱动方法不一样,只发现同样共阳怎么位选不一样, 把我搞晕了,所以请教一下大家,给我个准确答复。
2、数码管 消隐,共阳极数码管段选  是低电平有效。消隐就是关闭所有发光管,就是P0=0xff?
关于消隐程序 我最开始用的 郭天祥的, 如下:
         duEN=1;               
        P0=led[counthou/10];       
        duEN=0;
        P0=0Xff;       
        weiEN=1;       
        P0=wei[0];
        weiEN=0;
        ys(5);
居然 没法显示, 然后 从网上学了 这种:
        P0=led[counthou/10];
        duEN=1;       
        duEN=0;
        P0=wei[0];       
        weiEN=1;       
        weiEN=0;
        ys(5);
        P0=0xff;
        duEN=1;
        duEN=0;

消隐这个 我知道就是关掉P0,以免动态显示要输出下一位时,把上一位的段选给输过去.  我感觉我理解的很糙,还请大家帮我梳理一下。
然后还有一个单片机 跑程序的流程就是   逐行扫描运行,好像还默认的从头到尾不断循环。这个理解是不是对的?这个也请大家帮我梳理一下。

还有一个问题。
我想做成    按下SET键后,调整秒钟/分钟/时钟的时候, 秒/分/时的那2位会闪烁,这个怎么做?我完全没有思路。


回复

使用道具 举报

ID:7485 发表于 2016-5-16 22:33 | 显示全部楼层
本帖最后由 ahshmj 于 2016-5-16 22:35 编辑

不是“键值”,是按键次数。设一个计数器,每按一次加1 。根据这个计数值,确定调整的项目。当然循环完后转回0或1,

当需要调的项目需要闪烁时,可以用另一个定时器中断方法,一般取0.3~0.5秒中断一次,每次中断变换一次,在输出正常的段码和全灭之间变换即可。

我做的是设一个标志,中断一次标志转换一次,调显示程序时,根据标志输出亮、灭。
回复

使用道具 举报

ID:111634 发表于 2016-5-17 07:45 | 显示全部楼层
本帖最后由 zl2168 于 2016-5-17 08:58 编辑

模拟电子钟(由80C51定时器产生秒时基)已在本坛“51单片机”专栏2016.5.11上传,可参阅。
图7-13.jpg





K0K1K2具有时钟校正功能,其控制过程为:


按下K0(带锁),进入时钟修正;首先,时数据(包括时十位、时个位)快速闪烁(亮暗各131ms);


按一次K1(不带锁),被修正数据(快速闪烁)按时、分、秒(同时包括十位、个位)次序右移(循环往复);


按一次K2(不带锁),被修正数据整体加1(最大值不超过时钟规定值,超过复0);时钟修正期间,计时继续运行;


释放K0,退出时钟修正。



回复

使用道具 举报

ID:121267 发表于 2016-5-17 19:55 | 显示全部楼层
zl2168 发表于 2016-5-17 07:45
模拟电子钟(由80C51定时器产生秒时基)已在本坛“51单片机”专栏2016.5.11上传,可参阅。

谢谢,我去看看。
回复

使用道具 举报

ID:121267 发表于 2016-5-17 20:51 | 显示全部楼层
zl2168 发表于 2016-5-17 07:45
模拟电子钟(由80C51定时器产生秒时基)已在本坛“51单片机”专栏2016.5.11上传,可参阅。

好的,我去看看,谢谢了。
回复

使用道具 举报

ID:121267 发表于 2016-5-17 21:01 | 显示全部楼层
ahshmj 发表于 2016-5-16 22:33
不是“键值”,是按键次数。设一个计数器,每按一次加1 。根据这个计数值,确定调整的项目。当然循环完后转 ...

我试了一下,不知道是不是我没弄好。 结果是8位全部都在闪烁,就是动态扫描  显示延时 设太长的那种现象。我没用 2个定时器,因为我还不知道怎么设中断优先。待会学习下。然后在试一下。
回复

使用道具 举报

ID:111634 发表于 2016-5-19 18:38 | 显示全部楼层
本帖最后由 zl2168 于 2016-5-19 18:42 编辑

模拟电子钟(由80C51定时器产生秒时基)已在本坛“51单片机”专栏2016.5.11上传,可参阅。




图7-13.jpg




开机显示000秒,随后开始计时运行,2组发光二极管秒闪烁(亮暗各500ms。同时要求K0K1K2具有时钟校正功能,其控制过程为:按下K0(带锁),进入时钟修正;首先,时数据(包括时十位、时个位)快速闪烁(亮暗各131ms);按一次K1(不带锁),被修正数据(快速闪烁)按时、分、秒(同时包括十位、个位)次序右移(循环往复);按一次K2(不带锁),被修正数据整体加1(最大值不超过时钟规定值,超过复0);时钟修正期间,计时继续运行;释放K0,退出时钟修正。


实例94 模拟电子钟(由80C51定时器产生秒时基).rar (43.05 KB, 下载次数: 10)
回复

使用道具 举报

ID:111634 发表于 2016-5-19 21:13 | 显示全部楼层
试试上述模拟电子钟Proteus仿真演示,包你满意。
回复

使用道具 举报

ID:121267 发表于 2016-5-21 10:24 | 显示全部楼层
zl2168 发表于 2016-5-19 21:13
试试上述模拟电子钟Proteus仿真演示,包你满意。

恩! 我看了下,确实给力。谢谢了,让我知道有 74595这种 驱动。
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:25 | 显示全部楼层
本帖最后由 zl2168 于 2016-5-21 10:26 编辑

模拟电子钟程序如下:
disp6.jpg

key.jpg











t0t1.jpg
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:29 | 显示全部楼层
上述电路和程序引自张志良编著《单片机实验实训100例》 ISBN 978-7-5124-1603-1,北航社出版、《80C51单片机实用教程》ISBN 978-7-04-044532-9,高教社出版。欢迎咨询,zzlls@126.com
回复

使用道具 举报

ID:121267 发表于 2016-5-21 10:31 | 显示全部楼层
zl2168 发表于 2016-5-19 21:13
试试上述模拟电子钟Proteus仿真演示,包你满意。

前辈,请教一下,uchar 是无符号的吧。 可是在时钟里  按键调时间的时候,用到一句 :  如果减计数按键被按下,秒计数减一,如果秒计数=-1,秒计数=59。
我的秒计数变量是 uchar型的, uchar不是无符号吗?为什么程序 可以编译成功,仿真也可以用呢?

                                                       if(k1==0)
                                                       {
                                                            countsec--;
                                                            if(countsec==-1)
                                                            countsec=59;
                                                        }
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:39 | 显示全部楼层
为什么要秒计数减一?时钟都是加一的。你看我的程序,加到60,复0.
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:42 | 显示全部楼层
啊哦!你可能是到计时秒表。介绍你一本书,张志良编著《单片机实验实训100例》 ISBN 978-7-5124-1603-1,北航社出版,里面有99.9秒表和能预设初值的倒计时秒表实例。
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:55 | 显示全部楼层
啊哦!我知道你问的问题了。-1是补码,255,仍属于uchar。
回复

使用道具 举报

ID:111634 发表于 2016-5-21 10:57 | 显示全部楼层
0-1=255
回复

使用道具 举报

ID:121495 发表于 2016-5-21 14:41 | 显示全部楼层
还是用lcd1602写比较实用点
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:27 | 显示全部楼层
这是一个题目。有LED显示,也有LCD显示。本题是LED显示。
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:30 | 显示全部楼层
还有秒基准取自于外时钟芯片,还是取自于内振荡时钟。本题是内振荡时钟,分频后产生秒基准。
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:32 | 显示全部楼层
介绍你一本书,张志良编著《单片机实验实训100例》 ISBN 978-7-5124-1603-1,北航社出版,里面有4种1302的电路、程序和仿真案例
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:37 | 显示全部楼层
上述4种1302的电路、程序和仿真案例已上传至本坛“51单片机”专栏
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:38 | 显示全部楼层
2016-5-3 本人上传的“开机显示PC机时间的时钟1302”(1602显示)
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:38 | 显示全部楼层
2016-5-4 本人上传的“具有校正功能的时钟1302”(1602显示)
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:38 | 显示全部楼层
2016-5-5 本人上传的“开机显示PC机时分秒的时钟1302”(LED数码管显示)
回复

使用道具 举报

ID:111634 发表于 2016-5-21 15:39 | 显示全部楼层
2016-5-6 本人上传的“具有校正功能的时钟1302(LED数码管显示)”
回复

使用道具 举报

ID:111634 发表于 2016-5-21 19:49 | 显示全部楼层
Proteus仿真试了没有?试后满意再谢。
回复

使用道具 举报

ID:121267 发表于 2016-5-23 11:19 | 显示全部楼层
zl2168 发表于 2016-5-21 19:49
Proteus仿真试了没有?试后满意再谢。

试过了!效果很好,谢谢了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表