找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 8598|回復: 30
收起左側(cè)

關(guān)于LCD1602液晶光標的問題

[復制鏈接]
ID:446775 發(fā)表于 2021-3-1 16:40 | 顯示全部樓層 |閱讀模式
1602液晶的光標打開之后,本來是在設(shè)置好的位置進行閃爍的,但是閃爍一下后就跑到其它地方進行閃爍了,請問是什么原因呢?如圖片所示,我通過按鍵動作,調(diào)用RightShiftSet()函數(shù),而RightShiftSet()里又調(diào)用了RefreshCursorShow()函數(shù),在RefreshCursorShow()函數(shù)里本來運行的是case1,設(shè)置完光標后,并且光標閃爍,結(jié)果在這個位置閃爍一下后,就跑到case4所設(shè)置的位置進行閃爍了,很奇怪,請教下各位這是什么原因造成的呢?
光標.png
回復

使用道具 舉報

ID:883698 發(fā)表于 2021-3-1 17:04 | 顯示全部樓層
你的程序字符寫到一個位置,光標就在那里閃爍
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-1 17:20 | 顯示全部樓層
小貓電子 發(fā)表于 2021-3-1 17:04
你的程序字符寫到一個位置,光標就在那里閃爍

是寫到一個位置,光標就在那里閃爍,但是它只在寫的那個位置閃爍一下,就跑到其它位置了
回復

使用道具 舉報

ID:844772 發(fā)表于 2021-3-1 17:24 | 顯示全部樓層
四連擊啊,沒看出程序問題,倒是像按鍵程序帶連發(fā)功能,或是防抖問題?
回復

使用道具 舉報

ID:390416 發(fā)表于 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則不顯示光標。
不要把設(shè)備互相包含,這樣你會很亂的。比如執(zhí)行某個計算過程調(diào)用顯示,那就打亂了計算過程。
而顯示的時候顯示10次足夠了。你每次計算都顯示,那么計算1000次就顯示了1000次,白白浪費了9900次的CPU時間。記住“什么是單片機?玩的就是時間!”
回復

使用道具 舉報

