找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2089|回复: 12
收起左侧

51单片机秒表程序问题,无论k2在何时按都会清零

[复制链接]
ID:562692 发表于 2019-6-18 11:37 | 显示全部楼层 |阅读模式
做了一个秒表,硬件是pz的开发板。效果是开机后,按下k1后开始计时,在四位共阴管上显示xx.yy。其中xx是分,yy是秒。
k1是启动/暂停键,k2是归零键,目的是短按k1实现定时器启动与关闭,在暂停模式下再按k2才可归零。
按键扫描程序如下图,问题是无论k2在何时按都会清零
void keyscan()
{        u8 keymod=0;
        if(k1==0)
        {
                delay(1000);
                if(k1==0)
                {
                        TR0=!TR0;
                        keymod=!keymod;               
                }
                while(!k1);
        }
        if(keymod==0)
        {
                if(k2==0)
                {
                        delay(1000);
                        if(k2==0)
                        {
                                sec=0,min=0,hour=0;               
                        }
                        while(!k2);
                }
        }
}
对此不是很理解,单片机才学了二十天左右,要是有愚蠢错误别打。 clock.zip (20 KB, 下载次数: 12)
回复

使用道具 举报

ID:552614 发表于 2019-6-18 15:36 | 显示全部楼层
你的keymod初始化就已经等于零了啊,直接进入if(keymod==o)里面的语句了
回复

使用道具 举报

ID:332444 发表于 2019-6-18 16:41 | 显示全部楼层
那就应该判断暂停模式状态后才使K2有效,逻辑问题
回复

使用道具 举报

