找回密码
 立即注册

QQ登录

只需一步,快速开始

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

关于LCD1602液晶光标的问题

[复制链接]
跳转到指定楼层
楼主
ID:446775 发表于 2021-3-1 16:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1602液晶的光标打开之后,本来是在设置好的位置进行闪烁的,但是闪烁一下后就跑到其它地方进行闪烁了,请问是什么原因呢?如图片所示,我通过按键动作,调用RightShiftSet()函数,而RightShiftSet()里又调用了RefreshCursorShow()函数,在RefreshCursorShow()函数里本来运行的是case1,设置完光标后,并且光标闪烁,结果在这个位置闪烁一下后,就跑到case4所设置的位置进行闪烁了,很奇怪,请教下各位这是什么原因造成的呢?

光标.png (33.86 KB, 下载次数: 42)

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

使用道具 举报

沙发
ID:883698 发表于 2021-3-1 17:04 | 只看该作者
你的程序字符写到一个位置,光标就在那里闪烁
回复

使用道具 举报

板凳
ID:446775 发表于 2021-3-1 17:20 | 只看该作者
小猫电子 发表于 2021-3-1 17:04
你的程序字符写到一个位置,光标就在那里闪烁

是写到一个位置,光标就在那里闪烁,但是它只在写的那个位置闪烁一下,就跑到其它位置了
回复

使用道具 举报

地板
ID:844772 发表于 2021-3-1 17:24 | 只看该作者
四连击啊,没看出程序问题,倒是像按键程序带连发功能,或是防抖问题?
回复

使用道具 举报

5#
ID:390416 发表于 2021-3-1 17:33 | 只看该作者
        switch(LCD1602_Write_Cursor_Add)
        {
                case 0:LCD1602_Write_Add(0x0C);break;//不显示也不闪烁光标
                case 1:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xCa);break;
                case 2:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xCd);break;
                case 3:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xC7);break;
                case 4:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xC4);break;
                case 5:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xC1);break;
                case 6:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0xCf);break;
                case 7:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0x89);break;
                case 8:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0x86);break;
                case 9:LCD1602_Write_Add(0x0F);LCD1602_Write_Add(0x83);break;
        }

像我这样做,使用一个全局变量来控制光标闪烁的位置。变量是0则不显示光标。
不要把设备互相包含,这样你会很乱的。比如执行某个计算过程调用显示,那就打乱了计算过程。
而显示的时候显示10次足够了。你每次计算都显示,那么计算1000次就显示了1000次,白白浪费了9900次的CPU时间。记住“什么是单片机?玩的就是时间!”
回复

使用道具 举报

6#
ID:473159 发表于 2021-3-1 21:07 | 只看该作者
坛子里有你这种代码,可以去下下来练练,几次就能明白
回复

使用道具 举报

