51微控制器模擬串列埠的三種方法

2022-12-17 09:12:02 字數 3677 閱讀 1537

-- 51微控制器模擬串列埠的三種方法zt

隨著微控制器的使用日益頻繁,用其作前置機進行採集和通訊也常見於各種應用,一般是利用前置機採集各種終端資料後進行處理、儲存,再主動或被動上報給管理站。這種情況下下,採集會需要乙個串列埠,上報又需要另乙個串列埠,這就要求微控制器具有雙串列埠的功能,但我們知道一般的51系列只提供乙個串列埠,那麼另乙個串列埠只能靠程式模擬。

本文所說的模擬串列埠,就是利用51的兩個輸入輸出引腳如p1.0和p1.1,置1或0分別代表高低電平,也就是串列埠通訊中所說的位,如起始位用低電平,則將其置0,停止位為高電平,則將其置

1,各種資料位和校驗位則根據情況置1或置0。至於串列埠通訊的波特率,說到底只是每位電平持續的時間,波特率越高,持續的時間越短。如波特率為9600bps,即每一位傳送時間為

1000ms/9600=0.104ms,即位與位之間的延時為為0.104毫秒。

微控制器的延時是通過執行若干條指令來達到目的的,因為每條指令為1-3個指令週期,可即是通過若干個指令週期來進行延時的,微控制器常用11.0592m的的晶振,現在我要告訴你這個奇怪數字的來歷。用此頻率則每個指令週期的時間為(12/11.

0592)us,那麼波特率為9600bps每位要間融多少個指令週期呢?指令週期s=(1000000/9600)/(12/11.0592)=96,剛好為一整數,如果為4800bps則為

96x2=192,如為19200bps則為48,別的波特率就不算了,都剛好為整數個指令週期,妙吧。至於別的晶振頻率大家自已去算吧。

現在就以11.0592m的晶振為例,談談三種模擬串列埠的方法。

方法一:延時法

通過上述計算大家知道,串列埠的每位需延時0.104秒,中間可執行96個指令週期。#define uchar unsigned charsbit p1_0 = 0x90;sbit p1_1 = 0x91;sbit p1_2 = 0x92;#define rxd p1_0#define txd p1_1

#define wrdyn 44 //寫延時#define rddyn 43 //讀延時

//往串列埠寫乙個位元組

void wbyte(uchar input)

//傳送校驗位(無)

txd=(bit)1傳送結束位

delay2cp(46);}

//從串列埠讀乙個位元組uchar rbyte(void)

while(--temp在指定的時間內搜尋結束位。

return output;}

//延時程式*

void delay2cp(unsigned char i)

此種方法在接收上存在一定的難度,主要是取樣定位存在需較準確,另外還必須知道

每條語句的指令週期數。此法可能模擬若干個串列埠,實際中採用它的人也很多,但如果你用keilc,本人不建議使用此種方法,上述程式在p89c52、at89c52、w78e52三種微控制器上實驗通過。

方法二:計數法

51的計數器在每指令週期加1,直到溢位,同時硬體置溢位標誌位。這樣我們就可以

通過預置初值的方法讓機器每96個指令週期產生一次溢位,程式不斷的查詢溢位標誌來決定是否傳送或接收下一位。

//計數器初始化void s2ini(void)

void wbyte(uchar input)

//傳送校驗位(無)//傳送結束位txd=(bit)1;waittf0();tr0=0;}

//查詢計數器溢位標誌位void waittf0( void )

接收的程式,可以參考下一種方法,不再寫出。這種辦法個人感覺不錯,接收和傳送都很準確,另外不需要計算每條語句的指令週期數。

方法三:中斷法

中斷的方法和計數器的方法差不多,只是當計算器溢位時便產生一次中斷,使用者可以

在中斷程式中置標誌,程式不斷的查詢該標誌來決定是否傳送或接收下一位,當然程式中需對中斷進行初始化,同時編寫中斷程式。本程式使用timer0中斷。#define tm0_flag p1_2 //設傳輸標誌位//計數器及中斷初始化void s2ini(void)

