1602全過(guò)程C語(yǔ)言編程_第1頁(yè)
1602全過(guò)程C語(yǔ)言編程_第2頁(yè)
1602全過(guò)程C語(yǔ)言編程_第3頁(yè)
1602全過(guò)程C語(yǔ)言編程_第4頁(yè)
免費(fèi)預(yù)覽已結(jié)束,剩余63頁(yè)可下載查看

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

51單片機(jī)系列ー16021602字符液晶在實(shí)際的產(chǎn)品中運(yùn)用的也比較多了,前幾天留意了一下,發(fā)現(xiàn)宿舍門前的自動(dòng)售水機(jī)就是采用的1602液晶進(jìn)行顯示的。而且對(duì)于單片機(jī)的學(xué)習(xí)而言,掌握1602的用法是每ー個(gè)學(xué)習(xí)者必然要經(jīng)歷的過(guò)程。在此,我將使用1602過(guò)程中遇到的問(wèn)題以及感受記錄下來(lái),希望能夠給初學(xué)者帶來(lái)一點(diǎn)指導(dǎo),少走ー點(diǎn)彎路。所謂1602是指顯示的內(nèi)容為16*2,即可以顯示兩行,每行16個(gè)字符。目前市面上字符液晶絕大多數(shù)是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780寫的控制程序可以很方便地應(yīng)用于市面上大部分的字符型液晶。1602液晶的正面(綠色1602液晶的正面(綠色背光,黑色字體)1602液晶背面(綠色背光,黑色字體)1602液晶背面(綠色背光,黑色字體)背光白色字體字符型LCD1602通常有14條引腳線或16條引腳線的LCD,多出來(lái)的2條線是背光電源線VCC(15腳)和地線GND(16腳),其控制原理與14腳的LCD完全一樣,引腳定義如ド表所示:引腳號(hào)引腳g電平輸入,輸出作用1Uss電源地2Ucc電源(+5U)3Uee對(duì)比洞整電壓4RS0/1輸入然疑5R/W0/1輸入即向LCD寫入指令或數(shù)據(jù)“從LCDi矣取信息6E1,1—0輸入便能信號(hào),1吋渉取信息、?1ー。(下降沿)舲指令7DBO0/1輸入/輸出數(shù)據(jù)總線line。(最低位)8DB10/1輸入,輸出數(shù)據(jù)總線linel9DB20/1輸入/治出數(shù)據(jù)總線1ine210DB30/1箱!入,播出數(shù)據(jù)總線Une311DB40/1輸入ノ輸出數(shù)據(jù)總線line412DB50/1輸入,輸出數(shù)據(jù)總線lines13DB60/1輸入/輸出數(shù)據(jù)總線line614DB70/1輸入ノ輸出數(shù)據(jù)總線】ine7(最髙位)15A?Ucc"D背光電源正極16K接地"D背光電源負(fù)極HD44780內(nèi)置了DDRAM、CGROM和CGRAM。DDRAM就是顯示數(shù)據(jù)RAM,用來(lái)寄存待顯示的字符代碼。共80個(gè)字節(jié),其地址和屏幕的對(duì)應(yīng)關(guān)系如卜.表:顯示位置1234567 40DDRAM地址第一行0OH01H02H03H04H05H06H 27H第二行40H41H42H43H115H46H 67H也就是說(shuō)想要在LCD1602屏幕的第一行第一列顯示ー個(gè)"A"字,就要向DDRAM的OOH地址寫入“パ字的代碼就行了。但具體的寫入是要按LCD模塊的指令格式來(lái)進(jìn)行的,后面我會(huì)說(shuō)到的。那么一行可有40個(gè)地址呀?是的,在1602中我們就用前16個(gè)就行了。第二行也ー樣用前16個(gè)地址。對(duì)應(yīng)如下:DDRAM地址與顯示位置的對(duì)應(yīng)關(guān)系f )iOOH01H02H03H04H05H06H07H08H09HOAHOBHOCHODHOEHOFHj:40H41H42H43H44H45H46H47H48H49H4AH4BH4cHUDH"EH4FHiI J(事實(shí)上我們往DDRAM里的OOH地址處送ー個(gè)數(shù)據(jù),譬如0x31(數(shù)字1的代碼)并不能顯示1出來(lái)。這是ー個(gè)令初學(xué)者很容易出錯(cuò)的地方,原因就是如果你要想在DDRAM的00H地址處顯示數(shù)據(jù),則必須將00H加上80H,即80H,若要在DDRAM的01H處顯示數(shù)據(jù),則必須將01H加上80H即81H。依次類推。大家看一下控制指令的的8條:DDRAM地址的設(shè)定,即可以明白是怎么樣的一回事了)1602液晶模塊內(nèi)部的字符發(fā)生存儲(chǔ)器(CGROM)已經(jīng)存儲(chǔ)了160個(gè)不同的點(diǎn)陣字符圖形,如下表所示,這些字符有:阿拉伯?dāng)?shù)字、英文字母的大小寫、常用的符號(hào)、和日文假名等,每ー個(gè)字符都有一個(gè)固定的代碼,比如大寫的英文字母“A”的代碼是01000001B(41H),顯示時(shí)模塊把地址41H中的點(diǎn)陣字符圖形顯示出來(lái),我們就能看到字母“A”

