|
10黑幣
做的關于LCD1602仿手機顯示字符的實驗。
步驟:1、在keil里編譯無誤代碼生成hex文件 2、將hex文件導入proteus原理圖中
原理圖如下:
1.png (67.64 KB, 下載次數: 95)
下載附件
2019-5-13 20:42 上傳
正常的情況是下圖這種,LCD屏有顯示且按鍵有輸入:
2.png (68.55 KB, 下載次數: 96)
下載附件
2019-5-13 20:42 上傳
下面是我的代碼(為圖方便,把代碼一股腦寫在一塊了),編譯是沒問題的,但導出的hex導入proteus里,LCD液晶屏不顯示,檢查不出程序哪里出了問題,請各位大佬幫忙看一看:
- //-----------------------------------------------------------------
- // 名稱: 鍵盤矩陣掃描程序(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上顯示字符串*/
- #define LCD_PORT P2 //液晶端口(P2高4位)
- //LCD引腳定義
- sbit RS = P2^0; //LCD寄存器選擇
- sbit RW = P2^1; //LCD讀寫控制
- sbit EN = P2^2; //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)
- { LCD_Busy_Wait();
- RS=0; RW=0; //選擇命令寄存器,準備寫
- EN=0; _nop_(); _nop_(); LCD_PORT=cmd; //數據送到液晶屏端口
- delay5us(); EN=1; delay5us(); EN=0; //寫入后禁止液晶屏
- }
- //-----------------------------------------------------------------
- // 向液晶寫數據
- //-----------------------------------------------------------------
- void Write_LCD_Data(INT8U dat)
- { LCD_Busy_Wait();
- RS=1; RW=0;
- EN=0; LCD_PORT=dat; delay5us();
- EN=1; delay5us(); EN=0;
- }
- //-----------------------------------------------------------------
- // 液晶初始化
- //-----------------------------------------------------------------
- void Initialize_LCD()
- { Write_LCD_Command(0x38); delay_ms(1); //置功能,8位,雙行,5*7
- 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()); //等待釋放按鍵
- }
- }
復制代碼 附上原理圖,可在proteus中打開
1602LCD顯示仿手機鍵盤按鍵字符.zip
(16.37 KB, 下載次數: 15)
2019-5-13 20:35 上傳
點擊文件名下載附件
|
|