嵌入式工程師在開(kāi)發(fā)產(chǎn)品中經(jīng)常會(huì)用到MCU的片上UART和其它模塊進(jìn)行通信,為了在某些非正常的惡劣環(huán)境下能正常使用串口通信,可能需要對(duì)UART通信波特率進(jìn)行自適應(yīng)校準(zhǔn),在我們之前的微課堂中講解過(guò)關(guān)于MM32通用MCU的UART串口通信方面的基礎(chǔ)知識(shí),這里我們?cè)黾踊?a target="_blank">靈動(dòng)微電子MM32F013x 系列UART硬件自適應(yīng)波特率的使用。
1、原理
UART硬件波特率自適應(yīng)檢測(cè)首個(gè)通信字節(jié)的位寬(1bit、2bit、4bit、8bit),檢測(cè)前一個(gè)邊沿和后一個(gè)邊沿之間的位長(zhǎng),即檢測(cè)前一個(gè)邊沿為下降沿,后一個(gè)邊沿為上升沿或前一個(gè)邊沿為下降沿,后一個(gè)邊沿為下降沿,可通過(guò)軟件靈活配置。
本實(shí)例以串口工具作為上位機(jī),MM32F013x的UART1作為下位機(jī),MCU端初始化為非標(biāo)準(zhǔn)波特率9200,使能空閑中斷及其他狀態(tài)標(biāo)志位,上位機(jī)切換不同的波特率,由于上位機(jī)和MCU端的波特率不同,可能出現(xiàn)通信失敗的情況,啟動(dòng)UART硬件波特率自適應(yīng)功能,即檢測(cè)上位機(jī)發(fā)的首個(gè)字節(jié)位寬來(lái)識(shí)別上位機(jī)的波特率,MCU端通過(guò)硬件波特率自適應(yīng)切換到對(duì)應(yīng)的波特率,與上位機(jī)維持后續(xù)正常的通信。
如下圖所示,以首字節(jié)0XF8為例,首字節(jié)位寬為4bit的原理說(shuō)明:

