找回密码
 立即注册

QQ登录

只需一步,快速开始

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

代码调试高手进!LCD1602液晶屏无显示

[复制链接]
跳转到指定楼层
楼主
10黑币
做的关于LCD1602仿手机显示字符的实验。
步骤:1、在keil里编译无误代码生成hex文件  2、将hex文件导入proteus原理图中
原理图如下:

正常的情况是下图这种,LCD屏有显示且按键有输入:


下面是我的代码(为图方便,把代码一股脑写在一块了),编译是没问题的,但导出的hex导入proteus里,LCD液晶屏不显示,检查不出程序哪里出了问题,请各位大佬帮忙看一看:

  1. //-----------------------------------------------------------------
  2. //  名称: 键盘矩阵扫描程序(4*3)
  3. //-----------------------------------------------------------------
  4. #include <reg51.h>
  5. #include <intrins.h>
  6. #define INT8U   unsigned char
  7. #define INT16U  unsigned int
  8. #define KEY_PORT P1        //键盘端口定义
  9. INT8U KeyNo = 0xFF;        //当前按键序号,有效范围为0-15,0xFF表示无按键
  10. extern void delay_ms(INT16U);
  11. //-----------------------------------------------------------------
  12. // 判断键盘矩阵是否有键按下
  13. //-----------------------------------------------------------------
  14. INT8U KeyMatrix_Down()
  15. {
  16.         //高4位输出,低4位输入,高4位先置零,放入4行
  17.         KEY_PORT = 0x0F; delay_ms(1); //高4位置零,放入4行
  18.         return KEY_PORT != 0x0F ? 1:0;
  19. }

  20. //-----------------------------------------------------------------
  21. // 4*3键盘矩阵扫描
  22. //-----------------------------------------------------------------
  23. void Keys_Scan()
  24. {
  25.         //按键后00001111将变成0000XXXX,X中1个位0,3个仍为1
  26.         //判断按键发生于0~3列中的哪一列
  27.         switch (KEY_PORT)
  28.         {        case 0x0E: KeyNo = 0; break;
  29.                 case 0x0D: KeyNo = 1; break;
  30.                 case 0x0B: KeyNo = 2; break;
  31.         }
  32.         KEY_PORT=0xF0; delay_ms(1); //
  33.         //按键后11110000将变成XXXX0000,X中1个位0,3个仍为1
  34.         //对0~3行分别附加起始值0,4,8,12
  35.         switch (KEY_PORT)
  36.         {        //下面第一行可省略
  37.         case 0xE0: KeyNo += 0; break;
  38.         case 0xD0: KeyNo += 3; break;
  39.         case 0xB0: KeyNo += 6; break;
  40.         case 0x70: KeyNo += 9;
  41.         }
  42. }
  43. //-----------------------------------------------------------------
  44. //  名称: 1602LCD显示仿手机键盘按键字符
  45. //-----------------------------------------------------------------
  46. //  说明: 按下仿手机矩阵键盘按键时,对应按键字符显示在1602LCD上
  47. //
  48. //-----------------------------------------------------------------
  49. //#include "LCD1602-4bit.h"

  50. #include <reg51.h>
  51. #include <intrins.h>
  52. #include <string.h>
  53. #define INT8U  unsigned char
  54. #define INT16U unsigned int

  55. sbit SPK = P3^7;
  56. //12个键盘按键字符总表
  57. //注意串空间应设为6字节,因为最长串为5,设为5时会使部分长串无法附带串结束标志'\0'
  58. INT8U code Keypad_Chars[12][6] =
  59. {        "1 ",        "2ABC",        "3DEF",
  60.         "4GHI",        "5JKL",        "6MNO",
  61.         "7PQRS","8TUV",        "9WXYZ",
  62.         "*",        "0+",        "#"
  63. };
  64. extern INT8U KeyNo;                //键值
  65. INT8U Inner_Idx=0;        //同一按键的内部字符索引
  66. INT8U tSpan=0;                //同键位连续按键的时间间隔
  67. INT8U Buffer_Index=0; //英文/数字输入缓冲索引
  68. char  Input_Buffer[16]; //输入缓冲空间
  69. INT8U ENG_TEL=1;                //输入内容切换标识(ENG:英文输入,TEL:电话输入)
  70. extern void delay_ms(INT16U ms);
  71. extern INT8U KeyMatrix_Down();
  72. extern void Keys_Scan();

  73. extern          void Initialize_LCD();                                        //LCD初始化
  74. extern void LCD_ShowString(INT8U r, INT8U c,char *str);//在LCD上显示字符串*/


  75. #define LCD_PORT P2                //液晶端口(P2高4位)
  76. //LCD引脚定义
  77. sbit RS = P2^0;                        //LCD寄存器选择
  78. sbit RW = P2^1;                        //LCD读写控制
  79. sbit EN = P2^2;                        //LCD使能控制
  80. /*//LCD相关函数
  81. void delay_ms(INT16U x);                                //延时函数
  82. void LCD_Busy_Wait();                                        //忙等待
  83. void Write_LCD_Data(INT8U dat);                        //向LCD写数据
  84. void Write_LCD_Command(INT8U cmd);                //写LCD指令
  85. void Initialize_LCD();                                        //LCD初始化
  86. void LCD_ShowString(INT8U r, INT8U c,char *str);//在LCD上显示字符串*/  
  87. //-----------------------------------------------------------------
  88. //        名称: LCD1602液晶驱动程序
  89. //-----------------------------------------------------------------
  90. //#include "LCD1602-4bit.h"          
  91. #define delay5us() {_nop_();_nop_();_nop_();_nop_();_nop_();}
  92. //-----------------------------------------------------------------
  93. // 延时函数
  94. //-----------------------------------------------------------------
  95. void delay_ms(INT16U x)
  96. {
  97.         INT8U t; while(x--) for(t = 0; t < 120; t++);
  98. }

  99. //-----------------------------------------------------------------
  100. // 液晶忙等待
  101. //-----------------------------------------------------------------
  102. void LCD_Busy_Wait()
  103. {
  104.         INT8U  LCD_Status;                //液晶状态字节变量
  105.         do
  106.         {
  107.         LCD_PORT=0xFF;
  108.         RS=0; RW=1;
  109.         EN=1; delay5us(); LCD_Status=P2; EN=0;
  110.         }while (LCD_Status & 0x80);                        //液晶忙继续循环
  111. }
  112. //-----------------------------------------------------------------
  113. // 写液晶命令
  114. //-----------------------------------------------------------------
  115. void Write_LCD_Command(INT8U cmd)
  116. {        LCD_Busy_Wait();
  117.         RS=0; RW=0;                                                           //选择命令寄存器,准备写
  118.         EN=0; _nop_(); _nop_(); LCD_PORT=cmd; //数据送到液晶屏端口
  119.         delay5us(); EN=1; delay5us(); EN=0;           //写入后禁止液晶屏
  120. }

  121. //-----------------------------------------------------------------
  122. // 向液晶写数据
  123. //-----------------------------------------------------------------
  124. void Write_LCD_Data(INT8U dat)
  125. {        LCD_Busy_Wait();
  126.         RS=1; RW=0;
  127.         EN=0; LCD_PORT=dat; delay5us();
  128.         EN=1; delay5us(); EN=0;
  129. }
  130. //-----------------------------------------------------------------
  131. // 液晶初始化
  132. //-----------------------------------------------------------------
  133. void Initialize_LCD()
  134. {        Write_LCD_Command(0x38); delay_ms(1);        //置功能,8位,双行,5*7
  135.         Write_LCD_Command(0x06); delay_ms(1);        //字符进入模式:屏幕不动,字符后移
  136.         Write_LCD_Command(0x0C); delay_ms(1);        //显示开,关光标
  137.         Write_LCD_Command(0x01); delay_ms(1);        //清屏
  138. }

  139. //-----------------------------------------------------------------
  140. // 在指定位置显示字符串
  141. //-----------------------------------------------------------------
  142. void LCD_ShowString(INT8U r, INT8U c,char *str)
  143. {
  144.         INT8U i=0;
  145.     INT8U code DDRAM[] = {0x80,0xC0};         //液晶屏上下两行的DDRAM首地址
  146.         Write_LCD_Command(DDRAM[r] |c);         //设置显示起始位置
  147.         while (str[i] && i < 16) Write_LCD_Data(str[i++]);//输出显示字符
  148. }
  149. //-----------------------------------------------------------------
  150. // 蜂鸣器
  151. //-----------------------------------------------------------------
  152. void Beep()
  153. {
  154.         INT8U i; for(i=0;i<60;i++){SPK=!SPK; delay_ms(1);}
  155.         SPK=1;delay_ms(100);
  156. }

  157. //-----------------------------------------------------------------
  158. // 定时器0跟踪同位按键的时间间隔
  159. //-----------------------------------------------------------------
  160. void T0_INT() interrupt 1
  161. {
  162.         //重新设置50ms定时初值
  163.         TH0=-50000>>8; TL0=-50000&0xFF;
  164.         //tSpan最大值限制在41及以上即可
  165.         //不加限制时会使某次较长的延时累加超过255后,
  166.         //累加又从0开始,而程序判断时它可能刚好还在40以内,
  167.         //从而导致较长的延时却被误断为较短的延时
  168.         if(tSpan<50) tSpan++;else TR0=0;
  169. }

  170. //-----------------------------------------------------------------
  171. // 功能键处理 *(9):切换输入,#(11)键清除内容
  172. //-----------------------------------------------------------------
  173. void Function_Key_Process()
  174. {
  175.         if(KeyNo==9)                                //输入内容标识切换
  176.         {        ENG_TEL=!ENG_TEL;
  177.                 Inner_Idx=ENG_TEL?1:0;  //如果是输入英文,内部索引为1,否则设为0               
  178.         }
  179.         Buffer_Index=0;                                //输入缓冲索引归0
  180.         Input_Buffer[0]='\0';                //将输入缓冲设为空串
  181.         if(ENG_TEL)                LCD_ShowString(1,0,"ENG>        ");          //显示输入英文
  182.         else            LCD_ShowString(1,0,"TEL>        ");          //显示输入电话
  183.         while(KeyMatrix_Down());                                                  //等待释放按键
  184. }

  185. //-----------------------------------------------------------------
  186. // 主程序
  187. //-----------------------------------------------------------------
  188. void main()
  189. {
  190.         INT8U Pre_KeyNo=-1;
  191.         IE=0x82;                                 //使能T0中断
  192.         TMOD=0x01;                                 //T0工作于模式1(16位模式)
  193.         TH0=-50000>>8;                         //定时50ms
  194.         TL0=-50000&0xFF;
  195.         Initialize_LCD();        //液晶初始化
  196.         //显示固定信息部分(初始显示ENG>表示输入英文字符序列)
  197.         LCD_ShowString(0,0," Mobile KeyPad ");
  198.         LCD_ShowString(1,0,"ENG>                ");
  199.         while(1)
  200.         {        //有键按下则扫描,否则不进行任何处理
  201.                 if(KeyMatrix_Down()) Keys_Scan();else continue;
  202.                 if(KeyNo==0xFF) continue;
  203.                 //功能键处理(9[*]:切换英文/数字,11[#]:清除所有输入)
  204.                 if(KeyNo==9 || KeyNo == 11)
  205.                 {        Function_Key_Process(); Beep(); continue; }
  206.                 //如果是输入数字则直接显示
  207.                 if(!ENG_TEL) goto SHOW_MOBILE_KEY;
  208.                 //如果输入的不是英文字母则继续(英文字符在0~8号键,包括空格)
  209.                 if(KeyNo<0 || KeyNo>8) continue;
  210.                 //否则输入的是英文字符序列,以下代码将根据是否为同位按键进行相应处理
  211.                 if(Pre_KeyNo != KeyNo)         //按下新按键
  212.                 {        Pre_KeyNo = KeyNo;         //保存当前按键
  213.                         Inner_Idx = 1;                 //输入英文时内部索引起点为1
  214.                 }
  215.                 else //否则按下的时相同位置按键
  216.                 {        //同位按键时间间隔在50ms*30=1.5s内则认为是连续按键
  217.                         if(tSpan<31)
  218.                         {        //连续按键时在键内循环递增字符索引
  219.                                 if (++Inner_Idx == strlen(Keypad_Chars[KeyNo]))
  220.                                 Inner_Idx=1;
  221.                                 //因为是连续短按,故将每次显示后递增的输入缓冲索引后退一格,
  222.                                 //以便替换此前输入的字符
  223.                                 --Buffer_Index;
  224.                         } else Inner_Idx = 1; //否则按键内英文字符索引回归起点索引1
  225.                 }
  226.                 tSpan=0; TR0=1;                         //时间间隔归零,计时开始
  227.                 SHOW_MOBILE_KEY:                 //显示按键字符
  228.                 if(Buffer_Index >= 12) continue; //输入缓冲限制在12个字符以内
  229.                 //更新输入缓冲字符串并送LCD显示
  230.                 Input_Buffer[Buffer_Index++] = Keypad_Chars[KeyNo][Inner_Idx];
  231.                 Input_Buffer[Buffer_Index] = '\0';
  232.                 LCD_ShowString(1,4,Input_Buffer);
  233.                 Beep();                                         //输出提示音
  234.                 while(KeyMatrix_Down()); //等待释放按键
  235.         }
  236. }