ID:473159 發(fā)表于 2021-3-1 21:07 | 顯示全部樓層
壇子里有你這種代碼,可以去下下來練練,幾次就能明白
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-2 14:17 | 顯示全部樓層
人人學會單片機 發(fā)表于 2021-3-1 17:33
switch(LCD1602_Write_Cursor_Add)
        {
                case 0:LCD1602_Write_Add(0x0C);break;//不顯示也不閃爍光標

您這個沒每個選項是連續(xù)執(zhí)行的嘛?比如所我執(zhí)行完1之后,下一次進入就執(zhí)行2這樣子,還是說是隨機的,并不是連續(xù)的,還有就是每個選項里都有打開光標,后面的是寫入的光標位置嘛?
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-2 15:19 | 顯示全部樓層
glinfei 發(fā)表于 2021-3-1 17:24
四連擊啊,沒看出程序問題,倒是像按鍵程序帶連發(fā)功能,或是防抖問題?

使用的是薄膜鍵盤,觸發(fā)時間只有10ms左右,沒有進行消抖。
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-2 16:27 | 顯示全部樓層
1602液晶的光標默認顯示方式是寫一個字節(jié)自動移動1格。如果要保持光標閃爍位置不變就要在寫數(shù)據(jù)后立即寫前面相同命令,使光標位置不變,例如:
write_com(0x80+5);
write_date('2');
write_com(0x80+5);
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-2 22:23 | 顯示全部樓層
wulin 發(fā)表于 2021-3-2 16:27
1602液晶的光標默認顯示方式是寫一個字節(jié)自動移動1格。如果要保持光標閃爍位置不變就要在寫數(shù)據(jù)后立即寫前 ...

嗯嗯,是的,但是我這個是設(shè)置一個光標位置,然后鍵盤輸入數(shù)字,光標應(yīng)該還是跟著這個數(shù)字的位置,但是現(xiàn)在它不是,光標跑到另外一個位置了
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-3 09:17 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-2 22:23
嗯嗯,是的,但是我這個是設(shè)置一個光標位置,然后鍵盤輸入數(shù)字,光標應(yīng)該還是跟著這個數(shù)字的位置,但是現(xiàn) ...

沒有一招通吃的方法,要依據(jù)功能要求和硬件環(huán)境構(gòu)建程序框架和編寫代碼。
回復

使用道具 舉報

ID:462827 發(fā)表于 2021-3-3 10:01 | 顯示全部樓層
有新的顯示字符,光標位置當然就變了
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-4 14:35 | 顯示全部樓層
hantu 發(fā)表于 2021-3-3 10:01
有新的顯示字符,光標位置當然就變了

但是改變的位置沒有新的顯示字符啊,它自己就改變位置了,確實是很奇怪的現(xiàn)象
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-14 21:53 | 顯示全部樓層
wulin 發(fā)表于 2021-3-2 16:27
1602液晶的光標默認顯示方式是寫一個字節(jié)自動移動1格。如果要保持光標閃爍位置不變就要在寫數(shù)據(jù)后立即寫前 ...

嗯嗯,我這個實際是這個樣子的,就是把光標設(shè)置一個位置,然后打開光標,再然后在這個位置輸入數(shù)字,這個數(shù)字的位數(shù)不定,F(xiàn)在的問題是在我打開光標時,還沒有輸入數(shù)字呢,這個光標就跑到位置列表的最后一個位置了。這個設(shè)置光標位置和打開光標我是通過一個按鍵執(zhí)行的。而輸入數(shù)字的方式有兩種,一種是通過數(shù)字鍵盤輸入,一種是實時讀取傳感器的數(shù)據(jù),這兩種方式我在數(shù)字按鍵的動作函數(shù)里加了判斷,來進行選擇是用哪種方式進行輸入。
程序里涉及到光標位置的有光標右移、光標位置設(shè)置、輸入數(shù)字,刪除數(shù)字這幾個函數(shù)。
  1. /*設(shè)置光標位置,打開光標*/
  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. /*光標移動操作函數(shù),配合按鍵0x1B動作*/
  15. void RightShiftSet()
  16. {
  17.     if(setIndex <= 4)
  18.     {
  19.         setIndex++;
  20.         RefreshCursorShow(); //設(shè)置光標位置,并打開光標
  21.     }  
  22. }

  23. /*按鍵動作函數(shù),執(zhí)行相應(yīng)的動作*/
  24. void KeyAction(unsigned char keycode)
  25. {
  26.    if((keycode >= '0') && (keycode <= '9'))   //輸入數(shù)字
  27.    {
  28.         NumKeyAction(keycode - '0');
  29.    }
  30.    else if(keycode == 0x26)       //各特征值的切換
  31.    {
  32.         FunKeyAction();
  33.    }
  34.    else if(keycode == 0x1B)      //光標的循環(huán)移動
  35.    {
  36.         RightShiftSet();   
  37.    }
  38.    else if(keycode == 0x27)      //刪除當前數(shù)據(jù)
  39.    {
  40.         Deldata();       
  41.    }
  42.    else if(keycode == 0x23)      //去皮清零
  43.    {
  44.         ClearZeroKeyAction();
  45.    }
  46.    else if(keycode == 0x40)      //將當前A\B\C數(shù)據(jù)寫入
  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數(shù)據(jù)
  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. /*數(shù)字鍵動作函數(shù),n-按鍵輸入的數(shù)值*/
  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. /*刪除當前數(shù)據(jù)*/
  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. }
復制代碼

評分

參與人數(shù) 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-15 06:50 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-14 21:53
嗯嗯,我這個實際是這個樣子的,就是把光標設(shè)置一個位置,然后打開光標,再然后在這個位置輸入數(shù)字,這個 ...

單從代碼片段不易判斷問題所在,要看全碼,從程序框架結(jié)構(gòu)查找。
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-15 08:54 | 顯示全部樓層
wulin 發(fā)表于 2021-3-15 06:50
單從代碼片段不易判斷問題所在,要看全碼,從程序框架結(jié)構(gòu)查找。

全碼在此,可能有點大,另外源文件較多,請查看!

全碼.rar

119.12 KB, 閱讀權(quán)限: 50, 下載次數(shù): 6

回復

使用道具 舉報

ID:889832 發(fā)表于 2021-3-15 11:23 | 顯示全部樓層
看程序
指令有沒有問題
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-15 21:04 | 顯示全部樓層
wulin 發(fā)表于 2021-3-15 06:50
單從代碼片段不易判斷問題所在,要看全碼,從程序框架結(jié)構(gòu)查找。

您看下問題出在哪里?
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-15 22:37 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-15 21:04
您看下問題出在哪里?

代碼太長,看得實在頭疼。給你寫了一個示例程序,非常簡單明了,可以清楚的表達在什么時候開光標,什么時候關(guān)光標,光標位置控制方式。 LCD1602時鐘光標演示 仿真.zip (116.82 KB, 下載次數(shù): 48)

評分

參與人數(shù) 2黑幣 +35 收起 理由
karolyte + 15 絕世好帖!
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-16 11:26 | 顯示全部樓層
wulin 發(fā)表于 2021-3-15 22:37
代碼太長,看得實在頭疼。給你寫了一個示例程序,非常簡單明了,可以清楚的表達在什么時候開光標,什么時 ...

,讓您受累了,謝謝您,我先看一下
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-16 22:54 | 顯示全部樓層
wulin 發(fā)表于 2021-3-15 22:37
代碼太長,看得實在頭疼。給你寫了一個示例程序,非常簡單明了,可以清楚的表達在什么時候開光標,什么時 ...

您好,您發(fā)的代碼我看了,光標的控制確實很清晰,我采納了您的方法,發(fā)現(xiàn)問題還是沒有解決,感覺這個問題不是光標位置控制的問題,您看會不會是因為按鍵抖動引起的呢?因為打開光標,并設(shè)定第一個位置后,它在這個位置閃爍一下后就跑到位置列表中的最后一個位置了
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-17 07:03 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-16 22:54
您好,您發(fā)的代碼我看了,光標的控制確實很清晰,我采納了您的方法,發(fā)現(xiàn)問題還是沒有解決,感覺這個問題 ...

由于LcdShowStr函數(shù)寫的是指針字符串,字符量1~n個,光標位置當然隨著字符量移動。要把光標控制在初始位置必須在寫完字符串后再次給光標指定坐標。
/*在液晶上顯示字符串,(x,y)為對應(yīng)屏幕上的起始坐標,str為字符串指針*/
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)
{
    LcdSetCursor(x,y);                  //設(shè)置起始地址
    while(*str != '\0')                 //連續(xù)寫入字符串數(shù)據(jù),直到檢測到結(jié)束符
    {
        LcdWriteDat(*str++);
    }
        LcdSetCursor(x,y);//回到起始地址
}
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-17 09:46 | 顯示全部樓層
wulin 發(fā)表于 2021-3-17 07:03
由于LcdShowStr函數(shù)寫的是指針字符串,字符量1~n個,光標位置當然隨著字符量移動。要把光標控制在初始位 ...

