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