郟正學,李煒
(浙江省空間結構重點實驗室,杭州 310058)
?
單片機模擬串口數據接收程序的實現及優化
郟正學,李煒
(浙江省空間結構重點實驗室,杭州 310058)
進行單片機應用系統設計開發時,往往碰到單片機自身攜帶的串口不夠用,這時就需要通過I/O口模擬串口通信。本文簡單介紹了串口通信的基礎知識,分析了模擬串口接收數據的過程,介紹了模擬串口接收數據的實現方法,以ATmega64A單片機為例,詳細介紹了模擬串口數據接收程序的實現及優化方法。
ATmega64A單片機;串口通信;接收程序

圖1 串口通信數據幀格式
隨著信息技術的發展,單片機的應用越來越廣泛,尤其是在儀器儀表、物聯網、自動化、智能化等領域,應用非常多。近年來,各類傳感器不斷出現,為了提高系統自動化、智能化程度,往往需要單片機與多個傳感器等外圍器件進行連接通信。這類外圍器件中,串口通信用得比較多。因此,在嵌入式應用系統設計開發時,會經常需要多個串口,而一般的單片機自身只有一個或兩個串口,串口不夠用,這時就需要利用單片機的I/O口模擬串口通信,以滿足應用要求。
在工業上,串口通信用得比較多的是RS232、RS485通信,本文所講的串口通信是指RS232。RS232串口通信數據幀由起始位、數據位、校驗位、停止位組成,數據幀格式如圖1所示。St為起始位,1位,低電平;(n)為數據位,數據位可以是5~9位,具體多少位由串口通信協議設定;P為校驗位,1位,可以是奇校驗或偶校驗,也可以是無校驗位,是否有校驗位,由串口通信協議設定;Sp為停止位,1位或2位,停止位為高電平,停止位是1位還是2位,由串口通信協議設定。
當串口通信協議設定為8個數據位、無校驗位、1個停止位時,1個數據幀即由1位的起始位、8位的數據位、1位的停止位組成,幀長度為10位。在串口通信協議中,除了前面的參數設定外,還有1個比較重要的參數——波特率,波特率為串口通信傳輸數據的速度,單位為bps,即每秒傳輸的比特數。在串口通信中,可以設定的波特率有2 400、4 800、9 600、14 400、19 200、38 400等等。由于不同參數的串口通信,在編寫模擬串口程序時會稍有不同,因此本文以9 600波特率、8位數據位、無校驗位、1個停止位為例進行介紹。另外本文所講的是三線制串口通信,即RxD(接收)、TxD(發送)、GND三線。
串口通信發送或接收數據時,都是按照數據幀格式一位一位發送或接收的。發送數據時,數據低位先發送,高位后發送;接收數據時,數據低位先接收,高位后接收。
使用單片機自身的串口功能接收數據時,可以采用查詢方式或中斷方式接收數據。使用查詢方式接收數據時,單片機要不停地查詢控制和狀態寄存器的相應標志位,以判斷是否需要接收數據。一旦有數據需要接收,單片機即運行接收程序接收數據。當沒有數據需要接收時,單片機需要處于不定時查詢狀態,否則就不能及時獲知接收數據信息,造成數據丟失。即使查詢方式因單片機一直忙于查詢而不能處理其他事務,降低了單片機的利用率。使用中斷方式接收數據時,當串口沒有接收到數據時,單片機可以處理其他事情;當串口接收到數據時單片機立即產生中斷,通過中斷程序接收數據,這樣單片機接收數據比較實時,利用率也高。因此在實際應用中,比較多的是利用中斷方式接收數據。
用I/O口模擬串口接收數據時,為了實現中斷接收數據,需要選擇具有外部中斷功能的I/O口作為RxD引腳。之所以使用具有外部中斷功能的I/O口,是因為串口通信數據幀的起始位為低電平,利用低電平產生外部中斷功能,以實現中斷接收數據的目的。
未發生數據通信時,RxD引腳處于高電平狀態。當外部有數據發送過來時,RxD引腳會接收到數據幀格式的二進制數據序列。當接收到1個字節的數據時,RxD引腳接收到1個數據幀;當接收到多個字節的數據時,RxD引腳接收到多個數據幀。接收到數據幀時,RxD引腳首先接收到起始位,由于起始位是低電平,只要事先將外部中斷定義成低電平中斷,此刻即產生外部中斷,單片機轉入外部中斷處理程序,由外部中斷程序對發送來的二進制數據序列按照數據幀的格式進行一位一位地接收,先接收到是數據的低位,后接收到的是數據的高位。接收到1個數據幀的停止位后,如果緊接著接收到低電平信號,則認為有新的數據幀需要接收,此低電平信號是新數據幀的起始位;如果緊接著接收到高電平信號,則判斷為沒有新的數據幀需要接收,接收數據結束。
根據上面的描述,編寫模擬串口通信數據接收程序就是對外部中斷程序的編寫。因為波特率是9 600 bps,所以每位數據占用的時間為104 μs。在實現每位數據接收時,接收到一位數據后,需要延時104 μs后再接收另一位數據。在單片機編程時,可以用語句循環實現延時,也可以用定時器實現延時。定時器定時比較精確,因此本文采用定時器延時。
3.1定時器定時子程序
這里以ATmega64A單片機為例,單片機外接晶振為8 MHz。ATmega64A單片機有多個定時器,這里選用定時器TIMER0進行定時,以實現延時之目的。TIMER0為8位定時器/計數器,定時方法是給TCNT0寄存器賦初值,由初值開始計數,TIMER0每計數一個時鐘脈沖,TCNT0加1。當TCNT0的值由0xFF變為0x00時,TIMER0的溢出標志位置1,通過該標志位的值判斷定時是否已到。TIMER0的時鐘源可以由單片機的晶振分頻后提供,這里選擇8分頻,即TIMER0的時鐘頻率為1 MHz,每個時鐘脈沖的時間為1 μs,要實現104 μs定時,給TCNT0賦初值0x98即可。為了使定時器定時子程序可以實現不同的定時時間,將該子程序設計成帶參數,通過參數值改變定時時間,定時子程序如下:
void Timer0_Open(unsigned char value){
//通過參數value設定定時時間
TCCR0=0x00;//取消時鐘源,TIMER0停止工作
TIFR=0x01;//TIMER0溢出標志清零
TCNT0=value;
//定時器初值,定時時間為(0xFF-value+1)μs
TCCR0=0x02;
//設置時鐘8分頻,TIMER0獲得時鐘源后即開始工作
}
3.2接收程序流程圖
為了實現中斷接收數據,接收數據前RxD引腳開啟外部中斷功能,一旦有數據起始位到即產生中斷,此時立即將該引腳的外部中斷功能關閉,同時將該引腳設置為輸入,以開始接收數據流,接收程序按照數據幀的格式一位一位地接收數據,數據接收結束后再將此引腳的外部中斷功能開啟,以等待下一次接收數據。接收多個字節數據的接收程序流程圖如圖2所示。