嗯嗯,可能是我沒有表達清楚,我說的是光標跑到其它位置指的是,比如我現(xiàn)在在1602上定義的有4個位置,分別是(0,0,(5,0),(1,1)(5,1),這4個位置都需要輸入數(shù)字,那么我現(xiàn)在在設(shè)置位置1(0,0)的時候,打開光標,光標在這個位置上閃爍一下,然后就跑到位置4(5,1)上了,并在這個位置上閃爍,然后我移動光標到位置2(5,0)上,光標也是在這個位置上閃爍一下,然后還是跑到位置4(5,1)上了,接著我移動光標到位置3(1,1)上,同樣的,也是在這個位置上閃爍一下,還跑到位置4(5,1)上了,在把光標移動到位置4(5,1)時,就不知道到底光標是不是在這個位置上,因為前三個位置時,它就在這個位置4(5,1)上了,就是說,我移動位置都沒問題,并且在相應(yīng)的位置上都能夠正常輸入數(shù)字,也能正常顯示數(shù)字,這都沒問題,就是這個光標它不持續(xù)在給它設(shè)置的位置上
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-17 13:54 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-17 09:46
嗯嗯,可能是我沒有表達清楚,我說的是光標跑到其它位置指的是,比如我現(xiàn)在在1602上定義的有4個位置,分 ...

只要是光標跑到其它位置就說明有其它程序運行了LcdSetCursor(x,y); 你再在恰當?shù)胤竭\行LcdSetCursor(x,y); 把光標拉回來。
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-18 14:10 | 顯示全部樓層
wulin 發(fā)表于 2021-3-17 13:54
只要是光標跑到其它位置就說明有其它程序運行了LcdSetCursor(x,y); 你再在恰當?shù)胤竭\行LcdSetCursor(x,y) ...

