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