




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
學習情境2-可調式數字鐘基于DS1302和LCD1602的可調數字鐘前面的任務中我們學會了使用DS1302,知道了如何在單片機系統中的連接,也詳細的學習了如何得到DS1302的時鐘,并且我們使用了16個數碼管把年月日和時分秒實時地顯示出來。但數碼管的顯示畢竟有其自身的缺陷,現在在工業控制的各個環節,都使用液晶進行人機聯系。在日常生活中,我們對液晶顯示器并不陌生。液晶顯示模塊已作為很多電子產品的通用器件,如在計算器、萬用表、電子表及很多家用電子產品中都可以看到,顯示的主要是數字、專用符號和圖形。在單片機的人機交流界面中,一般的輸出方式有以下幾種:發光管、LED數碼管、液晶顯示器。發光管和LED數碼管比擬常用,軟硬件都比擬簡單。本任務中,我們使用LCD1602液晶顯示器芯片作為時鐘顯示的硬件,這將大大簡化電路結構,當然,在軟件設計方面就比數碼管復雜得多了。通過本任務的學習。希望能掌握LCD1602的軟硬件設計方法,為以后學習功能更強大的液晶芯片作好知識儲藏。3.1任務設計要求和設計原理一、設計要求1、利用專用時鐘芯片DS1302獲得秒、分、時、日、月、年等時間單位。2、用液晶顯示芯片LCD1602實時顯示時間3、能通過外部按鍵調節時間4、利用Proteus軟件設計電路原理圖、PCB圖、并結合軟件進行仿真測試5、利用Keil軟件設計C語言源程序,通過編譯、鏈接后生成HEX文件二、設計原理本任務主要由單片機AT89C52、時鐘芯片DS1302、液晶顯示芯片LCD1602等元器件組成。單片機是整個系統的主控芯片,主要負責對時鐘芯片內部數據進行讀寫、并把讀取的數據處理后實時送給數碼管顯示;DS1302時鐘芯片那么產生本任務所需的時間:秒、分、時、日、月、年這6個時間單元,DS1302通過串行方式與單片機相連,在該芯片的時鐘及復位引腳信號的控制下實現與單片機的數據通信,同時,利用4輸入與門和4個獨立按鍵實行對時間的調節,可調節年、月、日、時、分等5個時間單元,星期時間的調節會自動進行。在時間的顯示方面,使用了LCD1602,這大大簡化了電路結構,LCD1602通過P0口與單片機相連,顯示的時間數據均由單片機的P0口輸出,P0口外接上拉電阻。當系統上電后,LCD1602顯示時間〔在仿真條件下,可設置為顯示電腦時間〕,反復按下K1按鍵,可依次調節年、月、日、時、分,按下K2按鍵,可對相應時間進行加調節,按下K3按鍵,可對相應時間進行的減調節,按下確定按鍵K4,表示時間調節完畢。3.2硬件設計一、硬件電路設計本硬件系統電路包括:單片機最小系統〔包含時鐘電路、復位電路和電源電路〕、LCD顯示電路、按鍵調節電路和DS1302時鐘電路。系統原理框圖如以下圖所示:8051單8051單片機時鐘電路、復位電路、電源電路LCD顯示電路LCD顯示電路按鍵調節電路DS1302時鐘電路按鍵調節電路DS1302時鐘電路圖3-1系統框圖系統各局部電路結構簡單,在此不一一單獨介紹,只簡單介紹LCD顯示電路,其電路設計原理圖如圖3-2所示。圖3-2LCD1602液晶顯示電路從圖可知,液晶芯片LCD1602的D0-D7與單片機的P0口相連接,且也外接上拉電阻。引腳RS、RW和E分別與P2口的P2.O、P2.1和P2.2連接,當然你愿意的話也可以和其他未使用的端口相連。其余電路不作介紹,本任務整體系統電路原理圖如圖3-3所示。圖3-3整體系統電路原理圖二、LCD1602技術資料在單片機系統中應用液晶顯示器作為輸出器件有以下幾個優點:〔1〕顯示質量高,由于液晶顯示器每一個點在收到信號后就一直保持那種色彩和亮度,恒定發光,而不像陰極射線管顯示器〔CRT〕那樣需要不斷刷新新亮點。因此,液晶顯示器畫質高且不會閃爍?!?〕數字式接口,液晶顯示器都是數字式的,和單片機系統的接口更加簡單可靠,操作更加方便?!?〕體積小、重量輕,液晶顯示器通過顯示屏上的電極控制液晶分子狀態來到達顯示的目的,在重量上比相同顯示面積的傳統顯示器要輕得多。〔4〕功耗低,相對而言,液晶顯示器的功耗主要消耗在其內部的電極和驅動IC上,因而耗電量比其它顯示器要少得多。1、液晶顯示原理:液晶顯示的原理是利用液晶的物理特性,通過電壓對其顯示區域進行控制,有電就有顯示,這樣即可以顯示出圖形。液晶顯示器具有厚度薄、適用于大規模集成電路直接驅動、易于實現全彩色顯示的特點,目前已經被廣泛應用在便攜式電腦、數字攝像機、PDA移動通信工具等眾多領域。2、液晶顯示器的分類:液晶顯示的分類方法有很多種,通??砂雌滹@示方式分為段式、字符式、點陣式等。除了黑白顯示外,液晶顯示器還有多灰度有彩色顯示等。如果根據驅動方式來分,可以分為靜態驅動〔Static〕、單純矩陣驅動〔SimpleMatrix〕和主動矩陣驅動〔ActiveMatrix〕三種。3、液晶顯示器各種圖形的顯示原理:線段的顯示:點陣圖形式液晶由M×N個顯示單元組成,假設LCD顯示屏有64行,每行有128列,每8列對應1字節的8位,即每行由16字節,共16×8=128個點組成,屏上64×16個顯示單元與顯示RAM區1024字節相對應,每一字節的內容和顯示屏上相應位置的亮暗對應。例如屏的第一行的亮暗由RAM區的000H——00FH的16字節的內容決定,當〔000H〕=FFH時,那么屏幕的左上角顯示一條短亮線,長度為8個點;當〔3FFH〕=FFH時,那么屏幕的右下角顯示一條短亮線;當〔000H〕=FFH,〔001H〕=00H,〔002H〕=00H,……〔00EH〕=00H,〔00FH〕=00H時,那么在屏幕的頂部顯示一條由8段亮線和8條暗線組成的虛線。這就是LCD顯示的根本原理。字符的顯示:用LCD顯示一個字符時比擬復雜,因為一個字符由6×8或8×8點陣組成,既要找到和顯示屏幕上某幾個位置對應的顯示RAM區的8字節,還要使每字節的不同位為“1”,其它的為“0”,為“1”的點亮,為“0”的不亮。這樣一來就組成某個字符。但由于內帶字符發生器的控制器來說,顯示字符就比擬簡單了,可以讓控制器工作在文本方式,根據在LCD上開始顯示的行列號及每行的列數找出顯示RAM對應的地址,設立光標,在此送上該字符對應的代碼即可。漢字的顯示:漢字的顯示一般采用圖形的方式,事先從微機中提取要顯示的漢字的點陣碼〔一般用字模提取軟件〕,每個漢字占32B,分左右兩半,各占16B,左邊為1、3、5……右邊為2、4、6……根據在LCD上開始顯示的行列號及每行的列數可找出顯示RAM對應的地址,設立光標,送上要顯示的漢字的第一字節,光標位置加1,送第二個字節,換行按列對齊,送第三個字節……直到32B顯示完就可以LCD上得到一個完整漢字。1602字符型LCD簡介字符型液晶顯示模塊是一種專門用于顯示字母、數字、符號等點陣式LCD,目前常用16*1,16*2,20*2和40*2行等的模塊。一般1602字符型液晶顯示器實物如圖3-4:圖3-41602字符型液晶顯示器實物圖1602LCD分為帶背光和不帶背光兩種,其控制器大局部為HD44780,帶背光的比不帶背光的厚,是否帶背光在應用中并無差異。1602LCD主要技術參數:顯示容量:16×2個字符;芯片工作電壓:4.5—5.5V;工作電流:2.0mA(5.0V);模塊最正確工作電壓:5.0V;字符尺寸:2.95×4.35(W×H)mm
引腳功能說明:1602LCD采用標準的14腳〔無背光〕或16腳〔帶背光〕接口,各引腳接口說明如表1所示:第1腳:VSS為地電源。第2腳:VDD接5V正電源。第3腳:VL為液晶顯示器比照度調整端,接正電源時比照度最弱,接地時比照度最高,比照度過高時會產生“鬼影〞,使用時可以通過一個10K的電位器調整比照度。第4腳:RS為存放器選擇,高電平時選擇數據存放器、低電平時選擇指令存放器。第5腳:R/W為讀寫信號線,高電平時進行讀操作,低電平時進行寫操作。當RS和R/W共同為低電平時可以寫入指令或者顯示地址,當RS為低電平R/W為高電平時可以讀忙信號,當RS為高電平R/W為低電平時可以寫入數據。第6腳:E端為使能端,當E端由高電平跳變成低電平時,液晶模塊執行命令。第7~14腳:D0~D7為8位雙向數據線。第15腳:背光源正極。第16腳:背光源負極。表11602LCD引腳接口說明編號符號引腳說明編號符號引腳說明1VSS電源地9D2數據2VDD電源正極10D3數據3VL液晶顯示偏壓11D4數據4RS數據/命令選擇12D5數據5R/
W讀/寫選擇13D6數據6E使能信號14D7數據7D0數據15BL
A背光源正極8D1數據16BL
K背光源負極1602LCD的指令說明及時序1602液晶模塊內部的控制器共有11條控制指令,如表2所示:表2:控制命令表序號指令RSR/WD7D6D5D4D3D2D1D0功能1復位顯示器0000000001清屏,光標歸位2光標返回000000001*設置地址計數器清零,DDRAM數據不變,光標移到左上角3字符進入模式00000001I/DS設置字符進入時的屏幕移位方式4顯示開/關控制0000001DCB設置顯示開關,光標開關,閃爍開關5光標或字符移位000001S/CR/L**設置字符與光標移動6功能設置00001DLNF**設置DL,顯示行數,字體7設置字符發生存貯器地址0001字符發生存貯器地址設置6位的CGRAM地址以讀/寫數據8設置數據存貯器地址001顯示數據存貯器地址設置7位的DDRAM地址以讀/寫數據9讀忙標志或地址01BF計數器地址讀忙標志及地址計數器10寫數據到CGRAM或DDRAM〕10寫入一字節數據,需要先設置RAM地址向CGRAM/DDRAM寫入一字節的數據11從CGRAM或DDRAM讀數據11讀取入一字節數據,需要先設置RAM地址從CGRAM/DDRAM讀取一字節的數據I/D=1遞增,I/D=0遞減。S=0時顯示屏不移動,S=1時,如果I/D=1且有字符寫入時顯示屏左移,否那么右移。D=1顯示屏開,D=0顯示屏關。C=1時光標出現在地址計數器所指的位置,C=0時光標不出現。B=1時光標出現閃爍,B=0時光標不閃爍。S/C=0時,RL=0那么光標左移,否那么右移。S/C=1時,RL=0那么字符和光標左移,否那么右移。DL=1時數據長度為8位,DL=0時為使用D7-D4共4位,分兩次送一字節。N=0為單行顯示,N=1時為雙行顯示。F=1時為510點陣字體,F=0時為57點陣字體。BF=1時LCD忙,BF=0時LCD就緒。1602液晶模塊的讀寫操作、屏幕和光標的操作都是通過指令編程來實現的?!舱f明:1為高電平、0為低電平〕指令1:清顯示,指令碼01H,光標復位到地址00H位置。指令2:光標復位,光標返回到地址00H。指令3:光標和顯示模式設置I/D:光標移動方向,高電平右移,低電平左移S:屏幕上所有文字是否左移或者右移。高電平表示有效,低電平那么無效。指令4:顯示開關控制。D:控制整體顯示的開與關,高電平表示開顯示,低電平表示關顯示C:控制光標的開與關,高電平表示有光標,低電平表示無光標B:控制光標是否閃爍,高電平閃爍,低電平不閃爍。指令5:光標或顯示移位S/C:高電平時移動顯示的文字,低電平時移動光標。指令6:功能設置命令DL:高電平時為4位總線,低電平時為8位總線N:低電平時為單行顯示,高電平時雙行顯示F:低電平時顯示5x7的點陣字符,高電平時顯示5x10的點陣字符。指令7:字符發生器RAM地址設置。指令8:DDRAM地址設置。指令9:讀忙信號和光標地址BF:為忙標志位,高電平表示忙,此時模塊不能接收命令或者數據,如果為低電平表示不忙。指令10:寫數據。指令11:讀數據。
與HD44780相兼容的芯片時序表如下:表3:根本操作時序表讀狀態輸入RS=L,R/W=H,E=H輸出D0—D7=狀態字寫指令輸入RS=L,R/W=L,D0—D7=指令碼,E=高脈沖輸出無讀數據輸入RS=H,R/W=H,E=H輸出D0—D7=數據寫數據輸入RS=H,R/W=L,D0—D7=數據,E=高脈沖輸出無讀寫操作時序如圖3-5和3-6所示:圖3-5讀操作時序圖3-6寫操作時序1602LCD的RAM地址映射及標準字庫表液晶顯示模塊是一個慢顯示器件,所以在執行每條指令之前一定要確認模塊的忙標志位,如果該位為低電平,表示不忙,否那么此指令失效。要顯示字符時要先輸入顯示字符地址,也就是告訴模塊在哪里顯示字符,圖3-7是1602的內部顯示地址。圖3-71602LCD內部顯示地址例如第二行第一個字符的地址是40H,那么是否直接寫入40H就可以將光標定位在第二行第一個字符的位置呢?這樣不行,因為寫入顯示地址時要求最高位D7恒定為高電平1所以實際寫入的數據應該是01000000B〔40H〕+10000000B(80H)=11000000B(C0H)。在對液晶模塊的初始化中要先設置其顯示模式,在液晶模塊顯示字符時光標是自動右移的,無需人工干預。每次輸入指令前都要判斷液晶模塊是否處于忙的狀態。1602液晶模塊內部的字符發生存儲器〔CGROM〕已經存儲了160個不同的點陣字符圖形,如圖3-8所示,這些字符有:阿拉伯數字、英文字母的大小寫、常用的符號、和日文假名等,每一個字符都有一個固定的代碼,比方大寫的英文字母“A〞的代碼是01000001B〔41H〕,顯示時模塊把地址41H中的點陣字符圖形顯示出來,我們就能看到字母“A〞圖3-8字符代碼與圖形對應圖3.3軟件設計軟件設計中主要是針對DS1302芯片和LCD1602進行程序的設計,而DS1302的驅動程序在上個工程中我們已經作了詳細介紹,在此不再贅述。我們主要編制LCD的驅動程序。根據對LCD資料的分析,程序編制主要有:讀取LCD的狀態,忙檢查,向LCD寫入命令,向LCD寫入數據,LCD初始化,設置LCD液晶的顯示位置,顯示字符等,具體如下:1、讀取LCD的狀態//----------讀取LCD的狀態-------*/ucharRead_LCD_State(){ucharstate;RS=0;RW=1;EN=1;DelayMS(2);state=P0;EN=0;DelayMS(2);returnstate;}2、忙檢查//-------------忙檢查--------------*/voidLCD_Busy_Wait(){while((Read_LCD_State()&0x80)==0x80); DelayMS(5);}3、向LCD寫入命令//-----------寫LCD命令-----------------*/voidWrite_LCD_Command(ucharcmd){LCD_Busy_Wait();RS=0;RW=0;EN=0;P0=cmd;EN=1;DelayMS(2);EN=0;}4、向LCD寫入數據//-----------向LCD寫入數據-----------------*/voidWrite_LCD_Data(uchardat){LCD_Busy_Wait();RS=1;RW=0;EN=0;P0=dat;EN=1;DelayMS(2);EN=0;}5、LCD初始化//-----------LCD初始化-----------------*/voidInitialize_LCD1602()//液晶初始化函數{Write_LCD_Command(0x38);DelayMS(2);//功能設置,數據長度為8位,雙行顯示5×7點//陣字體Write_LCD_Command(0x01);DelayMS(2); //清屏Write_LCD_Command(0x06);DelayMS(2);//字符進入模式:屏幕不動,字符后移Write_LCD_Command(0x0c);DelayMS(2); //顯示開,關光標}6、設置LCD液晶的顯示位置//-----------設置液晶顯示位置-----------------*/voidSet_LCD_Position(ucharpos){Write_LCD_Command(pos|0x80); //設置7位的DDRAM地址值}7、顯示字符//-----------在LCD上顯示字符串-----------------*/voidLCD_Display(ucharp,uchar*str){uchari;Set_LCD_Position(p);for(i=0;i<16;i++){Write_LCD_Data(str[i]);DelayMS(2);}}除此之外,還有年、月、日、時、分等的設置函數,顯示函數,鍵盤處理函數等,在此不在詳細介紹,同學們可參考完整程序中的代碼。數組數組數組是在程序設計中,為了處理方便,把具有相同類型的假設干變量按有序的形式組織起來的一種形式。這些按序排列的同類數據元素的集合稱為數組。在C語言中,數組屬于構造數據類型。一個數組可以分解為多個數組元素,這些數組元素可以是根本數據類型或是構造類型。因此按數組元素的類型不同,數組又可分為數值數組、字符數組、指針數組、結構數組等各種類別。一、一維數組1、一組的定義定義:數組是有序數據(必須是相同的數據類型結構)的集合。格式:類型說明符數組名[常量表達式]例如:inttemp[5];表示數組名為a,有10個元素,并且每個元素的類型都是int型的。floatb[10],c[5];說明實型數組b有10個元素,實型數組c有5個元素;注意:〔1〕數組名的命名規那么和標示符的命名規那么相同。〔2〕常量表達式要有方括號括起來,不能用圓括號,inta(10);這是非法的!〔3〕常量表達式表示數組元素的個數,即數組長度。并且數組的第一個元素是從下標0開始的!〔4〕常量表達式可以是常量也可以是符號常量,不能包含變量。C語言絕對不允許對數組的大小作動態定義;例如:下面是非法的intn;scanf(“%d〞,&n);inta[n];〔5〕數組的類型實際上就是指數組元素的取值類型,對于同一數組,它所有元素的數據類型都是相同的;〔6〕數組名不能與其他變量名相同;例如:main(){inta;floata[10];………。。}是非法的!〔7〕允許在同一個類型說明中,說明多個數組和多個變量;例如:inta,b,c,d[10],e[5];2、一維數組元素的初始化有以下方法初始化:1〕在定義數組時,對數組元素賦初值;例如:inta[10]={0,1,2,3,4,5,6,7,8,9};上面的語句等價于a[0]=0,a[1]=1,2〕可以只給一局部元素賦初值,例如:inta[10]={0,1,2,3,4};表示只給數組的前5個元素賦初值,后5個元素的值,系統自動默認為03〕在對全部數組元素賦初值時,可以不指定數組長度;例如:inta[5]={0,1,2,3,4};可以改寫為:inta[]={0,1,2,3,4};但是,inta[10]={0,1,2,3,4};不能改寫為:inta[]={0,1,2,3,4};3、一維數組的引用數組必須先定義,后使用。C語言規定:只能逐個引用數組元素,而不能一次引用整個數組!數組的引用形式為:數組名[下標]其中,下標可以是整型常量也可以是整型表達式。例如:a[0]=a[5]+a[7]+a[2*3]4、一維數組的程序舉例〔1〕讀10個數存入數組中,輸出數組中的所有數據。main(){inti,a[10];for(i=0;i<=9;i++)a[i]=i;/*順序給數組元素賦初*/for(i=0;i<=9;i++)printf(“%d〞,a[i]);/*順序輸出數組元素*/}〔2〕讀10個整數存入數組中,輸出平均值。#include<stdio。h>#definesize10main(){intx[size],i;floats=0,ave;for(i=0;i<size;i++)scanf(“%d〞,&x[i]);for(i=0;i<size;i++)s+=x[i];ave=s/size;printf(“%d\n〞,ave);}二、二維數組1、二維數組的定義定義格式:類型說明符數組名[常量表達式1][常量表達式2]其中表達式1表示第一維下標的長度;表達式2表示第二維下標的長度;例如:inta[2][3];說明了一個2行3列的數組,數組名為a,數組元素的類型為整型,該數組共有2*3個元素;即:a[0][0],a[0][1],a[0][2],a[1][0],a[1][1],a[1][2]注意的是:二維數組在概念上是二維的,就是說其下標在兩個方向上變化,數組元素在數組中的位置也處于一個平面中,并不向一維數組,所有的元素是線性的,但是,二維數組中的元素和一維數組中的元素一樣,也是按線性存儲的;如何存儲呢?首先,它和一維數組一樣,也是按線性存儲的。在C語言中,二維數組是按行排列的,即存完一行后,順序存入第二行;還是上面那個例子:inta[2][3];由于數組a說明為int型,所以數組的每個元素在內存中占兩個字節的存儲空間,2、二維數組的引用引用形式:數組名[下標][下標]其中下標應該為整型常量或整型表達式;例如:inta[3][4];a[2][3]表示數組a的第三行第四列的元素。注意:下標變量和數組說明在形式上有些相似,但這兩者具有完全不同的含義;數組說明的方括號中給出的是某一維的長度;而數組元素中的下標是該元素在數組中的位置標識;數組說明中的方括號內只能是常量。而數組元素中方括號中的下標可以是常量,變量或表達式。3、二維數組的初始化二維數組初始化也是在類型說明時給各下標變量賦以初值。二維數組可以按行分段賦值,也可以按行連續賦值1〕按行分段賦值inta[2][3]={{1,2,3},{4,5,6}};2〕按行連續賦值inta[2][3]={1,2,3,4,5,6};這兩種賦值的結果是完全相同的;說明:1〕可以只對局部元素賦值,未賦值的元素自動取0;例如:inta[3][3]={{1},{2},{3}};是對每行的第一列元素賦值,未賦值的元素自動取02〕如果對所有的元素賦初值,那么第一維的長度可以不給出;例如:inta[3][3]={1,2,3,4,5,6,7,8,9};可以改為:inta[][3]={1,2,3,4,5,6,7,8,9};3〕數組是一種構造類型的數據,二維數組可以看作是一維數組的嵌套,設一維數組的每個元素又都是一個數組,就組成了一個二維數組,當然,前提是每個元素的類型必須一致;同理,一個二維數組也可以分解為多個一維數組,例如:a[3][4],可分解為3個一維數組,其數組名分別是:a[0],a[1],a[2];對這三個一維數組不需另作說明即可使用,這三個一維數組都有4個元素,例如:一維數組a[0]的元素是a[0][0],a[0][1],a[0][2],a[0][3];必須強調的是,a[0],a[1],a[2]不能當作下標變量使用,因為它們是數組名,不是一個單純的下標變量;對于一個數組,例如:a[3][4]可以通過循環語句來賦值;for(i=0;i<3;i++)for(j=0;j<4;j++)scanf(“%d〞,&a[i][j]);4、二維數組的使用舉例1〕將一個二維數組的行和列元素互換,存到另一個二維數組中。#include<stdio。h>main(){inta[2][3]={{1,2,3},{4,5,6}};intb[3][2],i,j;for(i=0;i<=1;i++){for(j=0;j<=2;j++){printf(“%d〞,a[i][j]);b[j][i]=a[i][j];}printf(“\n〞);}for(i=0;i<=2;i++){for(j=0;j<=1;j++)printf(“%d〞,b[i][j]);printf(“\n〞);}}三、字符型數組1、字符型數組的定義定義:每個數組元素的數據類型是字符型的一維數組。字符數組的引用,存儲,初始化的方法和一維數組相同例如:字符型數組的定義charc[10];定義了字符型數組c,它的數組元素有10個,由于字符型和整型是相通的,因此,上面的定義也可以改為:intc[10];例如:字符型數組的初始化charc[3]={‘a’,’b’,’c’};注意:如果花括號提供的數組元素個數大于數組長度,那么作語法錯誤處理;如果初值個數小于數組長度,那么只將這些字符賦給前面的元素,其余的元素自動定為空字符(‘\0’);比方:charc[5]={‘a’,’b’,’c’}abc\0\0如果提供的初值個數和預定的數組長度相同,在定義時可以省掉數組長度,系統自動根據初值個數確定數組長度。例如:chara[]={‘a’,’b’,’c’,’d’,’e’};也可以用字符串常量賦值;如:charch[6]={“hello〞};charch[6]=〞hello〞;charch[]=〞hello〞;hello\02、字符型數組的引用可以引用字符數組中的一個元素即得到一個字符!例如:輸出一個字符串Main(){chara[5]={‘a’,’b’,’c’,’d’,’e’};inti;for(i=0;i<5;i++)printf(“%c〞,a[i];)printf(“\n〞);}四、字符串1、字符串定義定義:C語言中用雙引號括起來的任意字符序列就是字符串。C語言中沒有字符串變量,對程序中的字符串,系統用字符數組方式保存,連續,順序的存放每一個字符,最后加上一個空字符〞\0”2、字符串的輸入輸出1〕通過逐個字符輸入和輸出:使用%c;2〕通過整個字符串輸入和輸出:使用%s;3、字符串數組字符串數組就是數組中的每個元素又都是存放字符串的數組。例如:可以將一個二維字符數組看成是一個字符串數組;charline[10][80];數組line共有10個元素,每個元素可以存放80個字符(79個普通字符,一個結束字符),第一個下標決定字符串的個數,第二個下標決定字符串的最大長度,line是有十個字符串的數組,這些字符串的最大長度是79。字符串的初始化方法:例如:charstr[3][5]={“a〞,〞ab〞,〞abc〞};/*根據定義的大小初始化*/charstr[][5]={“a〞,〞ab〞,〞abc〞};/*根據右邊字符串的個數,定義數組大小*/該數組的存儲示意圖為:a\0ab\0abc\03.4軟件硬件的仿真調試1、首先利用ISIS-Professional軟件設計好硬件電路圖。2、其次,利用KEIL軟件建立工程工程,把用C語言編好的程序通過該軟件平臺進行編譯,直至把C程序修改無錯誤為止,并生成HEX文件。3、在ISIS-Professional軟件平臺下導入由KEIL軟件生成的HEX文件,進行仿真,仔細觀察產生的現象和效果,根據仿真的效果,邊修改邊調試,直到仿真效果與我們對工程的要求一致為止。本任務我們用單片機和時鐘芯片DS1302和液晶LCD1602設計了一個電子時鐘,通過仿真,本系統能夠準確的顯示秒、分、時、星期、年、月、日等時間,由于使用了專門的時鐘芯片和液晶顯示芯片,比前一個任務無論視覺效果更佳。3.5知識拓展-I/O接口擴展〔二〕一、I/O擴展常用芯片〔1〕TTL/CMOS鎖存器/緩沖器芯片:如74LS377、74LS374、74LS373、74LS273、74LS244、74LS245等;〔2〕通用可編程I/O接口芯片:如8255、8155、8729等;〔3〕可編程陣列:如GAL16V8、GAL20V8等。I/O擴展中應注意的幾個問題〔1〕訪問擴展I/O的方法與訪問外部數據存儲器完全相同,使用相同的指令?!?〕擴展多片I/O芯片或多個I/O設備時,注意總線的驅動能力問題;〔3〕擴展I/O口的目的是為了單片機與外部設備進行信息交換而設置的一個輸入輸出通道,I/O口最終與外設相連?!?〕在軟件設計時,I/O口對應初始狀態設置、工作方式選擇要與外接設備相匹配。二、擴展簡單并行接口1.擴展并行輸出口〔1〕用74LS377擴展并行輸出口74LS377是帶有輸出允許端的8D鎖存器,有8個輸入端口、8個輸出端口、1個時鐘輸入端CLK〔上升沿有效〕和1個允許控制端OE。如圖3-9所示,OE與P2.7相連,74LS377的地址為7FFFH;假設與P2.0相連,那么地址相應為0EFFH。圖3-9MCS-51擴展輸出口74LS377【例3.1】假設以圖3-8為接口電路,將片內RAM地址為50H單元的數據通過該電路輸出。程序清單如下:MOVDPTR,#7FFFH;數據指針指向74LS377MOVA,50H;輸出的50H單元數據送累加器AMOVX@DPTR,A;P0口將數據通過74LS377輸出〔2〕用74LS374擴展并行輸出口74LS374是具有三態輸出的8D邊沿觸發器,其功能與74LS377相似,74LS374與單片機接口電路如圖3-10所示,74LS374的地址為7FFFH。74LS374具有較強的驅動能力,輸出低電平電流IOL最大可達24mA,是74LS377的3倍。在有較強驅動能力要求場合,可選用74LS374作為并行口擴展器件。圖3-1074LS374與單片機接口電路2.擴展并行輸入口并行輸入擴展口比擬簡單,只需采用8位緩沖器即可。常用的緩沖器有74LS244,74LS244為單向總線緩沖器,只能一個方向傳輸數據。并行輸入接口與單片機連接如圖3-11所示。圖3-11擴展74LS244并行輸入口【例3.2】如圖3-10所示,擴展并行輸入口,將輸入口中的8位數據送片內51H單元。程序清單如下:MOVDPTR,#7FFFH;數據指針指向74LS244MOVXA,@DPTR;外部數據經過74LS244送入累加器AMOV51H,A;數據送51H單元保存將上述輸入輸出電路合并即如圖3-12所示。在圖3-12的輸入輸出接口電路中,輸入采用三態門74HC244,輸出采用8D觸發器〔鎖存器〕74HC374。P0口為雙向數據線,既能從74HC244輸入數據,又能將數據通過74HC374輸出。輸出控制信號由P2.0和WR合成,當兩者同時為低電平時,或門輸出0,將P0口數據鎖存到74HC374,其輸出控制著發光二極管LED。當某線輸出為0時,該線上的LED發光。輸入控制信號由P2.0和RD合成,當二者同時為低電平時,或門輸出為0,選通74HC244,將外部信息輸入到總線。與74HC244相連的按鍵開關沒有按下時,輸入全為1;假設按下某鍵那么所在的線輸入為0??梢?,輸入輸出都是在P2.0為0時有效,因此它們的口地址為0FEFFH,即占用相同的地址空間。但是由于分別用RD和WR信號控制,因此不會發生沖突。圖3-12合并輸入輸出口正如前面所提到的,擴展I/O口和擴展外部RAM一樣,因此訪問外部I/O口就像訪問外部RAM一樣,用的是MOVX類指令。對于圖3-11,如果需要實現的功能是按下任意一個按鍵,對應的LED發光,那么程序如下:LOOP:MOVDPTR,#0FEFFH;數據指針指向擴展I/O地址MOVXA,@DPTR;從74HC244讀入數據,檢測按鍵MOVX@DPTR,A;向74HC374輸出數據,驅動LEDSJMPLOOP;循環三、可編程并行I/O口的擴展1、RAM/IO擴展芯片8155Intel8155是一個具有RAM、I/O和計數器的通用可編程接口多功能芯片。其具有的資源為:256B的靜態RAM;兩個可編程的8位并行I/O口PA和PB;一個可編程的6位并行I/O口PC;一個可編程14位減計數器TC;8位地址鎖存器?!?〕8155的結構及引腳功能8155的引腳如圖3-13〔a〕所示,邏輯框圖如圖3-13〔b〕所示。8155引腳符號的含義和功能如下:AD0~AD7:地址數據線;IO/M:IO/RAM選擇信號端,輸入高電平選擇I/O操作,低電平選擇訪問片內RAM;CE:片選信號輸入端,低電平有效;RD:讀選通輸入端,低電平有效;WR:寫選通輸入端,低電平有效;TI:計數器計數脈沖輸入端;TO:計數器的輸出信號端,輸出波形由內部定時工作方式決定;PA0~PA7:8位并行I/O口;PB0~PB7:8位并行I/O口;PC0~PC5:6位并行I/O口;ALE:地址鎖存信號輸入端,其下降沿時,鎖存AD0~AD7上的地址。RESET:復位輸入引腳,高電平復位。Vcc:電源+5V;Vss:接地。圖3-138155引腳及邏輯框圖〔2〕8155的RAM和I/O地址編碼8155的I/O端口及RAM地址在單片機應用系統中與外部數據存儲器是統一編址的,其控制操作見表3-4,對應I/O口存放器的地址編碼見表3-5。8155當IO/M為0時,單片機對8155的RAM進行操作,共256B,低八位的地址為:00H—0FFH。8155當IO/M為1時,單片機對8155的I/O口進行操作。表3-48155控制操作表低八位地址I/O口xxxxx000B命令/狀態口xxxxx001BPA口xxxxx010BPB口xxxxx011BPC口xxxxx100B定時器/計數器低字節存放器xxxxx101B定時器/計數器高字節存放器表3-5
8155的端口地址編碼AD7AD6AD5AD4AD3AD2AD1AD0對應端口×××××000命令/狀態存放器×××××001A口×××××010B口×××××011C口×××××100定時器/計數器低8位×××××101定時器/計數器高8位〔3〕命令/狀態存放器8155的命令/狀態存放器物理上只有一個端口地址〔見表3-5〕。對該口寫操作,命令字被寫入命令存放器;對該口讀操作,那么從狀態存放器讀出狀態字。8155所提供的每個I/O口和定時器都是可編程的。I/O的工作方式選擇,定時器/計數器的工作控制都是通過對8155內部命令存放器設定命令控制字的方式來實現的,通過對狀態字的讀取來判別它們的工作狀態。命令/狀態存放器共用一個口地址,通過讀/寫信號加以區分。命令字存放器只能寫不能讀,狀態存放器只能讀不能寫。8155命令字格式見表3-6;8155狀態字格式見表3-7。表3-68155命令字格式表TM1TM1TM2IEBIEAPC2PC1PAPAPBA口方式B口方式B口A口計數器方式00:空操作01:停止計數10:計滿后停止11:開始計數0:輸入1:輸出0:禁止中斷1:允許中斷00110110方式1:A、B口根本I/O;C口輸入方式2:A、B口根本I/O;C口輸出方式3:A口選通I/O;B口根本I/O方式4:A、B口選通I/O信號說明:INTRA、INTRB:中斷請求輸出線,高電平有效。STBA、STBB:設備選通信號輸入線,低電平有效。BFA、BFB:口緩沖器滿信號,高電平有效。表3-78155狀態字格式表〔4〕接口與編程①硬件連接。8155可以直接與MCS-51單片機連接,不需要任何外加邏輯。擴展一片8155系統將增加256B片外RAM,22位I/O口線及1個14位減法計數器。MCS-51與8155的連接方法如圖3-14所示。P0口不需要加鎖存器,可以直接與8155的AD0~AD7相連,它既是低8位地址線也是8位數據線。8155的鎖存信號ALE直接引自單片機ALE輸出,用以在內部鎖存地址。圖3-14MCS-51與8155的一種接口邏輯CE及IO/M與MCS-51的連接方式決定了8155的地址范圍:RAM字節地址范圍:7E00H~7EFFH命令/狀態存放器:7F00HPA口:7F01HPB口:7F02HPC口:7F03H定時器低8位存放器:7F04H定時器高8位存放器:7F05H②程序設計。圖3-13接口電路中,將單片機片內RAM50H~5FH單元的內容送8155片內的50H~5FH單元,設定8155的工作方式為:A口根本輸入方式,B口根本輸出方式,C口輸入方式,定時器作方波發生器,對輸入脈沖50分頻。程序清單如下:D8155:MOVR0,50H;將源數據單元首地址送存放器R0中MOVDPTR,#7E50H;數據指針指向8155內部RAM單元LP:MOVA,@R0;數據送累加器AMOVX@DPTR,A;數據從累加器A送8155內部RAM單元INCDPTR;指向下一個8155內部RAM單元INCR0;指向下一個CPU內部RAM單元CJNER0,#60H,LP;數據未傳送完繼續MOVDPTR,#7F04H;指向定時器低8位MOVA,#32H;分頻系數32H〔即50〕MOVX@DPTR,A;低8位初值裝入INCDPTR;指向定時器高8位MOVA,#40H;設定時器方式為連續方波(40H=01000000B)MOVX@DPTR,A;定時器/計數器方式及高6位初值裝入MOVDPTR,#7F00H;數據指針指向控制字存放器MOVA,#0C2H;設定A,B口方式,并啟動定時器〔0C2H=11000010B〕MOVX@DPTR,ARET;程序返回0C2H,其意義是:最高2位11的作用是啟動計數器,最低位D0=0設PA為輸入,D1=1設PB為輸出。D3D2=00設PA、PB為根本I/O,PC為輸入。完整程序代碼1、LCD1602.c源程序//---------------------LCD1602.c--------------------------//液晶控制與顯示驅動程序//--------------------------------------------------------#include<reg51.h>#include<intrins.h>#defineucharunsignedchar#defineuintunsignedintsbitRS=P2^0; //LCD存放器選擇sbitRW=P2^1; //LCD讀寫控制sbitEN=P2^2; // LCD啟動//*--------延時子程序--------*//voidDelayMS(uintK){uchari;while(K--){ for(i=0;i<120;i++); }}//----------讀取LCD的狀態-------*/ucharRead_LCD_State(){ucharstate;RS=0;RW=1;EN=1;DelayMS(2);state=P0;EN=0;DelayMS(2);returnstate;}//-------------忙檢查--------------*/voidLCD_Busy_Wait(){while((Read_LCD_State()&0x80)==0x80); DelayMS(5);}//-----------寫LCD命令-----------------*/voidWrite_LCD_Command(ucharcmd){LCD_Busy_Wait();RS=0;RW=0;EN=0;P0=cmd;EN=1;DelayMS(2);EN=0;}//-----------向LCD寫入數據-----------------*/voidWrite_LCD_Data(uchardat){LCD_Busy_Wait();RS=1;RW=0;EN=0;P0=dat;EN=1;DelayMS(2);EN=0;}//-----------LCD初始化-----------------*/voidInitialize_LCD1602()//液晶初始化函數{Write_LCD_Command(0x38);DelayMS(2); //功能設置,數據長度為8位,雙行顯示,5×7點陣字體Write_LCD_Command(0x01);DelayMS(2); //清屏Write_LCD_Command(0x06);DelayMS(2);//字符進入模式:屏幕不動,字符后移Write_LCD_Command(0x0c);DelayMS(2); //顯示開,關光標}//-----------設置液晶顯示位置-----------------*/voidSet_LCD_Position(ucharpos){Write_LCD_Command(pos|0x80); //設置7位的DDRAM地址值}//-----------在LCD上顯示字符串-----------------*/voidLCD_Display(ucharp,uchar*str){uchari;Set_LCD_Position(p);for(i=0;i<16;i++){ Write_LCD_Data(str[i]); DelayMS(2); }}2、main.c源程序//------------------------------------------------------------------------//名稱:用DS1302和1602液晶顯示的實時時鐘//-------------------------------------------------------------------------//說明:本程序運行時會以PC時間為默認時間開始運行,運行過程中可以通過K1按鍵選擇調節對象,用K2、K3//按鍵進行加減,用K4按鍵保存。//---------------------------------------------------------------------------------------#include<reg51.h>#include<string.h>#include<intrins.h>#defineucharunsignedchar#defineuintunsignedintvoidInitialize_LCD1602();//液晶初始化函數voidLCD_Display(ucharp,uchar*str);sbitSDA=P1^0; //DS1302數據線sbitCLK=P1^1; //DS1302時鐘線sbitRST=P1^2; //DS1302 復位線sbitk1=P3^3; //選擇按鍵sbitk2=P3^4; //加sbitk3=P3^5; // 減sbitk4=P3^6; // 確定uchartcount=0; ucharMonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};//一年中每個月的天數,二月的天數由年份決定uchar*Week[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"};//周日,周一到周六//LCD顯示緩沖ucharLCD_DSY_BUFFER1[]={"DATE00-00-00"};ucharLCD_DSY_BUFFER2[]={"TIME00:00:00"};ucharDateTime[7];//所讀取的日期時間charAdjust_Index=-1;//當前調節的時間對象:秒,分,時,日,月,年〔0,1,2,3,4,6〕ucharChange_Flag[]="-MHDM-Y";//(分,時,日,月,年)不調節秒和周//函數聲明voidWrite_Byte_TO_DS1302(ucharX);//向DS1302寫入一個字節ucharRead_Byte_FROM_DS1302(); //從DS1302中讀取一個字節ucharRead_Data_FROM_DS1302(ucharaddr);//從DS1302指定位置讀取數據 ,讀數據voidWrite_Data_TO_DS1302(ucharaddr,uchardat);//向DS1302指定位置寫入數據,寫數據voidSET_DS1302(); //設置時間voidGetTime(); //讀取當前時間voidInitialization();//初始化函數//------------------------------------------//主程序//----------------------------------------voidmain(){Initialization();while(1){ if(Adjust_Index==-1) GetTime(); }}//*-----------------初始化函數--------------*//voidInitialization(){Initialize_LCD1602();//調用液晶初始化函數IE=0x83; //允許中斷外部0中斷和T0中斷IP=0x01; // 設置中斷優先級IT0=0x01; // 設置外部中斷的脈沖觸發方式TMOD=0x01;//設置定時器的工作方式,為方式1TH0=-50000/256;//寫入初值TL0=-50000%256;//寫入初值TR0=1;// 啟動定時器}//*--------寫字節函數,向DS1302寫入一個字節--------*//voidWrite_Byte_TO_DS1302(ucharX)//向DS1302寫入一個字節{uchari; for(i=0;i<8;i++) { SDA=X&1; CLK=1; CLK=0; X>>=1; }}//*--------讀字節函數,從DS1302讀取一個字節--------*//ucharRead_Byte_FROM_DS1302() //從DS1302中讀取一個字節{uchari,byte,t;for(i=0;i<8;i++){ byte>>=1; t=SDA; byte|=t<<7;CLK=1; CLK=0; } //BCD碼轉換 returnbyte/16*10+byte%16;}//-------------------------------------------------------------//從DS1302指定位置讀取數據 ,讀數據//---------------------------------------------------------------ucharRead_Data_FROM_DS1302(ucharaddr)//從DS1302指定位置讀取數據 ,讀數據{uchardat; RST=0; CLK=0; RST=1; Write_Byte_TO_DS1302(addr);//向DS1302寫入一個地址 dat=Read_Byte_FROM_DS1302();//在上面寫入的地址中讀取數據 CLK=1; RST=0; returndat;}//-------------------------------------------------------------//向DS1302指定位置寫入數據,寫數據//---------------------------------------------------------------voidWrite_Data_TO_DS1302(ucharaddr,uchardat)//向DS1302指定位置寫入數據,寫數據{CLK=0; RST=1; Write_Byte_TO_DS1302(addr); Write_Byte_TO_DS1302(dat); CLK=1; RST=0;}//-----------------------------------------------------------//設置時間//---------------------------------------------------------voidSET_DS1302() //設置時間{uchari;Write_Data_TO_DS1302(0x8E,0x00);//寫控制字,取消寫保護//分,時,日,月,年依次寫入for(i=1;i<7;i++){ //分的起始地址是10000010(0x82),后面依次是時,日,月,周,年,寫入地址每次遞增2 Write_Data_TO_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10)); }Write_Data_TO_DS1302(0x8E,0x80);//寫控制字,加寫保護}//--------------------------------------------------------//讀取當前時間//-------------------------------------------------------voidGetTime() //讀取當前時間{uchari;for(i=0;i<7;i++){ DateTime[i]=Read_Data_FROM_DS1302(0x81+2*i); }}//------------------------------------------------------------//日期與時間值轉換為數字字符//-------------------------------------------------------------voidFormat_DateTime(uchard,uchar*a){ a[0]=d/10+'0'; a[1]=d%10+'0';}//-------------------------------------------------------------------//判斷是否為閏年//-------------------------------------------------------------------ucharIs_Leapyear(uintyear){return(year%4==0&&year%100!=0)||(year%400==0);}//------------------------------------------------------------------// 求自2000.1.1開始的任何一天是星期幾?//----------------------------------------------------------------------voidRefresh_Week_Day(){uinti,d,w=5;//1999年12.31是星期五for(i=2000;i<2000+DateTime[6];i++){ d=Is_Leapyear(i)?366:365; w=(w+d)%7; }d=0;for(i=1;i<DateTime[4];i++){d+=MonthsDays[i];}d+=DateTime[3];//保存星期,0-6表示星期日,星期一至星期六,為了與DS1302的星期格式匹配,返回值需要加1DateTime[5]=(w+d)%7+1;}//-------------------------------------------------//年,月,日和時,分++/--//----------------------------------------------------voidDatetime_Adjust(charX){switch(Adjust_Index){ case6: //年調整,00-99 if(X==1&&DateTime[6]<99) { DateTime[6]++; } if(X==-1&&DateTime[6]>0) { DateTime[6]--; } //獲取2月天數 MonthsDays[2]=Is_Leapyear(2000+DateTime[6])?29:28; //如果年份變化后當前月份的天數大于上限那么設為上限 if(DateTime[3]>MonthsDays[DateTime[4]]) { DateTime[3]=MonthsDays[DateTime[4]]; } Refresh_Week_Day();//刷新星期 break; case4://月調整01-12 if(X==1&&DateTime[4]<12) { DateTime[4]++; } if(X==-1&&DateTime[4]>1) { DateTime[4]--; } //獲取2月天數 MonthsDays[2]=Is_Leapyear(2000+DateTim
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 車輛居間合同協議書范本
- 補充延長協議合同
- 合作炒股協議合同
- 木頭加工合同協議書
- 隱私協議合同
- 農村修車合同協議書
- 物業管理解除合同協議書
- 豬舍租賃合同協議書模板
- 法人不變轉讓合同協議書
- 合同附屬協議書
- 縱隔腫瘤護理查房
- 眼鏡店銷售培訓課件
- 宜賓市屬國有企業人力資源中心宜賓臨港投資建設集團有限公司下屬子公司2025年第一批項目制員工公開招聘筆試參考題庫附帶答案詳解
- 2025年山東魯泰控股集團有限公司下屬駐陜西煤礦企業招聘(150人)筆試參考題庫附帶答案詳解
- 2025屆上海市浦東新區高三二模英語試卷(含答案)
- 2025年全民國家安全教育日主題班會
- 2024-2025學年高一政治統編版下學期期中考試測試卷B卷(含解析)
- 開曼群島公司法2024版中文譯本(含2024年修訂主要內容)
- 【MOOC】航空燃氣渦輪發動機結構設計-北京航空航天大學 中國大學慕課MOOC答案
- 2024年4月自考00150金融理論與實務試題及答案
- 工程變更通知單ECN模板-20220213
評論
0/150
提交評論