操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    本次講解STC8A8K64S4A12系列MCU串行口原理、4個UART串行口外設相關寄存器配置及程序設計。

    一、硬件設計

    1.開發板串口硬件電路

    STC8A8K64S4A12開發板上設計了USB轉TTL電路(CH340),其主要作用有3個:

    USB轉串口通信,可用于開發板串口通信調試。

    USB接口有5V電源,可為開發板供電。

    可使用短路帽選擇J5端子,將USB轉TTL電路的TTL信號連接到MCU的P3.0和P3.1引腳,這樣可用于開發板程序下載。

    USB轉TTL電路如下圖所示,串口接收和發送的引腳上均連接了LED指示燈,收發數據或程序下載時指示燈會閃爍,這樣,更方便我們從硬件的角度觀察串口有沒有在進行數據通信。電路中的1000mA自恢復保險絲用于保護開發板和計算機USB口。

    圖1:開發板USB轉TTL電路

    STC8A8K64S4A12開發板上還設計了RS232電路(MAX3232)及DB9接口,因為有的客戶電腦有DB9接口,那么開發板也有DB9接口就可以直接連接,方便調試。同樣可使用短路帽選擇J5端子,將該RS232電路的TTL信號連接到MCU的P3.0和P3.1引腳,這樣也可用于開發板程序下載和串口通信。

    圖2:開發板RS232電路

    USB轉TTL(RS232電路)占用的單片機的引腳如下表:

    UART功能描述對應IO口說明

    RXD串口接收P3.0獨立GPIO

    TXD串口發送P3.1獨立GPIO

    ☆注:獨立GPIO表示開發板沒有其他的電路使用這個GPIO。

    2.STC8A8K64S4A12系列單片機UART介紹

    STC8A8K64S4A12系列單片機有4個采用UART工作方式的全雙工異步串行通信接口,每個串行口由2個數據緩存器、1個移位寄存器、1個串行控制寄存器和1個波特率發生器等組成。每個串行口的數據緩存器由2個相互獨立的接收、發送緩沖器構成,因此可以同時發送和接收數據。

    ■ STC8A8K64S4A12系列單片機的4個串口引腳分配:

    STC8A8K64S4A12系列單片機的4個UART是相互獨立的,可以同時使用。但每個UART會有多組引腳與之對應(具體幾組還取決于芯片封裝引腳數),請注意同一個UART只能通過相關寄存器配置其中的一組使用,比如P3.0、P3.1是串口1,而P1.6、P1.7也是串口1,在使用串口1時必須選擇一個來使用。STC8A8K64S4A12系列單片機串口的引腳分配如下表。

    表2:單片機4個串口引腳分配

    ☆注:同一個串口各組之間切換是需要配置相關寄存器的相關位實現,如果沒有對該部分寄存器配置,一般默認選擇的都是第一組串口。

    ■ STC8A8K64S4A12系列單片機的4個串口用定時器:

    STC8A8K64S4A12系列單片機UART用于波特率發生器的定時器也是可以選擇的,但不是任意選擇哪個定時器都可以的。針對不同UART可供選擇的定時器如下表所示。

    表3:單片機4個串口波特率發生器用定時器

    ☆注:同一個串口的波特率發生器使用的定時器是需要配置相關寄存器的相關位實現,注意對寄存器按位進行操作,沒有使用的位不要去配置。

    3.串行口UART工作模式

    STC8A8K64S4A12系列單片機4個UART均有多種工作模式,串口1有4種工作模式,其中2種工作模式的波特率是可變的,另2種工作模式的波特率是固定的,以供不同應用場合選用。串口2、串口3和串口4都只用2種工作模式,這2種工作模式的波特率都是可變的。下面列表4個UART的工作模式。

    表4:單片機4個串口工作模式

    ☆注:艾克姆提供例程是按照“8位UART,波特率可變”模式進行配置。

    ■ UART1工作模式1原理介紹:

    “8位UART,波特率可變”的工作方式,其一幀信息為10位:1位起始位+8位數據位(低位在先)+1位停止位。

    發送過程:串行通信模式發送時,數據由串行發送端TXD輸出。當主機執行一條寫SBUF的指令就啟動串行通信的發送,寫“SBUF”信號還把“1”裝入發送移位寄存器的第9位,并通知TX控制單元開始發送。移位寄存器將數據不斷右移送TXD端口發送,在數據的左邊不斷移入“0”作補充。當數據的最高位移到移位寄存器的輸出位置,緊跟其后的是第9位“1”,在其左邊各位全為“0”,這個狀態條件,使TX控制單元作最后一次移位輸出,然后使允許發送信號“SEND”失效,完成一幀信息的發送,并置位中斷請求位TI,即TI=1,向主機請求中斷處理。

    圖3:UART1工作方式1發送數據示意圖

    接收過程:當軟件置位接收允許標志位REN,即REN=1時,接收器便對RXD端口的信號進行檢測,當檢測到RXD端口發送從“1”→“0”的下降沿跳變時就啟動接收器準備接收數據,并立即復位波特率發生器的接收計數器,將1FFH裝入移位寄存器。接收的數據從移位寄存器的右邊移入,已裝入的1FFH向左邊移出,當起始位“0”移到移位寄存器的最左邊時,使RX控制器作最后一次移位,完后一幀信息的接收。

    接收數據有效需同時滿足以下兩個條件:

    RI=0;

    SM2=0或接收到的停止位為1。

    ☆注:若上述兩條件不能同時滿足,則接收到的數據作廢并丟失,無論條件滿足與否,接收器重新檢測RXD端口上的“1”→“0”的跳變,繼續下一幀信息的接收。

    圖4:UART1工作方式1接收數據示意圖

    下面舉例介紹下串口1在進行工作方式選擇時,需要配置的是串口1控制寄存器SCON。該寄存器支持位尋址,該寄存器的B6和B7位便是用來選擇串口1工作方式的,寄存器的B5、B3和B2位是9位UART時需要配置的位,寄存器的B4位是串行接收控制位,寄存器的B0、B1位是串口接收和發送中斷請求標志位。

    圖5:串口1控制寄存器SCON

    ☆注:若上述兩條件不能同時滿足,則接收到的數據作廢并丟失,無論條件滿足與否,接收器重新檢測RXD端口上的“1”→“0”的跳變,繼續下一幀信息的接收。

    4.串行口使用引腳切換選擇

    在使用STC8A8K64S4A12系列單片機的4個UART時,需要確定使用串口的哪一組引腳。這需要通過操作P_SW1或P_SW2等寄存器實現。

    STC8A8K64S4A12系列單片機串口1有4組串口引腳可供選擇,實現引腳切換選擇需要P_SW1寄存器(即外設端口切換控制寄存器1)的B6和B7位,如下圖所示。

    圖6:P_SW1外設端口切換控制寄存器1

    ☆注:STC15W4K32S4系列單片機串口1只有3組供選擇,STC8A8K64S4A12系列單片機串口1有4組供選擇。同一時間只能使能其中的一組串口作為串口1使用。

    STC8A8K64S4A12系列單片機串口2、串口3和串口4均有2組串口引腳可供選擇,實現引腳切換選擇需要配置外設端口切換控制寄存器2的B0、B1和B2位,如下圖所示。

    圖7:P_SW2外圍設備功能切換控制寄存器2

    ☆注:因為串口2、串口3和串口4只有2組串口引腳供選擇,所以寄存器使用1位即可控制切換。

    5.串行口1工作模式1波特率計算公式

    STC8A8K64S4A12系列單片機4個UART在不同的工作模式下,選擇不同的定時器作為波特率發生器時,波特率計算公式都是不同的。下面舉例給出UART1工作模式1時的波特率計算公式。

    表5:UART1工作模式1波特率計算

    ☆注:SYSclk為系統工作頻率,SMOD是PCON寄存器最高位(用于波特率加倍選擇),定時器1模式0為16位自動重裝載模式,定時器1模式2為8位自動重裝載模式(詳見定時器部分介紹)。

    舉例,系統時鐘頻率為11.0592MHZ,配置定時器1為1T,工作模式為模式2, PCON寄存器SMOD位置為0,波特率預設置為9600bps,計算下定時器1重裝載值。

    SMOD=0,則2SMOD * SYSclk=11059200。

    11059200/(32*9600)=36。

    256 – 36=220。十進制220對應十六進制是DC。

    所以對定時器1的高8位寄存器初始裝載值和低8位寄存器初始裝載值賦值0xDC。

    如果已知定時器重裝載值,計算串口波特率,則是反推過來即可(建議使用軟件STC-ISP的波特率計算器)。

    6.串行口中斷配置步驟

    針對STC8A8K64S4A12系列單片機4個串行口外設,軟件的配置過程如下:

    圖8:串行口中斷軟件配置步驟

    ☆注:實驗例程即是按照上述配置步驟操作寄存器相關位實現,后有詳述

    二、軟件設計

    1.串行口寄存器匯集

    STC8A8K64S4A12系列單片機操作串行口時會用到18個寄存器,如下表所示:

    表6:STC8A8K64S4A12系列串行口使用寄存器匯總

    ☆注:串口波特率發生器需要用到定時器,定時器相關的寄存器沒有在上述表格中列舉。串口3和串口4是沒有中斷高優先級的,所以在中斷優先級控制寄存器中沒有對串口3和串口4中斷優先級的配置位。

    2.寄存器解析

    2.1.中斷允許寄存器IE

    外部中斷允許寄存器IE支持位尋址,該寄存器的B4位是串口1的中斷允許位。

    圖9:中斷允許寄存器

    2.2.中斷允許寄存器IE2

    中斷允許寄存器IE2不支持位尋址,該寄存器的B0、B3和B4位是串口2、串口3和串口4的中斷允許位。因為IE2寄存器不支持位尋址,所以舉例操作該寄存器B0位時,不可以直接“ES2=0;”進行操作,參考下圖。

    圖10:中斷允許寄存器2

    2.3.電源控制寄存器PCON

    電源控制寄存器PCON不支持位尋址,該寄存器的B6位和B7位是UART1的幀錯誤檢測有效控制位和波特率選擇位,具體含義如下圖。

    圖11:電源控制寄存器

    ☆注:PCON寄存器的SMOD位和SMOD0位是用于串口1的,換句話說,串口2、串口3和串口4沒有與之對應的控制位。

    2.4.輔助寄存器AUXR

    輔助寄存器AUXR不支持位尋址,該寄存器的B0位是串口1的波特率發生器定時器選擇控制位,寄存器的B5位是串口1模式0的通信速度設置位。

    圖12:輔助寄存器

    ☆注:AUXR寄存器的其他位用于定時器配置,操作串口時也會有對定時器的配置部分,請注意按位操作。

    2.5.中斷優先級控制寄存器IP

    中斷優先級控制寄存器IP支持位尋址,該寄存器的B4位是串口1中斷優先級控制位。

    圖13:中斷優先級控制寄存器

    ☆注:艾克姆例程沒有對串口1中斷優先級進行配置,可根據項目需要配置PS位。

    2.6.中斷優先級控制寄存器IP2

    中斷優先級控制寄存器2不支持位尋址,該寄存器的B0位是串口2中斷優先級控制位。

    圖14:中斷優先級控制寄存器2

    2.7.串行口2控制寄存器S2CON

    串行口2控制寄存器S2CON不支持位尋址,該寄存器的B7位是用來選擇串口2工作模式的,寄存器的B5、B3和B2位是9位UART時需要配置的位,寄存器的B4位是串行接收控制位,寄存器的B0、B1位是串口接收和發送中斷請求標志位。

    圖15:串行口2控制寄存器

    2.8.串行口3控制寄存器S3CON

    串行口3控制寄存器S3CON不支持位尋址,該寄存器的B7位是用來選擇串口3工作模式的,寄存器的B5、B3和B2位是9位UART時需要配置的位,寄存器的B4位是串行接收控制位,寄存器的B0、B1位是串口接收和發送中斷請求標志位。

    圖16:串行口3控制寄存器

    2.9.串行口4控制寄存器S4CON

    串行口4控制寄存器S4CON不支持位尋址,該寄存器的B7位是用來選擇串口4工作模式的,寄存器的B5、B3和B2位是9位UART時需要配置的位,寄存器的B4位是串行接收控制位,寄存器的B0、B1位是串口接收和發送中斷請求標志位。

    圖17:串行口4控制寄存器

    3.串口1收發實驗(P3.0和P3.1)

    3.1.工程需要用到的c文件

    本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

    表7:實驗需要用到的c文件

    序號文件名后綴功能描述

    1uart.c外部串行口有關的用戶自定義函數。

    2delay.c包含用戶自定義延時函數。

    3.2.頭文件引用和路徑設置

    ■ 需要引用的頭文件

    #include "delay.h"

    #include "uart.h"

    1

    2

    ■ 需要包含的頭文件路徑

    本例需要包含的頭文件路徑如下表:

    表8:頭文件包含路徑

    序號路徑描述

    1…\ Sourceuart.h和delay.h頭文件在該路徑,所以要包含。

    2…\UserSTC8.h頭文件在該路徑,所以要包含。

    MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。

    圖18:添加頭文件包含路徑

    3.3.編寫代碼

    首先,在uart.c文件中編寫串口1的初始化函數Uart1_Init,代碼如下。

    程序清單:串口1初始化函數

    /***************************************************************************

    * 描 述 : 串口1初始化函數

    * 入 參 : 無

    * 返回值 : 無

    備注:波特率9600bps 晶振11.0592MHz

    **************************************************************************/

    void Uart1_Init(void)

    {

    PCON &=0x3f; //波特率不倍速,串行口工作方式由SM0、SM1決定

    SCON=0x50; //8位數據,可變波特率,啟動串行接收器

    AUXR |=0x40; //定時器1時鐘為Fosc,即1T

    AUXR &=0xfe; //串口1選擇定時器1為波特率發生器

    TMOD &=0x0f; //清除定時器1模式位

    TMOD |=0x20; //設定定時器1為8位自動重裝方式

    TL1=0xDC; //設定定時初值

    TH1=0xDC; //設定定時器重裝值

    ET1=0; //禁止定時器1中斷

    TR1=1; //啟動定時器1

    ES=1; // 串口1中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    然后,編寫串口1發送數據函數,把要發送的字節存放于數據緩存寄存器中,直到數據發送完成,代碼如下。

    程序清單:數據發送函數函數

    /***************************************************************************

    * 描 述 : 串口1發送數據函數

    * 入 參 : uint8 數據

    * 返回值 : 無

    **************************************************************************/

    void SendDataByUart1(uint8 dat)

    {

    SBUF=dat; //寫數據到UART數據寄存器

    while(TI==0); //在停止位沒有發送時,TI為0即一直等待

    TI=0; //清除TI位(該位必須軟件清零)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    之后,編寫串口1的中斷服務函數,將接收的數據存放到用戶自定義變量uart1temp中,代碼如下。

    程序清單:中斷服務函數

    /***************************************************************************

    * 描 述 : 串口1中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart1() interrupt 4 using 1

    {

    ES=0; // 串口1中斷關閉

    Flag=TRUE; //接收到數據,接收標識符有效

    if (RI) //串行接收到停止位的中間時刻時,該位置1

    {

    RI=0; //清除RI位 (該位必須軟件清零)

    uart1temp=SBUF;

    }

    if (TI) //在停止位開始發送時,該位置1

    {

    TI=0; //清除TI位(該位必須軟件清零)

    }

    ES=1; // 串口1中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    最后,用戶定義一個自定義函數UART1_Tx_Puts,該函數將接收的數據原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART1_Tx_Puts

    /***************************************************************************

    * 描 述 : 串口1接收到數據后發送回去

    * 入 參 : 無

    * 返回值 : 無

    ***************************************************************************/

    void UART1_Tx_Puts(void)

    {

    if(Flag) //有新數據通過串口被接收到

    {

    ES=0; //串口1中斷關閉

    SendDataByUart1(uart1temp); //發送字符

    SendDataByUart1(0x0D); //發送換行符

    SendDataByUart1(0x0A); //發送換行符

    ES=1; //串口1中斷打開

    Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    代碼清單:主函數

    int main()

    {

    P3M1 &=0xFE; P3M0 &=0xFE; //設置P3.0為準雙向口

    P3M1 &=0xFD; P3M0 |=0x02; //設置P3.1為推挽輸出


    Uart1_Init(); //串口1初始化

    EA=1; //總中斷打開


    while(1)

    {

    UART1_Tx_Puts(); //串口接收到一個字符后返回該字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    3.4.硬件連接

    本實驗需要將USB線連接至PC,因為開發板板載CH340電路連接的就是單片機P3.0和P3.1口,所以無需外接USB轉TTL模塊做該實驗。

    圖19:串口1實驗連接圖

    4.串口2收發實驗(P1.0和P1.1)

    4.1.編寫代碼

    首先,在uart.c文件中編寫串口2的初始化函數Uart2_Init,代碼如下。

    程序清單:串口2初始化函數

    /***************************************************************************

    * 描 述 : 串口2初始化函數

    * 入 參 : 無

    * 返回值 : 無

    備注:波特率9600bps 晶振11.0592MHz

    **************************************************************************/

    void Uart2_Init(void)

    {

    S2CON=0x50; //8位數據,可變波特率,啟動串行接收器

    AUXR |=0x04; //定時器2時鐘為Fosc,即1T

    T2L=0xE0; //設定定時初值

    T2H=0xFE; //設定定時初值

    AUXR |=0x10; //啟動定時器2

    IE2 |=0x01; //串口2中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    然后,編寫串口2發送數據函數,把要發送的字節存放于數據緩存寄存器中,直到數據發送完成,代碼如下。

    程序清單:數據發送函數函數

    /***************************************************************************

    * 描 述 : 串口2發送數據函數

    * 入 參 : uint8 數據

    * 返回值 : 無

    **************************************************************************/

    void SendDataByUart2(uint8 dat)

    {

    S2BUF=dat; //寫數據到UART數據寄存器

    while(!(S2CON&S2TI)); //在停止位沒有發送時,S2TI為0即一直等待

    S2CON&=~S2TI; //清除S2CON寄存器對應S2TI位(該位必須軟件清零)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    之后,編寫串口2的中斷服務函數,將接收的數據存放到用戶自定義變量uart2temp中,代碼如下。

    程序清單:中斷服務函數

    /***************************************************************************

    * 描 述 : 串口2中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart2() interrupt 8 using 1

    {

    IE2 &=0xFE; // 串口2中斷關閉

    Flag=TRUE; //接收到數據,接收標識符有效

    if (S2CON & S2RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S2CON &=~S2RI; //清除S2CON寄存器對應S2RI位(該位必須軟件清零)

    uart2temp=S2BUF;

    }

    if (S2CON & S2TI) //在停止位開始發送時,該位置1

    {

    S2CON &=~S2TI; //清除S2CON寄存器對應S2TI位(該位必須軟件清零)

    }

    IE2 |=0x01; // 串口2中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    最后,用戶定義一個自定義函數UART2_Tx_Puts,該函數將接收的數據原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART2_Tx_Puts

    /***************************************************************************

    * 描 述 : 串口2接收到數據后發送出去

    * 入 參 : 無

    * 返回值 : 無

    ***************************************************************************/

    void UART2_Tx_Puts(void)

    {

    if(Flag) //有新數據通過串口被接收到

    {

    IE2 &=0xFE; // 串口2中斷關閉

    SendDataByUart2(uart2temp); //發送字符

    SendDataByUart2(0x0D); //發送換行符

    SendDataByUart2(0x0A); //發送換行符

    IE2 |=0x01; // 串口2中斷打開

    Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    代碼清單:主函數

    int main()

    {

    P1M1 &=0xFE; P1M0 &=0xFE; //設置P1.0為準雙向口

    P1M1 &=0xFD; P1M0 |=0x02; //設置P1.1為推挽輸出


    Uart2_Init(); //串口2初始化

    EA=1; //總中斷打開


    while(1)

    {

    UART2_Tx_Puts(); //串口接收到一個字符后返回該字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    4.2.硬件連接

    本實驗需要外接USB轉TTL模塊連接到開發板串口2上,該實驗串口2選擇的P1.0和P1.1,具體接線圖如下。

    圖20:串口2實驗連接圖

    5.串口3收發實驗(P0.0和P0.1)

    5.1.編寫代碼

    首先,在uart.c文件中編寫串口3的初始化函數Uart3_Init,代碼如下。

    程序清單:串口3初始化函數

    /***************************************************************************

    * 描 述 : 串口3初始化函數

    * 入 參 : 無

    * 返回值 : 無

    備注:波特率9600bps 晶振11.0592MHz

    **************************************************************************/

    void Uart3_Init(void)

    {

    S3CON |=0x10; //啟動串行接收器

    S3CON &=0x30; //8位數據,可變波特率,串口3選擇定時器2為波特率發生器

    AUXR |=0x04; //定時器2時鐘為Fosc,即1T

    T2L=0xE0; //設定定時初值

    T2H=0xFE; //設定定時初值

    AUXR |=0x10; //啟動定時器2

    IE2 |=0x08; // 串口3中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    然后,編寫串口3發送數據函數,把要發送的字節存放于數據緩存寄存器中,直到數據發送完成,代碼如下。

    程序清單:數據發送函數函數

    /***************************************************************************

    * 描 述 : 串口3發送數據函數

    * 入 參 : uint8 數據

    * 返回值 : 無

    **************************************************************************/

    void SendDataByUart3(uint8 dat)

    {

    S3BUF=dat; //寫數據到UART數據寄存器

    while(!(S3CON&S3TI)); //在停止位沒有發送時,S3TI為0即一直等待

    S3CON&=~S3TI; //清除S3CON寄存器對應S3TI位(該位必須軟件清零)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    之后,編寫串口3的中斷服務函數,將接收的數據存放到用戶自定義變量uart3temp中,代碼如下。

    程序清單:中斷服務函數

    /***************************************************************************

    * 描 述 : 串口3中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart3() interrupt 17 using 1

    {

    IE2 &=0xF7; // 串口3中斷關閉

    Flag=TRUE; //接收到數據,接收標識符有效

    if (S3CON & S3RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S3CON &=~S3RI; //清除S3CON寄存器對應S3RI位(該位必須軟件清零)

    uart3temp=S3BUF;

    }

    if (S3CON & S3TI) //在停止位開始發送時,該位置1

    {

    S3CON &=~S3TI; //清除S3CON寄存器對應S3TI位(該位必須軟件清零)

    }

    IE2 |=0x08; // 串口3中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    最后,用戶定義一個自定義函數UART3_Tx_Puts,該函數將接收的數據原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART3_Tx_Puts

    /**************************************************************************

    * 描 述 : 串口3接收到數據后發送出去

    * 入 參 : 無

    * 返回值 : 無

    *************************************************************************/

    void UART3_Tx_Puts(void)

    {

    if(Flag) //有新數據通過串口被接收到

    {

    IE2 &=0xF7; //串口3中斷關閉

    SendDataByUart3(uart3temp); //發送字符

    SendDataByUart3(0x0D); //發送換行符

    SendDataByUart3(0x0A); //發送換行符

    IE2 |=0x08; //串口3中斷打開

    Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    代碼清單:主函數

    int main()

    {

    P0M1 &=0xFE; P0M0 &=0xFE; //設置P0.0為準雙向口

    P0M1 &=0xFD; P0M0 |=0x02; //設置P0.1為推挽輸出


    Uart3_Init(); //串口3初始化

    EA=1; //總中斷打開


    while(1)

    {

    UART3_Tx_Puts(); //串口接收到一個字符后返回該字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    5.2.硬件連接

    本實驗需要外接USB轉TTL模塊連接到開發板串口3上,該實驗串口3選擇的P0.0和P0.1,具體接線圖如下。

    圖21:串口3實驗連接圖

    6.串口4收發實驗(P0.2和P0.3)

    6.1.編寫代碼

    首先,在uart.c文件中編寫串口4的初始化函數Uart4_Init,代碼如下。

    程序清單:串口4初始化函數

    /***************************************************************************

    * 描 述 : 串口4初始化函數

    * 入 參 : 無

    * 返回值 : 無

    備注:波特率9600bps 晶振11.0592MHz

    **************************************************************************/

    void Uart4_Init(void)

    {

    S4CON |=0x10; //啟動串行接收器

    S4CON &=0x30; //8位數據,可變波特率,串口4選擇定時器2為波特率發生器

    AUXR |=0x04; //定時器2時鐘為Fosc,即1T

    T2L=0xE0; //設定定時初值

    T2H=0xFE; //設定定時初值

    AUXR |=0x10; //啟動定時器2

    IE2 |=0x10; // 串口4中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    然后,編寫串口4發送數據函數,把要發送的字節存放于數據緩存寄存器中,直到數據發送完成,代碼如下。

    程序清單:數據發送函數函數

    /***************************************************************************

    * 描 述 : 串口4發送數據函數

    * 入 參 : uint8 數據

    * 返回值 : 無

    **************************************************************************/

    void SendDataByUart4(uint8 dat)

    {

    S4BUF=dat; //寫數據到UART數據寄存器

    while(!(S4CON&S4TI)); //在停止位沒有發送時,S4TI為0即一直等待

    S4CON&=~S4TI; //清除S4CON寄存器對應S4TI位(該位必須軟件清零)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    之后,編寫串口4的中斷服務函數,將接收的數據存放到用戶自定義變量uart4temp中,代碼如下。

    程序清單:中斷服務函數

    /***************************************************************************

    * 描 述 : 串口4中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart4() interrupt 18 using 1

    {

    IE2 &=0xEF; // 串口4中斷關閉

    Flag=TRUE; //接收到數據,接收標識符有效

    if (S4CON & S4RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S4CON &=~S4RI; //清除S4CON寄存器對應S4RI位(該位必須軟件清零)

    uart4temp=S4BUF;

    }

    if (S4CON & S4TI) //在停止位開始發送時,該位置1

    {

    S4CON &=~S4TI; //清除S4CON寄存器對應S4TI位(該位必須軟件清零)

    }

    IE2 |=0x10; // 串口4中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    最后,用戶定義一個自定義函數UART4_Tx_Puts,該函數將接收的數據原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART4_Tx_Puts

    /*************************************************************************

    * 描 述 : 串口4接收到數據后發送出去

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void UART4_Tx_Puts(void)

    {

    if(Flag) //有新數據通過串口被接收到

    {

    IE2 &=0xEF; // 串口4中斷關閉

    SendDataByUart4(uart4temp); //發送字符

    SendDataByUart4(0x0D); //發送換行符

    SendDataByUart4(0x0A); //發送換行符

    IE2 |=0x10; // 串口4中斷打開

    Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    代碼清單:主函數

    int main()

    {

    P0M1 &=0xFB; P0M0 &=0xFB; //設置P0.2為準雙向口

    P0M1 &=0xF7; P0M0 |=0x08; //設置P0.3為推挽輸出


    Uart4_Init(); //串口4初始化

    EA=1; //總中斷打開


    while(1)

    {

    UART4_Tx_Puts(); //串口接收到一個字符后返回該字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    6.2.硬件連接

    本實驗需要外接USB轉TTL模塊連接到開發板串口4上,該實驗串口4選擇的P0.2和P0.3,具體接線圖如下。

    圖22:串口4實驗連接圖

    7.串口1串口2同時收發字符串實驗

    7.1.工程需要用到的c文件

    本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

    表9:實驗需要用到的c文件

    序號文件名后綴功能描述

    1uart.c外部串行口有關的用戶自定義函數。

    2delay.c包含用戶自定義延時函數。

    3led.c包含與用戶led控制有關的用戶自定義函數。

    7.2.頭文件引用和路徑設置

    ■ 需要引用的頭文件

    #include "delay.h"

    #include "uart.h"

    1

    2

    ■ 需要包含的頭文件路徑

    本例需要包含的頭文件路徑如下表:

    表10:頭文件包含路徑

    序號路徑描述

    1…\ SourceLed.h、uart.h和delay.h頭文件在該路徑,所以要包含。

    2…\UserSTC8.h頭文件在該路徑,所以要包含。

    MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。

    圖23:添加頭文件包含路徑

    7.3.編寫代碼

    首先,在uart.c文件中編寫串口1的初始化函數Uart1_Init和串口1發送單個字符函數SendDataByUart1,這兩個函數不介紹了。下面介紹下串口1清緩存函數CLR_Buf1和發送字符串函數SendStringByUart1,代碼如下。

    程序清單:串口1發送字符串函數

    /***************************************************************************

    * 描 述 : 串口1發送字符串函數

    * 入 參 : 字符串

    * 返回值 : 無

    **************************************************************************/

    void SendStringByUart1(uint8 *s)

    {

    while(*s)

    {

    SendDataByUart1(*s++); //將字符串中的字符一個一個發送

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口1清緩存函數

    /*****************************************************************************

    功能描述:清除串口1緩存內容函數

    入口參數:無

    返回值:無

    ******************************************************************************/ void CLR_Buf1(void)

    {

    uint8 k;

    for(k=0;k<Buf1_Max;k++) //將串口1緩存數組的值都清為零

    {

    Rec_Buf1[k]=0;

    }

    i=0; //清零串口1接收數據個數變量

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    然后,串口2的初始化函數Uart2_Init和串口2發送單個字符函數SendDataByUart2,這兩個函數不介紹了。下面介紹下串口2清緩存函數CLR_Buf2和發送字符串函數SendStringByUart2,代碼如下。

    程序清單:串口2發送字符串函數

    /***************************************************************************

    * 描 述 : 串口2發送字符串函數

    * 入 參 : 字符串

    * 返回值 : 無

    **************************************************************************/

    void SendStringByUart2(uint8 *s)

    {

    while (*s) //檢測字符串結束標志

    {

    SendDataByUart2(*s++); //發送當前字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口2清緩存函數

    /**************************************************************************

    功能描述:清除串口2緩存內容函數

    入口參數:無

    返回值:無

    ***************************************************************************/

    void CLR_Buf2(void)

    {

    uint8 k;

    for(k=0;k<Buf2_Max;k++) //將串口2緩存數組的值都清為零

    {

    Rec_Buf2[k]=0;

    }

    j=0; //清零串口2接收數據個數變量

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    之后,編寫串口1和串口2的中斷服務函數,將接收的數據存放到用戶自定義數組Rec_Buf1和Rec_Buf2中,代碼如下。

    程序清單:串口1中斷服務函數

    /***************************************************************************

    * 描 述 : 串口1中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart1() interrupt 4 using 1

    {

    uint8 temp;

    ES=0; // 串口1中斷關閉

    if (RI) //串行接收到停止位的中間時刻時,該位置1

    {

    RI=0; //清除RI位 (該位必須軟件清零)

    temp=SBUF; //接收到的數賦值給臨時變量

    if(temp !='\n') //沒有接收到換行符

    {

    Rec_Buf1[i]=temp; //接收到的數存到接收數組中

    i++; //串口1接收數據個數變量累加

    }

    else //接收到結束符

    {

    Buf1_Length=i; //接收數據長度賦值

    i=0; //清零串口1接收數據個數變量

    Buf1_Flag=TRUE; //接收完數據,接收標識符有效

    led_toggle(LED_3); //翻轉用戶指示燈D3,方便觀察實驗現象

    }

    }

    if (TI) //在停止位開始發送時,該位置1

    {

    TI=0; //清除TI位(該位必須軟件清零)

    }

    ES=1; // 串口1中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    程序清單:串口2中斷服務函數

    /***************************************************************************

    * 描 述 : 串口2中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart2() interrupt 8 using 1

    {

    uint8 temp;

    IE2 &=0xFE; //串口2中斷關閉

    if (S2CON & S2RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S2CON &=~S2RI; //清除S2CON寄存器對應S2RI位(該位必須軟件清零)

    temp=S2BUF; //接收到的數賦值給臨時變量

    if(temp !='\n') //沒有接收到換行符

    {

    Rec_Buf2[j]=temp; //接收到的數存到接收數組中

    j++; //串口2接收數據個數變量累加

    }

    else //接收到結束符

    {

    Buf2_Length=j; //接收數據長度賦值

    j=0; //清零串口2接收數據個數變量

    Buf2_Flag=TRUE; //接收完數據,接收標識符有效

    led_toggle(LED_4); //翻轉用戶指示燈D4,方便觀察實驗現象

    }

    }

    if (S2CON & S2TI) //在停止位開始發送時,該位置1

    {

    S2CON &=~S2TI; //清除S2CON寄存器對應S2TI位(該位必須軟件清零)

    }

    IE2 |=0x01; //串口2中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    最后,用戶定義一個自定義函數UART1_2_Tx_Puts,該函數將接收的字符串原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART1_2_Tx_Puts

    /*************************************************************************

    * 描 述 : 串口1和串口2接收到字符串后發送出去

    * 入 參 : 無

    * 返回值 : 無

    ************************************************************************/

    void UART1_2_Tx_Puts(void)

    {

    if(Buf1_Flag) //串口1接收一組字符串完成

    {

    ES=0; //串口1中斷關閉

    SendStringByUart1(Rec_Buf1); //發送字符

    SendDataByUart1(0x0D); //發送換行符

    SendDataByUart1(0x0A); //發送換行符

    ES=1; //串口1中斷打開

    CLR_Buf1(); //清除串口1緩存

    Buf1_Flag=FALSE; //清除接收標識符

    }

    if(Buf2_Flag) //串口2接收一組字符串完成

    {

    IE2 &=0xFE; //串口2中斷關閉

    SendStringByUart2(Rec_Buf2); //發送字符

    SendDataByUart2(0x0D); //發送換行符

    SendDataByUart2(0x0A); //發送換行符

    IE2 |=0x01; //串口2中斷打開

    CLR_Buf2(); //清除串口2緩存

    Buf2_Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    代碼清單:主函數

    int main()

    {

    P3M1 &=0xFE; P3M0 &=0xFE; //設置P3.0為準雙向口

    P3M1 &=0xFD; P3M0 |=0x02; //設置P3.1為推挽輸出

    P1M1 &=0xFE; P1M0 &=0xFE; //設置P1.0為準雙向口

    P1M1 &=0xFD; P1M0 |=0x02; //設置P1.1為推挽輸出


    Uart1_Init(); //串口1初始化

    Uart2_Init(); //串口2初始化

    EA=1; //總中斷打開


    CLR_Buf1(); //清除串口1緩存

    CLR_Buf2(); //清除串口2緩存


    while(1)

    {

    UART1_2_Tx_Puts(); //UART1和UART2接收到字符串后發送出去

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    7.4.硬件連接

    圖24:串口1串口2實驗連接圖

    8.串口3串口4同時收發字符串實驗

    8.1.編寫代碼

    首先,在uart.c文件中編寫串口3的初始化函數Uart3_Init和串口3發送單個字符函數SendDataByUart3,這兩個函數不介紹了。下面介紹下串口3清緩存函數CLR_Buf3和發送字符串函數SendStringByUart3,代碼如下。

    程序清單:串口3發送字符串函數

    /***************************************************************************

    * 描 述 : 串口3發送字符串函數

    * 入 參 : 字符串

    * 返回值 : 無

    **************************************************************************/

    void SendStringByUart3(uint8 *s)

    {

    while (*s) //檢測字符串結束標志

    {

    SendDataByUart3(*s++); //發送當前字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口3清緩存函數

    /*****************************************************************************

    功能描述:清除串口3緩存內容函數

    入口參數:無

    返回值:無

    ****************************************************************************/

    void CLR_Buf3(void)

    {

    uint8 k;

    for(k=0;k<Buf3_Max;k++) //將串口3緩存數組的值都清為零

    {

    Rec_Buf3[k]=0;

    }

    i=0; //清零串口3接收數據個數變量

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    然后,串口4的初始化函數Uart4_Init和串口4發送單個字符函數SendDataByUart4,這兩個函數不介紹了。下面介紹下串口4清緩存函數CLR_Buf4和發送字符串函數SendStringByUart4,代碼如下。

    程序清單:串口4發送字符串函數

    /***************************************************************************

    * 描 述 : 串口4發送字符串函數

    * 入 參 : 字符串

    * 返回值 : 無

    **************************************************************************/

    void SendStringByUart4(char *s)

    {

    while (*s) //檢測字符串結束標志

    {

    SendDataByUart4(*s++); //發送當前字符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口4清緩存函數

    /**************************************************************************

    功能描述:清除串口4緩存內容函數

    入口參數:無

    返回值:無

    ***************************************************************************/

    void CLR_Buf4(void)

    {

    uint8 k;

    for(k=0;k<Buf4_Max;k++) //將串口4緩存數組的值都清為零

    {

    Rec_Buf4[k]=0;

    }

    j=0; //清零串口4接收數據個數變量

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    之后,編寫串口3和串口4的中斷服務函數,將接收的數據存放到用戶自定義數組Rec_Buf3和Rec_Buf4中,代碼如下。

    程序清單:串口3中斷服務函數

    /***************************************************************************

    * 描 述 : 串口3中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart3() interrupt 17 using 1

    {

    uint8 temp;

    IE2 &=0xF7; //串口3中斷關閉

    if (S3CON & S3RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S3CON &=~S3RI; //清除S3CON寄存器對應S3RI位(該位必須軟件清零)

    temp=S3BUF; //接收到的數賦值給臨時變量

    if(temp !='\n') //沒有接收到換行符

    {

    Rec_Buf3[i]=temp; //接收到的數存到接收數組中

    i++; //串口3接收數據個數變量累加

    }

    else //接收到結束符

    {

    Buf3_Length=i; //接收數據長度賦值

    i=0; //清零串口3接收數據個數變量

    Buf3_Flag=TRUE; //接收完數據,接收標識符有效

    led_toggle(LED_3); //翻轉用戶指示燈D3,方便觀察實驗現象

    }

    }

    if (S3CON & S3TI) //在停止位開始發送時,該位置1

    {

    S3CON &=~S3TI; //清除S3CON寄存器對應S3TI位(該位必須軟件清零)

    }

    IE2 |=0x08; //串口3中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    程序清單:串口2中斷服務函數

    /***************************************************************************

    * 描 述 : 串口4中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart4() interrupt 18 using 1

    {

    uint8 temp;

    IE2 &=0xEF; //串口4中斷關閉

    if(S4CON & S4RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S4CON &=~S4RI; //清除S4CON寄存器對應S4RI位(該位必須軟件清零)

    temp=S4BUF; //接收到的數賦值給臨時變量

    if(temp !='\n') //沒有接收到換行符

    {

    Rec_Buf4[j]=temp; //接收到的數存到接收數組中

    j++; //串口4接收數據個數變量累加

    }

    else //接收到結束符

    {

    Buf4_Length=j; //接收數據長度賦值

    j=0; //清零串口4接收數據個數變量

    Buf4_Flag=TRUE; //接收完數據,接收標識符有效

    led_toggle(LED_4); //翻轉用戶指示燈D4,方便觀察實驗現象

    }

    }

    if(S4CON & S4TI) //在停止位開始發送時,該位置1

    {

    S4CON &=~S4TI; //清除S4CON寄存器對應S4TI位(該位必須軟件清零)

    }

    IE2 |=0x10; //串口4中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    最后,用戶定義一個自定義函數UART3_4_Tx_Puts,該函數將接收的字符串原樣返回去并加上回車符。主函數main在主循環中調用該函數。具體代碼如下。

    代碼清單:用戶函數UART3_4_Tx_Puts

    /*************************************************************************

    * 描 述 : 串口3和串口4接收到字符串后發送出去

    * 入 參 : 無

    * 返回值 : 無

    ***********************************************************************/

    void UART3_4_Tx_Puts(void)

    {

    if(Buf3_Flag) //串口3接收一組字符串完成

    {

    IE2 &=0xF7; //串口3中斷關閉

    SendStringByUart3(Rec_Buf3); //發送字符

    SendDataByUart3(0x0D); //發送換行符

    SendDataByUart3(0x0A); //發送換行符

    IE2 |=0x08; //串口3中斷打開

    CLR_Buf3(); //清除串口3緩存

    Buf3_Flag=FALSE; //清除接收標識符

    }

    if(Buf4_Flag) //串口4接收一組字符串完成

    {

    IE2 &=0xEF; //串口4中斷關閉

    SendStringByUart4(Rec_Buf4); //發送字符

    SendDataByUart4(0x0D); //發送換行符

    SendDataByUart4(0x0A); //發送換行符

    IE2 |=0x10; //串口4中斷打開

    CLR_Buf4(); //清除串口4緩存

    Buf4_Flag=FALSE; //清除接收標識符

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    代碼清單:主函數

    int main()

    {

    P0M1 &=0xFA; P0M0 &=0xFA; //設置P0.0 P0.2為準雙向口

    P0M1 &=0xF5; P0M0 |=0x0A; //設置P0.1 P0.3為推挽輸出


    Uart3_Init(); //串口3初始化

    Uart4_Init(); //串口4初始化

    EA=1; //總中斷打開


    CLR_Buf3(); //清除串口3緩存

    CLR_Buf4(); //清除串口4緩存


    while(1)

    {

    UART3_4_Tx_Puts(); //UART3和UART4接收到字符串后發送出去

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    8.2.硬件連接

    圖26:串口3串口4實驗連接圖

    9.串口1串口2串口3串口4同時收發實驗

    9.1.編寫代碼

    首先,在uart.c文件中編寫串口1、串口2、串口3和串口4的初始化函數Uart1234_Init,代碼如下。

    程序清單:串口初始化函數

    /***************************************************************************

    * 描 述 : 串口1/2/3/4初始化函數

    * 入 參 : 無

    * 返回值 : 無

    備注:波特率9600bps 晶振11.0592MHz

    **************************************************************************/

    void Uart1234_Init(void)

    {

    //串口1配置

    PCON &=0x3f; //串口1波特率不倍速,串行口工作方式由SM0、SM1決定

    SCON=0x50; //串口1的8位數據,可變波特率,啟動串行接收器

    AUXR |=0x01; //串口1選擇定時器2為波特率發生器

    //串口2配置

    S2CON=0x50; //串口2的8位數據,可變波特率

    //串口3配置

    S3CON |=0x10; //串口3啟動串行接收器

    S3CON &=0x30; //串口3選擇定時器2為波特率發生器,8位數據,可變波特率

    //串口4配置

    S4CON |=0x10; //啟動串行接收器

    S4CON &=0x30; //8位數據,可變波特率,串口4選擇定時器2為波特率發生器


    //定時器2配置

    AUXR |=0x04; //定時器2時鐘為Fosc,即1T

    T2L=0xE0; //設定定時初值

    T2H=0xFE; //設定定時初值

    AUXR |=0x10; //啟動定時器2


    //打開串口中斷

    ES=1; //串口1中斷打開

    IE2 |=0x01; //串口2中斷打開

    IE2 |=0x08; //串口3中斷打開

    IE2 |=0x10; //串口4中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    然后,介紹下4個串口的握手函數,代碼如下。(串口1、串口2、串口3和串口4的發送函數、清緩存函數不作介紹)

    程序清單:串口1握手函數

    /******************************************************************************

    功能描述:握手成功與否函數

    入口參數:uint8 *a

    返回值:位

    ****************************************************************************/

    bit Hand1(uint8 *a)

    {

    if(strstr(Rec_Buf1,a)!=NULL) //判斷字符串a是否是字符串Rec_Buf1的子串

    return 1; //如果字符串a是字符串Rec_Buf1的子串

    else

    return 0; //如果字符串a不是字符串Rec_Buf1的子串

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口2握手函數

    /***************************************************************************

    功能描述:握手成功與否函數

    入口參數:uint8 *a

    返回值:位

    ****************************************************************************/

    bit Hand2(uint8 *a)

    {

    if(strstr(Rec_Buf2,a)!=NULL) //判斷字符串a是否是字符串Rec_Buf2的子串

    return 1; //如果字符串a是字符串Rec_Buf2的子串

    else

    return 0; //如果字符串a不是字符串Rec_Buf2的子串

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口3握手函數

    /*****************************************************************************

    功能描述:握手成功與否函數

    入口參數:uint8 *a

    返回值:位

    ************************************************************************/

    bit Hand3(uint8 *a)

    {

    if(strstr(Rec_Buf3,a)!=NULL) //判斷字符串a是否是字符串Rec_Buf3的子串

    return 1; //如果字符串a是字符串Rec_Buf3的子串

    else

    return 0; //如果字符串a不是字符串Rec_Buf3的子串

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    程序清單:串口4握手函數

    /***************************************************************************

    功能描述:握手成功與否函數

    入口參數:uint8 *a

    返回值:位

    ****************************************************************************/

    bit Hand4(uint8 *a)

    {

    if(strstr(Rec_Buf4,a)!=NULL) //判斷字符串a是否是字符串Rec_Buf4的子串

    return 1; //如果字符串a是字符串Rec_Buf4的子串

    else

    return 0; //如果字符串a不是字符串Rec_Buf4的子串

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    之后,編寫串口1、串口2、串口3和串口4的中斷服務函數,將接收的數據存放到用戶自定義數組Rec_Buf1、Rec_Buf2、Rec_Buf3和Rec_Buf4中,代碼如下。

    程序清單:串口1中斷服務函數

    /***************************************************************************

    * 描 述 : 串口1中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart1() interrupt 4 using 1

    {

    ES=0; // 串口1中斷關閉

    if (RI) //串行接收到停止位的中間時刻時,該位置1

    {

    RI=0; //清除RI位 (該位必須軟件清零)

    Rec_Buf1[i]=SBUF; //接收到的數存到接收數組中

    i++; //串口1接收數據個數變量累加

    if(i>Buf_Max) //判斷接收數據個數是否超限

    {

    i=0; //清零接收數據個數

    }

    }

    if (TI) //在停止位開始發送時,該位置1

    {

    TI=0; //清除TI位(該位必須軟件清零)

    }

    ES=1; // 串口1中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    程序清單:串口2中斷服務函數

    /***************************************************************************

    * 描 述 : 串口2中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart2() interrupt 8 using 1

    {

    IE2 &=0xFE; // 串口2中斷關閉

    if (S2CON & S2RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S2CON &=~S2RI; //清除S2CON寄存器對應S2RI位(該位必須軟件清零)

    Rec_Buf2[j]=S2BUF; //把串口2緩存SBUF寄存器數據依次存放到數組Rec_Buf2中

    j++; //串口2接收數據個數變量累加

    if(j>Buf_Max) //接收數大于定義接收數組最大個數時,覆蓋接收數組之前值

    {

    j=0; //清零串口2接收數據個數變量

    }

    }

    if (S2CON & S2TI) //在停止位開始發送時,該位置1

    {

    S2CON &=~S2TI; //清除S2CON寄存器對應S2TI位(該位必須軟件清零)

    }

    IE2 |=0x01; //串口2中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    程序清單:串口3中斷服務函數

    /***************************************************************************

    * 描 述 : 串口3中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart3() interrupt 17 using 1

    {

    IE2 &=0xF7; // 串口3中斷關閉

    if (S3CON & S3RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S3CON &=~S3RI; //清除S3CON寄存器對應S3RI位(該位必須軟件清零)

    Rec_Buf3[m]=S3BUF; //把串口3緩存SBUF寄存器數據依次存放到數組Rec_Buf3中

    m++; //串口3接收數據個數變量累加

    if(m>Buf_Max) //接收數大于定義接收數組最大個數時,覆蓋接收數組之前值

    {

    m=0; //清零串口3接收數據個數變量

    }

    }

    if (S3CON & S3TI) //在停止位開始發送時,該位置1

    {

    S3CON &=~S3TI; //清除S3CON寄存器對應S3TI位(該位必須軟件清零)

    }

    IE2 |=0x08; //串口3中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    程序清單:串口4中斷服務函數

    /***************************************************************************

    * 描 述 : 串口4中斷服務函數

    * 入 參 : 無

    * 返回值 : 無

    **************************************************************************/

    void Uart4() interrupt 18 using 1

    {

    IE2 &=0xEF; //串口4中斷關閉

    if(S4CON & S4RI) //串行接收到停止位的中間時刻時,該位置1

    {

    S4CON &=~S4RI; //清除S4CON寄存器對應S4RI位(該位必須軟件清零)

    Rec_Buf4[n]=S4BUF; //把串口4緩存SBUF寄存器數據依次存放到數組Rec_Buf4中

    n++; //串口4接收數據個數變量累加

    if(n>Buf_Max) //接收數大于定義接收數組最大個數時,覆蓋接收數組之前值

    {

    n=0; //清零串口4接收數據個數變量

    }

    }

    if(S4CON & S4TI) //在停止位開始發送時,該位置1

    {

    S4CON &=~S4TI; //清除S4CON寄存器對應S4TI位(該位必須軟件清零)

    }

    IE2 |=0x10; //串口4中斷打開

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    最后,主函數main在主循環中判斷對應串口接收到的字符串是不是規定的字符串,然后再發送另一串字符串。具體代碼如下。

    代碼清單:主函數

    int main()

    {

    P3M1 &=0xFE; P3M0 &=0xFE; //設置P3.0為準雙向口

    P3M1 &=0xFD; P3M0 |=0x02; //設置P3.1為推挽輸出

    P1M1 &=0xFE; P1M0 &=0xFE; //設置P1.0為準雙向口

    P1M1 &=0xFD; P1M0 |=0x02; //設置P1.1為推挽輸出

    P0M1 &=0xFA; P0M0 &=0xFA; //設置P0.0 P0.2為準雙向口

    P0M1 &=0xF5; P0M0 |=0x0A; //設置P0.1 P0.3為推挽輸出


    Uart1234_Init(); //串口1/2/3/4初始化

    EA=1; //總中斷打開

    CLR_Buf1(); //清除串口1緩存

    CLR_Buf2(); //清除串口2緩存

    CLR_Buf3(); //清除串口3緩存

    CLR_Buf4(); //清除串口4緩存


    while(1)

    {

    if(Hand1("UART1")) //串口1收到字符串UART1

    {

    CLR_Buf1(); //將串口1緩存數組的值都清為零

    ES=0; //串口1中斷關閉

    SendStringByUart1("UART1 CHECK OK!\r\n"); //串口1發送字符串UART1 CHECK OK!

    ES=1; //串口1中斷打開

    }

    if(Hand2("UART2")) //串口2收到字符串UART2

    {

    CLR_Buf2(); //將串口2緩存數組的值都清為零

    IE2 &=0xFE; //串口2中斷關閉

    SendStringByUart2("UART2 CHECK OK!\r\n"); //串口2發送字符串UART2 CHECK OK!

    IE2 |=0x01; //串口2中斷打開

    }

    if(Hand3("UART3")) //串口3收到字符串UART3

    {

    CLR_Buf3(); //將串口3緩存數組的值都清為零

    IE2 &=0xF7; //串口3中斷關閉

    SendStringByUart3("UART3 CHECK OK!\r\n"); //串口3發送字符串UART3 CHECK OK!

    IE2 |=0x08; //串口3中斷打開

    }

    if(Hand4("UART4")) //串口4收到字符串UART4

    {

    CLR_Buf4(); //將串口4緩存數組的值都清為零

    IE2 &=0xEF; //串口4中斷關閉

    SendStringByUart4("UART4 CHECK OK!\r\n"); //串口4發送字符串UART4 CHECK OK!

    IE2 |=0x10; //串口4中斷打開

    }

    }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    9.2.硬件連接

    圖28:4個串口同時通信實驗連接圖

    總結

    以上就是今天要講的內容,本文僅僅簡單介紹了:1、編寫程序實現單個串行口收發通信的程序設計;2、編寫程序實現多個串行口收發通信的程序設計。

    一、需要準備的工具

    表1:需要的工具軟件

    1.搭建開發環境所需工具在資料包中的位置:

    Keil C251 v5.60安裝文件:“…\第2部分:開發軟件工具\ 1 - KEIL C251安裝軟件”目錄下的“c251v560”。

    ch341ser驅動:“…\第2部分:開發軟件工具\ 3 - CH340驅動程序” 目錄下的“ch341ser”。

    stc-isp-15xx-v6.90D軟件:位于“…\第2部分:開發軟件工具\ 2 - STC-ISP下載軟件”目錄下的“stc-isp-15xx-v6.90D”。

    2.注意事項:

    Keil的安裝路徑不宜太深,安裝路徑不可有中文。(并非安裝路徑有中文就一定會出問題,只能說安裝路徑使用全是較簡潔的英文會大大降低安裝出錯的概率,請知悉!)

    用戶在安裝Keil C251前電腦可能已經安裝有了Keil C51版本的軟件,建議將Keil C251安裝在其他盤的目錄下。

    stc-isp-15xx-v6.90D軟件無需安裝,直接雙擊打開即可使用。

    二、搭建Keil開發環境

    1.Keil C251簡介

    Keil C251是美國Keil公司(該公司2005年被ARM公司收購)出品的針對251微控制器系列兼容單片機C語言軟件開發系統。

    與匯編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。Keil提供了包括C編譯器、宏匯編、連接器、庫管理和一個功能強大的仿真調試器等在內的完整開發方案,通過一個集成開發環境(uVision)將這些部分組合在一起。Keil C251是支持251微控制器體系結構的Keil開發工具,適合每個階段的開發人員,不管是專業的應用工程師,還是剛學習嵌入式軟件開發的學生。

    擴展:Keil公司開發的ARM開發工具MDK(Microcontroller Development Kit),是用來開發基于ARM核的系列微控制器的嵌入式應用程序。

    本文檔中使用的Keil C251版本是5.60,打開后的主界面如圖所示。

    圖1:Keil C251主界面

    2.安裝Keil C251

    開發板配套資料包里面已經下載好了Keil C251安裝文件,安裝文件的位置在開發板資料包的“…\第2部分:開發軟件工具\ 1 - KEIL C251安裝軟件”目錄下。

    1.解壓壓縮文件c251v560,雙擊打開 “c251v560.exe”,彈出 Keil C251 V5.60的安裝向導,單擊【Next】,如下圖所示。

    圖2:打開Keil C251安裝軟件

    2.勾選【I agree to …】,然后點擊【Next】,如下圖所示。

    圖3:勾選Keil C251安裝協議

    3.選擇安裝路徑,如下圖所示。

    此處,可以根據自己的需要選擇安裝路徑,本文檔設置的安裝路徑是C:\Keil_v5,即安裝在C盤。(也可選擇安裝路徑是D:\Keil_v5)

    圖4:添加Keil C251安裝路徑

    ☆注:用戶可安裝在默認路徑下,可以省去一些不必要的麻煩。如果用戶安裝在其他路徑,要注意路徑不宜過深,并且路徑中不要出現帶有中文的文件夾。

    4.根據提示填入相關用戶信息,然后點擊【Next】, 如下圖所示。

    圖5:填寫Keil C251安裝信息

    ☆說明:未注冊版本有2K的代碼限制,當超過2K時,是無法編譯工程的。

    5.Keil C251開始安裝,等待Keil C251安裝完成,如下圖所示。

    圖6:Keil C251安裝中

    6.點擊【Finish】完成安裝,如下圖所示。

    圖7:Keil C251安裝完后

    3.安裝ch341ser驅動

    開發板上設計了USB轉TTL電路,使用的USB轉串口芯片是CH340,使用前需要安裝驅動。

    ☆說明:如果計算機上已經安裝了CH340的驅動,則無需再安裝,可直接跳過此步驟。

    CH340和CH341的驅動一樣,開發板配套資料包里面已經下載好了驅動,驅動的位置在開發板資料包的“…\第2部分:開發軟件工具\ 3 - CH340驅動程序(支持WIN10)” 目錄下。

    1.解壓壓縮文件ch341ser,雙擊打開 “ch341ser.exe”,出現下面界面,點擊安裝。

    圖8:打開CH340驅動軟件

    ☆說明:安裝USB轉串口驅動失敗的處理方法。

    用Type-C USB數據線將開發板J1連接到電腦的USB口,并將開發板上的電源開關撥到“ON”的位置,確認開發板的電源指示燈已經點亮后,再安裝USB轉串口驅動即可。

    2.查看CH340的端口號:

    需要使用USB數據線連接電腦和開發板并打開開發板上的電源開關后才能查看。

    選中“我的電腦”后右鍵打開屬性窗口,再打開設備管理器,在設備管理器中查看CH340的端口號,如下圖所示。

    圖9:設備管理器中查看CH340設備

    4.stc-isp-15xx-v6.90D軟件安裝使用

    STC-ISP-15xx是 STC(宏晶科技)針對STC單片機提供的專用的ISP下載軟件, STC-ISP-15xx使用簡便,并且集成了眾多的實用工具,如串口調試助手、波特率和定時器計算工具等,現已被廣泛使用。該軟件版本會在STC官網上不斷更新,用戶后續可查看并下載最新版本,STC官網:http://www.stcmcudata.com/

    開發板配套資料包里面已經下載好了stc-isp-15xx-v6.90D安裝文件,安裝文件的位置在開發板資料包的位于“…\第2部分:開發軟件工具\ 2 - STC-ISP下載軟件”目錄下。

    STC-ISP-15xx是綠色軟件,無需安裝,解壓后即可使用,但是我們需要使用STC-ISP-15xx軟件將STC器件/頭文件和仿真驅動添加到keil,否則,keil里面是找不到對應的芯片的,操作步驟如下。

    解壓壓縮文件stc-isp-15xx-v6.90D,雙擊“stc-isp-15xx-v6.90D.exe” 打開STC-ISP-15xx軟件,打開后,會彈出產品通知信息窗口,如果下圖所示,點擊[關閉]按鈕關閉通知窗口即可。

    圖10:打開STC-ISP軟件

    打開“keil仿真設置”選項卡,點擊“添加型號和頭文件到keil中…”按鈕添加。

    圖11:添加頭文件和仿真設置

    ☆說明:無論開發板選擇的是不是仿真型芯片,都需要進行此步操作。

    在彈出的窗口中導航到keil C251的安裝文件夾,選中文件夾后點擊[確定],添加成功后會彈出提示窗口,如下圖所示。

    圖12:添加頭文件和仿真設置成功

    三、Keil常用操作

    1.批量注釋和批量取消注釋

    在編寫和調試程序的時候,我們經常會遇到需要注釋代碼塊的情況(多行代碼),這里我們給出兩種常用的批量注釋方法。

    1.第一種方法:使用菜單欄中的快捷按鈕

    批量注釋方法:先選中需要注釋的代碼,然后點擊下圖中紅框內的按鈕即可批量注釋代碼。

    圖13:批量注釋

    取消批量注釋方法:先選中需要取消注釋的代碼,然后點擊下圖中紅框內的按鈕即可批量取消代碼注釋。

    圖14:批量取消注釋

    2.第二種方法:使用條件編譯

    下圖中使用條件編譯命令“#if…endif”注釋了36、37、38行這三行代碼,如果要取消注釋,把0改為1即可,這種方法簡單快捷,在調試中很實用。

    圖15:使用條件編譯命令注釋代碼塊

    2.返回/前進

    瀏覽程序的時候,經常需要返回到上次瀏覽的位置或者前進到上次返回的位置,這時,可以使用下圖所示的快捷按鍵。

    圖16:前進和返回

    3.跳轉到變量或函數定義位置

    開發和調試程序時,經常需要查看一些變量或函數的定義,這時可以按照下圖所示的方法跳轉到變量或函數定義的位置,查看變量或函數。

    ☆說明:必須編譯成功后才可以跳轉。

    圖17:跳轉到變量或函數定義位置

    4.查找所有包含目標字符的出處

    開發和調試程序時,查找功能是必不可少的,keil C251中使用查找功能的步驟如下(以在整個工程中查找為例說明)。

    1.選中待查找的內容(也可以打開查找窗口后手動輸入查找內容),然后點擊菜單欄中的“Edit”,在彈出的下拉菜單中點擊“Find in files”打開查找窗口,如下圖所示。(也可鍵盤操作快捷鍵CTrl+F)

    圖18:打開查找窗口

    2.設置查找選項(這里設置:在文件中查找,查找條件是全文匹配,查找范圍為整個工程),之后點擊“Find All”按鈕,如下圖所示。

    圖19:查找窗口

    3.查看結果:Keil信息窗口中會顯示查找的結果,如下圖所示。

    圖20:查找結果

    5.快速打開工程map文件

    map文件將單片機存儲器的使用情況以及變量的信息展示給開發人員,通過分析map文件,開發人員可以了解往往可幫忙解決許多棘手的問題。map文件快遞打開方法如下圖所示。

    ☆說明:工程編譯成功后,才會生成map文件,因此工程必須編譯后才能打開map文件。

    圖21:打開工程map文件

    四、常見問題及解決辦法

    1.工程無法編譯

    1.現象:打開工程時,編譯按鈕等均無法點擊,出現下圖所示界面。

    圖22:提示信息

    2.原因:使用Keil C51打開了Keil C251的工程。

    3.解決方法:安裝Keil C251軟件。

    ☆注:我們電腦里面可能也安裝了用于開發ARM 的keil MDK,如果用MDK打開了Keil C251的工程,也會導致工程無法編譯。

    2.編譯時提示代碼超限

    1.現象:Keil C251編譯工程,出現如下圖所示信息。

    圖23:編譯報錯

    2.原因:Keil C251沒有注冊,未注冊版本有代碼限制,所以工程較大超出2K后編譯會報錯。

    3.解決方法: 注冊Keil C251。

    3.無法跳轉到函數或者變量的定義

    當我們在keil中選中函數或者變量右鍵跳轉到定義的時候,彈出錯誤提示“無可用的瀏覽信息”,從而無法跳轉,如下圖所示。

    圖24:無法跳轉到定義

    原因主要有以下兩個方面:

    1.工程沒有編譯或者程序中有錯誤,沒有編譯成功:這種情況下,編譯工程成功后,即可跳轉到定義。

    2.Browse information沒有勾選:點擊魔術棒,,如下圖所示。

    圖25:點擊魔術棒

    在彈出的對話框中切換到output選項卡,之后勾選“Browse information”選項,勾選后需要重新編譯工程。

    圖26:勾選“Browse information”選項

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有