//接收乙個字元uchar rbyte()

while(!tm0_flag) if(rxd) break;

tr0=0停止timer0

return output;}

//中斷1處理程式

void inttimer0() interrupt 1

//查詢傳輸標誌位void waittf0( void )

中斷法也是我推薦的方法,和計數法大同小異。傳送程式參考計數法,相信是件很容易的事。

另外還需註明的是本文所說的串列埠就是通常的三線制非同步通訊串列埠(uart),只用rxd、txd、gnd

**r軟體模擬串列埠程式

**:coldra資料室作者:coldra

m48,8mhz9600,1,8,1

輸出:用定時器控制普通io口輸出位輸入:用外部中斷+定時器,判斷位的寬度

好幾天沒休息,利用閒暇寫的,也沒找到別人的參考程式,不過終於算是穩定了,其實還應該有很多以試一下,比如用pwm輸出序列資料,用輸入捕獲接收資料,或定時查詢,或用任意乙個io口中斷,則可能

現在還有些問題,全雙工同時收發時傳送偶爾出錯,占用兩個定時器有些浪費,以後再修改吧,最好

本程式為直接摘出部分,刪了無關的部分,在此可能有些變數沒用,或有段落遺漏,請諒

#include#include#include#include

#define sbit1() portd =1<#define sbit0() portd&=~(1<

volatile unsigned inteep_ms,//毫秒計時

keytime等待時間

soundontimevolatile unsigned charrdata,key,

start=0,

keycodetxpoint,rtime,

int0_time中斷次數

rxlength=0接收長度

rudr摸擬串列埠接收的資料

txlength串列埠傳送資料長度sudr串列埠傳送的資料

unsigned char arr[10],dispbuff[10];

void initial_io(void)//io口初始化

void initial_int0(void)

void initial_timer0(void定時器0初始化

void initial_timer1(void)

void initial_wdr(void看門狗初始化

void initial(void)

/*啟動串列埠傳送*/

void senddata(unsigned char *p,unsigned char datalength)

int main (void)}}

/*定時器0,100us溢位中斷*/signal(sig_overflow0)else

else sbit1();//停止位}

if(start<10)start++;else//}}

/*定時器1,1ms溢位中斷*/signal(sig_overflow1)

/*定時器2*/

signal(sig_overflow2)

if(rtime<4)rtime++;//位元組間隔時間,間隔3個位元組重新開始一幀else rxlength=0;}

signal(sig_interrupt0)//int0,邊沿觸發中斷else

if(temp2>6)temp++;//計算位的個數,一般13為乙個位if(int0_time==1)temp-=1;if(int0_time&1)//奇數次中斷}rtime=0;}

MCS 51系列微控制器模擬SPI匯流排的方法

1.mcu序列輸入子程式spiin 從x25f008的spiso線上接收8位資料並放入暫存器r0中的應用子程式如下 spiin setb p1.1使p1.1 時鐘 輸出為1 clr p1.2選擇從機 mov r1,08h置迴圈次數 spiin1 clr p1.1使p1.1 時鐘 輸出為0 nop延時...

辨析近義詞的三種方法

掌握大量的近義詞知識,才能把話說得更加準確嚴密,把意思表達得更加清楚 明白。常見的近義詞辨析可以從下面三方面作手。no.1詞義辨析 語意的輕重不同。有的近義詞內涵雖然相同,但在表現其某種特徵或程度上,則有輕重的差別。例如 努力竭力努力 竭力 又如 輕視和鄙視 喜歡和酷愛 著急和焦急 等都有語意輕重的...

css去除浮動的三種方法

應用divcss網頁布局,經常性地會使用到float,很多邪門的事兒都有可能是浮動在作怪,清除浮動是必須要做的,而且隨時性地對父級元素清除浮動的做法也被認為是書寫css的良好習慣之一。下面看今天的教程,此為未清除浮動源 執行 無法檢視到父級元素淺黃色背景。left right 一 使用空標籤清除浮動...