單片機學習(七)串口

參考資料://www.bilibili.com/video/BV1Mb411e7re?p=19

一、串口相關資訊

1. 串口簡介

串口是一種應用十分廣泛的通訊介面,串口成本低、容易使用、通訊線路簡單,可實現兩個設備的互相通訊

單片機的串口可以使單片機與單片機單片機與電腦單片機與各式各樣的模組互相通訊,極大的擴展了單片機的應用範圍,增強了單片機系統的硬體實力。

51單片機內部自帶UART (Universal Asynchronous Receiver Transmitter,通用非同步收發器),可實現單片機的串口通訊

2. 串口線路的連接

  • 簡單雙向串口通訊兩根通訊線(發送端TXD和接收端RXD)
  • TXDRXD要交叉連接
  • 當只需單向的數據傳輸時,可以直接一根通訊線
  • 電平標準不一致時,需要加電平轉換晶片

示意圖:

image-20210820143544660

3. 串口電平標準

電平標準是數據1和數據0的表達方式,是傳輸線纜中人為規定的電壓與數據的對應關係,串口常用的電平標準有如下三種:

  • TTL電平: +5V表示10V表示0 (單片機使用的是這個)
  • RS232電平: -3–15V表示1,+3~+15V表示0
  • RS485電平:兩線壓差+2+6V表示1,-2-6V表示0 (差分訊號)

4. 常見通訊介面比較

image-20210820154209763

相關術語:

  • 全雙工:通訊雙方可以在同一時刻互相傳輸數據
  • 半雙工:通訊雙方可以互相傳輸數據,但必須分時復用一根數據線
  • 單工:通訊只能有一方發送到另一方,不能反向傳輸
  • 非同步:通訊雙方各自約定通訊速率
  • 同步:通訊雙方靠一根時鐘線來約定通訊速率
  • 匯流排:連接各個設備的數據傳輸線路(類似於一條馬路,把路邊各住戶連接起來,使住戶可以相互交流)

二、51單片機的UART

1. STC89C52的UART資源

STC89C521個UART
STC89C52的UART有四種工作模式

  • 模式0 :同步移位暫存器
  • 模式1 : 8位UART,波特率可變(常用)
  • 模式2 : 9位UART,波特率固定
  • 模式3 : 9位UART,波特率可變

2. 串口參數

波特率:串口通訊的速率(發送和接收各數據位的間隔時間)
檢驗位:用於數據驗證
停止位:用於數據幀間隔

示意圖如下:

image-20210820155624570

3. 串口模式圖

image-20210820160025475

4. 中斷通路的配置

image-20210820160204045

從大的方向來說就是當單片機使用串口來發送數據接受數據,都會先把數據寫入到快取SBUF,然後會提出中斷申請,然後再經過中斷通路運行對應的中斷程式

5. 串口相關暫存器

三、相關暫存器的配置

SCON暫存器

image-20210820162050496

1. SM0,SM1

image-20210820162343053

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

2. REN

image-20210820162942799

3. TI和RI

image-20210820162604210
image-20210820162645628

簡單地說就是當單片機使用串口發送或接收數據後TIRI位就會置一,告訴我們數據已被發送或接收了,然後我們需要在程式碼層對其重新置零

程式碼配置

SM0 SM1 SM2 REN TB8 RB8 TI RI
0 1 0 1 0 0 0 0

所以配置的程式碼為:

SCON = 0x50; // 0101 0000

PCON暫存器

image-20210820163639194
image-20210820163823208

由於我們不需要檢測幀錯誤,故我們這裡只需要配置SMOD,我們不需要波特率加倍,故這裡置零,所以總的配置為:

PCON = 0x7F;

至於為什麼其他的位全部為1我也不太清楚,我是根據STC-ISP軟體生成的程式碼配置的

使用STC-ISP軟體自動生成配置程式碼

其實後面還有幾項重要的配置,可是b站影片中的老師講的很不清楚,直接就使用軟體生成程式碼了,我也只能照做了。。。

打開STC-ISP軟體並打開到【波特率計算器】的tab:

image-20210820170428993

然後按照上圖這樣配置需要的參數,然後我們就獲得了串口配置的所有程式碼。

然後我們即可將這段程式碼複製到項目中,注意還需要將與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軟體自帶的串口助手:

image-20210820171213135

此時我們需要注意將波特率設置為和我們前面配置的一致,這樣我們才能確保接收到正確的數據。

運行結果:

image-20210820171404835

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) {}
}

然後我們即可使用【串口助手】發送資訊到單片機上了。

fv4R0I.gif

五、將串口相關功能封裝成模組

// 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;
    }
}
*/

頭文件寫上函數聲明即可。

Tags: