新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STC89C52通過串口控制流水燈亮滅

        STC89C52通過串口控制流水燈亮滅

        作者: 時間:2016-11-20 來源:網絡 收藏
        本次筆記包含兩個方面:

        1.只是控制LED的亮滅,不返回數值

        本文引用地址:http://www.104case.com/article/201611/318684.htm

        2.控制LED的亮滅,并返回數值

        看了幾講的視頻,都是在講串口的方式1。其他的還沒接觸,這里也只用串口的方式1實現這兩個功能。串口里面需要計算的地方是根據所要使用的波特率求定時器的初始值。定時器使用的是方式2,可以自動裝初始值,避免賦值語句裝初始值時出現誤差。

        以9800bps,定時器使用方式2,串口使用方式1,晶振波特率為 11.0592MHZ,求TH1跟TL1的值。

        方式1的波特率 = (2^SMOD/32)xT1溢出率。單片機復位后,電源管理寄存器PCON全部清零,SMOD作為其中一位自然也清零。

        波特率已經知道了。這樣就剩下T1溢出率了。

        假設初值為X,則定時器每次計256-X個數溢出一次(定時器為8位,最大為255 。256時發生溢出)。每計一個數的時間為一個機器周期,機器周期 = T時鐘周期 X 12 。于是溢出的時間為 = 個數X 每個時間 = ( 256 - X) * 12/Fosc . 那么基礎率就是溢出時間的倒數。

        于是結合公式“方式1的波特率 = (2^SMOD/32)xT1溢出率”,式子可以總結為:

        9600 = 2^0 /32 * Fosc / (256 - X)*12 帶入全部已知數據得到 9600 = 2^0 /32 * 11059200/ (256 - X)*12 =====》》》》 求得的X為: 253 .

        在此基礎上,如果把SMOD 設為1 ,則 求得波特率為 :

        波特率 = (2^1/32) * 11059200 / (256 - 253 ) = 2 * [ 1/32 * 11059200 / (256 - 253)] = 2 * 9600 = 19200 。即變為原來的兩倍。

        如果把晶振換成12MHZ再求初值,求得的X為: 252.744792…… 無窮小數。這樣就會產生誤差。以前一直感覺整數的晶振挺好,現在才知道為什么會有11.0592MHZ這種晶振的存在了,。

        這樣計算得到了初值,下面貼代碼。

        只是控制LED的亮滅,不返回數值

        實現這個又分為查詢和中斷兩種方法。

        A。先用查詢。感覺叫判斷更好些,因為是用if判斷來實現的

        #include void main(){  //設置參數TMOD = 0x20; //設定定時器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd;	 //裝載TH1、TL1TR1 = 1; //啟動定時器1REN = 1; //允許串行接收位SM0 = 0;SM1 = 1; //設定串口工作方式為方式1/**    	       EA = 1; //全局中斷允許位*		ES = 1; //串口中斷允許位*		此處使用的是查詢法判斷接收中斷標志位,所以即便不開啟中斷允許位,也可以**/while(1){	 	//查詢法檢測RIif(RI == 1)//RI為接收中斷標志位。硬件置為1,必須軟件清0{P1 = SBUF;RI = 0;} 		}}
        B 中斷法

        #include  void main(){  //設置參數TMOD = 0x20; //設定定時器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd;	 //裝載TH1、TL1TR1 = 1; //啟動定時器1REN = 1; //允許串行接收位SM0 = 0;SM1 = 1; //設定串口工作方式為方式1EA = 1; //全局中斷允許位ES = 1; //串口中斷允許位while(1) ;	//等待中斷的發生}//中斷檢測RIvoid ser() interrupt 4{P1 = SBUF;RI = 0;}

        這兩個除了代碼,感覺就是是否開啟中斷允許了。因為RI置為1是硬件自動執行的。即便是不開啟中斷允許位,照樣可以用if進行判斷。

        上面這兩個是單方向的,再來個雙向的。

        /**通過串口給下位機發送數據,并使之顯示在P1口的流水燈上。*同時單片機返回接收到的數據,顯示在串口助手上*/#include unsigned char flag;void main(){  //設置參數TMOD = 0x20; //設定定時器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd;	 //裝載TH1、TL1TR1 = 1; //啟動定時器1SM0 = 0;SM1 = 1; //設定串口工作方式為方式1REN = 1; //允許串行接收位EA = 1; //全局中斷允許位ES = 1; //串口中斷允許位while(1){	/* 剛開始單片機緩沖寄存器為空,無數據可以顯示* 先從串口接收數據,再返回該數據* 在中斷中接收數據,同時將flag標志位置為1.說明接收到了數據* 若接收到數據(flag == 1),說明接收到了;否則說明未接收到數據,不顯示。繼續判斷flag數值*/if(flag == 1) {						//發送數據ES = 0; //關閉串口中斷,發送數據SBUF = P1; //數據寫入SBUF寄存器while(!TI); //等待TI = 0;ES = 1; flag = 0;}		}}void ser() interrupt 4{//接收數據P1 = SBUF;flag = 1;RI = 0;}

        主函數里面那個flag = 0 。 一定不能少了。否則只要一小會兒的功能,串口助手就卡了。。。。

        這個例子里還有兩條語句比較關鍵:

        P1 = SBUF;//把SBUF寄存器中的數值賦給P1

        SBUF = P1;//把P1的數值寫入到SBUF

        SBUF是這么寫的:SBUF 串行數據緩沖寄存器,一個發送緩沖寄存器,一個接收緩沖寄存器。兩個公用一個地址99H,但在物理上是兩個獨立的寄存器。那么如何區分是發送還是接收呢?就用語句來區分了。

        控制流水燈的話,需要發送十六進制格式的。

        比如發送FB(1111,1011)。在我的開發板上是L2燈亮。如果發送字符,就不太好控制了。如果用2中的例程,以字符方式發送“fb”,單片機返回串口助手并用十六進制顯示為“62” .這個,嗯,目前不會算 :P

        沒啥值得紀念的圖片,還是幾個流水燈。不過此時的流水燈,非彼時的流水燈。現在的流水燈,可是我從電腦上就能控制開發板上的了:D

        只是不知道下次自己寫個上位機是什么時候了,



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 清原| 荥经县| 龙州县| 东丰县| 绥中县| 尤溪县| 邛崃市| 罗山县| 班玛县| 贞丰县| 抚松县| 垫江县| 拜城县| 偏关县| 内黄县| 潼南县| 保山市| 库尔勒市| 巴彦淖尔市| 黄龙县| 台南市| 宣武区| 达尔| 镇康县| 绥宁县| 青岛市| 额尔古纳市| 峨山| 安阳市| 秦皇岛市| 陕西省| 郯城县| 宝鸡市| 尚义县| 江安县| 重庆市| 洛川县| 遂川县| 浏阳市| 内黄县| 定南县|