微控制器學習(七)串列埠

CodeReaper發表於2021-08-21

參考資料:https://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) // 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軟體自帶的串列埠助手:

image-20210820171213135

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

執行結果:

image-20210820171404835

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

然後我們即可使用【串列埠助手】傳送資訊到微控制器上了。

fv4R0I.gif

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

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

標頭檔案寫上函式宣告即可。

相關文章