找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3247|回复: 17
打印 上一主题 下一主题
收起左侧

C51单片机问题请教,通过按键操作控制LCD1602的显示循环显示两个页面[已解决]

[复制链接]
跳转到指定楼层
楼主
这个问题困扰了我很久,十几天都没有解决,希望有站内大佬帮我一下。
1.问题描述:
通过按键操作控制LCD1602的显示循环显示两个页面。现有的现象是程序开始时,LCD屏保持在第一个页面不变,但是按动(按下再抬起)按钮后,LCD就自己不停的在两个页面之间循环跳变。只有在按下按钮不抬起来的时候LCD屏幕才能一直显示一个页面。PS:按键和LCD显示单独测试均正常,且引脚定义也已确定无误。
2.问题代码:#include<REG52.h>
#include"LCD1602.h"
#include"delay.h"
#include"Level_1Menu.h"
#include"Level_2Menu.h"
#include"Level_3Menu.h"
#include"Level_4Menu.h"
#include"EC11.h"
#include"PowerMode.h"
#include"interrupt.h"
#include"relay.h"


unsigned char menu = 0;

unsigned char  key_num = 0;

unsigned char EC11_Action()
{
        if(ENTER == 0)//判断ENTER键是否按下
                {
                        DelayXms(5);//延时消抖,时间一般为5-10ms
                        if(ENTER == 0)
                        {                        
                                key_num = 1;//分配ENTER的键值为“1”
                                while(ENTER == 0);//等待松手
                                LCDWriteCmd(LCD_SCREEN_CLR); //清屏
                        }

                }

        return key_num;        
}

unsigned char EC11_Scan()
{

        switch(EC11_Action())
        {
                case 0:break;
                case 1:menu++;if(menu>1) menu = 0;break;
                default:break;
        }
        return menu;
}


void LCDShowService()
{
                switch(EC11_Scan())
                {
                        case 0:BAIC_C62X();break;
                        case 1:BAIC_B40();break;
                        default:break;
                }        
}


void T0_Service() interrupt 1 using 0
{
        TR0=0;                 //关闭定时器
        TL0=0x33;    //低八位赋初值
        TH0=0XFE;    //高八位赋初值
        
        LCDShowService();

        TR0=1;//重新开启定时器        
}


void main()
{        
        LCDInit();
        T0_Init();
        while(1);
}



捕获.PNG (44.5 KB, 下载次数: 72)

捕获.PNG

DVP_MENU.rar

66.54 KB, 下载次数: 5

LCD驱动及相关模块

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:798631 发表于 2021-3-4 11:38 | 只看该作者
menu 的反转太快了   把反转速度降下来啊
回复

使用道具 举报

板凳
ID:888259 发表于 2021-3-4 11:40 | 只看该作者
问题补充:如果直接在EC11_Action()函数直接中做menu变量的增减操作,然后再中断函数中用switch函数处理menu的值,程序就没有问题。
回复

使用道具 举报

地板
ID:888259 发表于 2021-3-4 11:43 | 只看该作者
15830266185 发表于 2021-3-4 11:38
menu 的反转太快了   把反转速度降下来啊

您的意思是中断的时间太短了吗?我这边中断是5ms一次的,能否具体指明一下呢?谢谢啦
回复

使用道具 举报

5#
ID:798631 发表于 2021-3-4 11:51 | 只看该作者
中断是5ms一次             case 1:menu++;if(menu>1) menu = 0;break;  这句   menu反转就是10ms   
回复

使用道具 举报

6#
ID:888259 发表于 2021-3-4 11:54 | 只看该作者
15830266185 发表于 2021-3-4 11:51
中断是5ms一次             case 1:menu++;if(menu>1) menu = 0;break;  这句   menu反转就是10ms

我刚调整的定时中断时间为50ms,现象还是一样的。只是页面切换的没有那么快了。
回复

使用道具 举报

7#
ID:798631 发表于 2021-3-4 11:59 | 只看该作者
做成0.5秒切换啊      比方说  menu低于50显示 1界面  高于50显示2界面  =100 归0  调好计数就好
回复

使用道具 举报

8#
ID:451718 发表于 2021-3-4 12:03 | 只看该作者
定时器中断处理里面去操作定时器的开关,这不是一种好的程序结构思维。  你所预想的结果,并不一定是你希望得到的。  这样搞,不可预料的状态太多了,不是定时器的正确用法
回复

使用道具 举报

9#
ID:858964 发表于 2021-3-4 13:33 | 只看该作者
建议在按键处理函数中添加消除抖动的代码。
回复

使用道具 举报

10#
ID:888259 发表于 2021-3-4 13:38 | 只看该作者
robinsonlin 发表于 2021-3-4 12:03
定时器中断处理里面去操作定时器的开关,这不是一种好的程序结构思维。  你所预想的结果,并不一定是你希望 ...