7#
ID:446775 发表于 2021-3-2 14:17 | 只看该作者
人人学会单片机 发表于 2021-3-1 17:33
switch(LCD1602_Write_Cursor_Add)
        {
                case 0:LCD1602_Write_Add(0x0C);break;//不显示也不闪烁光标

您这个没每个选项是连续执行的嘛?比如所我执行完1之后,下一次进入就执行2这样子,还是说是随机的,并不是连续的,还有就是每个选项里都有打开光标,后面的是写入的光标位置嘛?
回复

使用道具 举报

8#
ID:446775 发表于 2021-3-2 15:19 | 只看该作者
glinfei 发表于 2021-3-1 17:24
四连击啊,没看出程序问题,倒是像按键程序带连发功能,或是防抖问题?

使用的是薄膜键盘,触发时间只有10ms左右,没有进行消抖。
回复

使用道具 举报

9#
ID:213173 发表于 2021-3-2 16:27 | 只看该作者
1602液晶的光标默认显示方式是写一个字节自动移动1格。如果要保持光标闪烁位置不变就要在写数据后立即写前面相同命令,使光标位置不变,例如:
write_com(0x80+5);
write_date('2');
write_com(0x80+5);
回复

使用道具 举报

10#
ID:446775 发表于 2021-3-2 22:23 | 只看该作者
wulin 发表于 2021-3-2 16:27
1602液晶的光标默认显示方式是写一个字节自动移动1格。如果要保持光标闪烁位置不变就要在写数据后立即写前 ...

嗯嗯,是的,但是我这个是设置一个光标位置,然后键盘输入数字,光标应该还是跟着这个数字的位置,但是现在它不是,光标跑到另外一个位置了
回复

使用道具 举报

11#
ID:213173 发表于 2021-3-3 09:17 | 只看该作者
karolyte 发表于 2021-3-2 22:23
嗯嗯,是的,但是我这个是设置一个光标位置,然后键盘输入数字,光标应该还是跟着这个数字的位置,但是现 ...

没有一招通吃的方法,要依据功能要求和硬件环境构建程序框架和编写代码。
回复

使用道具 举报

12#
ID:462827 发表于 2021-3-3 10:01 | 只看该作者
有新的显示字符,光标位置当然就变了
回复

使用道具 举报

13#
ID:446775 发表于 2021-3-4 14:35 | 只看该作者
hantu 发表于 2021-3-3 10:01
有新的显示字符,光标位置当然就变了

但是改变的位置没有新的显示字符啊,它自己就改变位置了,确实是很奇怪的现象
回复

使用道具 举报

14#
ID:446775 发表于 2021-3-14 21:53 | 只看该作者
wulin 发表于 2021-3-2 16:27
1602液晶的光标默认显示方式是写一个字节自动移动1格。如果要保持光标闪烁位置不变就要在写数据后立即写前 ...

嗯嗯,我这个实际是这个样子的,就是把光标设置一个位置,然后打开光标,再然后在这个位置输入数字,这个数字的位数不定。现在的问题是在我打开光标时,还没有输入数字呢,这个光标就跑到位置列表的最后一个位置了。这个设置光标位置和打开光标我是通过一个按键执行的。而输入数字的方式有两种,一种是通过数字键盘输入,一种是实时读取传感器的数据,这两种方式我在数字按键的动作函数里加了判断,来进行选择是用哪种方式进行输入。
程序里涉及到光标位置的有光标右移、光标位置设置、输入数字,删除数字这几个函数。
  1. /*设置光标位置,打开光标*/
  2. void RefreshCursorShow()
  3. {
  4.     switch(setIndex)
  5.     {
  6.         case 1:LcdSetCursor(4,0);LcdWriteCmd(0x0F);break;
  7.         case 2:LcdSetCursor(10,0);break;
  8.         case 3:LcdSetCursor(2,1);break;
  9.         case 4:LcdSetCursor(10,1);break;
  10.         case 5:LcdWriteCmd(0x0C);setIndex = 0;break;
  11.         default:break;
  12.     }
  13. }
  14. /*光标移动操作函数,配合按键0x1B动作*/
  15. void RightShiftSet()
  16. {
  17.     if(setIndex <= 4)
  18.     {
  19.         setIndex++;
  20.         RefreshCursorShow(); //设置光标位置,并打开光标
  21.     }  
  22. }

  23. /*按键动作函数,执行相应的动作*/
  24. void KeyAction(unsigned char keycode)
  25. {
  26.    if((keycode >= '0') && (keycode <= '9'))   //输入数字
  27.    {
  28.         NumKeyAction(keycode - '0');
  29.    }
  30.    else if(keycode == 0x26)       //各特征值的切换
  31.    {
  32.         FunKeyAction();
  33.    }
  34.    else if(keycode == 0x1B)      //光标的循环移动
  35.    {
  36.         RightShiftSet();   
  37.    }
  38.    else if(keycode == 0x27)      //删除当前数据
  39.    {
  40.         Deldata();       
  41.    }
  42.    else if(keycode == 0x23)      //去皮清零
  43.    {
  44.         ClearZeroKeyAction();
  45.    }
  46.    else if(keycode == 0x40)      //将当前A\B\C数据写入
  47.    {
  48.         WriteInDATA();
  49.         LcdAreaClear(10,0,6);
  50.         LcdAreaClear(2,1,6);
  51.         LcdAreaClear(10,1,6);
  52.    }
  53.    else if(keycode == 0x25)      //读出当前特征值的A\B\C数据
  54.    {
  55.         ReadOutDATA();
  56.    }
  57.    else if(keycode == 0x28)      //校正计算
  58.    {
  59.         EA = 0;
  60.         transition();
  61.         EA = 1;
  62.    }
  63.    else if(keycode == 0x0D)      //切换显示(实时和功能的切换)
  64.    {
  65.         SwDisplayKeyAction();
  66.    }
  67.    else if(keycode == 0x2B)      //校准值加
  68.    {
  69.         if(T2 < 50)
  70.         {
  71.             T2++;
  72.         }
  73.    }
  74.    else if(keycode == 0x2C)      //校准值减
  75.    {
  76.         if(T2 > 0)
  77.         {
  78.             T2--;
  79.         }
  80.    }
  81. }

  82. /*数字键动作函数,n-按键输入的数值*/
  83. void NumKeyAction(unsigned int n)
  84. {   
  85.     long xdata xe = 50;
  86.    
  87.     switch(setIndex)
  88.     {
  89.         case 1:
  90.             num0 = num0 * 10 + n;
  91.             GuigeToString(number,num0);
  92.             LcdShowStr(4,0,number);
  93.             num1 = 0;
  94.             break;
  95.         case 2:
  96.             if(Getval < xe)
  97.             {
  98.                 num1 = num1 * 10 + n;   
  99.             }
  100.             else
  101.             {
  102.                 num1 = Getval;
  103.             }
  104.             ValueToString(str,num1);
  105.             LcdShowStr(10,0,str);
  106.             num2 = 0;
  107.             break;
  108.         case 3:
  109.             if(Getval < xe)
  110.             {
  111.                 num2 = num2 * 10 + n;   
  112.             }
  113.             else
  114.             {
  115.                 num2 = Getval;
  116.                 num2 += num1;
  117.             }
  118.             ValueToString(str,num2);
  119.             LcdShowStr(2,1,str);
  120.             num3 = 0;
  121.             break;
  122.         case 4:
  123.             if(Getval < xe)
  124.             {
  125.                 num3 = num3 * 10 + n;   
  126.             }
  127.              else
  128.             {
  129.                 num3 = Getval;
  130.                 num3 += num2;
  131.             }
  132.             ValueToString(str,num3);
  133.             LcdShowStr(10,1,str);        
  134.             num0 = 0;
  135.             break;
  136.         default:
  137.             break;
  138.     }
  139. }

  140. /*删除当前数据*/
  141. void Deldata()
  142. {
  143.     switch(setIndex)
  144.     {
  145.         case 1:
  146.             LcdAreaClear(4,0,4);
  147.             num0 = 0;
  148.             RefreshCursorShow();
  149.             break;
  150.         case 2:
  151.             LcdAreaClear(10,0,6);
  152.             num1 = 0;
  153.             RefreshCursorShow();
  154.             break;
  155.         case 3:
  156.             LcdAreaClear(2,1,6);
  157.             num2 = 0;
  158.             RefreshCursorShow();
  159.             break;
  160.         case 4:
  161.             LcdAreaClear(10,1,6);
  162.             num3 = 0;
  163.             RefreshCursorShow();
  164.             break;
  165.         default:
  166.             break;   
  167.     }           
  168. }
复制代码

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

15#
ID:213173 发表于 2021-3-15 06:50 | 只看该作者
karolyte 发表于 2021-3-14 21:53
嗯嗯,我这个实际是这个样子的,就是把光标设置一个位置,然后打开光标,再然后在这个位置输入数字,这个 ...

单从代码片段不易判断问题所在,要看全码,从程序框架结构查找。
回复

使用道具 举报

16#
ID:446775 发表于 2021-3-15 08:54 | 只看该作者
wulin 发表于 2021-3-15 06:50
单从代码片段不易判断问题所在,要看全码,从程序框架结构查找。

全码在此,可能有点大,另外源文件较多,请查看!

全码.rar

119.12 KB, 阅读权限: 50, 下载次数: 6

回复

使用道具 举报

17#
ID:889832 发表于 2021-3-15 11:23 | 只看该作者
看程序
指令有没有问题
回复

使用道具 举报

18#
ID:446775 发表于 2021-3-15 21:04 | 只看该作者
wulin 发表于 2021-3-15 06:50
单从代码片段不易判断问题所在,要看全码,从程序框架结构查找。

您看下问题出在哪里?
回复

使用道具 举报

19#
ID:213173 发表于 2021-3-15 22:37 | 只看该作者
karolyte 发表于 2021-3-15 21:04
您看下问题出在哪里?

代码太长,看得实在头疼。给你写了一个示例程序,非常简单明了,可以清楚的表达在什么时候开光标,什么时候关光标,光标位置控制方式。 LCD1602时钟光标演示 仿真.zip (116.82 KB, 下载次数: 46)

评分

参与人数 2黑币 +35 收起 理由
karolyte + 15 绝世好帖!
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

20#
ID:446775 发表于 2021-3-16 11:26 | 只看该作者
wulin 发表于 2021-3-15 22:37
代码太长,看得实在头疼。给你写了一个示例程序,非常简单明了,可以清楚的表达在什么时候开光标,什么时 ...

,让您受累了,谢谢您,我先看一下
回复

使用道具 举报

21#
ID:446775 发表于 2021-3-16 22:54 | 只看该作者
wulin 发表于 2021-3-15 22:37
代码太长,看得实在头疼。给你写了一个示例程序,非常简单明了,可以清楚的表达在什么时候开光标,什么时 ...

您好,您发的代码我看了,光标的控制确实很清晰,我采纳了您的方法,发现问题还是没有解决,感觉这个问题不是光标位置控制的问题,您看会不会是因为按键抖动引起的呢?因为打开光标,并设定第一个位置后,它在这个位置闪烁一下后就跑到位置列表中的最后一个位置了
回复

使用道具 举报

22#
ID:213173 发表于 2021-3-17 07:03 | 只看该作者
karolyte 发表于 2021-3-16 22:54
您好,您发的代码我看了,光标的控制确实很清晰,我采纳了您的方法,发现问题还是没有解决,感觉这个问题 ...

由于LcdShowStr函数写的是指针字符串,字符量1~n个,光标位置当然随着字符量移动。要把光标控制在初始位置必须在写完字符串后再次给光标指定坐标。
/*在液晶上显示字符串,(x,y)为对应屏幕上的起始坐标,str为字符串指针*/
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)
{
    LcdSetCursor(x,y);                  //设置起始地址
    while(*str != '\0')                 //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
        LcdSetCursor(x,y);//回到起始地址
}
回复