確實是在有其它程序運行了LcdSetCursor(x,y),不過這個程序主函數(shù)的while(1)里,是需要一直運行的,我再看看能不能改改,非常感謝您的幫助!
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-18 17:06 | 顯示全部樓層
wulin 發(fā)表于 2021-3-17 13:54
只要是光標跑到其它位置就說明有其它程序運行了LcdSetCursor(x,y); 你再在恰當?shù)胤竭\行LcdSetCursor(x,y) ...

我這個問題的原因找到了,就拿您發(fā)的那個程序來說,是顯示時間的,但是不顯示"時分秒"這三個字符,如果要顯示這三個字符,就需要設(shè)置顯示位置,而且還需要在主函數(shù)的while(1)里一直顯示,那么就會一直運行LcdSetCursor(x,y)了,現(xiàn)在就是想辦法讓這個LcdSetCursor(x,y)只運行一次,并且要擦除這一次的設(shè)置,還不能影響字符的正常顯示。
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-18 19:53 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-18 17:06
我這個問題的原因找到了,就拿您發(fā)的那個程序來說,是顯示時間的,但是不顯示"時分秒"這三個字符,如果要 ...

對于固定字符是不需要刷新的,還以上面那個示例來說,時分秒之間的:號初始化時只寫一次,以后不再刷新。除非需要交替顯示其它內(nèi)容。
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-19 09:54 | 顯示全部樓層
wulin 發(fā)表于 2021-3-18 19:53
對于固定字符是不需要刷新的,還以上面那個示例來說,時分秒之間的:號初始化時只寫一次,以后不再刷新。 ...

嗯嗯,如果是需要切換界面,并且另外一個界面顯示的數(shù)字是實時讀取的,這個實時讀取的就需要不斷的刷新了吧,怎樣解決這個需要不斷刷新和不需要刷新的切換呢?
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-19 10:13 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-19 09:54
嗯嗯,如果是需要切換界面,并且另外一個界面顯示的數(shù)字是實時讀取的,這個實時讀取的就需要不斷的刷新了 ...

這個切換就涉及到不需要刷新的部分,它有光標定位,就是運行了LcdSetCursor(x,y),就是光標不在設(shè)定的位置上的問題,這些都是連在一起的問題
回復

使用道具 舉報

ID:213173 發(fā)表于 2021-3-19 13:13 | 顯示全部樓層
karolyte 發(fā)表于 2021-3-19 10:13
這個切換就涉及到不需要刷新的部分,它有光標定位,就是運行了LcdSetCursor(x,y),就是光標不在設(shè)定的位置 ...

前面好多說法主要是針對查找問題所在何處。如果是需要切換界面,并且另外一個界面顯示的數(shù)字是要實時更新的,不可能到處去跟蹤恢復閃爍地址。這樣做程序會很凌亂,不易讀且效率低下。解決問題的根本做法是重新搭建程序構(gòu)架,避免發(fā)生此類沖突。在19樓發(fā)給你的示例雖然簡單,但程序構(gòu)架明晰,功能模塊相對獨立,不論是添加功能或修改參數(shù)就可避免了互相牽扯。本來模塊化編程就是為了避免互相牽扯,易于移植。結(jié)果卻弄成亂麻。
回復

使用道具 舉報

ID:446775 發(fā)表于 2021-3-21 11:41 | 顯示全部樓層
wulin 發(fā)表于 2021-3-19 13:13
前面好多說法主要是針對查找問題所在何處。如果是需要切換界面,并且另外一個界面顯示的數(shù)字是要實時更新 ...

嗯嗯,是不是說像1602這種液晶的話不適合做界面切換的項目呢,聽您這么說感覺也挺復雜的,我這個項目的代碼也比較多,如果重新構(gòu)建架構(gòu)的話,應(yīng)該是只構(gòu)建顯示部分的吧
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表