圖2 接收程序流程圖
按照圖2接收程序流程圖用C語言編寫程序后,經測試,發現可以連續接收到3個字節的數據,前2個字節正確,但第3個字節數據是錯誤的。通過對測試結果和程序進行分析,發現產生錯誤的原因是程序在接收相鄰位數據的間隔時間超過了104 μs,每接收1位會產生△t誤差,連續接收N 位后,產生的累積誤差為N△t,當N△t達到104 μs時就會出錯。每接收1位數據產生時間誤差的主要原因有:①定時器本身有誤差;②每次調用延時子程序、子程序返回、執行子程序語句需要時間,設計延時子程序時未將這些時間予以減除;③接收數據之后,調用延時子程序之前執行程序語句產生的時間。
為了降低△t,需要計算調用子程序及返回、執行有關語句所需的時間,以便對延時子程序的延時時間作相應調整。由于程序是用C語言編寫的,計算這些時間比匯編語言復雜一些。在精確度要求不是很高的情況下,可以用簡便的方法進行估算,估算方法:接收第3個字節出錯,說明有可能在接收20位數據后產生的累積時間誤差達到104 μs,也有可能是在接收第30個字節時產生的累積誤差達到104 μs;假如接收20位數據后產生的累積誤差達到104 μs,則說明接收每位產生時間誤差為5.2 μs;假如接收30位數據后產生的累積誤差達到104 μs,則說明接收每位產生的時間誤差為3.47 μs;分別選取3、4、5、6 μs對延時子程序的延時時間作相應調整,進行調試測試,選取最佳的方案即可。
根據上述思路和方法對延時進行調整,通過調試測試,選取結果較好的方案對延時時間進行調整,以優化程序,優化后的接收程序語句如下:
EIMSK&=0xFE; //關閉外部中斷使能
DDRD&=0xFE; //PD0引腳設為輸入
while(ReceiveContinue){
//程序開始時已賦值為1,ReceiveContinue等于1,繼續接收
Timer0_Ooen(0x99) ;
//起始位延時103 μs
for( unsigned char i=0;i<8;i++){
//接收一個字節的 8個位
while( ! ( TIFR& 0x01) );
//前一位延時結束
ReceiveRegister>>= 1;
if(PIND&0x01)
//讀取PD0即RxD引腳的值
ReceiveRegiste|= 0x80;
//如果PD0為高電平,說明接收到二進制1,否則為0
Timer0_Ooen(0x9C);
//延時100 μs
}
while( ! ( TIFR& 0x01) );
ReceiveBuffer[ReceiveCount]=ReceiveRegister;
//將接收到數據存放在接收緩存器
ReceiveCount++;
//接收到1個字節后該值加1
ReceiveRegister=0;
//賦值為0,以便接收下一個字節數據
StartTimer0(0x9B) ;
//延時101 μs
while( ! ( TIFR& 0x01) );
if(PIND&0x01)
//PD0為1,無起始位,接收結束
ReceiveContinue=0;
}
EIMSK |= 0x01;
//開外部中斷 0
需要說明的是,上述程序的前提是ATmega64A單片機采用INT0引腳作為模擬串口通信的接收端口。
分別對優化前和優化后的程序進行了測試,優化前的程序只能連續接收3個字節的數據,接收到的前2個字節數據是正確的,第3個字節數據是錯誤的。
優化后的程序可以連續接收48個字節的數據,接收到的數據是正確的,超過48個字節就容易出錯。要使程序能連續接收更多字節的數據,還需要進一步優化。
本文主要介紹了用單片機I/O口模擬串口通信接收數據的過程方法、數據接收程序的實現及優化方法。通過優化,數據接收程序連續接收數據的能力得到了大大的增強,可以實現連續接收48個字節的數據,能滿足較多場合的應用要求。
在優化過程中,提出了簡便地估算程序運行產生時間誤差的方法,通過估算得到的誤差值,對程序的延時時間進行調整調試,實現程序的優化,這是本文的新穎之處。本文的不足之處:一是僅通過調整延時時間進行程序優化,未進行其他優化;二是優化后的數據接收程序,連續接收數據能力有限,有待進一步優化提高。
[1] Atmel .Atmel-8160E-ATmega64A_Datasheet_Complete-09/2015[EB/OL].[2016-05].http://www.atmel.com/.
郟正學(工程師),主要從事嵌入式應用系統設計開發。
Realization and Optimization of Serial Port Data Receiving Program Based on MCU
Jia Zhengxue,Li Wei
(Zhejiang Provincial Key Laboratory of Space Structures,Hangzhou 310058,China)
In the design,we often encounter the case that the quantity of the serial ports of MCU is not enough.In order to meet the application requirements,the serial communication can be simulated by using the I/O ports.In the paper,the basic knowledge of the serial communication is introduced.The process of simulating the serial ports receiving data is analyzed.The realization method of simulating the serial port receiving data is introduced.Taking ATmega64A MCU as the example,the realization and optimization of the receiving data program are introduced in detail.
ATmega64A MCU;serial port communication;receiving program
TP311
A
(責任編輯:楊迪娜2016-05-03)