MM32F0020 UART1硬體自動波特率的使用

Armny發表於2022-03-31

目錄:

1.MM32F0020簡介

2.UART自動波特率校準應用場景

3.MM32F0020 UART自動波特率校準原理簡介

4.MM32F0020 UART1 NVIC硬體自動波特率配置以及初始化

5.編寫MM32F0020 UART1傳送資料函式

6.編寫MM32F0020 UART1中斷接收函式以及自動波特率校準的實現

7.編寫MM32F0020 UART1處理中斷接收資料函式

8.驗證MM32F0020 UART1自動波特率校準功能

提要:

  學習MM32F0020 UART自動波特率校準功能的使用。例如:上位機串列埠除錯助手UART通訊波特率為19200,往下位機UART1波特率為9600的MM32F0020 傳送一幀資料:

0xF8 0x55 0x2 0x03 0x04 0x05 0x06 0x07;下位機通過UART內部硬體自動檢測接收到資料幀的首位元組的位寬的波特率時間來識別上位機的波特率,並重置下位機MCU的波特率

暫存器使得下位機MCU的波特率與上位機的通訊波特率一致,從而實現資料幀的正常收發(注意:上位機與下位機的通訊波特率不應相差太大,否則無法自動檢測識別)。

本部落格為原創文章,轉載請註明出處!!!

內容:

1、MM32F0020簡介

(1)MM32F0020微控制器是基於Arm® Cortex®-M0核心,最高工作頻率可達48MHz;

(2)供電電壓支援:2.0V - 5.5V;

(3)多達32KB的Flash,2KB的SRAM;

(4)1個I2C;

(5)2個UART;

(6)1個12位的共8通道的ADC;

(7)1個I2C或I2S;

(8)1個16位高階定時,1個16位通用定時器,1個16位基本定時器;

(9)1個IWDG和一個WWDG看門狗。

2.UART自動波特率校準應用場景

  嵌入式軟體工程師在開發產品時,經常會用到MCU的UART串列埠模組做產品功能方面的除錯或主從機通訊,當產品的主從機通訊波特率有偏差時,或經過TTL電平轉換電路轉換後波特率出現

偏差或產品的工作環境相對比較惡劣時也會出現UART的主從機通訊波特率偏差,這時如果MCU的UART內部整合了自動波特率檢測校準功能,就能通過自動波特率檢測校準從而維持MCU的UART

主從機的正常通訊功能。

3.MM32F0020 UART自動波特率校準原理簡介

  MM32F0020系列MCU的UART內部整合了硬體自動波特率檢測電路,自動檢測接收到資料幀的首位元組的位寬波特率時間來識別通訊方的波特率引數,並重置MCU的UART波特率暫存器,使得通訊雙方儲存通訊波特率一致。

4.MM32F0020 UART1 NVIC硬體自動波特率配置以及初始化

  MM32F0020 UART1的GPIO初始化,根據MM32F0020的DS資料手冊選擇PA12:UART1_TX,PA3:UART1_RX做為UART1的傳送和接收資料的引腳,具體配置步驟,及其初始化如下所示:

(1)使能GPIOA外設時鐘;

(2)配置IO管腳GPIO_AFx複用為UART1功能;

(3)配置UARTx IO的管腳;

(4)配置GPIO的輸出速度;

(5)配置IO管腳的工作模式;

(6)根據GPIOA配置的引數整體初始化GPIO各管腳的成員引數。

void Bsp_UART1_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    //Enable GPIOA Clock
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); 
    //PA3 AF UART1_RX
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_1);
    //PA12 AF UART1_TX
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_1);

    //PA12:UART1_TX   
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    //PA3:UART1_RX    
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

  MM32F0020 UART1 NVIC硬體自動波特率配置以及初始化步驟如下所示:

(1)使能UART1外設時鐘;

(2)呼叫之前配置的UART1GPIO初始化函式;

(3)配置UART1通訊波特率為9600;

(4)配置UART1字長為8位;

(5)配置UART1收發資料為1位停止位;

(6)配置UART1收發資料為無奇偶校驗位;

(7)配置UART1允許串列埠收發資料;

(8)根據以上配置引數初始化UART1結構體成員;

(9)配置UART1硬體自動波特率檢測首位元組的位寬(包含起始位寬)的長度和檢測的邊緣模式,可從UM手冊UART_ABRCR自動波特率暫存器相關位查詢到如下圖1所示,本例項檢測首位元組的

邊緣選擇前一個邊沿為下降沿(包含起始位)後一個邊沿為上升沿,符合這個條件的位元組為0xF8(b:1111 1000)等。

                     圖1

(10)使能UART1接收資料中斷、接收幀錯誤中斷、自動波特率結束中斷、自動波特率錯誤中斷、空閒中斷;

