單片機(jī)課程筆記_第1頁
單片機(jī)課程筆記_第2頁
單片機(jī)課程筆記_第3頁
單片機(jī)課程筆記_第4頁
單片機(jī)課程筆記_第5頁
已閱讀5頁,還剩84頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

單片機(jī)課程筆記單片機(jī)課程筆記/NUMPAGES89單片機(jī)課程筆記單片機(jī)課程筆記注意:本課件為上課筆記的一個(gè)整理,其中難免存在錯(cuò)誤,請讀者不吝賜教,如有問題請發(fā)送E-mail到zhaojian@。本文根據(jù)教學(xué)的情況,隨時(shí)進(jìn)行修改和完善,所以歡迎同學(xué)隨時(shí)注意本文檔在課件中的更新情況。單片機(jī)基礎(chǔ)知識單片機(jī)的外部結(jié)構(gòu):DIP40雙列直插;P0,P1,P2,P3四個(gè)8位準(zhǔn)雙向I/O引腳;(作為I/O輸入時(shí),要先輸出高電平)電源VCC(PIN40)和地線GND(PIN20);高電平復(fù)位RESET(PIN9);(10uF電容接VCC與RESET,即可實(shí)現(xiàn)上電復(fù)位)內(nèi)置振蕩電路,外部只要接晶體至X1(PIN18)和X0(PIN19);(頻率為主頻的12倍)程序配置EA(PIN31)接高電平VCC;(運(yùn)行單片機(jī)內(nèi)部ROM中的程序)P3支持第二功能:RXD、TXD、INT0、INT1、T0、T1單片機(jī)內(nèi)部I/O部件:(所為學(xué)習(xí)單片機(jī),實(shí)際上就是編程控制以下I/O部件,完成指定任務(wù))四個(gè)8位通用I/O端口,對應(yīng)引腳P0、P1、P2和P3;兩個(gè)16位定時(shí)計(jì)數(shù)器;(TMOD,TCON,TL0,TH0,TL1,TH1)一個(gè)串行通信接口;(SCON,SBUF)一個(gè)中斷控制器;(IE,IP)針對AT89C52單片機(jī),頭文件AT89x52.h給出了SFR特殊功能寄存器所有端口的定義。教科書的160頁給出了針對MCS51系列單片機(jī)的C語言擴(kuò)展變量類型。C語言編程基礎(chǔ):十六進(jìn)制表示字節(jié)0x5a:二進(jìn)制為01011010B;0x6E為01101110。如果將一個(gè)16位二進(jìn)數(shù)賦給一個(gè)8位的字節(jié)變量,則自動截?cái)酁榈?位,而丟掉高8位。++var表示對變量var先增一;var—表示對變量后減一。x|=0x0f;表示為x=x|0x0f;TMOD=(TMOD&0xf0)|0x05;表示給變量TMOD的低四位賦值0x5,而不改變TMOD的高四位。6、While(1);表示無限執(zhí)行該語句,即死循環(huán)。語句后的分號表示空循環(huán)體,也就是{;}第一章單片機(jī)最小應(yīng)用系統(tǒng):單片機(jī)最小系統(tǒng)的硬件原理接線圖:接電源:VCC(PIN40)、GND(PIN20)。加接退耦電容0.1uF接晶體:X1(PIN18)、X2(PIN19)。注意標(biāo)出晶體頻率(選用12MHz),還有輔助電容30pF接復(fù)位:RES(PIN9)。接上電復(fù)位電路,以及手動復(fù)位電路,分析復(fù)位工作原理接配置:EA(PIN31)。說明原因。具體接法如下圖所示:第二章基本I/O口的應(yīng)用。例1:用P1口輸出一倍頻方波。#include<reg52.h>//reg52.h為包含51資源的庫文件voidmain(void){ while(1==1) { ++P1;//使P1口加一完成一倍頻方波, }}注意:P0的每個(gè)引腳要輸出高電平時(shí),必須外接上拉電阻(如4K7)至VCC電源。例2:用P1口輸出一倍頻方波,要求能用萬用表測出方波。其實(shí),只需要在上面的程序中添加延時(shí)程序即可。#include<reg52.h>voidmain(void){ unsignedinti,j;while(1==1) { ++P1; for(i=0;i<1000;i++) for(j=0;j<1000;j++);//該循環(huán)是一個(gè)大概的延時(shí),具體時(shí)間要看匯編語言的指令才能判斷。 }}例3:要求從P1口輸出一方波,要求P1.7變化的最快,P1.0變化的最慢。#include<reg52.h>voidmain(void){ unsignedcharm,n;//定義兩個(gè)中間變量完成交換過程 unsignedinti,j; while(1) { n=0; ++m; n|=(m<<7)&0x80;//將第0位的值送至第7位 n|=(m<<5)&0x40;//將第1位的值送至第6位 n|=(m<<3)&0x20;//將第2位的值送至第5位 n|=(m<<1)&0x10;//將第3位的值送至第4位 n|=(m>>1)&0x08;//將第4位的值送至第3位 n|=(m>>3)&0x04;//將第5位的值送至第2位 n|=(m>>5)&0x02;//將第6位的值送至第1位 n|=(m>>7)&0x01;//將第7位的值送至第0位 P1=n; for(i=0;i<1000;i++) for(j=0;j<1000;j++);}}注意:一個(gè)字節(jié)的8位D7、D6至D0,分別輸出到P3.7、P3.6至P3.0,比如P3=0x0f,則P3.7、P3.6、P3.5、P3.4四個(gè)引腳都輸出低電平,而P3.3、P3.2、P3.1、P3.0四個(gè)引腳都輸出高電平。同樣,輸入一個(gè)端口P2,即是將P2.7、P2.6至P2.0,讀入到一個(gè)字節(jié)的8位D7、D6至D0。第三章顯示驅(qū)動數(shù)碼管的接法和驅(qū)動原理一支七段數(shù)碼管實(shí)際由8個(gè)發(fā)光二極管構(gòu)成,其中7個(gè)組形構(gòu)成數(shù)字8的七段筆畫,所以稱為七段數(shù)碼管,而余下的1個(gè)發(fā)光二極管作為小數(shù)點(diǎn)。作為習(xí)慣,分別給8個(gè)發(fā)光二極管標(biāo)上記號:a,b,c,d,e,f,g,h。對應(yīng)8的頂上一畫,按順時(shí)針方向排,中間一畫為g,小數(shù)點(diǎn)為h。我們通常又將各二極與一個(gè)字節(jié)的8位對應(yīng),a(D0),b(D1),c(D2),d(D3),e(D4),f(D5),g(D6),h(D7),相應(yīng)8個(gè)發(fā)光二極管正好與單片機(jī)一個(gè)端口Pn的8個(gè)引腳連接,這樣單片機(jī)就可以通過引腳輸出高低電平控制8個(gè)發(fā)光二極的亮與滅,從而顯示各種數(shù)字和符號;對應(yīng)字節(jié),引腳接法為:a(Pn.0),b(Pn.1),c(Pn.2),d(Pn.3),e(Pn.4),f(Pn.5),g(Pn.6),h(Pn.7)。如果將8個(gè)發(fā)光二極管的負(fù)極(陰極)內(nèi)接在一起,作為數(shù)碼管的一個(gè)引腳,這種數(shù)碼管則被稱為共陰數(shù)碼管,共同的引腳則稱為共陰極,8個(gè)正極則為段極。否則,如果是將正極(陽極)內(nèi)接在一起引出的,則稱為共陽數(shù)碼管,共同的引腳則稱為共陽極,8個(gè)負(fù)極則為段極。以單支共陰數(shù)碼管為例,可將段極接到某端口Pn,共陰極接GND,則可編寫出對應(yīng)十六進(jìn)制碼的七段碼表字節(jié)數(shù)據(jù)如下圖:動態(tài)顯示的電路連接如下圖所示:P1口P1口下面,我們編程在數(shù)碼管上顯示出“1234”。程序如下:#include<reg52.h>CodeunsignedcharSeg7Code[16]= //用十六進(jìn)數(shù)作為數(shù)組下標(biāo),可直接取得對應(yīng)的七段編碼字節(jié)//0123456789AbCdEF{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};voidmain(void){ unsignedinti; while(1) { P2|=0x0f;//消隱,讓數(shù)碼管開始處于不亮的狀態(tài) P0=LedCode[1]; //將“1”的代碼送出 P2&=0xfe;//選中第一個(gè)數(shù)碼管 for(i=0;i<1000;i++);P2|=0x0f; P0=LedCode[2]; P2&=0xfd; for(i=0;i<1000;i++);P2|=0x0f; P0=LedCode[3]; P2&=0xfb;for(i=0;i<1000;i++);P2|=0x0f; P0=LedCode[4]; P2&=0xf7; for(i=0;i<1000;i++); }}關(guān)于DRIVER編寫DRIVER的目的是讓程序能適應(yīng)更多的場合,讓我們的使用更加方便,大家可以把一些自己編過的有用的程序做成DRIVER便于自己以后的使用。下面介紹顯示的驅(qū)動程序:首先,定義一個(gè)頭文檔<LedDriver.H>,描述可用函數(shù),如下:HYPERLINK\o"條件編譯控制。意是如果沒有定義過某符號"#ifndef_LedDriver_H_ //防止重復(fù)引用該文檔,如果沒有定義過符號_KEY_H_,則編譯下面語句HYPERLINK\o"符號定義。意是定義一個(gè)符號,符號可以為空"#define_LedDriver_H_ //只要引用過一次,即#include<key.h>,則定義符號_KEY_H_voidLedPrint(unsignedcharDat)//數(shù)據(jù)緩沖區(qū)間,完成移位功能voidLedWork(void)//送數(shù)到顯示數(shù)碼管HYPERLINK\o"條件編譯控制。與#ifdef或#ifndef配對使用"#endif然后,定義函數(shù)體文檔LedDriver.C,如下:#include<reg52.h>#include“LedDriver.h”CodeunsignedcharLedCode[16]= //Code是表示這個(gè)數(shù)組的存儲空間{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unsignedcharDisBuf[4];voidLedPrint(unsignedcharDat){ DisBuf[0]=DisBuf[1];//每次用后一個(gè)數(shù)沖掉前一個(gè)數(shù),便于擴(kuò)展顯示位數(shù) DisBuf[1]=DisBuf[2];DisBuf[2]=DisBuf[3];DisBuf[3]=Dat;}voidLedWork(void){ staticunsignedchari=0;//static表示靜態(tài)變量,指變量的賦值只在第一次定義的時(shí)候賦 P2|=0x0f; P0=LedCode[DisBuf[i]]; Switch(i)//選擇數(shù)據(jù)送到哪個(gè)管子 { case0:P2_0=0;break; case1:P2_1=0;break; case2:P2_2=0;break; case3:P2_3=0;break; } if(++i>=4)i=0;//判斷四位數(shù)是否都已經(jīng)送完 for(m=0;m<1000;m++);//延時(shí)}這樣DRIVER的程序就編好了,我們以后用的時(shí)候直接調(diào)用函數(shù)就可以了。主程序可以編寫如下:#include<reg52.h>#include“LedDriver.h”voidmian(void){ LedPrint(1);//調(diào)用函數(shù),把想顯示的數(shù)據(jù)送如緩存 LedPrint(2); LedPrint(3); LedPrint(4); While(1) { LedWork(); }}下面介紹一個(gè)例子供大家參考。顯示“12345678”P1端口接8聯(lián)共陰數(shù)碼管SLED8的段極:P1.7接段h,…,P1.0接段aP2端口接8聯(lián)共陰數(shù)碼管SLED8的段極:P2.7接左邊的共陰極,…,P2.0接右邊的共陰極方案說明:晶振頻率fosc=12MHz,數(shù)碼管采用動態(tài)刷新方式顯示,在1ms定時(shí)斷服務(wù)程序中實(shí)現(xiàn)#include<reg52.h>unsignedcharDisBuf[8]; //全局顯示緩沖區(qū),DisBuf[0]對應(yīng)右SLED,DisBuf[7]對應(yīng)左SLED,voidDisplayBrush(void){ codeunsignedcharcathode[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //陰極控制碼codeunsignedcharSeg7Code[16]= //用十六進(jìn)數(shù)作為數(shù)組下標(biāo),可直接取得對應(yīng)的七段編碼字節(jié){0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};staticunsignedchari=0;//(0≤i≤7)循環(huán)刷新顯示,由于是靜態(tài)變量,此賦值只做一次。 P2=0xff; //顯示消隱,以免下一段碼值顯示在前一支SLED P1=Seg7Code[DisBuf[i]]; //從顯示緩沖區(qū)取出原始數(shù)據(jù),查表變?yōu)槠叨未a后送出顯示P2=cathode[i]; //將對應(yīng)陰極置低,顯示if(++i>=8)i=0; //指向下一個(gè)數(shù)碼管和相應(yīng)數(shù)據(jù)}voidTimer0IntRoute(void)interrupt1{ TL0=-1000; //由于TL0只有8bits,所以將(-1000)低8位賦給TL0 TH0=(-1000)>>8; //取(-1000)的高8位賦給TH0,重新定時(shí)1ms DisplayBrush();}voidTimer0Init(void){ TMOD=(TMOD&0xf0)|0x01; //初始化,定時(shí)器T0,工作方式1 TL0=-1000; //定時(shí)1ms TH0=(-1000)>>8; TR0=1; //允許T0開始計(jì)數(shù) ET0=1; //允許T0計(jì)數(shù)溢出時(shí)產(chǎn)生中斷請求}voidDisplay(unsignedcharindex,unsignedchardataValue){DisBuf[index]=dataValue;}voidmain(void){unsignedchari;for(i=0;i<8;i++){Display(i,8-i);}//DisBuf[0]為右,DisBuf[0]為左Timer0Init();EA=1; //允許CPU響應(yīng)中斷請求While(1);} 第四章鍵盤驅(qū)動單片機(jī)I/O口作為輸入的前提是必須首先輸出一個(gè)高電平。charKbhit(void) {P1.0P1_0=1; if(P1_9==0)return(1); elsereturn(0); )下面我們對上面的程序作個(gè)改進(jìn):charKbhit(void){ P1=0xff; if((P1^0xff)!=0)return(1);}一般來說,按鍵的時(shí)候會有抖動,我們可以用加延時(shí)的辦法來去除抖動。即:P1=0xff;if((P1^0xff)!=0)延時(shí)20ms;if((P1^0xff)!=0)return(1);4X4按鍵。由P1端口的高4位和低4位構(gòu)成4X4的矩陣鍵盤,本程序只認(rèn)為單鍵操作為合法,同時(shí)按多鍵時(shí)無效。P1.0(0xE)P1.0(0xE)P1.1(0xD)P1.2(0xB)P1.3(0x7)P1.4(E)P1.5(D)P1.6(B)P1.7(7)FEDCBA9876A543210取鍵值的程序如下:unsignedchargetch(void){ unsignedcharX,Y,Z;P1=0xf0; X=P1; P1=0x0f; Y=P1; Z=X|Y; switch(Z) { case0xee:return(0); case0xde:return(1); case0xbe:return(2); case0x7e:return(3); case0xed:return(4); case0xdd:return(5); case0xbd:return(6); case0x7d:return(7); case0xeb:return(8); case0xdb:return(9); case0xbb:return(10); case0x7b:return(11); case0xe7:return(12); case0xd7:return(13); case0xb7:return(14); case0x77:return(15);}}判斷有無鍵按下的程序:charKbhit(void){ P1=0xf0; if(P1==0xf0)return(0); elsereturn(1);}下面是鍵盤的Driver程序:首先我們還是來寫KeyDriver.h這個(gè)程序:#ifndef_KeyDriver_h_#define_KeyDriver_h_charKhbit(void);charGetch(void);#endif接著,我們來寫KeyDriver.c程序#include<reg52.h>#include“KeyDriver.h”charKbhit(void){ P1=0xf0; if(P1==0xf0)return(0); elsereturn(1);}unsignedchargetch(void){ unsignedcharX,Y,Z;P1=0xf0; X=P1; P1=0x0f; Y=P1; Z=X|Y; switch(Z) { case0xee:return(0); case0xde:return(1); case0xbe:return(2); case0x7e:return(3); case0xed:return(4); case0xdd:return(5); case0xbd:return(6); case0x7d:return(7); case0xeb:return(8); case0xdb:return(9); case0xbb:return(10); case0x7b:return(11); case0xe7:return(12); case0xd7:return(13); case0xb7:return(14); case0x77:return(15);}}按鍵顯示程序如下:#include<reg52.h>#include“LedDriver.h”#include“KeyDriver.h”voidmain(void){ unsignedchari; for(i=1;i<5;i++) {LedPrint(i);} while(1) { if(Kbhit()) {LedPrint(Getch());} LedWork(); }}下面是另一個(gè)鍵盤值的算法,供大家參考。P1.0(0xE)P1.0(0xE)P1.1(0xD)P1.2(0xB)P1.3(0x7)P1.4(E)P1.5(D)P1.6(B)P1.7(7)FEDCBA9876543210定義一個(gè)頭文檔<KEY.H>,描述可用函數(shù),如下:HYPERLINK\o"條件編譯控制。意是如果沒有定義過某符號"#ifndef_KEY_H_ //防止重復(fù)引用該文檔,如果沒有定義過符號_KEY_H_,則編譯下面語句HYPERLINK\o"符號定義。意是定義一個(gè)符號,符號可以為空"#define_KEY_H_ //只要引用過一次,即#include<key.h>,則定義符號_KEY_H_HYPERLINK\o"無符號字符。實(shí)際是一個(gè)字節(jié)、八位二進(jìn)制的無符號數(shù),取值范圍從0到255"unsignedcharkeyHit(HYPERLINK\o"表示空,即沒有。"void); //如果按鍵,則返回非0,否則返回0unsignedcharkeyGet(void); //讀取按鍵值,如果沒有按鍵則等待到按鍵為止voidkeyPut(unsignedcharucKeyVal); //保存按鍵值ucKeyVal到按鍵緩沖隊(duì)列末voidkeyBack(unsignedcharucKeyVal); //退回鍵值ucKeyVal到按鍵緩沖隊(duì)列首HYPERLINK\o"條件編譯控制。與#ifdef或#ifndef配對使用"#endif定義函數(shù)體文檔KEY.C,如下:#include“key.h”#defineKeyBufSize 16 //定義按鍵緩沖隊(duì)列字節(jié)數(shù)unsignedcharKeyBuf[KeyBufSize]; //定義一個(gè)無符號字符數(shù)組作為按鍵緩沖隊(duì)列。該隊(duì)列為先進(jìn) //先出,循環(huán)存取,下標(biāo)從0到KeyBufSize-1unsignedcharKeyBufWp=0; //作為數(shù)組下標(biāo)變量,記錄存入位置unsignedcharKeyBufRp=0; //作為數(shù)組下標(biāo)變量,記錄讀出位置//如果存入位置與讀出位置相同,則表明隊(duì)列中無按鍵數(shù)據(jù)unsignedcharkeyHit(void){ if(KeyBufWp==KeyBufRp)return(0);elsereturn(1);}unsignedcharkeyGet(void){ unsignedcharretVal; //暫存讀出鍵值while(keyHit()==0); //等待按鍵,因?yàn)楹瘮?shù)keyHit()的返回值為0表示無按鍵retVal=KeyBuf[KeyBufRp]; //從數(shù)組中讀出鍵值if(++KeyBufRp>=KeyBufSize)KeyBufRp=0; //讀位置加1,超出隊(duì)列則循環(huán)回初始位置 return(retVal);}voidkeyPut(unsignedcharucKeyVal){ KeyBuf[KeyBufWp]=ucKeyVal; //鍵值存入數(shù)組 if(++KeyBufWp>=KeyBufSize)KeyBufWp=0; //存入位置加1,超出隊(duì)列則循環(huán)回初始位置}/*****************************************************************************************由于某種原因,讀出的按鍵,沒有用,但其它任務(wù)要用該按鍵,但傳送又不方便。此時(shí)可以退回按鍵隊(duì)列。就如取錯(cuò)了信件,有必要退回一樣******************************************************************************************/voidkeyBack(unsignedcharucKeyVal){/*如果KeyBufRp=0;減1后則為FFH,大于KeyBufSize,即從數(shù)組頭退回到數(shù)組尾?;蛘哂捎诟蓴_使得KeyBufRp超出隊(duì)列位置,也要調(diào)整回到正常位置,*/ if(--KeyBufRp>=KeyBufSize)KeyBufRp=KeyBufSize-1;KeyBuf[KeyBufRp]=ucKeyVal; //回存鍵值}#include<at89x52.h>#include“KEY.H”unsignedcharkeyScan(void) //返回0表示無按鍵,或無效按鍵,其它值為按鍵編碼值{ codeunsignedcharkeyCode[16]= /0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF{0,0,0,0,0,0,0,1,0,0,0,2,0,3,4,0};unsignedcharx,y,retVal;P1=0x0f; //低四位輸入,高四位輸出0x=P1&0x0f; //P1輸入后,清高四位,作為X值P1=0xf0; //高四位輸入,低四位輸出0y=(P1>>4)&0x0f; //P1輸入后移位到低四位,并清高四位,作為Y值retVal=keyCode[x]*4+keyCode[y]; //根據(jù)本公式倒算按鍵編碼if(retVal==0)return(0);elsereturn(retVal-4); } //比如按鍵‘1’,得X=0x7,Y=0x7,算得retVal=5,所以返回函數(shù)值1。//雙如按鍵‘7’,得X=0xb,Y=0xd,算得retVal=11,所以返回函數(shù)值7。voidmain(void){ TMOD=(TMOD&0xf0)|0x01; //不改變T1的工作方式,T0為定時(shí)器方式1TL0=-20000; //計(jì)數(shù)周期為20000個(gè)主頻脈,自動取低8位TH0=(-20000)>>8; //右移8位,實(shí)際上是取高8位TR0=1; //允許T0開始計(jì)數(shù)ET0=1; //允許T0計(jì)數(shù)溢出時(shí)產(chǎn)生中斷請求EA=1; //允許CPU響應(yīng)中斷請求while(1) //永遠(yuǎn)為真,即死循環(huán) {if(keyHit()!=0) //如果隊(duì)列中有按鍵P2=Seg7Code[keyGet()]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上 }}voidtimer0int(void)interrupt1 //20ms;T0的中斷號為1{ staticunsignedcharsts=0;TL0=-20000; //方式1為軟件重載TH0=(-20000)>>8; //右移8位,實(shí)際上是取高8位 P1_0=1; //作為輸入引腳,必須先輸出高電平switch(sts) { case0:if(keyScan()!=0)sts=1;break; //按鍵則轉(zhuǎn)入狀態(tài)1 case1:if(keyScan()==0)sts=0; //假按錯(cuò),或干擾,回狀態(tài)0else{sts=2;keyPut(keyScan());} //確實(shí)按鍵,鍵值入隊(duì)列,并轉(zhuǎn)狀態(tài)2break; case2:if(keyScan()==0)sts=3;break; //如果松鍵,則轉(zhuǎn)狀態(tài)3 case3: if(keyScan()!=0)sts=2; //假松鍵,回狀態(tài)2 elsests=0; //真松鍵,回狀態(tài)0,等待下一次按鍵過程 }}第五章中斷系統(tǒng)應(yīng)用對于51系列單片機(jī)的中斷資源在本課件中就不再多加描述 ,同學(xué)們可以參考書上的一些資料,主要在這里是介紹它的應(yīng)用。序號中斷源中斷控制位(允許否)優(yōu)先控制位中斷狀態(tài)其他0X0 EX0 PX0 IE0INT01Timer0ET0 PT0 TF0 T02X1EX1 PX1 IE1 INT13Timer1ET1PT1TF1T14UARTESPSRXD/TXDRI/TI5Timer2ET2PT2TF2 T2EA完成以下程序設(shè)計(jì)(初始化):要求:1、將串口中斷的級別設(shè)置為最高;2、INT0工作于邊沿模式,INT1工作于電平模式,這兩個(gè)中斷都是從外部輸入;3、允許T1定時(shí)器中斷。#include<reg52.h>voidmain(void){ EA=0; PS=1;PT1=0;PT0=0;PX0=0;PX1=0;//設(shè)置串口的中斷級別最高 INT1=1;INT0=1;//設(shè)置外部輸入中斷 IT0=1;IT1=0;//設(shè)置INT0工作于邊沿模式,INT1工作于電平模式 ET1=1;//允許定時(shí)器1中斷 EX0=1;EX1=1;//允許外部中斷0、1工作 ES=1;//允許串口中斷 EA=1; //開中斷 while(1);}下面的程序?yàn)橹袛嗟木唧w應(yīng)用,主要是針對T2定時(shí)器的中斷。#include<REG52.h>voidmain(void){ EA=0; //disableinterruptforsystem C_T2=0; //time CP_RL2=0; //Reload RCAP2L=-1000; //low8bits RCAP2H=(-1000)>>8; //high8bits TL2=RCAP2L; //firstloadtoT2 TH2 =RCAP2H; TR2=1; //startcount ET2=1; //enableTimer2interrupt EA =1; //openinterruptforsystem while(1){;}}voidTimer2Int(void)interrupt5{ TF2=0; P1^=0xff;}下面的程序是將按鍵和顯示放在中斷服務(wù)程序中進(jìn)行處理。程序內(nèi)容為上課時(shí)的例子test2。clock.h文件編寫如下:#ifndef_clock_h_#define_clock_h_#defineSysClock 3686400structsClock{ unsignedcharflag; unsignedlongsecond; //2^32secondsfor136years unsignedintms;};voidClockOpen(void);structsClock*ClockGet(void);//voidClockSet(structsClock*ptr);voidClockCall(void);externstructsClockgClock;#endif——————————————————————————————————clock.c文件編寫如下:#include<reg52.h>#include"clock.h"#include"LedDriver.h"#include"KeyDriver.h"voidClockCall_ms(void){ LedTimeCall(); KeyTimeCall();}voidClockOpen(void) //初始化Timer2產(chǎn)生1ms定時(shí)中斷{ gClock.ms=0; gClock.second=0; CP_RL2=0; //重載模式 C_T2=0; //定時(shí)器方式 RCAP2H=(-(SysClock/1000))>>8; //重載值高8位 RCAP2L=(-(SysClock/1000))&0x00ff; //重載值低8位 TR2 =1; //允許定時(shí)計(jì)數(shù) ET2=1; //允許Timer2中斷}voidT2int(void)interrupt5{ TF2=0; //clearinterruptstatus ClockCall_ms();}——————————————————————————————————————KeyDriver.h文件編寫如下:#ifndef_KeyDriver_H_#define_KeyDriver_H_#define KeyBufSize4charkbhit(void);chargetch(void);voidKeyBufIn(chardat);voidKeyTimeCall(void);#endifKeyDriver.c文件編寫如下:#include<reg52.h>#include"KeyDriver.h"unsignedcharKeyBufWp=0;unsignedcharKeyBufRp=0;unsignedcharKeyBuf[KeyBufSize];charkbhit(void){ return(KeyBufWp-KeyBufRp);}chargetch(void){ charret; ret=KeyBuf[KeyBufRp]; if(++KeyBufRp>=KeyBufSize)KeyBufRp=0; return(ret);}voidKeyBufIn(chardat){ KeyBuf[KeyBufWp]=dat; if(++KeyBufWp>=KeyBufSize)KeyBufWp=0;}voidKeyTimeCall(void){ codecharKeyCode[]={ /*01234 5 6 7 8 9 A B C D E F*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, //0 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//1 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//2 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//3 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//4 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//5 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//6 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0F,0xff,0xff,0xff,0x0B,0xff,0x07,0x03,0xff,//7 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//8 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//9 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//A 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0E,0xff,0xff,0xff,0x0A,0xff,0x06,0x02,0xff,//B 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//C 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0D,0xff,0xff,0xff,0x09,0xff,0x05,0x01,0xff,//D 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0C,0xff,0xff,0xff,0x08,0xff,0x04,0x00,0xff,//E 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff//F }; unsignedcharKeyScan; staticunsignedcharKeyScanCode=0; staticunsignedcharsts=0; staticunsignedcharms=20; if(--ms)return; ms=20; P1=0x0f; KeyScan=P1; P1=0xf0; KeyScan|=P1; switch(sts) { case0: if(KeyScan!=0xff) //可能有按鍵 {sts=1;KeyScanCode=KeyScan;} break; case1: if(KeyScanCode==KeyScan) //去抖后確為鍵按下 { sts=2; KeyBufIn(KeyCode[KeyScan]); //返回鍵值 } else //否則認(rèn)為是干擾,重新檢測 sts=0; break; case2: if(KeyScanCode!=KeyScan) //檢測松開按鍵 { if(KeyScan==0xff)sts=3; } break; //按鍵超過1秒認(rèn)為是連續(xù)按鍵 //其后每0.2秒一次鍵,直到松開為止 //要處理組合按鍵(即0.1秒后確認(rèn)讀鍵,保證所有組合鍵到位 //還可能保持不松開全部按鍵的情況下,轉(zhuǎn)換按其它鍵組合 // case3: if(KeyScan==0xff)sts=0; //去抖后確為松開按鍵 elsests=2; //是干擾 break; }}——————————————————————————————————————————————LedDriver.h文件編寫如下:#ifndef_LedDriver_H_#define_LedDriver_H_/*顯示數(shù)據(jù)為一個(gè)字節(jié),由兩部分組成,高三位為屬性,低五位為值 BIT7:為小數(shù)點(diǎn) BIT6:為閃爍位 BIT5:保留*/#defineCharAtr_POINT 0x80#defineCharAtr_FLASH 0x40#defineChar_0 0#defineChar_1 1#defineChar_2 2#defineChar_3 3#defineChar_4 4#defineChar_5 5#defineChar_6 6#defineChar_7 7#defineChar_8 8#defineChar_9 9#defineChar_a 10#defineChar_b 11#defineChar_c 12#defineChar_d 13#defineChar_e 14#defineChar_f 15#defineChar_N 16 //singned-#defineChar_H 17#defineChar_L 18#defineChar_P 19#defineChar_o 20externunsignedcharDisBuf[];#defineLedPutchar(bitN,Dat){DisBuf[bitN]=Dat;}voidLedPrint(unsignedchar);voidLedTimeCall(void);#endifLedDriver.c文件編寫如下:#include<reg52.h>#include"LedDriver.h"codeunsignedcharLedHexCode[]= { //01234567 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //89abcdef 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71, //-HLPo 0x40,0x76,0x38,0x73, 0x5c, };unsignedcharDisBuf[4];voidLedPrint(unsignedchardat){ DisBuf[0]=DisBuf[1]; DisBuf[1]=DisBuf[2]; DisBuf[2]=DisBuf[3]; DisBuf[3]=dat;}voidLedTimeCall(void){ staticunsignedcharindex=0; P2|=0x0f; P0=LedHexCode[DisBuf[index]]; P2&=(1<<index)^0xff; if(++index==4)index=0;}main.c文件編寫如下:程序功能描述:多彩的世界,變化無窮實(shí)現(xiàn)方法:控制單片機(jī)左右兩排發(fā)光二極管注意事項(xiàng):運(yùn)行本程序時(shí),撥碼開關(guān)SW1.SW2全部撥到'OFF'位置(即左邊). 如果LED6、LED7和LED8不工作,按一下S2和S3即可工作方式控制:按鍵K1、K2、K3和K4可做出不同的顯示。*/#include<reg52.h> //該頭文檔描述單片機(jī)所有特殊功能寄存器的稱名,程序中可直接使用,比喻'P1'#include"LedDriver.h"#include"KeyDriver.h"#include"clock.h"unsignedcharfunction=0;voidmain(void) //一個(gè)工程項(xiàng)目必須有一個(gè)main函數(shù),并且只能有一個(gè)main函數(shù){ charkeyVal=0; EA=0; ClockOpen(); LedPrint(Char_6); LedPrint(Char_o); LedPrint(Char_o); LedPrint(Char_d); EA=1; while(1) { if(kbhit()) //如果有鍵按下返回非0值 { keyVal=getch(); //K1K16返回的鍵值分別為015 LedPrint(keyVal); } }}/*1.參考任一個(gè)顯不方式的模塊,增加一種顯示方式對應(yīng)鍵K4,左右兩排發(fā)光二極管交替亮滅2.每個(gè)按鍵Ki(i=1...16)對應(yīng)一個(gè)發(fā)光二極管LEDi,按相應(yīng)的鍵Ki,則對應(yīng)的燈LEDi亮,再按,則滅,交替工作。3.你現(xiàn)在可以做一下十字路的交通燈管制系統(tǒng)了,做產(chǎn)品就這么容量^=^下面的程序是test3。只有主程序部分于上面的test2有不同,現(xiàn)將main.c寫在下面供大家參考。#include<reg52.h> //該頭文檔描述單片機(jī)所有特殊功能寄存器的稱名,程序中可直接使用,比喻'P1'#include"LedDriver.h"#include"KeyDriver.h"#include"clock.h"unsignedcharfunction=0;voidmain(void) //一個(gè)工程項(xiàng)目必須有一個(gè)main函數(shù),并且只能有一個(gè)main函數(shù){ charkeyVal=0; if(INT0==0)function=1; if(INT1==0)function=2; if(T0==0)function=3; if(T1==0)function=4; EA=0; ClockOpen(); LedPrint(Char_6); LedPrint(Char_o); LedPrint(Char_o); LedPrint(Char_d); EA=1; switch(function) { case0: while(1) { if(kbhit()) //如果有鍵按下返回非0值 { keyVal=getch(); //K1K16返回的鍵值分別為015 LedPrint(keyVal); } } case1: while(1) { unsignedintold,new; unsignedcharminute,second; new=ClockGet()->second; if(old!=new) { minute=(new%3600)/60; second=new%60; LedPrint(minute/10); LedPrint((minute%10)|CharAtr_POINT); LedPrint(second/10); LedPrint(second%10); } old=new; } default:function=0; } }第六章計(jì)數(shù)器/定時(shí)器的應(yīng)用對于T0,T1定時(shí)器,主要的控制寄存器為TMOD、TCON,我們可以通過設(shè)置這些寄存器的值來改變定時(shí)器的工作情況。例1:設(shè)置Timer1工作于計(jì)數(shù)模式,工作于方式2狀態(tài),要求每16個(gè)脈沖中斷一次。#include<reg52.h>voidmain(void){EA=1;TMOD=(TMOD&0XF0)|0x60;//設(shè)置定時(shí)器1工作于方式2,計(jì)數(shù)模式,并且不改變定時(shí)器0的工作狀態(tài)。 T1=1;//設(shè)置P3.5為輸入狀態(tài)ET1=1;//允許定時(shí)器1中斷TH1=-16;TL1=TH1;//給定時(shí)器送初值TR1=1; //開啟定時(shí)器1(使計(jì)數(shù)開始)EA=1;//允許中斷while(1);voidTimer1_int(void)interrupt3//定時(shí)器1的中斷號是3{ TF1=0;//對于定時(shí)器0和定時(shí)器1可以不用寫這句,因?yàn)橛布詣訉F1進(jìn)行清零TXD=!TXD;}例2:完成下面的程序:要求:1、Timer0工作在方式2,作為定時(shí)器使用,受門控,每100個(gè)脈沖中斷一次,中斷服務(wù)程序?qū)XD取反;2、Timer1工作在方式1,作為計(jì)數(shù)器使用,不受門控,每4567個(gè)脈沖中斷一次,中斷后取反TXD。程序如下:#include<reg52.h>voidmain(void){ EA=0; TMOD=0X5A;//設(shè)置好兩個(gè)定時(shí)器的工作情況 TH0=-100;TL0=TH0;//給定時(shí)器0置初值 ET0=1; TH1=(-4567)>>8;TL1=-4567; ET1=1;T1=1;INT0=1; TR0=1; EA=1; while(1);}voidTimer0_int(void)interrupt1{ RXD=!RXD;}voidTimer1_int(void)interrupt3{ TXD=!TXD; TH1=(-4567)>>8; TL1=-4567;}例3:晶體fosc=12M,12分頻,用T0或者T1,每毫秒運(yùn)行一次函數(shù)TimerCall(),定時(shí)精度與晶體相同。#include<reg52.h>voidmain(void){ EA=0; TMOD=(TMOD&0X0F)|0X2F;//因?yàn)橐笈c晶體的時(shí)間一致,所以必須采用方式2 TH1=-200;TL1=TH1; TR1=1; EA=1; while(1);}voidTimer0_int(void)interrupt3{ staticunsignedcharTimerC=4; if(--TimerC==0) TimerCall(); TimerC=4;}低頻頻率計(jì)的設(shè)計(jì)LedDriver.h如下:**************************************************#ifndef_LedDriver_H_#define_LedDriver_H_/*顯示數(shù)據(jù)為一個(gè)字節(jié),由兩部分組成,高三位為屬性,低五位為值 BIT7:為小數(shù)點(diǎn) BIT6:為閃爍位 BIT5:保留*/#defineCharAtr_POINT 0x80#defineCharAtr_FLASH 0x40#defineChar_0 0#defineChar_1 1#defineChar_2 2#defineChar_3 3#defineChar_4 4#defineChar_5 5#defineChar_6 6#defineChar_7 7#defineChar_8 8#defineChar_9 9#defineChar_a 10#defineChar_b 11#defineChar_c 12#defineChar_d 13#defineChar_e 14#defineChar_f 15#defineChar_N 16 //singned-#defineChar_H 17#defineChar_L 18#defineChar_P 19#defineChar_o 20externunsignedcharDisBuf[];#defineLedPutchar(bitN,Dat){DisBuf[bitN]=Dat;}voidLedPrint(unsignedchar);voidLedTimeCall(void);#endifKeyDriver.h如下:**************************************************#ifndef_KeyDriver_H_#define_KeyDriver_H_#define KeyBufSize4charkbhit(void);chargetch(void);voidKeyBufIn(chardat);voidKeyTimeCall(void);#endifClock.h如下:************************************************#ifndef_clock_h_#define_clock_h_#defineSysClock 3686400structsClock{ unsignedcharflag; unsignedlongsecond; //2^32secondsfor136years unsignedintms;}voidClockOpen(void);structsClock*ClockGet(void);//voidClockSet(structsClock*ptr);voidClockCall(void);externstructsClockgClock;#endifLedDriver.c如下:*******************************************************#include<reg52.h>#include"LedDriver.h"codeunsignedcharLedHexCode[]= { //01234567 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //89abcdef 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71, //-HLPo 0x40,0x76,0x38,0x73, 0x5c, };unsignedcharDisBuf[4];voidLedPrint(unsignedchardat){ DisBuf[0]=DisBuf[1]; DisBuf[1]=DisBuf[2]; DisBuf[2]=DisBuf[3]; DisBuf[3]=dat;}voidLedTimeCall(void){ staticunsignedcharindex=0; P2|=0x0f; P0=LedHexCode[DisBuf[index]&0x1f]|(DisBuf[index]&0x80); P2&=(1<<index)^0xff; if(++index==4)index=0;}KeyDriver.c如下:**************************************************#include<reg52.h>#include"KeyDriver.h"unsignedcharKeyBufWp=0;unsignedcharKeyBufRp=0;unsignedcharKeyBuf[KeyBufSize];charkbhit(void){ return(KeyBufWp-KeyBufRp);}chargetch(void){ charret; ret=KeyBuf[KeyBufRp]; if(++KeyBufRp>=KeyBufSize)KeyBufRp=0; return(ret);}voidKeyBufIn(chardat){ KeyBuf[KeyBufWp]=dat; if(++KeyBufWp>=KeyBufSize)KeyBufWp=0;}voidKeyTimeCall(void){ codecharKeyCode[]={ /*01234 5 6 7 8 9 A B C D E F*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, //0 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//1 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//2 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//3 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//4 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//5 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//6 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0F,0xff,0xff,0xff,0x0B,0xff,0x07,0x03,0xff,//7 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//8 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//9 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//A 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0E,0xff,0xff,0xff,0x0A,0xff,0x06,0x02,0xff,//B 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//C 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0D,0xff,0xff,0xff,0x09,0xff,0x05,0x01,0xff,//D 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0C,0xff,0xff,0xff,0x08,0xff,0x04,0x00,0xff,//E 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff//F }; unsignedcharKeyScan; staticunsignedcharKeyScanCode=0; staticunsignedcharsts=0; staticunsignedcharms=20; if(--ms)return;ms=20; P1=0x0f;KeyScan=P1;P1=0xf0;KeyScan|=P1;P1=0xff; switch(sts) { case0: if(KeyScan!=0xff) //可能有按鍵 {sts=1;KeyScanCode=KeyScan;} break; case1: if(KeyScanCode==KeyScan) //去抖后確為鍵按下 { sts=2; KeyBufIn(KeyCode[KeyScan]); //返回鍵值 } else //否則認(rèn)為是干擾,重新檢測 sts=0; break; case2: if(KeyScanCode!=KeyScan) //檢測松開按鍵 { if(KeyScan==0xff)sts=3; } break; //按鍵超過1秒認(rèn)為是連續(xù)按鍵 //其后每0.2秒一次鍵,直到松開為止 //要處理組合按鍵(即0.1秒后確認(rèn)讀鍵,保證所有組合鍵到位 //還可能保持不松開全部按鍵的情況下,轉(zhuǎn)換按其它鍵組合 // case3: if(KeyScan==0xff)sts=0; //去抖后確為松開按鍵 elsests=2; //是干擾 break; }}clock.c如下:*************************************************#include<reg52.h>#include"clock.h"#include"LedDriver.h"#include"KeyDriver.h"structsClockgClock;voidClockCall_ms(void){ LedTimeCall(); KeyTimeCall();}voidClockCall_second(void){}voidClockOpen(void) //初始化Timer2產(chǎn)生1ms定時(shí)中斷{ gClock.ms=0; gClock.second=0; CP_RL2=0; //重載模式 C_T2=0; //定時(shí)器方式 RCAP2H=(-(SysClock/1000))>>8; //

溫馨提示

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

評論

0/150

提交評論