的确在中断函数里不应该进行过多操作,所以我在进入定时器中断函数中就把中断给关闭了,等待按键处理完成后再把中断打开。这个是不是不会对程序有什么影响呢?
回复

使用道具 举报

11#
ID:888259 发表于 2021-3-4 13:42 | 只看该作者
15830266185 发表于 2021-3-4 11:59
做成0.5秒切换啊      比方说  menu低于50显示 1界面  高于50显示2界面  =100 归0  调好计数就好

您可能没有完全明白我的描述,我的按键处理是在定时器中断中做的操作,EC11_Action()这个函数仅是检测按键操作并分配一个key_num(键值),之后通过EC11_Scan()函数来捕获键值,通过判断键值来做menu的增减,menu的值实际是代表了所显示页面的索引。
回复

使用道具 举报

12#
ID:888259 发表于 2021-3-4 13:44 | 只看该作者
Kxuan163 发表于 2021-3-4 13:33
建议在按键处理函数中添加消除抖动的代码。

在EC11_Action()函数中已经做了DelayXms(5) 【5ms】的消抖了
回复

使用道具 举报

13#
ID:451718 发表于 2021-3-4 14:03 | 只看该作者
17826075805 发表于 2021-3-4 13:38
的确在中断函数里不应该进行过多操作,所以我在进入定时器中断函数中就把中断给关闭了,等待按键处理完成 ...

定时中断是有很高优先级的,你在高优先级的响应中,处理按键,也就是让主程序的都停下来,等着执行按键响应,而且是一直在循环执行。你的程序一直都在执行中断响应中,还有多少资源去响应主程序?
回复

使用道具 举报

14#
ID:888259 发表于 2021-3-4 14:06 | 只看该作者
17826075805 发表于 2021-3-4 13:38
的确在中断函数里不应该进行过多操作,所以我在进入定时器中断函数中就把中断给关闭了,等待按键处理完成 ...

如果不采用按键分配键值的办法,直接在EC11_Action()函数中做menu的增减操作,同样在中断函数中检测,其结果就表现正常了。只是这样做会影响代码结构,在多级菜单编程时会操作会十分繁琐。
回复

使用道具 举报

15#
ID:798631 发表于 2021-3-4 14:08 | 只看该作者
你的 key_num 没有归零处理  不就是menu一直自加么
回复

使用道具 举报

16#
ID:888259 发表于 2021-3-4 14:16 | 只看该作者
robinsonlin 发表于 2021-3-4 14:03
定时中断是有很高优先级的,你在高优先级的响应中,处理按键,也就是让主程序的都停下来,等着执行按键响 ...

进入定时器中断后,定时器关闭不再计时,中断函数可以安心处理其内部的操作,包含按键检测,LCD显示。待处理完成后定时器再次打开,准备进入下一次中断。main函数中的while(1)就是提供给中断处理任务的。有中断任务就处理,没有的话主程序也是一直等待呀。
回复

使用道具 举报

17#
ID:888259 发表于 2021-3-4 14:21 | 只看该作者
15830266185 发表于 2021-3-4 14:08
你的 key_num 没有归零处理  不就是menu一直自加么

强!刚试了一下,问题解决了,多谢啦。今后还请多指教。
回复

使用道具 举报

18#
ID:213173 发表于 2021-3-4 20:51 | 只看该作者
#include <REG52.h>
#include"LCD1602.h"
#include"delay.h"
#include"Level_1Menu.h"
#include"Level_2Menu.h"
#include"Level_3Menu.h"
#include"Level_4Menu.h"
#include"EC11.h"
#include"PowerMode.h"
#include"interrupt.h"
#include"relay.h"


//unsigned char menu = 0;

unsigned char  key_num = 0;

unsigned char EC11_Action()
{
        if(ENTER == 0)//判断ENTER键是否按下
        {
                DelayXms(5);//延时消抖,时间一般为5-10ms
                if(ENTER == 0)
                {                       
//                        key_num = 1;//分配ENTER的键值为“1”
                        key_num=++key_num%2;
                        while(ENTER == 0);//等待松手
                        LCDWriteCmd(LCD_SCREEN_CLR); //清屏
                }
        }
        return key_num;       
}
/*
unsigned char EC11_Scan()
{

        switch(EC11_Action())
        {
                case 0:break;
                case 1:menu++;if(menu>1) menu = 0;break;
                default:break;
        }
        return menu;
}
*/

void LCDShowService()
{
//        switch(EC11_Scan())
        switch(EC11_Action())
        {
                case 0:BAIC_C62X();break;
                case 1:BAIC_B40();break;
                default:break;
        }       
}

void T0_Service() interrupt 1 using 0
{
        TR0=0;                 //关闭定时器
        TH0=0XFE;    //高八位赋初值500
        TL0=0x33;    //低八位赋初值
        LCDShowService();
        TR0=1;//重新开启定时器       
}

void main()
{       
        LCDInit();
        T0_Init();
        while(1);
}

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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