參考資料:https://www.bilibili.com/video/BV1Mb411e7re?p=19
一、串口相關信息
1. 串口簡介
串口是一種應用十分廣泛的通訊接口,串口成本低、容易使用、通信線路簡單,可實現兩個設備的互相通信。
單片機的串口可以使單片機與單片機、單片機與電腦、單片機與各式各樣的模塊互相通信,極大的擴展了單片機的應用范圍,增強了單片機系統的硬件實力。
51單片機內部自帶UART (Universal Asynchronous Receiver Transmitter,通用異步收發器),可實現單片機的串口通信。
2. 串口線路的連接
- 簡單雙向串口通信有兩根通信線(發送端
TXD
和接收端RXD
) TXD
與RXD
要交叉連接- 當只需單向的數據傳輸時,可以直接一根通信線
- 當電平標准不一致時,需要加電平轉換芯片
示意圖:

3. 串口電平標准
電平標准是數據1和數據0的表達方式,是傳輸線纜中人為規定的電壓與數據的對應關系,串口常用的電平標准有如下三種:
- TTL電平:
+5V
表示1
,0V
表示0
(單片機使用的是這個) - RS232電平: -3--15V表示1,+3~+15V表示0
- RS485電平:兩線壓差+2+6V表示1,-2-6V表示0 (差分信號)
4. 常見通信接口比較

相關術語:
- 全雙工:通信雙方可以在同一時刻互相傳輸數據
- 半雙工:通信雙方可以互相傳輸數據,但必須分時復用一根數據線
- 單工:通信只能有一方發送到另一方,不能反向傳輸
- 異步:通信雙方各自約定通信速率
- 同步:通信雙方靠一根時鍾線來約定通信速率
- 總線:連接各個設備的數據傳輸線路(類似於一條馬路,把路邊各住戶連接起來,使住戶可以相互交流)
二、51單片機的UART
1. STC89C52的UART資源
STC89C52
有1個UART
STC89C52
的UART有四種工作模式:
- 模式0 :同步移位寄存器
- 模式1 : 8位UART,波特率可變(常用)
- 模式2 : 9位UART,波特率固定
- 模式3 : 9位UART,波特率可變
2. 串口參數
波特率:串口通信的速率(發送和接收各數據位的間隔時間)
檢驗位:用於數據驗證
停止位:用於數據幀間隔
示意圖如下:

3. 串口模式圖

4. 中斷通路的配置

從大的方向來說就是當單片機使用串口來發送數據或接受數據,都會先把數據寫入到緩存SBUF
中,然后會提出中斷申請,然后再經過中斷通路運行對應的中斷程序。
5. 串口相關寄存器

三、相關寄存器的配置
SCON寄存器

1. SM0,SM1

我們主要通過配置這兩位來設置UART
的工作模式,如上所說,串口有4種工作模式,而我們常用的為第二種,故需要設置SM0=0
,SM1=1
。
2. REN

3. TI和RI


簡單地說就是當單片機使用串口發送或接收數據后,TI
或RI
位就會置一,告訴我們數據已被發送或接收了,然后我們需要在代碼層對其重新置零。
代碼配置
SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
所以配置的代碼為:
SCON = 0x50; // 0101 0000
PCON寄存器


由於我們不需要檢測幀錯誤,故我們這里只需要配置SMOD
,我們不需要波特率加倍,故這里置零,所以總的配置為:
PCON = 0x7F;
至於為什么其他的位全部為1我也不太清楚,我是根據STC-ISP軟件生成的代碼配置的
使用STC-ISP軟件自動生成配置代碼
其實后面還有幾項重要的配置,可是b站視頻中的老師講的很不清楚,直接就使用軟件生成代碼了,我也只能照做了。。。
打開STC-ISP軟件並打開到【波特率計算器】的tab:

然后按照上圖這樣配置需要的參數,然后我們就獲得了串口配置的所有代碼。
然后我們即可將這段代碼復制到項目中,注意還需要將與AUXR
相關的兩個語句刪除掉,上一部分已經說明過我們當前版本的單片機是不需要配置這個的。
總的代碼如下:
void UartInit(void) // 4800bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; // 8位數據,可變波特率
TMOD &= 0x0F; //清除定時器1模式位
TMOD |= 0x20; //設定定時器1為8位自動重裝方式
TL1 = 0xFA; //設定定時初值
TH1 = 0xFA; //設定定時器重裝值
ET1 = 0; //禁止定時器1中斷
TR1 = 1; //啟動定時器1
}
四、通過代碼使用串口
1. 通過串口發送數據
編寫函數:
void UartSendByte(unsigned char Data) {
SBUF = Data;
while (TI == 0);
TI = 0;
}
即我們將一個字節的數據寫入到SBUF
寄存器中,然后單片機即會自動將這個字節的數據發送出去,發送后TI
位會被置一。此時代表信息發送完成,我們需要手動將TI
位置零。
然后我們可以編寫一個每隔一段時間發送一個遞增的數字的程序:
unsigned char dataToSend = 0;
int main() {
UartInit();
while (1) {
UartSendByte(dataToSend);
dataToSend++;
defaultDeley();
}
}
tips:
接收數據可以使用STC-ISP軟件自帶的串口助手:
![]()
此時我們需要注意將波特率設置為和我們前面配置的一致,這樣我們才能確保接收到正確的數據。
運行結果:

2. 通過串口接收數據
我們使用串口接收數據並進行處理需要借助中斷系統,當單片機使用串口發送或接收數據時都會發出中斷請求,此時我們需要先配置中斷通路(二. 4),即:
ES = 1;
EA = 1;
在Uart_Init()
函數中添加這兩句即可。
總的配置語句為:
void Uart_Init(void) // 4800bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; // 8位數據,可變波特率
TMOD &= 0x0F; //清除定時器1模式位
TMOD |= 0x20; //設定定時器1為8位自動重裝方式
TL1 = 0xFA; //設定定時初值
TH1 = 0xFA; //設定定時器重裝值
ET1 = 0; //禁止定時器1中斷
TR1 = 1; //啟動定時器1
// 配置中斷通路
ES = 1;
EA = 1;
}
然后我們在查看串口中斷信號對應的中斷號:

由圖可知對應的中斷號為4
,因此我們可以像定時器那樣編寫中斷程序(函數):
void UART_Routine() interrupt 4 {
...
}
因為接受數據和發送數據都會觸發中斷程序,我們這里只使用中斷程序來接受數據,故我們可以先使用一個if
語句進行過濾:
void UART_Routine() interrupt 4 {
if(RI == 1) {
...
}
}
當RI == 1
,即遇到接受信息而觸發的中斷時,我們將接受到的信息進行處理,我們可以用接收到的字節數據來控制LED燈的亮滅,則我們可以如下編寫:
void UART_Routine() interrupt 4 {
if(RI == 1) {
// 將接收到的數據取反后賦值到P2,則bit為1時亮燈
P2 = ~SBUF;
// 然后將接收到的數據發送出去
Uart_SendByte(SBUF);
// RI需要手動置零
RI = 0;
}
}
不要忘記
RI
位需要手動置零
主函數:
int main() {
Uart_Init();
while (1) {}
}
然后我們即可使用【串口助手】發送信息到單片機上了。

五、將串口相關功能封裝成模塊
// Uart.c
#include "Uart.h"
#include<Atmel/REGX52.H>
void Uart_Init(void) // 4800bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; // 8位數據,可變波特率
TMOD &= 0x0F; //清除定時器1模式位
TMOD |= 0x20; //設定定時器1為8位自動重裝方式
TL1 = 0xFA; //設定定時初值
TH1 = 0xFA; //設定定時器重裝值
ET1 = 0; //禁止定時器1中斷
TR1 = 1; //啟動定時器1
ES = 1;
EA = 1;
}
void Uart_SendByte(unsigned char Data) {
SBUF = Data;
while (TI == 0);
TI = 0;
}
/*
接收串口數據中斷函數模板
void UART_Routine() interrupt 4 {
if(RI == 1) {
RI = 0;
}
}
*/
頭文件寫上函數聲明即可。