■■CGRO!中字符碼與字字符字模關(guān)系對(duì)奧表■ 〇(2000010010001101000101011001111000100110101011H00110111101111oxkOOOCCGRAN(1)00P、戸ーyW瞑PoxxOOOl⑵i!1舊@ヨ回oIアチ心后q?x*x0010(3)"IZIBIRIblrl「四加"e.xx<00:1(4)1#|3|C|S|c|s|Z5M&mxxxOIOC0*|4|D|T|d|tゝセ叵GoxkOIOI<>>15i|5|ElU|e|u|?幣ナロ后??MXxxOl10&|6|F|U|f|u|引力に目ゆ,)000(0111*331§酮向ア芹岡ラ目?x*<W:(1)1(|8H|X|h|x|イり津リGXMJUU1001(2)|>l9IIIVIi|y|司ケリ吁HoomlO^O(3)J*|5|J|Z|J|Z|エロ同レ5xxxxlOHH)1+ISIKIC|k|(|オけ舊口聲萬(wàn)MXXXllOC(S)/ぐL用1111向ンGワ年円mxmIIOI(6)JEHHIIlnlHュ國(guó)へ麻*■(7)|-l>INrinH回セIホド肝JOUU1111(8)Jノl?IOl_lo*l?y|U|?|B[o1上表中的字符代碼與我們PC中的字符代碼是基本一致的。因此我們?cè)谙駾DRAM寫C51字符代碼程序時(shí)甚至可以直接用P1='A'這樣的方法。PC在編譯時(shí)就把“A”先轉(zhuǎn)為41H代碼了。字符代碼OxOO-OxOF為用戶自定義的字符圖形RAM(對(duì)于5X8點(diǎn)陣的字符,可以存放8組,5X10點(diǎn)陣的字符,存放4組),就是CGRAM了。后面我會(huì)詳細(xì)說(shuō)的。0x2〇?0x7F為標(biāo)準(zhǔn)的ASCII碼,OxA〇?OxFF為日文字符和希臘文字符,其余字符碼(0x1〇?0x1F及0x8〇?0x9F)沒(méi)有定義。那么如何對(duì)DDRAM的內(nèi)容和地址進(jìn)行具體操作呢,ド面先說(shuō)說(shuō)HD44780的指令集及其設(shè)置說(shuō)明,請(qǐng)瀏覽該指令集,并找出對(duì)DDRAM的內(nèi)容和地址進(jìn)行操作的指令。共11條指令:

1.清屏指令指令功能指令編碼齬/HSRSR/VDB7DB6DBSDBUDB3DB2DB1DBO清屏0?電00000011.611功能:<1>清除液晶顯示器,即將DDRAM的內(nèi)容全部填入"空白"的ASCII碼20H;<2>光標(biāo)歸位,即將光標(biāo)撤冋液晶顯示屏的左上方;<3>將地址計(jì)數(shù)器(AC)的值設(shè)為〇。2.光標(biāo)歸位指令1指令功能指令編碼執(zhí)行時(shí)間ノRSRSR/WD87DB6DBSDB"DB3DB2OB1DBD光標(biāo)歸位000000001X1.611功能:把光標(biāo)撤冋到顯示器的左上方;<2>把地址計(jì)數(shù)器(AC)的值設(shè)置為〇;<3>保持DDRAM的內(nèi)容不變.進(jìn)入模式設(shè)置指令指令功能指令編碼牖/USRSR/WDB7DB6DBSDBHDB3DB2DB1DBO逬入模式設(shè)置00000001I/DSiiO功能:設(shè)定每次定入1位數(shù)據(jù)后光標(biāo)的移位方向,并且設(shè)定每次寫入的ー個(gè)字符是否移動(dòng)。參數(shù)設(shè)定的情況如ド所示:位名設(shè)置I/D〇=寫入新數(shù)據(jù)后光標(biāo)左移1=寫入新數(shù)據(jù)后光標(biāo)右移S0=寫入新數(shù)據(jù)后顯示屏不移動(dòng)1=寫入新數(shù)據(jù)后顯示屏整體右移1個(gè)字

.顯示開(kāi)關(guān)控制指令指令功能指令編碼駆/USRSR/WDB7DB6DBSDB"DB3DB2DB1DBO顯示開(kāi)關(guān)控制0000001DCB功能:控制顯示器開(kāi)/關(guān)、光標(biāo)顯示/關(guān)閉以及光標(biāo)是否閃爍。參數(shù)設(shè)定的情況如下:位名設(shè)置D0=顯示功能關(guān)1=顯示功能開(kāi)C0=無(wú)光標(biāo)1=有光標(biāo)B0=光標(biāo)閃爍1=光標(biāo)不閃爍.設(shè)定顯示屏或光標(biāo)移動(dòng)方向指令指令功能指令編碼牆/USRSR/WDB7DB6DBSDB"DB3DB2DB1DBO聯(lián)齬關(guān)000001S/CR/LXX功能:使光標(biāo)移位或使整個(gè)顯示屏幕移位。參數(shù)設(shè)定的情況如ド:S/CR/L設(shè)定情況00光標(biāo)左移1格,且AC值減101光標(biāo)右移1格,且AC值加110顯示器上字符全部左移一格,但光標(biāo)不動(dòng)11顯示器上字符全部右移一格,但光標(biāo)不動(dòng).功能設(shè)定指令指令功能指令編碼辦行時(shí)向/USRSR/VDB7DB6DBSDB4DB3DB2DB1DBO功能設(shè)定0■001DLNFXx40功能:設(shè)定數(shù)據(jù)總線位數(shù)、顯示的行數(shù)及字型。參數(shù)設(shè)定的情況如下:

位名設(shè)置DL0=數(shù)據(jù)總線為4位1=數(shù)據(jù)總線為8位N0=顯示1行1=顯示2行F0=5x7點(diǎn)陣/每字符1=5x10點(diǎn)陣/每字符.設(shè)定CGRAM地址指令指令功能指令編碼嬌/USRSR/WDB7086DB5DB4DB3DB2DB1DB0設(shè)定CGRAM地址0001CGRAM的地址(6位)40功能:設(shè)定下ー個(gè)要存入數(shù)據(jù)的CGRAM的地址。.設(shè)定DDRAM地址指令I(lǐng)指令功能指令編碼豊行時(shí)間/USRSR/WDB7DB6DBSDB4DB3DB2DB1DB0設(shè)定DDRAM地址001CGRAM的地址(7位)40功能:設(shè)定ドー個(gè)要存入數(shù)據(jù)的CGRAM的地址。(注意這里我們送地址的時(shí)候應(yīng)該是0x80+Address,這也是前面說(shuō)到寫地址命令的時(shí)候要加上0x80的原因).讀取忙信號(hào)或AC地址指令指令功能指令編碼時(shí)恂/USRSR/WDB7DB6DB5DB4DB3DB2DB1DB0族取忙對(duì)或AC先灌號(hào)01FBAC內(nèi)容(7位)40功能:<1>讀取忙碌信號(hào)BF的內(nèi)容,BF=1表示液晶顯示器忙,暫時(shí)無(wú)法接收單片機(jī)送來(lái)的數(shù)據(jù)或指令;當(dāng)BF=O時(shí),液晶顯示器可以接收單片機(jī)送來(lái)的數(shù)據(jù)或指令;<2>讀取地址計(jì)數(shù)器(AC)的內(nèi)容。!〇.數(shù)據(jù)寫入DDRAM或CGRAM指令一覽指令功能指令編碼時(shí)拘/USRSR/WDB70B6DBSDB4DB3DB2?!癉BO數(shù)據(jù)寫入到DDRAM或CGRAM10要寫人的數(shù)據(jù)07-00H0功能:<1>將字符碼寫入DDRAM,以使液晶顯示屏顯示出相對(duì)應(yīng)的字符;<2>將使用者自己設(shè)計(jì)的圖形存入CGRAM。11.從CGRAM或DDRAM讀出數(shù)據(jù)的指令一覽指令功能指令編碼嬌/usRSR/WDBZDB6DBSDB8DB3DB2DH1DBO從CGRAM或DDRAMi笑出數(shù)據(jù),11要讀岀的數(shù)據(jù)07-0040功能:讀取DDRAM或CGRAM中的內(nèi)容?;静僮鲿r(shí)序:讀狀態(tài) 輸入:RS=L,RW=H,E=H輸出:DB〇?DB7=狀態(tài)字寫指令 輸入:RS=L,RW=L,E=下降沿脈沖,DB〇?DB7=指令碼輸出:無(wú)讀數(shù)據(jù) 輸入:RS=H,RW=H,E=H輸出:DB〇?DB7=數(shù)據(jù)寫數(shù)據(jù) 輸入:RS=H,RW=L,E=下降沿脈沖,DB〇?DB7=數(shù)據(jù)輸出:無(wú)呵呵,看到這么多的控制指令希望你沒(méi)有頭暈。其實(shí)這么多的指令剛開(kāi)始的時(shí)候沒(méi)有必要全部掌握,隨著學(xué)習(xí)的深入可以再嘗試去用更復(fù)雜的控制指令。卜.面讓我們ー起驅(qū)動(dòng)1602的液晶吧。卜,面是我的液晶的連接圖,用的是那種藍(lán)底白字的液晶,其實(shí)藍(lán)底白字和那種綠底黑字的液晶唯一的區(qū)別就是顏色的問(wèn)題,至于用哪種液晶,就看各位自己的喜好咯。這就是我做測(cè)試用的最小系統(tǒng),單片機(jī)是STC89c516,晶振為12M。液晶為藍(lán)底白字的那種1602。當(dāng)我們硬件連接錯(cuò)誤,或者程序錯(cuò)誤時(shí)就會(huì)出現(xiàn)ド圖這種情況,就是上排顯示16的白色的塊(藍(lán)底黑字的液晶則顯示的是16個(gè)黑塊)。ド面我們來(lái)驅(qū)動(dòng)1602吧在1602的上排顯示“LCD1602checkok”下排顯示,'studyup”程序中沒(méi)有用到忙檢測(cè),而是用的是延時(shí)函數(shù)來(lái)替代忙檢測(cè)include<reg52.h> 〃包含頭文件,這個(gè)嘛,就不用多說(shuō)了??defineuintunsignedint〃預(yù)定義一下defineucharunsignedcharsbitrs=P3A5; //1602的數(shù)據(jù)/指令選擇控制線sbitrw=P3A6; 〃1602的讀寫控制線sbiten=P3A7; //1602的使能控制線/*P2口接1602的D0~D7,注意不要接錯(cuò)了順序,我以前可在這上面吃過(guò)虧??/ucharcodetable[]="LCD1602checkok";〃要顯示的內(nèi)容1放入數(shù)組tabletucharcodetablel[]="studyup"; 〃要顯示的內(nèi)容2放入數(shù)組tablelvoiddelay(uintn) 〃延時(shí)函數(shù)uintx,y;for(x=n;x>0;x--)for(y=110;y>0;y--);}voidlcd_wcom(ucharcom)//1602寫命令函數(shù){rs=O; 〃選擇指令寄存器rw=0; 〃選擇寫P2=com; 〃把命令字送入P2delay(5); 〃延時(shí)ー小會(huì)兒,讓1602準(zhǔn)備接收數(shù)據(jù)en=1J 〃使能線電平變化,命令送入1602的8位數(shù)據(jù)口en=0;)voidlcd_wdat(uchardat)//1602寫數(shù)據(jù)函數(shù){rs=1; 〃選擇數(shù)據(jù)寄存器rw=0;〃選擇寫P2=dat; 〃把要顯示的數(shù)據(jù)送入P2delay(5); 〃延時(shí)ー小會(huì)兒,讓1602準(zhǔn)備接收數(shù)據(jù)en=1J 〃使能線電平變化,數(shù)據(jù)送入1602的8位數(shù)據(jù)口en=0;)voidlcd_init() //1602初始化函數(shù)(Icd_wcom(0x38); 〃8位數(shù)據(jù),雙列,5*7字形lcd_wcom(0x0c); 〃開(kāi)啟顯示屏,關(guān)光標(biāo),光標(biāo)不閃爍Icd_wcom(0x06); 〃顯示地址遞增,即寫ー個(gè)數(shù)據(jù)后,顯示位置右移一位Icd_wcom(0x01); 〃清屏)voidmain() 〃主函數(shù)(ucharn,m=0;lcd_init(); 〃液晶初始化Icd_wcom(0x80);〃顯示地址設(shè)為80H(即00H,)上排第一位for(m=0;m<16;m++) 〃將table口中的數(shù)據(jù)依次寫入1602顯示(lcd_wdat(table[m]);delay(200);)Icd_wcom(0x80+0x44);〃重新設(shè)定顯示地址為0xc4,即卜,排第5位for(n=0;n<8;n++)〃將tablel口中的數(shù)據(jù)依次寫入1602顯示(Icd_wdat(table1[n]);delay(200);)while(1); 〃動(dòng)態(tài)停機(jī)程序?qū)懞煤鬅龑戇M(jìn)單片機(jī),現(xiàn)在讓我們看看效果吧這就是顯示的效果,你做成功了嗎?ド面讓我們來(lái)看看如何顯示ー個(gè)自定義的字符吧我們從CGROM表上可以看到,在表的最左邊是一列可以允許用戶自定義的CGRAM,從上往下看著是16個(gè),實(shí)際只有8個(gè)字節(jié)可用。它的字符碼是〇〇〇〇()〇〇〇ー00000111這8個(gè)地址,表的ド面還有8個(gè)字節(jié),但因?yàn)檫@個(gè)CGRAM的字符碼規(guī)定〇一2位為地址,3位無(wú)效,4-7全為零。因此CGRAM的字符碼只有最后三位能用也就是8個(gè)字節(jié)了。等效為0000X111,X為無(wú)效位,最后三位為000—111共8個(gè)。如果我們要想顯示這8個(gè)用戶自定義的字符,操作方法和顯示CGROM的ー樣,先設(shè)置DDRAM位置,再向DDRAM寫入字符碼,例如“A”就是41H?,F(xiàn)在我們要顯示CGRAM的第一個(gè)自定義字符,就向DDRAM寫入000000OOB(OOH),如果要顯示第8個(gè)就寫入00000111(08H),簡(jiǎn)單吧!好!現(xiàn)在我們來(lái)看怎么向這八個(gè)自定義字符寫入字模。有個(gè)設(shè)置CGRAM地址的指令大家還記得嗎?趕快再找出來(lái)看看。指令功能指令編碼離/USRSR/WDB7DB6DBSDB4DB3DB2DB1DHI1設(shè)定CCRAM地址0001CGRAN的地址(地)k0從這個(gè)指令可以看出指令數(shù)據(jù)的高2位已固定是01,只有后面的6位是地址數(shù)據(jù),而這6位中的高3位就表示這八個(gè)自定義字符,最后的3位就是字模數(shù)據(jù)的八個(gè)地址了。例如第一個(gè)自定義字符的字模地址為01000000—01000111八個(gè)地址。我們向這8個(gè)字節(jié)寫入字模數(shù)據(jù),讓它能顯示出“。C”地址:01000000數(shù)據(jù):00010000圖小:OOOBOOOO0100000100000110OOOOOHBO0100001000001001ooooioob0100001100001000oooobooo0100010000001000oooobooo0100010100001001OOOOBOOB0100011000000110OOOOOBBO0100011100000000oooooooo下面我們寫一段程序讓這8個(gè)自定義字符顯示出ー個(gè)心的圖案:(由于上面那個(gè)顯示程序已經(jīng)有很詳細(xì)的注釋了,因此這個(gè)程序只對(duì)與上個(gè)程序不同的地方寫注釋)include<reg52.h>defineuintunsignedint#defineucharunsignedcharsbitrs=P3A5;sbitrw=P3A6;sbiten=P3A7;ucharcodetable[]={0x03,0x07,OxOf,Ox1f,0x1f,0x1f,0x1f,0x1f,0x18,0x1E,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x07,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x10,0x18,0x1c,0x1E,0x1E,0x1E,0x1E,0x1E,OxOf,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x07,0x01,0x1f,0x1f,0x1f,0x1f,0x1f,0x1c,0x18,0x00,0x1c,0x18,0x10,0x00,0x00,0x00,0x00,0x00};〃心圖案/*ucharcodetable1[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00}"/字符℃*/voiddelay(uintn)(uintx,y;for(x=n;x>0;x--)for(y=110;y>0;y--);}voidlcd_wcom(ucharcom)(rs=O;rw=0;R2=com;delay(5);en=1;en=0;)voidlcd_wdat(uchardat){rs=1;rw=0;P2=dat;delay(5);en=1;en=0;)voidlcd_init()|Icd_wcom(0x38);lcd_wcom(0x0c);Icd_wcom(0x06);Icd_wcom(0x01);)voidmain()(charm=0;lcd_init();Icd_wcom(0x40); 〃設(shè)定CGRAM地址for(m=0;m<64;m+) 〃將心型代碼寫入CGRAM中Icd_wdat(table[m]);Icd_wcom(0x85);〃設(shè)定上排的顯示位置Icd_wcom(0x85);〃設(shè)定上排的顯示位置for(m=for(m=0;m<4;m++)〃顯示心型圖案的上半部分lcd_wdat(m);lcd_wdat(m);Icd_wcom(0xc5);〃將顯示坐標(biāo)轉(zhuǎn)移到Icd_wcom(0xc5);〃將顯示坐標(biāo)轉(zhuǎn)移到卜.排和上排相對(duì)應(yīng)的地方for(m=4;m<8;m++)//顯示心型圖案的for(m=4;m<8;m++)//顯示心型圖案的ド半部分lcd_wdat(m);)lcd_wdat(m);)while(1);讓我們ー起來(lái)看看顯示的效果吧??在綠底黑字液晶模塊和藍(lán)底白字液晶模塊上分別顯示的效果。在綠底黑字液晶模塊和藍(lán)底白字液晶模塊上分別顯示的效果。ド面再為大家展示幾種可能出現(xiàn)的問(wèn)題1;通電之后,程序也燒寫進(jìn)去了,但是1602就是不顯示,只顯示ー排黑塊(一般都是在上排8個(gè)小黑塊,記得剛開(kāi)始用1602液晶的時(shí)候,被這個(gè)整怕了??),怎么樣,你郁悶了吧,其實(shí)出現(xiàn)這種問(wèn)題的原因無(wú)非以下幾種:硬件連線上的錯(cuò)誤,這種錯(cuò)誤一般用萬(wàn)用表仔細(xì)檢查后很容易找出來(lái)。第二種情況就是硬件連接上是正確的,那么此時(shí)出問(wèn)題最大的就是程序上了,如果你用的是忙檢測(cè),看ート,忙檢測(cè)函數(shù)寫對(duì)了沒(méi),如果用的是延時(shí)函數(shù),那么看看延時(shí)的時(shí)間是否夠長(zhǎng)。再就是看看時(shí)序圖,這點(diǎn)很重要的哦。如果硬件和軟件都沒(méi)有錯(cuò),那么就要考慮1602是否壞了,但是出現(xiàn)這種情況的幾率很小,如果遇到這種情況,你可以考慮去買彩票了??ド面這種情況你遇到過(guò)嗎?我遇到過(guò)了的,搞得我很是郁悶??我做的實(shí)驗(yàn)是要液晶顯示ABC這三個(gè)字母,并且開(kāi)光標(biāo),光標(biāo)閃爍。大家可以在第ー排的最后幾位看到ABC和光標(biāo)都已經(jīng)顯示出來(lái)了。但是為什么其它位會(huì)顯示這么多8呢?嘿嘿??郁悶吧。出現(xiàn)這種情況的原因就是在初始化液晶的時(shí)候,要把清屏指令放在最后面,否則就會(huì)出現(xiàn)上圖這種情況。怎么樣,第一次聽(tīng)說(shuō)吧?不過(guò),我不知道其它的液晶是否也有這個(gè)問(wèn)題出現(xiàn),至少我用的這塊就有這種情況,但是我的另ー個(gè)液晶則沒(méi)有這種情況出現(xiàn),不管是在ー開(kāi)始就清屏還是最后清屏。大家注意ド就可以了,萬(wàn)一出現(xiàn)了這種情況,就會(huì)處理了—上面這張圖是用1602作為顯示的溫度電子鐘??上面的年月日三個(gè)字就是用自定義字符的方法顯示的。呵呵,怎么樣??到此1602的驅(qū)動(dòng)基本上結(jié)束了,剩下的就靠大家自己去發(fā)揮了。*LCD1602.pdf(2010-02-0516:03:05,Size:579KB,Downloads:23)tiankai(2010-2-0516:31:51)晨輝教你輕松學(xué)51 按鍵篇對(duì)于?個(gè)由單片機(jī)為核心構(gòu)成的系統(tǒng)而言。輸入通道是相當(dāng)重要的??梢钥吹絻汉趺?樣基于單片機(jī)的產(chǎn)品都有人機(jī)交互的部分。如各種儀器設(shè)備上的各種按鈕和開(kāi)關(guān),以及我們手機(jī)上的鍵盤,MP3上的按鍵等等。最常見(jiàn)的輸入部分,莫非就是按鍵了。對(duì)于大多數(shù)初學(xué)者而言,編寫?個(gè)好的按鍵程序是?件頗為頭疼的事情。于是乎在網(wǎng)上亂搜ー氣,程序倒是找到了不少,但是看了半天依然是不明白?;蛘咴谀衬痴搲厦姘l(fā)帖“跪求xx按健程序,大蝦幫忙…..”如果你偶然間進(jìn)了這個(gè)論壇,乂偶然看到了這個(gè)帖ア,而且恰好你對(duì)按鍵程序的寫法也不是很淸楚,那么我希望你能夠靜靜的看完這個(gè)帖子。如果你覺(jué)得對(duì)你很有幫助,那么我希望你能夠在以后的口子中能夠堅(jiān)持到這個(gè)論壇來(lái),?起交流學(xué)習(xí),分享自己學(xué)習(xí)過(guò)程中的喜悅或擰ー起探討棘手的問(wèn)題,這是我寫這個(gè)帖子的最大的初衷了。〇K.不能再說(shuō)了,再說(shuō)就變成水帖了。那么我們開(kāi)始吧。按鍵的種類很多。不過(guò)原理基本相似。下面我們以ー種輕觸開(kāi)關(guān)為例講解按鍵程序的寫法。這種輕觸開(kāi)關(guān)大家不陌生吧"_A一般情況下,按鍵與單片機(jī)的連接如下面這幅圖所示。(圖中電阻值?般去4.7k~10k之間,對(duì)于內(nèi)部端口有上拉電阻的単片機(jī)則可省略此電阻)單片機(jī)對(duì)于按鍵的按下與否則是通過(guò)檢測(cè)相應(yīng)引腳上的電平來(lái)實(shí)現(xiàn)的。對(duì)于上圖而言,當(dāng)P17引腳上面的電平為低時(shí),則友示按鍵已經(jīng)按下。反之,則發(fā)明按鍵沒(méi)有按下。我們?cè)诔绦蛑兄灰獧z測(cè)到了P17引腳上面的電平為低了,就可以判斷按鍵按下。呵呵,簡(jiǎn)單吧。等會(huì),您先別樂(lè)呵,話還沒(méi)說(shuō)完呢。下面我們來(lái)看看,當(dāng)按鍵按下時(shí),P17引腳上面的波形是怎么變化的。上圖是ー個(gè)理想波形圖,當(dāng)按鍵按下時(shí),P17U的電平馬上被拉低到0V了。當(dāng)然理想的東西都是不現(xiàn)實(shí)的。所以我們還是看看現(xiàn)實(shí)的波形圖吧??闯鍪裁磪^(qū)別來(lái)了沒(méi)。呵呵,只要你不是傻子我相信都能看出其中的區(qū)別。由于按鍵的機(jī)械特性。當(dāng)按鍵閉合時(shí),并不能馬上保存良好的接觸,而是來(lái)回彈跳。這個(gè)時(shí)間很短,我們的手根本感覺(jué)不出來(lái)。但是對(duì)于一秒鐘執(zhí)行百萬(wàn)條指令的單片機(jī)而言,這個(gè)時(shí)間是相當(dāng)?shù)拈L(zhǎng)了。那么在這段抖動(dòng)的時(shí)間內(nèi),單片機(jī)可能讀到多次高低電平的變化。如果不加任何處理的話,就會(huì)認(rèn)為已經(jīng)按下,或者松開(kāi)很多次了。而事實(shí)上,我們的手一直按在按鍵上,并沒(méi)有重復(fù)按動(dòng)很多次。要想能夠正確的判斷按鍵是否按下就要避開(kāi)這段抖動(dòng)的時(shí)間。根據(jù)?般按鍵的機(jī)械特點(diǎn),以及按鍵的新舊程度等而言,這段抖動(dòng)的時(shí)間?般在5Ms~20Ms之間??吹竭@里你明白了該如何做了吧??纯聪旅娴倪@個(gè)流程圖,你應(yīng)該不陌生吧。這個(gè)流程是好多教科書(shū)上的做法??上?,誤導(dǎo)了好多人。為什么呢。因?yàn)樗揪蜎](méi)有考慮實(shí)際情況。我們根據(jù)這幅流程圖來(lái)寫它的代碼看看。unsignedcharv_ReadKey_f(void)(unsignedcharKeyPress;if(P17==0)(Delay(20); 〃延時(shí)20Mslf(P17==0)While(!P17);〃等待釋放elseKeyPress=0;)}這樣?個(gè)程序,相信對(duì)很多初學(xué)者而言都不陌生。因?yàn)楹枚鄷?shū)上基本都是這樣的?個(gè)流程和寫法??墒钱?dāng)有一天,我們想做ー個(gè)數(shù)碼管加按鍵調(diào)整的時(shí)鐘,發(fā)現(xiàn)當(dāng)我們按鍵按下去的時(shí)候,數(shù)碼管就不亮了。為什么呢。原因就在這個(gè)鍵盤掃描函數(shù)。平常沒(méi)有按鍵按下還好。?旦有鍵按下,它先是浪費(fèi)了CPU的大部分時(shí)間(就是那個(gè)什么事情都沒(méi)做的延時(shí)20Ms函數(shù))然后,又霸占CPU(就是哪個(gè)死死等在那里的while(P17):語(yǔ)句)直到按鍵釋放。對(duì)于這種情況我們是忍無(wú)可忍的,那么就讓我們徹底的拋棄它吧。那么到底按鍵掃描函數(shù)改如何寫呢……所謂眾里尋她千百度,驀然回首,那人卻在燈火闌珊處。如果我們把CPU延時(shí)的那20Ms拿出來(lái)去做其它事情,那么不就充分利用CPU的時(shí)間了嗎。而一般情況下我們只要前沿去抖動(dòng)就可以了。也就是說(shuō)了,我們只需在按鍵按下后去抖就可以了,對(duì)于按鍵的釋放抖動(dòng)可以不必要過(guò)于關(guān)注。當(dāng)然這主要和應(yīng)用的場(chǎng)合有關(guān)。?個(gè)能有效識(shí)別按鍵按下并支持連發(fā)功能的按鍵已經(jīng)能夠應(yīng)用到大多數(shù)的場(chǎng)合了。下面以四個(gè)獨(dú)立按鍵的處理程序?yàn)槔齺?lái)講解(支持單擊和連發(fā))#include"regx52.hMsbitKeyOne=P1A0;sbitKeyTwo=P1A1;sbitKeyThree=P1A2;sbitKeyFour=P1A3;defineuintl6unsignedintdefineuint8unsignedchardefineNOKEYOxffdefineKEY_WOBBLE__TIME500 〃去抖動(dòng)時(shí)間(待定)#defineKEY_OVER_TIME15000 〃等待進(jìn)入連擊時(shí)間(待定),該常數(shù)要比正?!ò存I時(shí)間要長(zhǎng),防止非目的性進(jìn)入連擊模式#defineKEY_QUICK_TIME1000〃等待按鍵抬起的連擊時(shí)間(待定)voidv_Keylnit_f(void)(KeyOne=1; 〃按鍵初始化(相應(yīng)端口寫1)KeyTwo=1;KeyThree=1;KeyFour=1;uint8u8_ReadKey_f(void)staticuint8LastKey=NOKEY; 〃保存上一次的鍵值staticuint16KeyCount=0; 〃按鍵延時(shí)計(jì)數(shù)器staticuint16KeyOverTime=KEY_OVER_TIME;〃按鍵抬起時(shí)間uint8KeyTemp=NOKEY; 〃臨時(shí)保存讀到的鍵值KeyTemp=P1&OxOfJ 〃讀鍵值if(KeyTemp==OxOf)(KeyCount=0;KeyOverTime=KEY_OVER_TIME;returnNOKEY; 〃無(wú)鍵按下返回NOKEY)else(if(KeyTemp==LastKey)〃是否第?次按下(if(++KeyCount==KEY_WOBBLE_TIME) 〃不是第?次按下,則判斷〃抖動(dòng)是否結(jié)束(returnKeyTemp; 〃去抖動(dòng)結(jié)束,返回鍵值)else(if(KeyCount>KeyOverTime)(KeyCount=0;KeyOverTime=KEY_QUICK_TIME;)returnNOKEY;})else 〃是第一次按下則保存鍵值,以便下次執(zhí)行此函數(shù)時(shí)與讀到的鍵值作比較(LastKey=KeyTemp; 〃保存第一次讀到的鍵值KeyCount=0; 〃延時(shí)計(jì)數(shù)器清零KeyOverTime=KEY_OVER_TIME;returnNOKEY;}})下面是我測(cè)試用的主程序(相關(guān)頭文件未列出,僅僅作測(cè)試演示用)voidmain(void)uint8KeyValue;int16Count;v_Lcdlnit_f();v_Keylnit_f();CLSLOCATE(3,1)PRINT(MKeyTest")LOCATE(6,2)SHOW_ICONwhile(1)KeyValue=u8_ReadKey_f();if(KeyValue!=NOKEY){LOCATE(1,2)if(KeyValue==OxOe)Count++;if(KeyValue==OxOd)Count--;if(KeyValue==OxOb)Count=0;if(KeyValue==0x07)Count=0;HIDE_ICONPRINTD(Count,5)LOCATE(6,2))else(//SHOW_ICON)))每次執(zhí)行讀鍵盤函數(shù)時(shí),只是對(duì)ー些標(biāo)忐進(jìn)行判斷,然后退出。因此能夠充分的利用CPU的資源。同時(shí)可以處理連發(fā)按鍵。此按鍵掃描按鍵函數(shù)可以直接放在主函數(shù)中。如果感覺(jué)按鍵太過(guò)靈敏或者遲鈍則改ー下相關(guān)消抖動(dòng)的宏定義即可。此函數(shù)也可以通過(guò)中斷標(biāo)志位進(jìn)行定時(shí)的掃描。此時(shí),需要添加個(gè)定時(shí)標(biāo)志位,并將相關(guān)消抖動(dòng)的和連擊時(shí)間的宏定義改小即可。然后在主程序類似下面這樣寫即可if(KeyTime) 〃定時(shí)掃描時(shí)間到(KeyValue=u8_ReadKey_f();)具體的工作就交給您去完成啦??纯葱Ч?按鍵單擊連發(fā)時(shí)候的截圖至此,關(guān)于單個(gè)按鍵的學(xué)習(xí)就告一段落了,您是否ビ經(jīng)明白了。如果您還不明白,那么把這個(gè)程序好好的看看,并畫(huà)下流程圖,分析分析。估計(jì)您就會(huì)恍然大悟。關(guān)鍵是思路要轉(zhuǎn)換過(guò)來(lái)。下而我們來(lái)看看多個(gè)按鍵的情況吧?般情況下,如果多個(gè)按鍵每個(gè)都直接接在單片機(jī)的I/O上的話會(huì)占用很多的I/O資源。比較合理的?種做法是,按照行列接成矩陣的形式。按鍵接在每ー個(gè)的行列的相交處。這樣対于m行n列的矩陣,可以接的按鍵總數(shù)是m*n。這里我們以常見(jiàn)的4*4矩陣鍵盤來(lái)講解矩陣鍵盤的編程。上圖就是矩陣鍵盤的?般接法。這里我們要介紹ー種快速的鍵盤掃描法:線反轉(zhuǎn)法(或者稱為行列翻轉(zhuǎn)法)。具體流程如ド。首先,讓單片機(jī)的行全部輸出0,列全部輸出1,讀取列的值(假設(shè)行接P3口的高四位,列接低四位)。即P3=OxOf!此時(shí)讀列的值,如果冇鍵按ド,則相應(yīng)的列讀冋來(lái)的值應(yīng)該為低。譬如此時(shí)讀冋來(lái)的值為OxOe;即按鍵列的位置已經(jīng)確定。這時(shí)反過(guò)來(lái),把行作為輸入,列作為輸出,即P0=OxfO;此時(shí)再讀行的值,如果按鍵仍然被按ド,則相應(yīng)的行的值應(yīng)該為低,如果此時(shí)讀冋來(lái)的值為OxeO,則確定了行的位置。說(shuō)到這里,您應(yīng)該笑了,知道了一個(gè)按鍵被按下的行和列的位置,那么就可以肯定確定它的位置了。我們把讀回來(lái)的行值和列值進(jìn)行或運(yùn)算。即OxeO|Ox0e即Oxee。那么Oxee就是我們按ド的按鍵的鍵值了。怎么樣。只需幾步就可以判斷所有的鍵值,簡(jiǎn)單吧。下面再結(jié)合一個(gè)例子具體看看。/******************************************此模塊所需相關(guān)支持庫(kù) ?#include"regx52.h"defineuint8unsignedchardefineuintl6unsignedint與硬件連接相關(guān)的定義及宏定義和操作宏?*****************************************/defineKEYBOARDP3 〃鍵盤連接到單片機(jī)上的端口位置defineREAD_ROW_ENLABLEKEYBOARD=OxOf; 〃讀端口之前先把相應(yīng)U置位(由基本51單片機(jī)特性決定的)defineREAD_COL_ENLABLEKEYBOARD=OxfO; 〃根據(jù)實(shí)際硬件連接情況修改,模塊內(nèi)相關(guān)的宏定義及常數(shù)宏 ,******************************************/defineNOKEYOxff 〃定義無(wú)鍵按下時(shí)的返回值defineDELAY_COUNT2 〃消抖時(shí)間常數(shù)此模塊所需的全局或者外部變量 ?*****************************************/bitbdataStartScan=0;〃此變量需放在定時(shí)中斷中置位.按鍵掃描函數(shù),按下去后經(jīng)去抖,確定按下?則返回鍵值。~15:無(wú)鍵按下則返回Oxff;?此函數(shù)需要定時(shí)器的支持(去抖….) *uint8u8_KeyBoardScan_f()(staticuint8DelayCount=0;uint8KeyValueRow=0;uint8KeyValueCol=0;uint8KeyValue=0;if(StartScan) 〃開(kāi)始掃描,StartScan在定時(shí)中斷中置位(StartScan=0; 〃清除開(kāi)始掃描標(biāo)忐位,避免多次重復(fù)執(zhí)行掃描程序〃讀入按鍵狀態(tài)前先向相應(yīng)端口寫1(由基本51單片機(jī)硬件結(jié)構(gòu)決定)READROWENLABLEif((KEYBOARD&OxOf)!=OxOf)〃判斷是否有鍵按下DelayCount++;if(DelayCount<=DELAY_COUNT) 〃有鍵按下則判斷延時(shí)去抖的時(shí)間是否達(dá)到(returnNOKEY;)else 〃消除了抖動(dòng)(if((KEYBOARD&OxOf)!=OxOf) 〃再次判斷是否按鍵真的按下{DelayCount=0; 〃確定按下后,延時(shí)去抖計(jì)時(shí)器清〇KeyValueRow=KEYBOARD&OxOf;〃取得彳了碼〃準(zhǔn)備讀列,先向相應(yīng)端口寫1(由基本51單片機(jī)硬件結(jié)構(gòu)決定)READ_COL_ENLABLEif((KEYBOARD&OxfO)!=OxfO)〃反轉(zhuǎn),讀列碼(KeyValueCol=KEYBOARD&OxfO;〃取得列碼〃合并取得的行碼和列碼,即是相應(yīng)按鍵的鍵值switch(KeyValueCol|KeyValueRow)(case0x77:KeyValue=0;break;case0xb7:KeyValue=1;break;case0xd7:KeyValue=2;break;case0xe7:KeyValue=3;break;case0x7b:KeyValue=4;break;caseOxbb:KeyValue=5;break;caseOxdb:KeyValue=6;break;caseOxeb:KeyValue='7;break;case0x7d:KeyValue=8;break;caseOxbd:KeyValue=9;break;caseOxdd:KeyValue=10;break;caseOxed:KeyValue=11;break;case0x7e:KeyValue=12;break;caseOxbe:KeyValue=13;break;caseOxde:KeyValue=14;break;caseOxee:KeyValue=15;break;default:returnNOKEY;returnKeyValue;}else{DelayCount=0;returnNOKEY;))else{DelayCount=0;returnNOKEY;})}else(DelayCount=0;returnNOKEY;)))voidv_T0_lsr_f(void)interruptINTERRUPT_TIMER2_OVERFLOWStartScan?模塊調(diào)試〃主函數(shù)僅作演示用,主函數(shù)除按鍵掃描外的函數(shù)并沒(méi)在這里給出voidv_lnit_T2_f(void)T2CON=0x04;T2MOD=0x00;TOC\o"1-5"\h\zTH2 =0xd8 ;RCAP2H=0xd8;TL2 =OxfO ;RCAP2L=OxfO;ET2 =1;TR2 =1;voidmain(void)(uint8readkey=0;v_lnit_T2,f();v_Lcdlnit_f();LOCATE(1,1)PRINT(H4*4KeyBoardTest*1)EA=1;LOCATE(3,2)while(1)(SHOW_ICONreadkey=u8_KeyBoardScan_f()if)readkey!=NOKEY)(PRINTN)readkey,2)LOCATE)3,2)continue;}elsecontinue;})}呵呵,按鍵掃描程序己經(jīng)注釋的很詳細(xì)了。我就不多費(fèi)嘴后了。如果有不清楚的地方,歡迎跟帖討論。下面是按鍵測(cè)試的截圖我的門己搭建的實(shí)驗(yàn)板OK,Enioyit!自此按鍵檢測(cè)告?段落。下次如果再講按鍵。將會(huì)討論另外種按鍵的寫法:基于狀態(tài)機(jī)的按鍵程序設(shè)計(jì)。歡迎討論。tiankai(2010-2-0516:37:53)晨輝教你輕松學(xué)51 按鍵篇對(duì)于ー個(gè)由單片機(jī)為核心構(gòu)成的系統(tǒng)而言。輸入通道是相當(dāng)重:要的??梢钥吹綆缀趺咯`樣基于單片機(jī)的產(chǎn)品都有人機(jī)交互的部分。如各種儀器設(shè)備上的各種按鈕和開(kāi)關(guān),以及我們手機(jī)上的鍵盤,MP3上的按鍵等等。最常見(jiàn)的輸入部分,莫非就是按鍵了。對(duì)于大多數(shù)初學(xué)者而言,編寫ー個(gè)好的按鍵程序是一件頗為頭疼的事情。于是乎在網(wǎng)上亂搜?氣,程序倒是找到了不少,但是看了半天依然是不明白?;蛘咴谀衬痴搲厦姘l(fā)帖“跪求XX按鍵程序,大蝦幫忙….:’如果你偶然間進(jìn)了這個(gè)論壇,又偶然看到了這個(gè)帖子,而且恰好你對(duì)按鍵程序的寫法也不是很清楚,那么我希望你能夠靜靜的看完這個(gè)帖子。如果你覺(jué)得對(duì)你很有幫助,那么我希望你能夠在以后的日子中能夠堅(jiān)持到這個(gè)論壇來(lái),ー起交流學(xué)習(xí),分享自己學(xué)習(xí)過(guò)程中的喜悅或者?起探討棘手的問(wèn)題,這是我寫這個(gè)帖子的最大的初衷了。〇K,不能再說(shuō)了,再說(shuō)就變成水帖了。那么我們開(kāi)始吧。按鍵的種類很多。不過(guò)原理基本相似。下面我們以種輕觸開(kāi)關(guān)為例講解按鍵程序的寫法。

這種輕觸開(kāi)關(guān)大家不陌生吧"_A一一般情況下,按鍵與單片機(jī)的連接如下面這幅圖所示。U1U1(圖中電阻值一般去4.7k~10k之間,對(duì)于內(nèi)部端口有上拉電阻的單片機(jī)則可省略此電阻)單片機(jī)對(duì)于按鍵的按ド與否則是通過(guò)檢測(cè)相應(yīng)引腳上的電平來(lái)實(shí)現(xiàn)的。對(duì)于上圖而言,當(dāng)P17引腳上面的電平為低時(shí),則表示按鍵已經(jīng)按下。反之,則表明按鍵沒(méi)有按下。我們?cè)诔绦蛑兄灰獧z測(cè)到了P17引腳I:面的電平為低了,就可以判斷按鍵按ド。呵呵,簡(jiǎn)單吧。等會(huì),您先別樂(lè)呵,話還沒(méi)說(shuō)完呢。ド面我們來(lái)看看,當(dāng)按鍵按下時(shí),P17引腳I:面的波形是怎么變化的。

上圖是ー個(gè)理想波形圖,當(dāng)按鍵按下時(shí),P17U的電平馬上被拉低到0V了。當(dāng)然理想的東西都是不現(xiàn)實(shí)的。所以我們還是看看現(xiàn)實(shí)的波形圖吧。看出什么區(qū)別來(lái)了沒(méi)。呵呵,只耍你不是傻子我相信都能看出其中的區(qū)別。由丁?按鍵的機(jī)械特性。當(dāng)按鍵閉合時(shí),并不能馬上保存良好的接觸,而是來(lái)冋彈跳。這個(gè)時(shí)間很短,我們的手根本感覺(jué)不出來(lái)。但是對(duì)于一?秒鐘執(zhí)行百萬(wàn)條指令的單片機(jī)而言,這個(gè)時(shí)間是相當(dāng)?shù)拈L(zhǎng)了。那么在這段抖動(dòng)的時(shí)間內(nèi),單片機(jī)可能讀到多次高低電平的變化。如果不

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論