教你如何在51微控制器上模擬串列埠通訊!!!
我們可以不使用微控制器本身帶有的串列埠,而自己用程式去模擬一個串列埠並達到和本身的串列埠具有同樣的功能,
首先,我們需要用到CH340串列埠模組,大家可以上某寶自行購買。
正面:
反面:
然後我們需要了解一下這串列埠模組上的引腳:
5V :與VCC短路為5V TLL輸出(電源和訊號輸出都是5V)
VCC:可以與3.3V和5V用跳帽連線
3.3V:與VCC短路為3.3V TLL輸出(電源和訊號輸出都是3.3V)
TXD:傳送資料埠(與微控制器上的接收引腳用杜邦線連線)
RXD:接收資料埠(與微控制器上的傳送引腳用杜邦線連線)
GND:地線
因為我是有另外一條串列埠提供了51微控制器的電源,所以就沒連線5V和VCC,只與微控制器連發送、接收和地埠。
現在,讓我們一起了解一下串列埠通訊協議是怎樣的
我們可以將該協議分成三部分
一、 起始訊號
二、 資料位
三、 結束訊號
首先,串列埠主要有傳送和接受兩個主要功能,
傳送
比如說我們需要傳送一個0X48的十六進位制數,它的二進位制為 01001011
則過程為
一、起始訊號
預設電平為高(1),先將傳送端的引腳電平拉低(0)持續104us,來作為一個起始訊號
二、八個資料位
資料的傳送,是從最低位開始到最高位一位一位傳送的,每一個數據位都需要持續104us,
三、結束訊號
需要將傳送端的引腳電平拉高(1)持續104us以上。
接收
其實接收也很好理解的,怎樣傳送就怎樣接收,只是看接收的技巧而已
比如說剛剛傳送的0X48從主機發送到了微控制器上,我們需要接收
則過程為
一、起始訊號
我們需要讀取到它的起始訊號,就是當它把你的接收端引腳持續拉低104us之後,就可以當作是開始接收了。
二、八個資料位
因為是八個資料位了,所以所接收的資料也會按照發送一樣一個一個傳送,我們只要去讀取這時候的引腳電平就好。
三、結束訊號
最後也是一樣,再需要確認一次結束訊號,讀取電平是否為高電平,如果全部確認成功後,就可以認為是接收一個有效的資料了。
下面為個人圖解
理論已經說完,接下來就是怎樣用程式碼實現了
那我們一步一步開始吧
第一、建立工程
第二、建立延時函式
程式碼:
1 void Delay_us(int x) //微秒 2 { 3 while( x-- != 0 ) 4 { 5 _nop_(); 6 _nop_(); 7 } 8 } 9 void Delay_ms(int x) //毫秒 10 { 11 int i,j; 12 while( x-- !=0 ) 13 { 14 for(j=0;j<10;j++) 15 for(i=0;i<85;i++); 16 } 17 }
這裡的Delay.c裡面有兩個延時函式,一個為微秒級,一個為毫秒級。
我們還需要再建立一個Delay.h標頭檔案來向外宣告這兩個函式。
標頭檔案的話,我們還需要把它的路徑新增到工程裡,步驟如圖
我不把這兩個函式寫進main.c的原因是如果以後寫的程式碼過長了,全部都堆在主函式裡的話不方便管理,而這樣分開的話可以降低他們的耦合關係,下面也同理了。
第三、串列埠函式
這裡的函式建立和上面的步驟是一樣的了
傳送函式:
程式碼:
void vFn_Uart_Send(unsigned char uContent) { unsigned int i; unsigned char uSendContent =0xff; //定義一個傳送資料的變數 uSendContent = uContent; //將要傳送的值賦給該變數 //起始訊號 P05 = 0; //P05作為傳送端的引腳 Delay_us(61); //延遲104us //資料傳送 for(i=0;i<8;i++) { P05 = uSendContent & 0x01; //將所要傳送的八位資料的最低位和0x01進行於運算,若最低位為1,相於後的結果為1,則P05電平為高,否則為0 uSendContent = uSendContent >> 1; //將第二位資料位移到最低位,重複進行七次移動 Delay_us(61); } //結束訊號 P05 = 1; //將該引腳電平拉高 Delay_us(61); //延時104us }
這裡的104us延遲函式,我已經用示波器測試過時間的了,是可以直接使用的。
因為燒寫時候不同的頻率也會造成延時函式改變,所以大家有條件的話,也可以自己具體去測量一下的
接收函式:
程式碼:
void vFn_Uart_Receive() { unsigned int i; unsigned char uContent = 0x00; //定義一個用於接收資料變數 //起始訊號 if(P21 == 0) //判斷是否接收到起始訊號 { Delay_us(29); //延時52微秒 if(P21 == 0) //再判斷一次接收端電平是否被拉低 { //資料接收 for(i=0;i<8;i++) { uContent = uContent >> 1; //將值右移一位 Delay_us(61); //延時104微秒 if(P21 == 1) //判斷是否為高電平 { uContent |= 0x80; //若為1則與0x80進行或運算(加上0x80也是一樣的道理) } } } Delay_us(61); //延時104微秒 //結束訊號 if(P21 == 1) //判斷電平是否被拉高 { vFn_Uart_Send(uContent); //將uContent的值用傳送函式傳送出來 Delay_ms(1000); } } }
這裡講解一下接收函式,我們知道起始訊號拉低後,有104us的延時,延時完後就是八個資料位了,如果我們每一次都等完104us再去讀取引腳的電平的話可能會不太穩定,所以我們可以在每個電平中間去讀取,這個時候是最穩定的。下面為圖解
第四、主函式編寫
因為都把函式放到了其他檔案中,這樣主函式會看的比較簡潔,我們也直接呼叫相關的函式就行了,主函式使用也沒有太多的要求。
這裡的話是需要每寫完一個函式就去測試的,不過我是已經是全部測試通過的了,然後大家就還是寫完一個測試一個,因為一次性寫完所有函式然後馬上通過的機率不大,還是要修改很多東西
然後我用的是下載軟體是這個,燒寫的時候我們需要將IRC的頻率改成12MHz進行燒寫
串列埠助手的話,我用的是SSCOM,另外因為我這個微控制器的主晶片是IAP15W4K48S4,裡面的GPIO的波特率也設定為了9600,所以我們也需要將其設定為9600的波特率才能看到資料,不然就是一堆亂碼了,再然後就是點選HEX顯示和HEX傳送了。
我們來看是已經發送出來了。
再就是測試接收了
這裡是把接收直接放到while(1)裡面跑,大家也可以使用定時器的,用中斷去跑的話就更好了,這裡只是一個小小的示範。
傳送了0x52,也接收了0x52,成功了。
這樣一來,我們也就完成模擬串列埠的收發了。
最後再教一下如何用模擬串列埠傳送文字吧,非常簡單的一個小函式,
然後再在主函式呼叫就可以實現了。
我的關於51微控制器模擬串列埠到這就結束了,謝謝大家。