4线式LCD程序同时控制端也用的是P2口
- //-----------------------------------------------------------------
- // 名称: 键盘矩阵扫描程序(4*3)
- //-----------------------------------------------------------------
- #include <reg51.h>
- #include <intrins.h>
- #define INT8U unsigned char
- #define INT16U unsigned int
- #define KEY_PORT P1 //键盘端口定义
- INT8U KeyNo = 0xFF; //当前按键序号,有效范围为0-15,0xFF表示无按键
- extern void delay_ms(INT16U);
- //-----------------------------------------------------------------
- // 判断键盘矩阵是否有键按下
- //-----------------------------------------------------------------
- INT8U KeyMatrix_Down()
- {
- //高4位输出,低4位输入,高4位先置零,放入4行
- KEY_PORT = 0x0F; delay_ms(1); //高4位置零,放入4行
- return KEY_PORT != 0x0F ? 1:0;
- }
- //-----------------------------------------------------------------
- // 4*3键盘矩阵扫描
- //-----------------------------------------------------------------
- void Keys_Scan()
- {
- //按键后00001111将变成0000XXXX,X中1个位0,3个仍为1
- //判断按键发生于0~3列中的哪一列
- switch (KEY_PORT)
- {
- case 0x0E: KeyNo = 0; break;
- case 0x0D: KeyNo = 1; break;
- case 0x0B: KeyNo = 2; break;
- }
- KEY_PORT=0xF0; delay_ms(1); //
- //按键后11110000将变成XXXX0000,X中1个位0,3个仍为1
- //对0~3行分别附加起始值0,4,8,12
- switch (KEY_PORT)
- { //下面第一行可省略
- case 0xE0: KeyNo += 0; break;
- case 0xD0: KeyNo += 3; break;
- case 0xB0: KeyNo += 6; break;
- case 0x70: KeyNo += 9;
- }
- }
- //-----------------------------------------------------------------
- // 名称: 1602LCD显示仿手机键盘按键字符
- //-----------------------------------------------------------------
- // 说明: 按下仿手机矩阵键盘按键时,对应按键字符显示在1602LCD上
- //
- //-----------------------------------------------------------------
- //#include "LCD1602-4bit.h"
- #include <reg51.h>
- #include <intrins.h>
- #include <string.h>
- #define INT8U unsigned char
- #define INT16U unsigned int
- sbit SPK = P3^7;
- //12个键盘按键字符总表
- //注意串空间应设为6字节,因为最长串为5,设为5时会使部分长串无法附带串结束标志'\0'
- INT8U code Keypad_Chars[12][6] =
- {
- "1 ", "2ABC", "3DEF",
- "4GHI", "5JKL", "6MNO",
- "7PQRS","8TUV", "9WXYZ",
- "*", "0+", "#"
- };
- extern INT8U KeyNo; //键值
- INT8U Inner_Idx=0; //同一按键的内部字符索引
- INT8U tSpan=0; //同键位连续按键的时间间隔
- INT8U Buffer_Index=0; //英文/数字输入缓冲索引
- char Input_Buffer[16]; //输入缓冲空间
- INT8U ENG_TEL=1; //输入内容切换标识(ENG:英文输入,TEL:电话输入)
- extern void delay_ms(INT16U ms);
- extern INT8U KeyMatrix_Down();
- extern void Keys_Scan();
- extern void Initialize_LCD(); //LCD初始化
- extern void LCD_ShowString(INT8U r, INT8U c,char *str); //在LCD上显示字符串*/
- //是4线式(穿行数据输入)程序
- //程序同时控制端也用的是P2口
- #define LCD_PORT P2 //液晶端口(P2高4位)
- //LCD引脚定义
- sbit RS = P2^0; //LCD寄存器选择
- sbit RW = P2^1; //LCD读写控制
- sbit EN = P2^2; //LCD使能控制
- //sbit RS = P3^2; //LCD寄存器选择
- //sbit RW = P3^3; //LCD读写控制
- //sbit EN = P3^4; //LCD使能控制
- /*//LCD相关函数
- void delay_ms(INT16U x); //延时函数
- void LCD_Busy_Wait(); //忙等待
- void Write_LCD_Data(INT8U dat); //向LCD写数据
- void Write_LCD_Command(INT8U cmd); //写LCD指令
- void Initialize_LCD(); //LCD初始化
- void LCD_ShowString(INT8U r, INT8U c,char *str); //在LCD上显示字符串*/
- //-----------------------------------------------------------------
- // 名称: LCD1602液晶驱动程序
- //-----------------------------------------------------------------
- //#include "LCD1602-4bit.h"
- #define delay5us() {_nop_();_nop_();_nop_();_nop_();_nop_();}
- //-----------------------------------------------------------------
- // 延时函数
- //-----------------------------------------------------------------
- void delay_ms(INT16U x)
- {
- INT8U t; while(x--) for(t = 0; t < 120; t++);
- }
- //-----------------------------------------------------------------
- // 液晶忙等待
- //-----------------------------------------------------------------
- /*
- void LCD_Busy_Wait()
- {
- INT8U LCD_Status; //液晶状态字节变量
- do
- {
- LCD_PORT=0xFF;
- RS=0; RW=1;
- EN=1; delay5us(); LCD_Status=P2; EN=0;
- }while (LCD_Status & 0x80); //液晶忙继续循环
- } */
- //-----------------------------------------------------------------
- // 写液晶命令
- //-----------------------------------------------------------------
- void Write_LCD_Command(INT8U cmd)
- {
- INT8U Temp1, Temp2;
- //LCD_Busy_Wait();
- EN = 0; //使能清零
- RS=0; RW=0; //选择命令寄存器,准备写
- EN=0; _nop_(); _nop_();
- //由于4位的接线是接到LCD_PORT口的高四位,所以传送高四位不用改
- Temp1 = LCD_PORT&0x0f;
- Temp2= (cmd&0xf0);
- LCD_PORT= (Temp2|Temp1); //数据送到液晶屏端口
- delay_ms(1);
- EN=1; //写入时序
- delay_ms(1); EN=0; //写入后禁止液晶屏
- Temp2= (cmd << 4);
- Temp2&=0xf0;
- LCD_PORT= (Temp2|Temp1); //写入低四位
- EN=1; //写入时序
- delay_ms(1); EN=0;
-
- }
- //-----------------------------------------------------------------
- // 向液晶写数据
- //-----------------------------------------------------------------
- void Write_LCD_Data(INT8U dat)
- {
- INT8U Temp1, Temp2;
- //LCD_Busy_Wait();
- EN = 0; //使能清零
- RS=1; RW=0;
- EN=0;
- Temp1 = LCD_PORT&0x0f;
- Temp2= (dat&0xf0); //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
- LCD_PORT=(Temp2|Temp1); //数据送到液晶屏端口
- delay_ms(1);
- EN=1; //写入时序
- delay_ms(1); EN=0;
- Temp2= (dat << 4);
- Temp2&=0xf0;
- LCD_PORT = (Temp2|Temp1); //写入低四位
- EN=1; //写入时序
- delay_ms(1); EN=0;
-
- }
- //-----------------------------------------------------------------
- // 液晶初始化
- //-----------------------------------------------------------------
- void Initialize_LCD()
- {
- //Write_LCD_Command(0x38); delay_ms(1); //置功能,8位,双行,5*7
- Write_LCD_Command(0x32); delay_ms(1); //将8位总线转为4位总线
- Write_LCD_Command(0x28); delay_ms(1); // 在四位线下的初始化
- Write_LCD_Command(0x06); delay_ms(1); //字符进入模式:屏幕不动,字符后移
- Write_LCD_Command(0x0C); delay_ms(1); //显示开,关光标
- Write_LCD_Command(0x01); delay_ms(1); //清屏
- }
- //-----------------------------------------------------------------
- // 在指定位置显示字符串
- //-----------------------------------------------------------------
- void LCD_ShowString(INT8U r, INT8U c,char *str)
- {
- INT8U i=0;
- INT8U code DDRAM[] = {0x80,0xC0}; //液晶屏上下两行的DDRAM首地址
- Write_LCD_Command(DDRAM[r] |c); //设置显示起始位置
- while (str[i] && i < 16) Write_LCD_Data(str[i++]);//输出显示字符
- }
- //-----------------------------------------------------------------
- // 蜂鸣器
- //-----------------------------------------------------------------
- void Beep()
- {
- INT8U i; for(i=0;i<60;i++){SPK=!SPK; delay_ms(1);}
- SPK=1;delay_ms(100);
- }
- //-----------------------------------------------------------------
- // 定时器0跟踪同位按键的时间间隔
- //-----------------------------------------------------------------
- void T0_INT() interrupt 1
- {
- //重新设置50ms定时初值
- TH0=-50000>>8; TL0=-50000&0xFF;
- //tSpan最大值限制在41及以上即可
- //不加限制时会使某次较长的延时累加超过255后,
- //累加又从0开始,而程序判断时它可能刚好还在40以内,
- //从而导致较长的延时却被误断为较短的延时
- if(tSpan<50) tSpan++;else TR0=0;
- }
- //-----------------------------------------------------------------
- // 功能键处理 *(9):切换输入,#(11)键清除内容
- //-----------------------------------------------------------------
- void Function_Key_Process()
- {
- if(KeyNo==9) //输入内容标识切换
- { ENG_TEL=!ENG_TEL;
- Inner_Idx=ENG_TEL?1:0; //如果是输入英文,内部索引为1,否则设为0
- }
- Buffer_Index=0; //输入缓冲索引归0
- Input_Buffer[0]='\0'; //将输入缓冲设为空串
- if(ENG_TEL) LCD_ShowString(1,0,"ENG> "); //显示输入英文
- else LCD_ShowString(1,0,"TEL> "); //显示输入电话
- while(KeyMatrix_Down()); //等待释放按键
- }
- //-----------------------------------------------------------------
- // 主程序
- //-----------------------------------------------------------------
- void main()
- {
- INT8U Pre_KeyNo=-1;
- IE=0x82; //使能T0中断
- TMOD=0x01; //T0工作于模式1(16位模式)
- TH0=-50000>>8; //定时50ms
- TL0=-50000&0xFF;
- Initialize_LCD(); //液晶初始化
- //显示固定信息部分(初始显示ENG>表示输入英文字符序列)
- LCD_ShowString(0,0," Mobile KeyPad ");
- LCD_ShowString(1,0,"ENG> ");
- while(1)
- { //有键按下则扫描,否则不进行任何处理
- if(KeyMatrix_Down()) Keys_Scan();else continue;
- if(KeyNo==0xFF) continue;
- //功能键处理(9[*]:切换英文/数字,11[#]:清除所有输入)
- if(KeyNo==9 || KeyNo == 11)
- { Function_Key_Process(); Beep(); continue; }
- //如果是输入数字则直接显示
- if(!ENG_TEL) goto SHOW_MOBILE_KEY;
- //如果输入的不是英文字母则继续(英文字符在0~8号键,包括空格)
- if(KeyNo<0 || KeyNo>8) continue;
- //否则输入的是英文字符序列,以下代码将根据是否为同位按键进行相应处理
- if(Pre_KeyNo != KeyNo) //按下新按键
- { Pre_KeyNo = KeyNo; //保存当前按键
- Inner_Idx = 1; //输入英文时内部索引起点为1
- }
- else //否则按下的时相同位置按键
- { //同位按键时间间隔在50ms*30=1.5s内则认为是连续按键
- if(tSpan<31)
- { //连续按键时在键内循环递增字符索引
- if (++Inner_Idx == strlen(Keypad_Chars[KeyNo]))
- Inner_Idx=1;
- //因为是连续短按,故将每次显示后递增的输入缓冲索引后退一格,
- //以便替换此前输入的字符
- --Buffer_Index;
- } else Inner_Idx = 1; //否则按键内英文字符索引回归起点索引1
- }
- tSpan=0; TR0=1; //时间间隔归零,计时开始
- SHOW_MOBILE_KEY: //显示按键字符
- if(Buffer_Index >= 12) continue; //输入缓冲限制在12个字符以内
- //更新输入缓冲字符串并送LCD显示
- Input_Buffer[Buffer_Index++] = Keypad_Chars[KeyNo][Inner_Idx];
- Input_Buffer[Buffer_Index] = '\0';
- LCD_ShowString(1,4,Input_Buffer);
- Beep(); //输出提示音
- while(KeyMatrix_Down()); //等待释放按键
- }
- }
复制代码 |