复制代码
附上原理图,可在proteus中打开
1602LCD显示仿手机键盘按键字符.zip (16.37 KB, 下载次数: 15)


最佳答案

查看完整内容

给你改了,对比一下就知道哪里错了。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:155507 发表于 2019-5-13 20:49 | 只看该作者
给你改了,对比一下就知道哪里错了。



  1. //-----------------------------------------------------------------
  2. //  名称: 键盘矩阵扫描程序(4*3)
  3. //-----------------------------------------------------------------
  4. #include <reg51.h>
  5. #include <intrins.h>
  6. #define INT8U   unsigned char
  7. #define INT16U  unsigned int
  8. #define KEY_PORT P1        //键盘端口定义
  9. INT8U KeyNo = 0xFF;        //当前按键序号,有效范围为0-15,0xFF表示无按键
  10. extern void delay_ms(INT16U);
  11. //-----------------------------------------------------------------
  12. // 判断键盘矩阵是否有键按下
  13. //-----------------------------------------------------------------
  14. INT8U KeyMatrix_Down()
  15. {
  16.         //高4位输出,低4位输入,高4位先置零,放入4行
  17.         KEY_PORT = 0x0F; delay_ms(1); //高4位置零,放入4行
  18.         return KEY_PORT != 0x0F ? 1:0;
  19. }

  20. //-----------------------------------------------------------------
  21. // 4*3键盘矩阵扫描
  22. //-----------------------------------------------------------------
  23. void Keys_Scan()
  24. {
  25.         //按键后00001111将变成0000XXXX,X中1个位0,3个仍为1
  26.         //判断按键发生于0~3列中的哪一列
  27.         switch (KEY_PORT)
  28.         {
  29.         case 0x0E: KeyNo = 0; break;
  30.         case 0x0D: KeyNo = 1; break;
  31.         case 0x0B: KeyNo = 2; break;
  32.         }
  33.         KEY_PORT=0xF0; delay_ms(1); //
  34.         //按键后11110000将变成XXXX0000,X中1个位0,3个仍为1
  35.         //对0~3行分别附加起始值0,4,8,12
  36.         switch (KEY_PORT)
  37.         {        //下面第一行可省略
  38.         case 0xE0: KeyNo += 0; break;
  39.         case 0xD0: KeyNo += 3; break;
  40.         case 0xB0: KeyNo += 6; break;
  41.         case 0x70: KeyNo += 9;
  42.         }
  43. }
  44. //-----------------------------------------------------------------
  45. //  名称: 1602LCD显示仿手机键盘按键字符
  46. //-----------------------------------------------------------------
  47. //  说明: 按下仿手机矩阵键盘按键时,对应按键字符显示在1602LCD上
  48. //
  49. //-----------------------------------------------------------------
  50. //#include "LCD1602-4bit.h"

  51. #include <reg51.h>
  52. #include <intrins.h>
  53. #include <string.h>
  54. #define INT8U  unsigned char
  55. #define INT16U unsigned int

  56. sbit SPK = P3^7;
  57. //12个键盘按键字符总表
  58. //注意串空间应设为6字节,因为最长串为5,设为5时会使部分长串无法附带串结束标志'\0'
  59. INT8U code Keypad_Chars[12][6] =
  60. {
  61.         "1 ",        "2ABC",        "3DEF",
  62.         "4GHI",        "5JKL",        "6MNO",
  63.         "7PQRS","8TUV",        "9WXYZ",
  64.         "*",        "0+",        "#"
  65. };
  66. extern INT8U KeyNo;       //键值
  67. INT8U Inner_Idx=0;        //同一按键的内部字符索引
  68. INT8U tSpan=0;            //同键位连续按键的时间间隔
  69. INT8U Buffer_Index=0;     //英文/数字输入缓冲索引
  70. char  Input_Buffer[16];   //输入缓冲空间
  71. INT8U ENG_TEL=1;          //输入内容切换标识(ENG:英文输入,TEL:电话输入)
  72. extern void delay_ms(INT16U ms);
  73. extern INT8U KeyMatrix_Down();
  74. extern void Keys_Scan();

  75. extern void Initialize_LCD();                                        //LCD初始化
  76. extern void LCD_ShowString(INT8U r, INT8U c,char *str);  //在LCD上显示字符串*/


  77. #define LCD_PORT P2                //液晶端口(P2高4位)
  78. //LCD引脚定义
  79. sbit RS = P3^2;                        //LCD寄存器选择
  80. sbit RW = P3^3;                        //LCD读写控制
  81. sbit EN = P3^4;                        //LCD使能控制
  82. /*//LCD相关函数
  83. void delay_ms(INT16U x);                          //延时函数
  84. void LCD_Busy_Wait();                             //忙等待
  85. void Write_LCD_Data(INT8U dat);                   //向LCD写数据
  86. void Write_LCD_Command(INT8U cmd);                //写LCD指令
  87. void Initialize_LCD();                            //LCD初始化
  88. void LCD_ShowString(INT8U r, INT8U c,char *str);  //在LCD上显示字符串*/  
  89. //-----------------------------------------------------------------
  90. //        名称: LCD1602液晶驱动程序
  91. //-----------------------------------------------------------------
  92. //#include "LCD1602-4bit.h"         
  93. #define delay5us() {_nop_();_nop_();_nop_();_nop_();_nop_();}
  94. //-----------------------------------------------------------------
  95. // 延时函数
  96. //-----------------------------------------------------------------
  97. void delay_ms(INT16U x)
  98. {
  99.         INT8U t;  while(x--) for(t = 0; t < 120; t++);
  100. }

  101. //-----------------------------------------------------------------
  102. // 液晶忙等待
  103. //-----------------------------------------------------------------
  104. /*
  105. void LCD_Busy_Wait()
  106. {
  107.         INT8U  LCD_Status;                //液晶状态字节变量
  108.         do
  109.         {
  110.                 LCD_PORT=0xFF;
  111.                 RS=0; RW=1;
  112.                 EN=1; delay5us(); LCD_Status=P2; EN=0;
  113.         }while (LCD_Status & 0x80);               //液晶忙继续循环
  114. } */
  115. //-----------------------------------------------------------------
  116. // 写液晶命令
  117. //-----------------------------------------------------------------
  118. void Write_LCD_Command(INT8U cmd)
  119. {
  120.         //LCD_Busy_Wait();
  121.         EN = 0;          //使能清零       
  122.         RS=0; RW=0;                                                           //选择命令寄存器,准备写
  123.         EN=0; _nop_(); _nop_();
  124.     //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  125.         LCD_PORT=cmd;      //数据送到液晶屏端口
  126.         delay_ms(1);
  127.         EN=1;   //写入时序
  128.         delay_ms(1); EN=0;        //写入后禁止液晶屏
  129.         LCD_PORT= cmd << 4; //写入低四位
  130.         EN=1;   //写入时序
  131.         delay_ms(1); EN=0;
  132.        
  133. }

  134. //-----------------------------------------------------------------
  135. // 向液晶写数据
  136. //-----------------------------------------------------------------
  137. void Write_LCD_Data(INT8U dat)
  138. {
  139.         //LCD_Busy_Wait();
  140.         EN = 0;          //使能清零
  141.         RS=1; RW=0;
  142.         EN=0;
  143.         LCD_PORT=dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  144.         delay_ms(1);
  145.         EN=1;   //写入时序
  146.         delay_ms(1); EN=0;
  147.         LCD_PORT= dat << 4; //写入低四位
  148.         EN=1;   //写入时序
  149.         delay_ms(1); EN=0;

  150. }
  151. //-----------------------------------------------------------------
  152. // 液晶初始化
  153. //-----------------------------------------------------------------
  154. void Initialize_LCD()
  155. {
  156.         //Write_LCD_Command(0x38); delay_ms(1);        //置功能,8位,双行,5*7
  157.         Write_LCD_Command(0x32); delay_ms(1);        //将8位总线转为4位总线
  158.         Write_LCD_Command(0x28); delay_ms(1);        // 在四位线下的初始化
  159.         Write_LCD_Command(0x06); delay_ms(1);        //字符进入模式:屏幕不动,字符后移
  160.         Write_LCD_Command(0x0C); delay_ms(1);        //显示开,关光标
  161.         Write_LCD_Command(0x01); delay_ms(1);        //清屏
  162. }

  163. //-----------------------------------------------------------------
  164. // 在指定位置显示字符串
  165. //-----------------------------------------------------------------
  166. void LCD_ShowString(INT8U r, INT8U c,char *str)
  167. {
  168.         INT8U i=0;
  169.         INT8U code DDRAM[] = {0x80,0xC0};         //液晶屏上下两行的DDRAM首地址
  170.         Write_LCD_Command(DDRAM[r] |c);         //设置显示起始位置
  171.         while (str[i] && i < 16) Write_LCD_Data(str[i++]);//输出显示字符
  172. }
  173. //-----------------------------------------------------------------
  174. // 蜂鸣器
  175. //-----------------------------------------------------------------
  176. void Beep()
  177. {
  178.         INT8U i; for(i=0;i<60;i++){SPK=!SPK; delay_ms(1);}
  179.         SPK=1;delay_ms(100);
  180. }

  181. //-----------------------------------------------------------------
  182. // 定时器0跟踪同位按键的时间间隔
  183. //-----------------------------------------------------------------
  184. void T0_INT() interrupt 1
  185. {
  186.         //重新设置50ms定时初值
  187.         TH0=-50000>>8; TL0=-50000&0xFF;
  188.         //tSpan最大值限制在41及以上即可
  189.         //不加限制时会使某次较长的延时累加超过255后,
  190.         //累加又从0开始,而程序判断时它可能刚好还在40以内,
  191.         //从而导致较长的延时却被误断为较短的延时
  192.         if(tSpan<50) tSpan++;else TR0=0;
  193. }

  194. //-----------------------------------------------------------------
  195. // 功能键处理 *(9):切换输入,#(11)键清除内容
  196. //-----------------------------------------------------------------
  197. void Function_Key_Process()
  198. {
  199.         if(KeyNo==9)                         //输入内容标识切换
  200.         {        ENG_TEL=!ENG_TEL;
  201.                 Inner_Idx=ENG_TEL?1:0;  //如果是输入英文,内部索引为1,否则设为0               
  202.         }
  203.         Buffer_Index=0;                      //输入缓冲索引归0
  204.         Input_Buffer[0]='\0';                //将输入缓冲设为空串
  205.         if(ENG_TEL)     LCD_ShowString(1,0,"ENG>        ");          //显示输入英文
  206.         else            LCD_ShowString(1,0,"TEL>        ");          //显示输入电话
  207.         while(KeyMatrix_Down());                                     //等待释放按键
  208. }

  209. //-----------------------------------------------------------------
  210. // 主程序
  211. //-----------------------------------------------------------------
  212. void main()
  213. {
  214.         INT8U Pre_KeyNo=-1;
  215.         IE=0x82;                               //使能T0中断
  216.         TMOD=0x01;                             //T0工作于模式1(16位模式)
  217.         TH0=-50000>>8;                         //定时50ms
  218.         TL0=-50000&0xFF;
  219.         Initialize_LCD();        //液晶初始化
  220.         //显示固定信息部分(初始显示ENG>表示输入英文字符序列)
  221.         LCD_ShowString(0,0," Mobile KeyPad ");
  222.         LCD_ShowString(1,0,"ENG>                ");
  223.         while(1)
  224.         {        //有键按下则扫描,否则不进行任何处理
  225.                 if(KeyMatrix_Down()) Keys_Scan();else continue;
  226.                 if(KeyNo==0xFF) continue;
  227.                 //功能键处理(9[*]:切换英文/数字,11[#]:清除所有输入)
  228.                 if(KeyNo==9 || KeyNo == 11)
  229.                 {        Function_Key_Process(); Beep(); continue; }
  230.                 //如果是输入数字则直接显示
  231.                 if(!ENG_TEL) goto SHOW_MOBILE_KEY;
  232.                 //如果输入的不是英文字母则继续(英文字符在0~8号键,包括空格)
  233.                 if(KeyNo<0 || KeyNo>8) continue;
  234.                 //否则输入的是英文字符序列,以下代码将根据是否为同位按键进行相应处理
  235.                 if(Pre_KeyNo != KeyNo)         //按下新按键
  236.                 {        Pre_KeyNo = KeyNo;         //保存当前按键
  237.                         Inner_Idx = 1;                 //输入英文时内部索引起点为1
  238.                 }
  239.                 else //否则按下的时相同位置按键
  240.                 {        //同位按键时间间隔在50ms*30=1.5s内则认为是连续按键
  241.                         if(tSpan<31)
  242.                         {        //连续按键时在键内循环递增字符索引
  243.                                 if (++Inner_Idx == strlen(Keypad_Chars[KeyNo]))
  244.                                 Inner_Idx=1;
  245.                                 //因为是连续短按,故将每次显示后递增的输入缓冲索引后退一格,
  246.                                 //以便替换此前输入的字符
  247.                                 --Buffer_Index;
  248.                         } else Inner_Idx = 1; //否则按键内英文字符索引回归起点索引1
  249.                 }
  250.                 tSpan=0; TR0=1;                         //时间间隔归零,计时开始
  251.                 SHOW_MOBILE_KEY:                 //显示按键字符
  252.                 if(Buffer_Index >= 12) continue; //输入缓冲限制在12个字符以内
  253.                 //更新输入缓冲字符串并送LCD显示
  254.                 Input_Buffer[Buffer_Index++] = Keypad_Chars[KeyNo][Inner_Idx];
  255.                 Input_Buffer[Buffer_Index] = '\0';
  256.                 LCD_ShowString(1,4,Input_Buffer);
  257.                 Beep();                                         //输出提示音
  258.                 while(KeyMatrix_Down()); //等待释放按键
  259.         }
  260. }