(11)配置UART1的NVIC中斷優先順序為0,並使能和初始化NVIC中斷(優先順序為0-3均可,引數越小優先順序越高)。

MM32F0020 UART1 NVIC硬體自動波特率配置以及初始化程式碼如下所示:

void Bsp_UART1_NVIC_Init(u32 baudrate)
{
    UART_InitTypeDef UART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;  
    //Enable UART1 Clock
    RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART1, ENABLE);
    //UART1 GPIO Init
    Bsp_UART1_GPIO_Init();
    
    UART_StructInit(&UART_InitStruct);
    //Baud rate
    UART_InitStruct.BaudRate = baudrate;
    //The word length is in 8-bit data format.
    UART_InitStruct.WordLength = UART_WordLength_8b;
    //One stop bit
    UART_InitStruct.StopBits = UART_StopBits_1;
    //No even check bit.
    UART_InitStruct.Parity = UART_Parity_No;
    //No hardware data flow control.
    UART_InitStruct.HWFlowControl = UART_HWFlowControl_None;
    UART_InitStruct.Mode = UART_Mode_Rx | UART_Mode_Tx;   
    UART_Init(UART1, &UART_InitStruct);

    //___                   _______
    //   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test
    UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);
    
    //接收資料中斷、接收幀錯誤中斷、自動波特率結束中斷、自動波特率錯誤中斷、空閒中斷、
    //Enable Receive data interrupt、Receive frame error interrupt、Automatic baud rate end interrupt、
    //Automatic baud rate error interrupt、Idle interrupt    
    UART_ITConfig(UART1,UART_IT_RXIEN | UART_IER_RXFERR | UART_IER_ABREND_IEN | \
    UART_IER_ABRERR_IEN | UART_IER_RXIDLE,ENABLE);                    
    
    //UART1 NVIC IRQ Channel
    NVIC_InitStruct.NVIC_IRQChannel = UART1_IRQn;
    //UART1 Priority
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    //Enable UART1_IRQn
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(& NVIC_InitStruct);   
    //Enable UART1
    UART_Cmd(UART1, ENABLE);
}

5.編寫MM32F0020 UART1傳送資料函式

(1)MM32F0020 UART1傳送位元組函式如下所示:

void Bsp_UART_SendByte(UART_TypeDef* uart,u8 data)
{
    UART_SendData(uart,data);
    while(!UART_GetFlagStatus(uart, UART_FLAG_TXEPT));
}

(2)MM32F0020  UART1傳送多位元組函式如下所示:

void Bsp_UART_SendBytes(UART_TypeDef* uart,u8 *buf, u16 len)
{
    while(len--)
    {
        Bsp_UART_SendByte(uart,*buf++);
    }
}

(3)MM32F0020  UART1傳送ASCII字串函式如下所示:

void Bsp_UART_SendString(UART_TypeDef* uart,char *str)
{
    while(*str)
    {
        Bsp_UART_SendByte(uart,*str++);
    }
}

6.編寫MM32F0020 UART1中斷接收函式以及自動波特率校準的實現

(1)定義與MM32F0020 UART1相關的變數,快取,以及標頭檔案變數、函式宣告,程式碼如下所示:

//UART1 Receive count
u8 gUART1_Rx_Cnt = 0;  
//UART1 Receive Buffer 
u8 gUART1_Rx_Buf[UART1_REC_LEN];      
//UART1 Receiving Flag
bool gUART1_Rx_Flag = false;
//Hardware automatic baud rate error flag
u8 Auto_BaudRate_FraErr_Flag = 0;
//注:上位機串列埠助手傳送如下資料幀格式第1位元組為波特率檢測位寬,第2位元組之後為可變位元組方便觀察收發資料幀
/***************************************************************************************************
--------------Falling edge to rising edge(including start bit)--------------------------------------
//The first byte is 0xF8 use test
//___                   _______
//   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
//AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test
串列埠上位機傳送資料格式:
0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
下位機分別給串列埠上位機原樣回覆收到的資料命令:
0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 
***************************************************************************************************/

//UART1 Baud Rate
#define UART1_BAUDRATE  (9600)
//UART1 maximum receiving length 200       
#define UART1_REC_LEN   (200) 
     
//UART1 Receive Buffer 
extern u8 gUART1_Rx_Buf[UART1_REC_LEN]; 
//UART1 Receive count
extern u8 gUART1_Rx_Cnt;  
//UART1 Receive Timing
//extern u8 UART1_Rx_TimeCnt;
//UART1 Receiving Flag
extern bool gUART1_Rx_Flag;


