STC89C52通過串口控制流水燈亮滅
1.只是控制LED的亮滅,不返回?cái)?shù)值
本文引用地址:http://m.butianyuan.cn/article/201611/318684.htm2.控制LED的亮滅,并返回?cái)?shù)值
看了幾講的視頻,都是在講串口的方式1。其他的還沒接觸,這里也只用串口的方式1實(shí)現(xiàn)這兩個(gè)功能。串口里面需要計(jì)算的地方是根據(jù)所要使用的波特率求定時(shí)器的初始值。定時(shí)器使用的是方式2,可以自動(dòng)裝初始值,避免賦值語(yǔ)句裝初始值時(shí)出現(xiàn)誤差。
以9800bps,定時(shí)器使用方式2,串口使用方式1,晶振波特率為 11.0592MHZ,求TH1跟TL1的值。
方式1的波特率 = (2^SMOD/32)xT1溢出率。單片機(jī)復(fù)位后,電源管理寄存器PCON全部清零,SMOD作為其中一位自然也清零。
波特率已經(jīng)知道了。這樣就剩下T1溢出率了。
假設(shè)初值為X,則定時(shí)器每次計(jì)256-X個(gè)數(shù)溢出一次(定時(shí)器為8位,最大為255 。256時(shí)發(fā)生溢出)。每計(jì)一個(gè)數(shù)的時(shí)間為一個(gè)機(jī)器周期,機(jī)器周期 = T時(shí)鐘周期 X 12 。于是溢出的時(shí)間為 = 個(gè)數(shù)X 每個(gè)時(shí)間 = ( 256 - X) * 12/Fosc . 那么基礎(chǔ)率就是溢出時(shí)間的倒數(shù)。
于是結(jié)合公式“方式1的波特率 = (2^SMOD/32)xT1溢出率”,式子可以總結(jié)為:
9600 = 2^0 /32 * Fosc / (256 - X)*12 帶入全部已知數(shù)據(jù)得到 9600 = 2^0 /32 * 11059200/ (256 - X)*12 =====》》》》 求得的X為: 253 .
在此基礎(chǔ)上,如果把SMOD 設(shè)為1 ,則 求得波特率為 :
波特率 = (2^1/32) * 11059200 / (256 - 253 ) = 2 * [ 1/32 * 11059200 / (256 - 253)] = 2 * 9600 = 19200 。即變?yōu)樵瓉淼膬杀丁?/p>
如果把晶振換成12MHZ再求初值,求得的X為: 252.744792…… 無窮小數(shù)。這樣就會(huì)產(chǎn)生誤差。以前一直感覺整數(shù)的晶振挺好,現(xiàn)在才知道為什么會(huì)有11.0592MHZ這種晶振的存在了,。
這樣計(jì)算得到了初值,下面貼代碼。
只是控制LED的亮滅,不返回?cái)?shù)值
實(shí)現(xiàn)這個(gè)又分為查詢和中斷兩種方法。
A。先用查詢。感覺叫判斷更好些,因?yàn)槭怯胕f判斷來實(shí)現(xiàn)的
#includeB 中斷法void main(){ //設(shè)置參數(shù)TMOD = 0x20; //設(shè)定定時(shí)器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd; //裝載TH1、TL1TR1 = 1; //啟動(dòng)定時(shí)器1REN = 1; //允許串行接收位SM0 = 0;SM1 = 1; //設(shè)定串口工作方式為方式1/** EA = 1; //全局中斷允許位* ES = 1; //串口中斷允許位* 此處使用的是查詢法判斷接收中斷標(biāo)志位,所以即便不開啟中斷允許位,也可以**/while(1){ //查詢法檢測(cè)RIif(RI == 1)//RI為接收中斷標(biāo)志位。硬件置為1,必須軟件清0{P1 = SBUF;RI = 0;} }}
#includevoid main(){ //設(shè)置參數(shù)TMOD = 0x20; //設(shè)定定時(shí)器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd; //裝載TH1、TL1TR1 = 1; //啟動(dòng)定時(shí)器1REN = 1; //允許串行接收位SM0 = 0;SM1 = 1; //設(shè)定串口工作方式為方式1EA = 1; //全局中斷允許位ES = 1; //串口中斷允許位while(1) ; //等待中斷的發(fā)生}//中斷檢測(cè)RIvoid ser() interrupt 4{P1 = SBUF;RI = 0;}
這兩個(gè)除了代碼,感覺就是是否開啟中斷允許了。因?yàn)镽I置為1是硬件自動(dòng)執(zhí)行的。即便是不開啟中斷允許位,照樣可以用if進(jìn)行判斷。
上面這兩個(gè)是單方向的,再來個(gè)雙向的。
/**通過串口給下位機(jī)發(fā)送數(shù)據(jù),并使之顯示在P1口的流水燈上。*同時(shí)單片機(jī)返回接收到的數(shù)據(jù),顯示在串口助手上*/#includeunsigned char flag;void main(){ //設(shè)置參數(shù)TMOD = 0x20; //設(shè)定定時(shí)器1的工作方式為方式2TH1 = 0xfd;TL1 = 0xfd; //裝載TH1、TL1TR1 = 1; //啟動(dòng)定時(shí)器1SM0 = 0;SM1 = 1; //設(shè)定串口工作方式為方式1REN = 1; //允許串行接收位EA = 1; //全局中斷允許位ES = 1; //串口中斷允許位while(1){ /* 剛開始單片機(jī)緩沖寄存器為空,無數(shù)據(jù)可以顯示* 先從串口接收數(shù)據(jù),再返回該數(shù)據(jù)* 在中斷中接收數(shù)據(jù),同時(shí)將flag標(biāo)志位置為1.說明接收到了數(shù)據(jù)* 若接收到數(shù)據(jù)(flag == 1),說明接收到了;否則說明未接收到數(shù)據(jù),不顯示。繼續(xù)判斷flag數(shù)值*/if(flag == 1) { //發(fā)送數(shù)據(jù)ES = 0; //關(guān)閉串口中斷,發(fā)送數(shù)據(jù)SBUF = P1; //數(shù)據(jù)寫入SBUF寄存器while(!TI); //等待TI = 0;ES = 1; flag = 0;} }}void ser() interrupt 4{//接收數(shù)據(jù)P1 = SBUF;flag = 1;RI = 0;}
主函數(shù)里面那個(gè)flag = 0 。 一定不能少了。否則只要一小會(huì)兒的功能,串口助手就卡了。。。。
這個(gè)例子里還有兩條語(yǔ)句比較關(guān)鍵:
P1 = SBUF;//把SBUF寄存器中的數(shù)值賦給P1
SBUF = P1;//把P1的數(shù)值寫入到SBUF
SBUF是這么寫的:SBUF 串行數(shù)據(jù)緩沖寄存器,一個(gè)發(fā)送緩沖寄存器,一個(gè)接收緩沖寄存器。兩個(gè)公用一個(gè)地址99H,但在物理上是兩個(gè)獨(dú)立的寄存器。那么如何區(qū)分是發(fā)送還是接收呢?就用語(yǔ)句來區(qū)分了。
控制流水燈的話,需要發(fā)送十六進(jìn)制格式的。
比如發(fā)送FB(1111,1011)。在我的開發(fā)板上是L2燈亮。如果發(fā)送字符,就不太好控制了。如果用2中的例程,以字符方式發(fā)送“fb”,單片機(jī)返回串口助手并用十六進(jìn)制顯示為“62” .這個(gè),嗯,目前不會(huì)算 :P
沒啥值得紀(jì)念的圖片,還是幾個(gè)流水燈。不過此時(shí)的流水燈,非彼時(shí)的流水燈。現(xiàn)在的流水燈,可是我從電腦上就能控制開發(fā)板上的了:D
只是不知道下次自己寫個(gè)上位機(jī)是什么時(shí)候了,
評(píng)論