找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10637|回復(fù): 5
打印 上一主題 下一主題
收起左側(cè)

第4章 單片機(jī)串口通信

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
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ù)值與字符串




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)范圍:

+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)
D7
D6
D5
D4
D3
D2
D1
D0

位名稱

SMOD








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ì)算公式與表格

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é)果如圖所示。

例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é)果如下圖所示


本程序使用了一個(gè)程序包和程序包對應(yīng)的頭文件,程序移植時(shí)請將這兩個(gè)
文件復(fù)制到自己的工程文件夾, 串口初始化函數(shù)UART_init(); 默認(rèn)波特率:
9600 /22.1184MHZ,可調(diào)整,其余部分不要修改。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏10 分享淘帖 頂1 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:118796 發(fā)表于 2016-6-22 11:19 | 只看該作者
不太懂!
回復(fù)

使用道具 舉報(bào)

板凳
ID:350005 發(fā)表于 2018-7-16 20:55 | 只看該作者
請問"uart_debug.h"里面的程序是什么   看書沒找到
回復(fù)

使用道具 舉報(bào)

地板
ID:439493 發(fā)表于 2018-12-4 19:45 | 只看該作者
初步學(xué)習(xí)一下,謝謝
回復(fù)

使用道具 舉報(bào)

5#
ID:288930 發(fā)表于 2019-1-29 10:10 | 只看該作者
謝謝分享!
回復(fù)

使用道具 舉報(bào)

6#
ID:676789 發(fā)表于 2019-12-29 18:01 | 只看該作者

謝謝分享!!
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表