//UART1 NVIC Init
void Bsp_UART1_NVIC_Init(u32 baudrate);
//Process UART1 Recv Task
void Bsp_UART1_Recv_Task(void);
//UART sends a byte data
void Bsp_UART_SendByte(UART_TypeDef* uart,u8 data);
//Send ASCII characters
void Bsp_UART_SendString(UART_TypeDef* uart,char *str);
//UART sends multi-byte data
void Bsp_UART_SendBytes(UART_TypeDef* uart,u8 *buf, u16 len);

(2)MM32F0020 UART1中斷接收函式以及自動波特率校準程式碼如下所示:

void Bsp_UART1_NVIC_Init(u32 baudrate)
{
    UART_InitTypeDef UART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;  
    //Enable UART1 Clock
    RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART1, ENABLE);
    //UART1 GPIO Init
    Bsp_UART1_GPIO_Init();
    
    UART_StructInit(&UART_InitStruct);
    //Baud rate
    UART_InitStruct.BaudRate = baudrate;
    //The word length is in 8-bit data format.
    UART_InitStruct.WordLength = UART_WordLength_8b;
    //One stop bit
    UART_InitStruct.StopBits = UART_StopBits_1;
    //No even check bit.
    UART_InitStruct.Parity = UART_Parity_No;
    //No hardware data flow control.
    UART_InitStruct.HWFlowControl = UART_HWFlowControl_None;
    UART_InitStruct.Mode = UART_Mode_Rx | UART_Mode_Tx;   
    UART_Init(UART1, &UART_InitStruct);

    //___                   _______
    //   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test
    UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);
    
    //接收資料中斷、接收幀錯誤中斷、自動波特率結束中斷、自動波特率錯誤中斷、空閒中斷、
    //Enable Receive data interrupt、Receive frame error interrupt、Automatic baud rate end interrupt、
    //Automatic baud rate error interrupt、Idle interrupt    
    UART_ITConfig(UART1,UART_IT_RXIEN | UART_IER_RXFERR | UART_IER_ABREND_IEN | \
    UART_IER_ABRERR_IEN | UART_IER_RXIDLE,ENABLE);                    
    
    //UART1 NVIC IRQ Channel
    NVIC_InitStruct.NVIC_IRQChannel = UART1_IRQn;
    //UART1 Priority
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    //Enable UART1_IRQn
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(& NVIC_InitStruct);   
    //Enable UART1
    UART_Cmd(UART1, ENABLE);
}

7.編寫MM32F0020 UART1處理中斷接收資料函式

  MM32F0020 UART1處理中斷接收資料函式程式碼如下所示:

void UART1_IRQHandler(void)
{
    u8 Recbyte;
    
    //UART1 receive interrupt,receive valid data interrupt flag bit
    if(UART_GetITStatus(UART1,UART_ISR_RX) != RESET)         
    {
        //Clear UART1 receive interrupt flag      
        UART_ClearITPendingBit(UART1,UART_ICR_RX);
        
        //Read the data received by UART1
        Recbyte = UART_ReceiveData(UART1);
        
        //UART1 receive data buffered
        gUART1_Rx_Buf[gUART1_Rx_Cnt] = Recbyte;
        
        //Determine whether the received data of UART1 overflows
        if(gUART1_Rx_Cnt < UART1_REC_LEN-1)
        {
            //UART1 Receive count
            gUART1_Rx_Cnt++;
        }
        else
        {
            gUART1_Rx_Cnt = 0;
        }
    }  
    //Receive data frame error interrupt flag 
    if(UART_GetITStatus(UART1, UART_ISR_RXFERR_INTF) != RESET)    
    {            
        //Hardware automatic baud rate error flag
        Auto_BaudRate_FraErr_Flag = 1;        
        UART_ClearITPendingBit(UART1,UART_ICR_RXFERRCLR);
    }
    //Idle interrupt hardware automatic baud rate self-calibration  
    if(UART_GetITStatus(UART1, UART_ISR_RXIDLE) != RESET)    
    {
        UART_ClearITPendingBit(UART1,UART_ICR_RXIDLE);
        
        //Hardware automatic baud rate error flag
        if(Auto_BaudRate_FraErr_Flag == 1)
        {
            Auto_BaudRate_FraErr_Flag = 0;          
//-------------------------------------Check MM32F0140 UART_AutoBaudRateHard--------------------------------------------------------- 
//Configure MM32F013x hardware automatic baud rate self-calibration,Falling edge to rising edge(including start bit)               
            //___                   _______
            //   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
            //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test
            UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);
        }
        //UART1 Receiving Flag
        gUART1_Rx_Flag = true;
    }   
    //Automatic baud rate error clear bit
    if(UART_GetITStatus(UART1, UART_ISR_ABRERR_INTF) != RESET)    
    {   //Auto baud rate error clear bit   
        UART_ClearITPendingBit(UART1,UART_ICR_ABRERRCLR);  
    }    
    //Automatic baud rate end interrupt clear bit
    if(UART_GetITStatus(UART1, UART_ISR_ABREND_INTF) != RESET)     
    {
        //Auto baud rate end clear bit
        UART_ClearITPendingBit(UART1,UART_ICR_ABRENDCLR);
    }
}