复制代码

评分

参与人数 1黑币 +8 收起 理由
划船须划水 + 8 很给力!

查看全部评分

回复

使用道具 举报

板凳
ID:149451 发表于 2019-5-14 07:24 | 只看该作者
大致看了下,你的lcd1602驱动貌似是并口的,但proteus图示是4线式(穿行数据输入)程序同时控制端也用的是P2口,有点乱

评分

参与人数 1黑币 +2 收起 理由
划船须划水 + 2 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:536476 发表于 2019-5-14 09:07 | 只看该作者
w1179benp 发表于 2019-5-14 07:24
大致看了下,你的lcd1602驱动貌似是并口的,但proteus图示是4线式(穿行数据输入)程序同时控制端也用的是P ...

大佬,所以说有什么解决办法么
回复

使用道具 举报

5#
ID:514919 发表于 2019-5-14 14:52 | 只看该作者
#include "STC15.H" #include "lcd1602.h" #include "ds1302.h" //#include"clock.h" SYSTEMTIME timer; /*************************************** main() ***************************************/ void main() {         P0M1=0;P0M0=0;         P1M1=0;P1M0=0;         P2M1=0;P2M0=0;         P3M1=0;P3M0=0;         lcd_initial();         ds1302_init();         while(1)         {                                     Ds1302_Read_Time(&timer);                    LCD_Write_Char(5,1,timer.Hour/10 + '0');        //ê±                         LCD_Write_Char(6,1,timer.Hour%10 + '0');                          LCD_Write_Char(8,1,timer.Minute/10 + '0');        //·Ö                         LCD_Write_Char(9,1,timer.Minute%10 + '0');                          LCD_Write_Char(11,1,timer.Second/10 + '0');        //Ãë                         LCD_Write_Char(12,1,timer.Second%10 + '0');                                    LCD_Write_Char(7,0,timer.Year/10  + '0');        //Äê                         LCD_Write_Char(8,0,timer.Year%10 + '0');                          LCD_Write_Char(10,0,timer.Month/10 + '0');        //ÔÂ                         LCD_Write_Char(11,0,timer.Month%10 + '0');                          LCD_Write_Char(13,0,timer.Day /10 + '0');        //èÕ                         LCD_Write_Char(14,0,timer.Day %10 + '0');         } },有个类似的程序,可以看看
回复

