單片機學習(七)串口
參考資料://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) // [email protected]
{
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) // [email protected]
{
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) // [email protected]
{
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;
}
}
*/
頭文件寫上函數聲明即可。