8.驗證MM32F0020 UART1自動波特率校準功能

(1)在main函式初始化中呼叫UART1 NVIC硬體自動波特率檢測初始化函式即Bsp_UART1_NVIC_Init(UART1_BAUDRATE);呼叫LED初始化函式用於指示收到資料後做狀態翻轉,在while(1)

主迴圈中迴圈檢測MM32F0020 UART1處理中斷接收資料函式,程式碼如下所示:

int main(void)
{
    //LED Init
    LED_Init();
    //UART1 NVIC Init Baudrate 115200
    Bsp_UART1_NVIC_Init(UART1_BAUDRATE);
    
    while(1) 
    {
        //Test UART1 Recv IDLE
        Bsp_UART1_Recv_Task();
    }
}

(2)驗證MM32F0020 UART1自動波特率校準功能

驗證說明:

  以上MCU的UART預設初始化的通訊波特率為9600,通過改變上位機串列埠除錯助手的通訊波特率分別設定為:19200,38400,57600,115200並分別傳送如下資料幀:

//注:上位機串列埠助手傳送如下資料幀格式第1位元組為波特率檢測位寬,第2位元組之後為可變位元組方便觀察收發資料幀
/***************************************************************************************************
--------------Falling edge to rising edge(including start bit)--------------------------------------
//The first byte is 0xF8 use test
//___                   _______
//   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
//AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test
串列埠上位機傳送資料格式:
0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
下位機分別給串列埠上位機原樣回覆收到的資料命令:
0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 
***************************************************************************************************/

  如果下位機MCU檢測到資料幀的首位元組前一個邊沿為下降沿,後一個邊沿為上升沿的4個位寬的資料,例如0xF8(含起始位b:1111 1000)晶片內部波特率自動檢測電路識別首位元組的波特率位寬,

並重置MCU的UART波特率暫存器,以達到MCU的通訊波特率與上位機的通訊分別一致,並原樣回覆收到的資料給上位機串列埠助手顯示出來,測試結果如下圖2,圖3,圖4,圖5所示:

圖1 如上串列埠助手顯示MM32F0020的UART1已自動檢測到19200波特率並列印出收到的正確資料

圖2 如上串列埠助手顯示MM32F0020的UART1已自動檢測到38400波特率並列印出收到的正確資料

圖3 如上串列埠助手顯示MM32F0020的UART1已自動檢測到57600波特率並列印出收到的正確資料

圖4 如上串列埠助手顯示MM32F0020的UART1已自動檢測到115200波特率並列印出收到的正確資料

總結:

  學習MM32F0020 UART自動波特率校準功能的使用。例如:上位機串列埠除錯助手UART通訊波特率為19200,往下位機UART1波特率為9600的MM32F0140 傳送一幀資料:

0xF8 0x55 0x2 0x03 0x04 0x05 0x06 0x07;下位機通過UART內部硬體自動檢測接收到資料幀的首位元組的位寬波特率的時間來識別上位機的波特率,並重置下位機MCU的波特率

暫存器使得下位機MCU的波特率與上位機的通訊波特率一致,從而實現資料幀的正常收發(注意:上位機與下位機的通訊波特率不應相差太大,否則無法自動檢測識別)。

注意事項:

  (1)MM32F0020每個外設都有自己獨立的時鐘,需使能UART1 傳送和接收引腳的GPIO時鐘;

  (2)使能UART1外設時鐘;

  (3)配置GPIOA的 PA3和PA12複用成UART1功能

  (4)接收資料中斷、接收幀錯誤中斷、自動波特率結束中斷、自動波特率錯誤中斷、空閒中斷;

  (5)使能UART1自動波特率檢測資料幀首位元組的邊緣模式前一個邊沿為下降沿,後一個邊沿為上升沿(具體組合可檢視UM手冊)並設定檢測首位元組的檢測位寬(可設定1,2,4或8位寬)

      本例項4位寬檢測的首位元組為0xF8;

  (6)使能UART1 NVIC中斷;

  (7)驗證MM32F0020 UART1自動波特率校準功能時記得切換上位機助手的通訊波特率,記得設定首位元組為0xF8(本例項);

  (8)UART2操作方法與UART1的方法一樣,可參考以上UART1把對應的UART1引數改成UART2,使能相應外設時鐘編寫對應中斷函式即可。

 

相關文章