使用道具 举报

6#
ID:155507 发表于 2019-5-15 23:52 | 只看该作者
4线式LCD程序同时控制端也用的是P2口

  1. //-----------------------------------------------------------------
  2. //  名称: 键盘矩阵扫描程序(4*3)
  3. //-----------------------------------------------------------------
  4. #include <reg51.h>
  5. #include <intrins.h>
  6. #define INT8U   unsigned char
  7. #define INT16U  unsigned int
  8. #define KEY_PORT P1        //键盘端口定义
  9. INT8U KeyNo = 0xFF;        //当前按键序号,有效范围为0-15,0xFF表示无按键
  10. extern void delay_ms(INT16U);
  11. //-----------------------------------------------------------------
  12. // 判断键盘矩阵是否有键按下
  13. //-----------------------------------------------------------------
  14. INT8U KeyMatrix_Down()
  15. {
  16.         //高4位输出,低4位输入,高4位先置零,放入4行
  17.         KEY_PORT = 0x0F; delay_ms(1); //高4位置零,放入4行
  18.         return KEY_PORT != 0x0F ? 1:0;
  19. }

  20. //-----------------------------------------------------------------
  21. // 4*3键盘矩阵扫描
  22. //-----------------------------------------------------------------
  23. void Keys_Scan()
  24. {
  25.         //按键后00001111将变成0000XXXX,X中1个位0,3个仍为1
  26.         //判断按键发生于0~3列中的哪一列
  27.         switch (KEY_PORT)
  28.         {
  29.         case 0x0E: KeyNo = 0; break;
  30.         case 0x0D: KeyNo = 1; break;
  31.         case 0x0B: KeyNo = 2; break;
  32.         }
  33.         KEY_PORT=0xF0; delay_ms(1); //
  34.         //按键后11110000将变成XXXX0000,X中1个位0,3个仍为1
  35.         //对0~3行分别附加起始值0,4,8,12
  36.         switch (KEY_PORT)
  37.         {        //下面第一行可省略
  38.         case 0xE0: KeyNo += 0; break;
  39.         case 0xD0: KeyNo += 3; break;
  40.         case 0xB0: KeyNo += 6; break;
  41.         case 0x70: KeyNo += 9;
  42.         }
  43. }
  44. //-----------------------------------------------------------------
  45. //  名称: 1602LCD显示仿手机键盘按键字符
  46. //-----------------------------------------------------------------
  47. //  说明: 按下仿手机矩阵键盘按键时,对应按键字符显示在1602LCD上
  48. //
  49. //-----------------------------------------------------------------
  50. //#include "LCD1602-4bit.h"

  51. #include <reg51.h>
  52. #include <intrins.h>
  53. #include <string.h>
  54. #define INT8U  unsigned char
  55. #define INT16U unsigned int

  56. sbit SPK = P3^7;
  57. //12个键盘按键字符总表
  58. //注意串空间应设为6字节,因为最长串为5,设为5时会使部分长串无法附带串结束标志'\0'
  59. INT8U code Keypad_Chars[12][6] =
  60. {
  61.         "1 ",        "2ABC",        "3DEF",
  62.         "4GHI",        "5JKL",        "6MNO",
  63.         "7PQRS","8TUV",        "9WXYZ",
  64.         "*",        "0+",        "#"
  65. };
  66. extern INT8U KeyNo;       //键值
  67. INT8U Inner_Idx=0;        //同一按键的内部字符索引
  68. INT8U tSpan=0;            //同键位连续按键的时间间隔
  69. INT8U Buffer_Index=0;     //英文/数字输入缓冲索引
  70. char  Input_Buffer[16];   //输入缓冲空间
  71. INT8U ENG_TEL=1;          //输入内容切换标识(ENG:英文输入,TEL:电话输入)
  72. extern void delay_ms(INT16U ms);
  73. extern INT8U KeyMatrix_Down();
  74. extern void Keys_Scan();

  75. extern void Initialize_LCD();                                        //LCD初始化
  76. extern void LCD_ShowString(INT8U r, INT8U c,char *str);  //在LCD上显示字符串*/
  77. //是4线式(穿行数据输入)程序
  78. //程序同时控制端也用的是P2口
  79. #define LCD_PORT P2                //液晶端口(P2高4位)
  80. //LCD引脚定义
  81. sbit RS = P2^0;                        //LCD寄存器选择
  82. sbit RW = P2^1;                        //LCD读写控制
  83. sbit EN = P2^2;                        //LCD使能控制
  84. //sbit RS = P3^2;                        //LCD寄存器选择
  85. //sbit RW = P3^3;                        //LCD读写控制
  86. //sbit EN = P3^4;                        //LCD使能控制
  87. /*//LCD相关函数
  88. void delay_ms(INT16U x);                          //延时函数
  89. void LCD_Busy_Wait();                             //忙等待
  90. void Write_LCD_Data(INT8U dat);                   //向LCD写数据
  91. void Write_LCD_Command(INT8U cmd);                //写LCD指令
  92. void Initialize_LCD();                            //LCD初始化
  93. void LCD_ShowString(INT8U r, INT8U c,char *str);  //在LCD上显示字符串*/  
  94. //-----------------------------------------------------------------
  95. //        名称: LCD1602液晶驱动程序
  96. //-----------------------------------------------------------------
  97. //#include "LCD1602-4bit.h"         
  98. #define delay5us() {_nop_();_nop_();_nop_();_nop_();_nop_();}
  99. //-----------------------------------------------------------------
  100. // 延时函数
  101. //-----------------------------------------------------------------
  102. void delay_ms(INT16U x)
  103. {
  104.         INT8U t;  while(x--) for(t = 0; t < 120; t++);
  105. }

  106. //-----------------------------------------------------------------
  107. // 液晶忙等待
  108. //-----------------------------------------------------------------
  109. /*
  110. void LCD_Busy_Wait()
  111. {
  112.         INT8U  LCD_Status;                //液晶状态字节变量
  113.         do
  114.         {
  115.                 LCD_PORT=0xFF;
  116.                 RS=0; RW=1;
  117.                 EN=1; delay5us(); LCD_Status=P2; EN=0;
  118.         }while (LCD_Status & 0x80);               //液晶忙继续循环
  119. } */
  120. //-----------------------------------------------------------------
  121. // 写液晶命令
  122. //-----------------------------------------------------------------
  123. void Write_LCD_Command(INT8U cmd)
  124. {
  125.         INT8U  Temp1, Temp2;
  126.         //LCD_Busy_Wait();
  127.         EN = 0;          //使能清零       
  128.         RS=0; RW=0;                                                           //选择命令寄存器,准备写
  129.         EN=0; _nop_(); _nop_();
  130.         //由于4位的接线是接到LCD_PORT口的高四位,所以传送高四位不用改
  131.         Temp1 = LCD_PORT&0x0f;
  132.         Temp2= (cmd&0xf0);
  133.         LCD_PORT= (Temp2|Temp1);      //数据送到液晶屏端口
  134.         delay_ms(1);
  135.         EN=1;   //写入时序
  136.         delay_ms(1); EN=0;        //写入后禁止液晶屏
  137.         Temp2= (cmd << 4);
  138.         Temp2&=0xf0;
  139.         LCD_PORT= (Temp2|Temp1); //写入低四位
  140.         EN=1;   //写入时序
  141.         delay_ms(1); EN=0;

  142.        
  143. }

  144. //-----------------------------------------------------------------
  145. // 向液晶写数据
  146. //-----------------------------------------------------------------
  147. void Write_LCD_Data(INT8U dat)
  148. {
  149.         INT8U  Temp1, Temp2;
  150.         //LCD_Busy_Wait();
  151.         EN = 0;          //使能清零
  152.         RS=1; RW=0;
  153.         EN=0;
  154.         Temp1 = LCD_PORT&0x0f;
  155.         Temp2= (dat&0xf0);  //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  156.         LCD_PORT=(Temp2|Temp1);    //数据送到液晶屏端口
  157.         delay_ms(1);
  158.         EN=1;   //写入时序
  159.         delay_ms(1); EN=0;
  160.         Temp2= (dat << 4);
  161.         Temp2&=0xf0;
  162.         LCD_PORT = (Temp2|Temp1); //写入低四位
  163.         EN=1;   //写入时序
  164.         delay_ms(1); EN=0;

  165.        
  166. }
  167. //-----------------------------------------------------------------
  168. // 液晶初始化
  169. //-----------------------------------------------------------------
  170. void Initialize_LCD()
  171. {
  172.         //Write_LCD_Command(0x38); delay_ms(1);        //置功能,8位,双行,5*7
  173.         Write_LCD_Command(0x32); delay_ms(1);        //将8位总线转为4位总线
  174.         Write_LCD_Command(0x28); delay_ms(1);        // 在四位线下的初始化
  175.         Write_LCD_Command(0x06); delay_ms(1);        //字符进入模式:屏幕不动,字符后移
  176.         Write_LCD_Command(0x0C); delay_ms(1);        //显示开,关光标
  177.         Write_LCD_Command(0x01); delay_ms(1);        //清屏
  178. }

  179. //-----------------------------------------------------------------
  180. // 在指定位置显示字符串
  181. //-----------------------------------------------------------------
  182. void LCD_ShowString(INT8U r, INT8U c,char *str)
  183. {
  184.         INT8U i=0;
  185.         INT8U code DDRAM[] = {0x80,0xC0};         //液晶屏上下两行的DDRAM首地址
  186.         Write_LCD_Command(DDRAM[r] |c);         //设置显示起始位置
  187.         while (str[i] && i < 16) Write_LCD_Data(str[i++]);//输出显示字符
  188. }
  189. //-----------------------------------------------------------------
  190. // 蜂鸣器
  191. //-----------------------------------------------------------------
  192. void Beep()
  193. {
  194.         INT8U i; for(i=0;i<60;i++){SPK=!SPK; delay_ms(1);}
  195.         SPK=1;delay_ms(100);
  196. }

  197. //-----------------------------------------------------------------
  198. // 定时器0跟踪同位按键的时间间隔
  199. //-----------------------------------------------------------------
  200. void T0_INT() interrupt 1
  201. {
  202.         //重新设置50ms定时初值
  203.         TH0=-50000>>8; TL0=-50000&0xFF;
  204.         //tSpan最大值限制在41及以上即可
  205.         //不加限制时会使某次较长的延时累加超过255后,
  206.         //累加又从0开始,而程序判断时它可能刚好还在40以内,
  207.         //从而导致较长的延时却被误断为较短的延时
  208.         if(tSpan<50) tSpan++;else TR0=0;
  209. }

  210. //-----------------------------------------------------------------
  211. // 功能键处理 *(9):切换输入,#(11)键清除内容
  212. //-----------------------------------------------------------------
  213. void Function_Key_Process()
  214. {
  215.         if(KeyNo==9)                         //输入内容标识切换
  216.         {        ENG_TEL=!ENG_TEL;
  217.                 Inner_Idx=ENG_TEL?1:0;  //如果是输入英文,内部索引为1,否则设为0               
  218.         }
  219.         Buffer_Index=0;                      //输入缓冲索引归0
  220.         Input_Buffer[0]='\0';                //将输入缓冲设为空串
  221.         if(ENG_TEL)     LCD_ShowString(1,0,"ENG>        ");          //显示输入英文
  222.         else            LCD_ShowString(1,0,"TEL>        ");          //显示输入电话
  223.         while(KeyMatrix_Down());                                     //等待释放按键
  224. }

  225. //-----------------------------------------------------------------
  226. // 主程序
  227. //-----------------------------------------------------------------
  228. void main()
  229. {
  230.         INT8U Pre_KeyNo=-1;
  231.         IE=0x82;                               //使能T0中断
  232.         TMOD=0x01;                             //T0工作于模式1(16位模式)
  233.         TH0=-50000>>8;                         //定时50ms
  234.         TL0=-50000&0xFF;
  235.         Initialize_LCD();        //液晶初始化
  236.         //显示固定信息部分(初始显示ENG>表示输入英文字符序列)
  237.         LCD_ShowString(0,0," Mobile KeyPad ");
  238.         LCD_ShowString(1,0,"ENG>                ");
  239.         while(1)
  240.         {        //有键按下则扫描,否则不进行任何处理
  241.                 if(KeyMatrix_Down()) Keys_Scan();else continue;
  242.                 if(KeyNo==0xFF) continue;
  243.                 //功能键处理(9[*]:切换英文/数字,11[#]:清除所有输入)
  244.                 if(KeyNo==9 || KeyNo == 11)
  245.                 {        Function_Key_Process(); Beep(); continue; }
  246.                 //如果是输入数字则直接显示
  247.                 if(!ENG_TEL) goto SHOW_MOBILE_KEY;
  248.                 //如果输入的不是英文字母则继续(英文字符在0~8号键,包括空格)
  249.                 if(KeyNo<0 || KeyNo>8) continue;
  250.                 //否则输入的是英文字符序列,以下代码将根据是否为同位按键进行相应处理
  251.                 if(Pre_KeyNo != KeyNo)         //按下新按键
  252.                 {        Pre_KeyNo = KeyNo;         //保存当前按键
  253.                         Inner_Idx = 1;                 //输入英文时内部索引起点为1
  254.                 }
  255.                 else //否则按下的时相同位置按键
  256.                 {        //同位按键时间间隔在50ms*30=1.5s内则认为是连续按键
  257.                         if(tSpan<31)
  258.                         {        //连续按键时在键内循环递增字符索引
  259.                                 if (++Inner_Idx == strlen(Keypad_Chars[KeyNo]))
  260.                                 Inner_Idx=1;
  261.                                 //因为是连续短按,故将每次显示后递增的输入缓冲索引后退一格,
  262.                                 //以便替换此前输入的字符
  263.                                 --Buffer_Index;
  264.                         } else Inner_Idx = 1; //否则按键内英文字符索引回归起点索引1
  265.                 }
  266.                 tSpan=0; TR0=1;                         //时间间隔归零,计时开始
  267.                 SHOW_MOBILE_KEY:                 //显示按键字符
  268.                 if(Buffer_Index >= 12) continue; //输入缓冲限制在12个字符以内
  269.                 //更新输入缓冲字符串并送LCD显示
  270.                 Input_Buffer[Buffer_Index++] = Keypad_Chars[KeyNo][Inner_Idx];
  271.                 Input_Buffer[Buffer_Index] = '\0';
  272.                 LCD_ShowString(1,4,Input_Buffer);
  273.                 Beep();                                         //输出提示音
  274.                 while(KeyMatrix_Down()); //等待释放按键
  275.         }
  276. }

复制代码
回复

使用道具 举报

7#
ID:55211 发表于 2019-5-16 00:22 | 只看该作者
回复

使用道具 举报

8#
ID:162037 发表于 2023-6-19 14:39 | 只看该作者
#define LCD_PORT P2                //液晶端口(P2高4位)这里宏定义错了,应该是:#define LCD_PORT P0                //液晶端口(P0高4位)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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