2、程序配置
2.1 初始化MM32F013x UART1串口
從官網(wǎng)下載MM32F013x例程,這里我們?cè)贛M32F0133C7P的樣例程序中添加注釋并對(duì)代碼修改。
#include "bsp_UART.h" #include "led.h" /******************************************************************************* * 函數(shù)名稱:void bsp_UART1_Init(u32 baudrate) * 函數(shù)功能:初始化UART1 PA9/PA10分別作為UART1的TX/RX * 輸入?yún)?shù):無(wú) * 返回?cái)?shù)值:無(wú) ******************************************************************************/ void bsp_UART1_Init(u32 baudrate) { //GPIO初始化結(jié)構(gòu)體 GPIO_InitTypeDef GPIO_InitStructure; //UART初始化結(jié)構(gòu)體 UART_InitTypeDef UART_InitStructure; //NVIC初始化結(jié)構(gòu)體 NVIC_InitTypeDef NVIC_InitStructure; //使能UART1時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE); //使能GPIOA時(shí)鐘 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //開(kāi)啟GPIOA PA9復(fù)用于UART1_TX功能 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1); //開(kāi)啟GPIOA PA10復(fù)用于UART1_RX功能 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1); //UART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //配置GPIOA.9 速度為高速50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置GPIOA.9為復(fù)用推挽輸出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //根據(jù)GPIO結(jié)構(gòu)體初始化UART1_TX GPIOA.9 GPIO_Init(GPIOA, &GPIO_InitStructure); //UART1_RX GPIOA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //配置UART1_RX GPIOA.10為上拉輸入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //根據(jù)GPIO結(jié)構(gòu)體初始化UART1_RX GPIOA.10 GPIO_Init(GPIOA, &GPIO_InitStructure); //串口波特率 UART_InitStructure.UART_BaudRate = baudrate; //字長(zhǎng)為8位數(shù)據(jù)格式 UART_InitStructure.UART_WordLength = UART_WordLength_8b; //一位停止位 UART_InitStructure.UART_StopBits = UART_StopBits_1; //無(wú)奇偶校驗(yàn)位 UART_InitStructure.UART_Parity = UART_Parity_No; //無(wú)硬件數(shù)據(jù)流控 UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; //允許收發(fā)模式 UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; //根據(jù)UART結(jié)構(gòu)體初始化串口UART1 UART_Init(UART1, &UART_InitStructure); //硬件自動(dòng)波特率檢測(cè)第1個(gè)字節(jié)位的位寬前一個(gè)邊沿為下降沿,后一個(gè)邊沿為上升沿 //___ _______ // |_ _ _ _|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); //接收數(shù)據(jù)中斷、接收幀錯(cuò)誤中斷、自動(dòng)波特率結(jié)束中斷、自動(dòng)波特率錯(cuò)誤中斷、空閑中斷 UART_ITConfig(UART1, UART_IT_RXIEN | UART_ICR_RXFERRCLR | UART_ICR_ABRENDCLR |\ UART_ICR_ABRERRCLR | UART_ICR_RXIDLE | UART_IT_ERR, ENABLE); //使能UART1 UART_Cmd(UART1, ENABLE); //UART1 NVIC中斷優(yōu)先級(jí)設(shè)置 NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn; //UART通道優(yōu)先級(jí)0 NVIC_InitStructure.NVIC_IRQChannelPriority = 0; //IRQ通道使能 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //根據(jù)指定的參數(shù)初始化NVIC寄存器 NVIC_Init(&NVIC_InitStructure); }
2.2 編寫(xiě)MM32F013x UART1串口中斷服務(wù)函數(shù)
繼續(xù)在bsp_UART.c文件中編寫(xiě)MM32F013x UART1串口中斷服務(wù)函數(shù)如下所示。
/*******************************************************************************
* 函數(shù)名稱:void UART1_IRQHandler(void)
* 函數(shù)功能:串口1 UART1中斷服務(wù)程序
* 輸入?yún)?shù):無(wú)
* 返回?cái)?shù)值:無(wú)
*******************************************************************************/
//自動(dòng)波特率幀錯(cuò)誤標(biāo)志
u8 Auto_BaudRate_FraErr_Flag = 0;
void UART1_IRQHandler(void)
{
u8 Res;
//UART1接收中斷
if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)
{
//清UART1接收中斷標(biāo)志
UART_ClearITPendingBit(UART1,UART_IT_RXIEN);
//讀取UART1接收到的數(shù)據(jù)
Res = UART_ReceiveData(UART1);
//UART1接收數(shù)據(jù)緩存起來(lái),最大接收UART1_REC_LEN個(gè)字節(jié)
UART1_Rx_Buf[UART1_Rx_Cnt] = Res;
//UART1作接收緩存溢出判斷,最大接收UART1_REC_LEN個(gè)字節(jié)
if(UART1_Rx_Cnt < UART1_REC_LEN-1)
{
//還有數(shù)據(jù)要接收,接收計(jì)數(shù)變量自加
UART1_Rx_Cnt++;
}
else
{
UART1_Rx_Cnt = 0;
}
}
//幀錯(cuò)誤中斷標(biāo)志位
if(UART_GetITStatus(UART1, UART_IER_RXFERR) != RESET)
{
//自動(dòng)波特率幀錯(cuò)誤標(biāo)志置1
Auto_BaudRate_FraErr_Flag = 1;
//清幀錯(cuò)誤中斷標(biāo)志位
UART_ClearITPendingBit(UART1,UART_IER_RXFERR);
}
//接收數(shù)據(jù)幀錯(cuò)誤中斷
if(UART_GetITStatus(UART1, UART_ICR_RXFERRCLR) != RESET)
{
UART_ClearITPendingBit(UART1,UART_ICR_RXFERRCLR);
}
//空閑中斷硬件波特率自校準(zhǔn)
if(UART_GetITStatus(UART1, UART_ICR_RXIDLE) != RESET)
{
UART_ClearITPendingBit(UART1,UART_ICR_RXIDLE);
//自動(dòng)波特率幀錯(cuò)誤標(biāo)志
if(Auto_BaudRate_FraErr_Flag == 1)
{
Auto_BaudRate_FraErr_Flag = 0;
//----------------Check MM32F013x UART_AutoBaudRateHard----------
//___ _______
// |_ _ _ _|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);
}
}
//自動(dòng)波特率錯(cuò)誤中斷清除位
if(UART_GetITStatus(UART1, UART_ICR_ABRERRCLR) != RESET)
{
UART_ClearITPendingBit(UART1,UART_ICR_ABRERRCLR);
}
//自動(dòng)波特率結(jié)束中斷清除位
if(UART_GetITStatus(UART1, UART_ICR_ABRENDCLR) != RESET)
{
UART_ClearITPendingBit(UART1,UART_ICR_ABRENDCLR);
}
}
2.3 MM32F013x UART1串口接收函數(shù)
在bsp_UART.h文件中宏定義UART1波特率、接收字節(jié)長(zhǎng)度,變量聲明以及UART1接收數(shù)據(jù)函數(shù)和發(fā)送數(shù)據(jù)函數(shù)聲明。
void UART1_Recv_Task(void)
{
//收到的數(shù)據(jù)原樣返回到串口上位機(jī)
UART_SendBytes(UART1,UART1_Rx_Buf, UART1_Rx_Cnt);
}
2.4 MM32F013x UART串口發(fā)送函數(shù)
在bsp_UART.c文件中編寫(xiě)MM32F013x UART1發(fā)送數(shù)據(jù)函數(shù),發(fā)送單字節(jié)數(shù)據(jù)和發(fā)送多字節(jié)數(shù)據(jù)函數(shù)分別如下所示:
/*******************************************************************************
* 函數(shù)名稱:void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
* 函數(shù)功能:UART發(fā)送單字節(jié)數(shù)據(jù)
* 輸入?yún)?shù):UARTx:UART1/UART2;dat:待發(fā)送的數(shù)據(jù)
* 返回?cái)?shù)值:無(wú)
*******************************************************************************/
void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
{
UART_SendData(UARTx, dat);
while(!UART_GetFlagStatus(UARTx, UART_FLAG_TXEPT));
}
/*******************************************************************************
* 函數(shù)名稱:void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
* 函數(shù)功能:UART發(fā)送多字節(jié)數(shù)據(jù)
* 輸入?yún)?shù):UARTx:UART1/UART2;buf:待發(fā)送的數(shù)據(jù);len:待發(fā)送數(shù)據(jù)的長(zhǎng)度
* 返回?cái)?shù)值:無(wú)
*******************************************************************************/
void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
{
while(len--)
{
UART_SendByte(UARTx,*buf++);
}
}
3、MM32F013x UART硬件 自適應(yīng)波特率的功能演示
在main.c文件的main函數(shù)里初始化bsp_UART1_Init(9200)串口初始化函數(shù),在while(1)大循環(huán)里調(diào)用測(cè)試UART1硬件自動(dòng)波特率收發(fā)數(shù)據(jù)函數(shù):UART1_Recv_Task();這里以檢測(cè)UART1通信首字節(jié)為4bit寬為例,模式為前一個(gè)邊沿為下降沿,后一個(gè)邊沿為上升沿。
MCU端設(shè)置非標(biāo)準(zhǔn)波特率9200,我們通過(guò)上位機(jī)以不同的波特率發(fā)送F8進(jìn)行硬件波特率自適應(yīng),自適應(yīng)完成后UART1就切換到對(duì)應(yīng)的波特率,MCU端收到數(shù)據(jù)后直接返回給上位機(jī)。

編輯:hfy
-
mcu
+關(guān)注
關(guān)注
147文章
18420瀏覽量
380691 -
uart
+關(guān)注
關(guān)注
22文章
1288瀏覽量
105821 -
串口通信
+關(guān)注
關(guān)注
34文章
1653瀏覽量
57457
發(fā)布評(píng)論請(qǐng)先 登錄
UART波特率計(jì)算及UART收發(fā)回顯實(shí)驗(yàn)
請(qǐng)問(wèn)如何使用低功耗 UART (LP UART) 波特率補(bǔ)償?
波特率是什么
靈動(dòng)微電子推出基于Arm Cortex-M0+內(nèi)核的MM32G0005系列MCU
靈動(dòng)微電子MM32MCU的主流型芯片選型
靈動(dòng)微電子推出全新超值型MM32F0050系列MCU
AN-891: ADuC703x系列LIN波特率計(jì)算
靈動(dòng)微電子MM32F5370 MCU產(chǎn)品特色

基于靈動(dòng)微電子MM32F013x 系列的UART硬件自適應(yīng)波特率
評(píng)論