51單片機輕松入門—基于STC15W4K系列(C語言版)
李友全 編著:http://www.zg4o1577.cn/bbs/dpj-37954-1.html
第4章 串 口 通 信 1 串口通信電路 2 串口數(shù)據(jù)發(fā)送格式 3 串口相關(guān)寄存器 4 波特率計算公式與表格 5 單片機與計算機通信的簡單例子 6 數(shù)據(jù)通信中的錯誤校驗(校驗和) 7 單片機串口向計算機串口發(fā)送2進制、16進 制、數(shù)值與字符串
2 串口數(shù)據(jù)發(fā)送格式 串口數(shù)據(jù)發(fā)送格式如圖4-1所示,注意這里的格式是對于單片機串口TXD引腳而言的,信 號經(jīng)過SP3232或MAX232芯片后會被倒相,即+5V(邏輯1)變-9V(邏輯0,典型值是-9V, RS232標準范圍:-3V~-15V),0V(邏輯0)變+9V(邏輯1,典型值是+9V,RS232標準范圍:
+3V~+15V)。 圖4-1 串口數(shù)據(jù)發(fā)送格式 當單片機執(zhí)行一條寫SBUF的指令時,就啟動串行通信的發(fā)送,數(shù)據(jù)由串行發(fā)送端TXD輸 出,發(fā)送時,先發(fā)送一個起始位(低電平),用來表示數(shù)據(jù)傳輸開始,接著將1個字節(jié)的8個位 按低位在前高位在后的順序發(fā)送輸出,第9 位通常作為奇偶校驗位,最后發(fā)送停止位(高電平) 用來表示數(shù)據(jù)傳送結(jié)束。這樣的數(shù)據(jù)格式通常作為一個串行幀,如無奇偶校驗位,即是最為常 見的N.8.1幀格式(無奇偶校驗、8位數(shù)據(jù)位、1位停止位)。 接收時,只要單片機允許接收(REN=1),單片機硬件就會不斷的以16倍波特率的采樣速率 采樣RXD引腳電壓,一旦檢測到RXD引腳上出現(xiàn)一個從“1”到“0”的負跳變(即起始 位)時,就啟動接收。串行通信中,每秒鐘傳送二進制碼的位數(shù)稱為波特率,單位是 bps,即 “位/秒”,比如數(shù)據(jù)傳送的波特率為9600 比特,采用N.8.1 幀格式(10 位),則每秒傳送字節(jié)為9600/10=960 個,而字節(jié)中每一位傳送時間即為波特率的倒 數(shù):T = 1/9600 (S) = 104uS,根據(jù)數(shù)據(jù)傳送的波特率即字節(jié)中每一位的傳送時間, 我們也可通過編寫程序控制普通I/O 口實現(xiàn)圖4-1的通信時序。
圖4-1數(shù)據(jù)格式進一步說明如下: l ① 起始位:發(fā)送線TXD上沒有發(fā)送數(shù)據(jù)時呈高電平1狀態(tài)(即5V),當需要發(fā)送一幀數(shù) 據(jù)時,首先發(fā)送一位0(低電平)信號,稱起始位。 l ② 數(shù)據(jù)位:緊接起始位后是8位數(shù)據(jù)位(51單片機格式固定8位,不能修改),發(fā)送時 從數(shù)據(jù)的最低位開始,順序發(fā)送輸出)。 l ③ 奇偶校驗位:緊接數(shù)據(jù)位后是1位奇偶校驗位(SCON寄存器設(shè)為方式0和方式1沒有 這一位),奇偶校驗位無實用價值,實際運用是可靠性高的校驗和、異或校驗或CRC。 l ④ 停止位:在校驗位后是停止位1 (高電平5V),用于表示一幀數(shù)據(jù)結(jié)束(51單片機 停止位固定1位,不能修改)。 l ⑤ 幀與幀之間間隙不固定,間隙處用空閑位1(高電平)填補。 3 串口相關(guān)寄存器 串口1控制寄存器SCON:我們把此寄存器設(shè)為“格式固定的10位串口通信,允許 接收”,固定值:0x50,幾乎任何時候都不用修改用這個值,可使用定時器1或 定時器2作波特率發(fā)生器。 輔助寄存器 AUXR :使用語句AUXR &= 0xFE; 串口1選擇定時器1為波特率發(fā)生 器,使用語句AUXR |= 0x01;串口1選擇定時器2為波特率發(fā)生器(默認值,建 議),當然還需在程序中啟動相應(yīng)定時器。 電源控制寄存器PCON(復(fù)位值為0011 0000B) SMOD用于設(shè)置串口1的波特率是否加倍,其它串口波特率與此寄存器無關(guān)。 1:波特率加倍。0:波特率不加倍。 串口1數(shù)據(jù)緩沖區(qū)寄存器SBUF,復(fù)位值是xxxx xxxxB(即不確定的數(shù)據(jù)),需要發(fā)送 輸出的數(shù)據(jù)放這里就能自動發(fā)送出去,串口自動接收到的數(shù)據(jù)也存放在這里 串口2控制寄存器S2CON ,我們把此寄存器設(shè)為“格式固定的10位串口通信 , 允許接收”,固定值:0x10,只能使用定時器2作波特率發(fā)生器,當然還需在程 序中啟動定時器2。 串口3控制寄存器S3CON ,我們把此寄存器設(shè)為“格式固定的10位串口通信 , 允許接收”,值為0x10時使用定時器2作波特率發(fā)生器(建議),值為0x50時 使用定時器3作波特率發(fā)生器,當然還需在程序中啟動相應(yīng)定時器。 串口4控制寄存器S4CON ,我們把此寄存器設(shè)為“格式固定的10位串口通信 , 允許接收”,值為0x10時使用定時器2作波特率發(fā)生器(建議),值為0x50時 使用定時器4作波特率發(fā)生器,當然還需在程序中啟動相應(yīng)定時器。 4 波特率計算公式與表格
表4-17 常用波特率與定時器初值對應(yīng)表(T1定時器8位自動重裝方式) 時鐘頻率 | 定時器 分頻模式 | 波特率(bps) | 預(yù)置初值 (SMOD=0) | 預(yù)置初值 (SMOD=1) |
11.0592 | 1T | 9600 | DCH | B8H | 57600 | FAH | F4H | 115200 | FDH | FAH |
| 12T | 9600 | FDH | FAH | 57600 | 不能實現(xiàn) | FFH | 115200 | 不能實現(xiàn) | 不能實現(xiàn) |
|
| 22.1184 | 1T | 9600 | B8H | 70H | 57600 | F4H | E8H | 115200 | FAH | F4H |
| 12T | 9600 | FAH | F4H | 57600 | FFH | FEH | 115200 | 不能實現(xiàn) | FFH |
|
|
對于表4-17中“不能實現(xiàn)”的波特率,一般可以通過換用16位定時器方式解決,因為16位 定時器出來的溢出信號傳輸速度更快,適用于波特率要求很高的場合。 注意:對于STC15系列單片機,當各個串口的波特率都相同時,各串口可以共享定時器2 作為其波特率發(fā)生器,實際使用中建議各串口都優(yōu)先選擇定時器T2作波特率發(fā)生器。
5 單片機與計算機通信的簡單例子 例4.1 單片機向電腦發(fā)送0~255范圍內(nèi)不斷增大的數(shù)據(jù),使用串口1,定時器T1作波特率 發(fā)生器,波特率9600/22.1184MHz。單片機串口1接收引腳是RXD/P3.0,串口1發(fā)送引腳是 TXD/P3.1,也就是默認的程序下載引腳,程序下載完畢即可通過串口助手進行測試。 #include "STC15W4K.H" // 包含 "STC15W4K.H"寄存器定義頭文件 void delay500ms(void) { // 由第一章介紹的軟件計算得出 } void UART_init(void) { // 下面代碼設(shè)置定時器1 TMOD = 0x20; // 0010 0000 定時器1工作于方式2(8位自動重裝方式) TH1 = 0xFA; // 波特率:9600 /22.1184MHZ TL1 = 0xFA; // 波特率:9600 /22.1184MHZ TR1 = 1; // 下面代碼設(shè)置定串口 AUXR = 0x00; // 很關(guān)鍵,使用定時器1作為波特率發(fā)生器,S1ST2=0 SCON = 0x50; // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1 (允許接收) } void UART_send_byte(unsigned char dat) { SBUF = dat; while(!TI); TI=0; // 此句可以不要,不影響后面數(shù)據(jù)的發(fā)送,只供代碼查詢數(shù)據(jù)是否發(fā)送完成 } void main() { unsigned char num=0; UART_init(); while(1) { UART_send_byte(num++); delay500ms(); } } 運行結(jié)果如圖所示。
例4.2 單片機接收電腦數(shù)據(jù),加1后發(fā)回電腦,使用串口1,定時器T2作波特率發(fā)生器,波特率9600/22.1184MHz。 #include "STC15W4K.H" // 包含 "STC15W4K.H"寄存器定義頭文件 unsigned char num=0; // 存放接收到的1個字節(jié)的數(shù)據(jù) void UART_init(void) { } void main() { }
// 下面代碼設(shè)置定時器2
T2H = 0xFD; // 波特率:9600 /22.1184MHZ,1T T2L = 0xC0; // 波特率:9600 /22.1184MHZ,1T AUXR = 0x15; // 0001 0101,T2R=1啟動T2運行,T2x12=1,定時器2按1T計數(shù),S1ST2=1 // 下面代碼設(shè)置定串口1 SCON = 0x50; // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允許接收) // 下面代碼設(shè)置中斷 ES = 1; // 開串口1中斷 EA = 1; // 開總中斷 UART_init(); while(1); void UART1(void) interrupt 4 // 串行口1中斷函數(shù) { if(TI) { } if(RI) { } }
TI = 0; RI = 0; num = SBUF; num++; SBUF = num; // 啟動數(shù)據(jù)發(fā)送過程 6 數(shù)據(jù)通信中的錯誤校驗
數(shù)據(jù)通信難免可能發(fā)生錯誤,為了讓接收端判斷數(shù)據(jù)傳輸過程是否發(fā)生錯誤,我們需要 在發(fā)送的數(shù)據(jù)中傳送額外的附加數(shù)據(jù),簡單常用的附加數(shù)據(jù)是校驗和。 校驗和的方法就是把需要發(fā)送或接收的一組數(shù)據(jù)的所有字節(jié)進行相加,相加結(jié)果與256進行 相除,取其余數(shù),將此余數(shù)組合成發(fā)送數(shù)據(jù)的一部分而發(fā)送出去,同樣,接收數(shù)據(jù)的一方也 以相同的方式將所發(fā)送過來的數(shù)據(jù)進行相加計算,并與發(fā)送方所發(fā)過來的計算值比較,若其 值相同,則代表所發(fā)送的數(shù)據(jù)是正確的,反之則是錯誤的,檢查錯誤時,接收方可能要求發(fā) 送方重新發(fā)送,以確保數(shù)據(jù)的正確性。 例如,被發(fā)送數(shù)值為 0xAB 0xCD 0xEF 0x01 0x02 0x03 ,則將它們數(shù)值相加結(jié)果是 0x026D,以十進制表示為 621,與256 相除后取余數(shù),其值為109,再轉(zhuǎn)換成16進制為 0x6D,因此發(fā)送數(shù)據(jù)時在數(shù)據(jù)的尾端再加上一個字節(jié)0x6D,因此實際發(fā)送出去的數(shù)據(jù)成為 0xAB 0xCD 0xEF 0x01 0x02 0x03 0x6D,對方收到所發(fā)送的數(shù)據(jù)后會根據(jù)以上方式再進行一 次計算,如果計算出來的結(jié)果是0x6D,表示此次發(fā)送的數(shù)據(jù)是正確的。校驗和計算函數(shù)如下: unsigned char CheckSum(unsigned char *ptr, unsigned char len) { unsigned char i; unsigned char a; unsigned int Value=0; for(i=0;i<len;i++) //len結(jié)束后第一個字節(jié)為接收到的校驗和 { Value = Value + ptr[ i ]; } a=Value; // 長送短,傳送完整低字節(jié) return(a); } 7 單片機串口向計算機串口發(fā)送2進制、16進制、數(shù)值與字符串 例4.15 單片機串口向計算機串口發(fā)送2進制、16進制、數(shù)值與字符串 //////////////////////////////// main.c ////////////////////////////// #include "uart_debug.h" void main() { unsigned char a=0x55; unsigned int b=0xAB98; unsigned long c=1234567890; unsigned char Buf[]="歡迎使用STC15單片機!\n"; //字符串在內(nèi)存結(jié)尾必然有一個附 加字符:\0 UART_init(); // 波特率:9600 /22.1184MHZ UART_Send_Str("串口設(shè)置完畢:123ABC\n"); // 發(fā)送字符串 UART_Send_Str(Buf); UART_Send_Num(b); // 發(fā)送數(shù)值 UART_Send_StrNum("數(shù)值=:",c); // 發(fā)送字符串+數(shù)值 UART_Send_Hex(b) ; // 發(fā)送16進制 UART_Send_binary(a); // 發(fā)送2進制 while(1); }
實驗結(jié)果如下圖所示
本程序使用了一個程序包和程序包對應(yīng)的頭文件,程序移植時請將這兩個 文件復(fù)制到自己的工程文件夾, 串口初始化函數(shù)UART_init(); 默認波特率: 9600 /22.1184MHZ,可調(diào)整,其余部分不要修改。 |