ID:565305 发表于 2019-6-18 17:50 | 显示全部楼层
你这个函数是被别的函数调用吧, keymod 是一个局部变量,进一次函数就会初始化一次
void keyscan()
{        u8 keymod=0;

解决方法,要么这个变量设定为全局变量,要么透过入口参数传入
=======================
另外不得不说一下,这种到处写 while(!xxxxx) 真心要不得,阻塞主程序流程不说,还不方便做并行操作

=======================
//  请确保 main 函数的 while 循环和 delay_1ms 均存在并且不会超时。并且带下文三个全局变量
int  keymod=0;
int  k1_count=0, k2_count=0;
void main()
{
    while(1)   
    {
        scan_key();
        other_event_func();
        delay_1ms(); ....
     }
}

void scan_key()
{
    // 判断:两个按键必须有连续 10ms 处于按住(去抖)状态才能当做“有效按下”
    // 由于只需要判断按下瞬间,所以下文 100 的常量只是让其不溢出且大于 10ms 即可
    if(k1==0){ if(k1_count<100) k1_count++; } else k1_count=0;
    if(k2==0){ if(k2_count<100) k2_count++; } else k2_count=0;

    // 有按住的时序计数器了,那么计数器等于 10 的瞬间就是“按下瞬间”,而不是“按住瞬间”
    if(k1_count==10)
    {
        TR0=!TR0; keymod=!keymode;  // 进入状态切换
    }
    // k2 按下瞬间,只要 keymod==0 (暂停态),就做归零
    if(k2_count==10 && keymod==0)
    {
        sec=0;min=0;hour=0;  
    }
}


回复

使用道具 举报

ID:562692 发表于 2019-6-18 20:54 | 显示全部楼层
egypt 发表于 2019-6-18 17:50
你这个函数是被别的函数调用吧, keymod 是一个局部变量,进一次函数就会初始化一次
void keyscan()
{    ...

谢谢指点,发现只要把keymod设置成全局变量,然后用
if((k2==0)&&(keymod==0))
替换那两句就可以了
回复

使用道具 举报

ID:562692 发表于 2019-6-18 21:03 | 显示全部楼层
egypt 发表于 2019-6-18 17:50
你这个函数是被别的函数调用吧, keymod 是一个局部变量,进一次函数就会初始化一次
void keyscan()
{    ...

我是按照教程上学的while(!xxxx),学习教程是买开发板送的,原来不好啊。不知道您有什么好的教程推荐?
回复

使用道具 举报

ID:517466 发表于 2019-6-18 23:22 | 显示全部楼层
你的程序中有错误。定时器TR没有设成1,导致定时器不工作,没法计时。程序修改如下:
/*采用普中科技ES-V2.0开发板作为实验硬件*/
#include<reg52.h>
typedef unsigned int u16;
typedef unsigned char u8;

sbit LSA=P2^0;
sbit LSB=P2^1;
sbit LSC=P2^2;
sbit LSD=P2^3;
sbit k1=P3^1;  
sbit k2=P3^0;

u8 sec,min,hour;

u8 code  shuzu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                                  0x7f,0x6f,0x77};        //共阳数码管码表,code表示保存到flash空间,节省rom       
u8 code table[]={   // 共阴数码管,笔段=0时,笔段点亮。0-0xC0
    0xc0,0xf9,0xa4,0xb0,0x99,
        0x92,0x82,0xf8,0x80,0x90,0xff, 0xbf};
void delay(u16 i)
{
        while(i--);       
}
void Timer0Init()
{
        TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
        TH0=0X3c;        //给定时器赋初值,定时50ms
        TL0=0Xb0;       
        ET0=1;//打开定时器0中断允许
        EA=1;//打开总中断
        TR0=1;//关闭定时器                       
}
void keyscan()
{        u8 keymod=0;
        if(k1==0)
        {
                delay(1000);
                if(k1==0)
                {
                        TR0=!TR0;
                        keymod=!keymod;               
                }
                while(!k1);
        }
        if(keymod==0)
        {
                if(k2==0)
                {
                        delay(1000);
                        if(k2==0)
                        {
                                sec=0,min=0,hour=0;               
                        }
                        while(!k2);
                }
        }
}

void DigDisplay(u8 min,u8 sec)
{
        u8 i;
        for(i=0;i<4;i++)
        {
                switch(i)         //位选,选择点亮的数码管,
                {
                  // 共阴用
                        case(0):
                                LSA=0;LSB=1;LSC=1;LSD=1;P0=shuzu[min/10]; break;//显示第0位
                        case(1):
                                LSA=1;LSB=0;LSC=1;LSD=1;P0=shuzu[min%10];break;//显示第1位
                        case(2):
                                LSA=1;LSB=1;LSC=0;LSD=1;P0=shuzu[sec/10];break;//显示第2位
                        case(3):
                                LSA=1;LSB=1;LSC=1;LSD=0;P0=shuzu[sec%10]; break;//显示第3位                               
                }
    delay(100); //间隔一段时间扫描       
                // 共阴用
                P0=0x00;//消隐笔段
        }
}
void main()
{       
        Timer0Init();
        while(1)
        {       
                P1=sec;
                DigDisplay(min,sec);
                keyscan();
                       
        }               
}


void Timer0() interrupt 1
{
        static u16 i;
        TH0=0X3c;        //给定时器赋初值,定时50ms
        TL0=0Xb0;
        i++;
        if(i==20)
        {
                i=0;
                sec++;
                if(sec==60)
                {
                        sec=0;
                        min++;
                        if(min==60)
                        {
                                min=0;
                                hour++;
                                if(hour==99)
                                {
                                        hour=0;

                                }
                        }
                }       
        }       
}               
回复

使用道具 举报

ID:517466 发表于 2019-6-18 23:25 | 显示全部楼层
附上proteus的仿真文件

test.zip

15.92 KB, 下载次数: 10

回复

使用道具 举报

ID:207421 发表于 2019-6-19 01:08 | 显示全部楼层
其实把 u8 keymod=0; 变为全局变量,改为 u8 keymod=1; 就好了。
当按K1, TR0 =1; keymod=0;
此时 K2有效
回复

使用道具 举报

ID:565305 发表于 2019-6-19 08:46 | 显示全部楼层
带多个锁死 while 的程序,真正测试的时候,会发现有按键不响应的 BUG

你试着按住 k1 后不松手,再按 k2 ,试个两三次就知道了

或者按住 k2 不松手,再按 k1 看看功能正常不
回复

使用道具 举报

ID:566603 发表于 2019-6-19 11:36 | 显示全部楼层
将下面的if(keymod==0)改为if(keymod!=0)试试,keymod应该是在key1按下后取反,表示key1已经按下,那么下面的判断就不能是keymod==0,因为keymod的初始化情况就是0,当然按下key2会清零.-----建议仅供参考
回复

使用道具 举报

ID:160500 发表于 2019-6-19 16:39 | 显示全部楼层
建议你先画一个流程图,理清其中的逻辑关系,根据流程图再编程实现所需要的功能
回复

使用道具 举报

ID:564631 发表于 2019-6-19 17:49 | 显示全部楼层
void keyscan()
{        u8 keymod=0;
        if(k1==0)
        {
                delay(1000);
                if(k1==0)
                {
                        TR0=!TR0;
                        keymod=!keymod;               
                }
                while(!k1);
        }
        if(keymod==1)
        {
                if(k2==0)
                {
                        delay(1000);
                        if(k2==0)
                        {
                                sec=0,min=0,hour=0;               
                        }
                        while(!k2);
                }
        }
}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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