使用道具 举报

23#
ID:446775 发表于 2021-3-17 09:46 | 只看该作者
wulin 发表于 2021-3-17 07:03
由于LcdShowStr函数写的是指针字符串,字符量1~n个,光标位置当然随着字符量移动。要把光标控制在初始位 ...

嗯嗯,可能是我没有表达清楚,我说的是光标跑到其它位置指的是,比如我现在在1602上定义的有4个位置,分别是(0,0,(5,0),(1,1)(5,1),这4个位置都需要输入数字,那么我现在在设置位置1(0,0)的时候,打开光标,光标在这个位置上闪烁一下,然后就跑到位置4(5,1)上了,并在这个位置上闪烁,然后我移动光标到位置2(5,0)上,光标也是在这个位置上闪烁一下,然后还是跑到位置4(5,1)上了,接着我移动光标到位置3(1,1)上,同样的,也是在这个位置上闪烁一下,还跑到位置4(5,1)上了,在把光标移动到位置4(5,1)时,就不知道到底光标是不是在这个位置上,因为前三个位置时,它就在这个位置4(5,1)上了,就是说,我移动位置都没问题,并且在相应的位置上都能够正常输入数字,也能正常显示数字,这都没问题,就是这个光标它不持续在给它设置的位置上
回复

使用道具 举报

24#
ID:213173 发表于 2021-3-17 13:54 | 只看该作者
karolyte 发表于 2021-3-17 09:46
嗯嗯,可能是我没有表达清楚,我说的是光标跑到其它位置指的是,比如我现在在1602上定义的有4个位置,分 ...

只要是光标跑到其它位置就说明有其它程序运行了LcdSetCursor(x,y); 你再在恰当地方运行LcdSetCursor(x,y); 把光标拉回来。
回复

使用道具 举报

25#
ID:446775 发表于 2021-3-18 14:10 | 只看该作者
wulin 发表于 2021-3-17 13:54
只要是光标跑到其它位置就说明有其它程序运行了LcdSetCursor(x,y); 你再在恰当地方运行LcdSetCursor(x,y) ...

确实是在有其它程序运行了LcdSetCursor(x,y),不过这个程序主函数的while(1)里,是需要一直运行的,我再看看能不能改改,非常感谢您的帮助!
回复

使用道具 举报

26#
ID:446775 发表于 2021-3-18 17:06 | 只看该作者
wulin 发表于 2021-3-17 13:54
只要是光标跑到其它位置就说明有其它程序运行了LcdSetCursor(x,y); 你再在恰当地方运行LcdSetCursor(x,y) ...

我这个问题的原因找到了,就拿您发的那个程序来说,是显示时间的,但是不显示"时分秒"这三个字符,如果要显示这三个字符,就需要设置显示位置,而且还需要在主函数的while(1)里一直显示,那么就会一直运行LcdSetCursor(x,y)了,现在就是想办法让这个LcdSetCursor(x,y)只运行一次,并且要擦除这一次的设置,还不能影响字符的正常显示。
回复

使用道具 举报

27#
ID:213173 发表于 2021-3-18 19:53 | 只看该作者
karolyte 发表于 2021-3-18 17:06
我这个问题的原因找到了,就拿您发的那个程序来说,是显示时间的,但是不显示"时分秒"这三个字符,如果要 ...

对于固定字符是不需要刷新的,还以上面那个示例来说,时分秒之间的:号初始化时只写一次,以后不再刷新。除非需要交替显示其它内容。
回复

使用道具 举报

28#
ID:446775 发表于 2021-3-19 09:54 | 只看该作者
wulin 发表于 2021-3-18 19:53
对于固定字符是不需要刷新的,还以上面那个示例来说,时分秒之间的:号初始化时只写一次,以后不再刷新。 ...

嗯嗯,如果是需要切换界面,并且另外一个界面显示的数字是实时读取的,这个实时读取的就需要不断的刷新了吧,怎样解决这个需要不断刷新和不需要刷新的切换呢?
回复

使用道具 举报

29#
ID:446775 发表于 2021-3-19 10:13 | 只看该作者
karolyte 发表于 2021-3-19 09:54
嗯嗯,如果是需要切换界面,并且另外一个界面显示的数字是实时读取的,这个实时读取的就需要不断的刷新了 ...

这个切换就涉及到不需要刷新的部分,它有光标定位,就是运行了LcdSetCursor(x,y),就是光标不在设定的位置上的问题,这些都是连在一起的问题
回复

使用道具 举报

30#
ID:213173 发表于 2021-3-19 13:13 | 只看该作者
karolyte 发表于 2021-3-19 10:13
这个切换就涉及到不需要刷新的部分,它有光标定位,就是运行了LcdSetCursor(x,y),就是光标不在设定的位置 ...

前面好多说法主要是针对查找问题所在何处。如果是需要切换界面,并且另外一个界面显示的数字是要实时更新的,不可能到处去跟踪恢复闪烁地址。这样做程序会很凌乱,不易读且效率低下。解决问题的根本做法是重新搭建程序构架,避免发生此类冲突。在19楼发给你的示例虽然简单,但程序构架明晰,功能模块相对独立,不论是添加功能或修改参数就可避免了互相牵扯。本来模块化编程就是为了避免互相牵扯,易于移植。结果却弄成乱麻。
回复

使用道具 举报

31#
ID:446775 发表于 2021-3-21 11:41 | 只看该作者
wulin 发表于 2021-3-19 13:13
前面好多说法主要是针对查找问题所在何处。如果是需要切换界面,并且另外一个界面显示的数字是要实时更新 ...

嗯嗯,是不是说像1602这种液晶的话不适合做界面切换的项目呢,听您这么说感觉也挺复杂的,我这个项目的代码也比较多,如果重新构建架构的话,应该是只构建显示部分的吧
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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