UART簡(jiǎn)介
UART是通用異步收發(fā)器,全稱(chēng)為Universal Asynchronous Receiver and Transmitter,屬于異步串口通信協(xié)議的一種,能夠靈活進(jìn)行全雙工數(shù)據(jù)交換。
MM32F0140的UART支持全雙工數(shù)據(jù)交換、同步單向通信、半雙工單線(xiàn)通信、多處理器之間的通信以及調(diào)制解調(diào)器(CTS/RTS)操作。
串行通信
串行通信是指使用一條數(shù)據(jù)線(xiàn),將數(shù)據(jù)一位一位地依次傳輸,每一位數(shù)據(jù)占據(jù)一個(gè)固定的時(shí)間長(zhǎng)度,只需要少數(shù)幾條線(xiàn)就可以在系統(tǒng)間交換信息。
串行通信按照數(shù)據(jù)傳輸方向分為:
● 單工通信
數(shù)據(jù)只能在一個(gè)方向上傳輸,通常采用兩線(xiàn)進(jìn)行通信,分別是:GND、TX(發(fā)送數(shù)據(jù)輸出引腳)或RX(接收數(shù)據(jù)輸入引腳),發(fā)送設(shè)備與接收設(shè)備共地將參考電壓調(diào)節(jié)一致,MCU做發(fā)送或接收。
● 半雙工通信
相當(dāng)于可切換方向的單工通信,在具體時(shí)刻,只允許數(shù)據(jù)在一個(gè)方向上傳輸,不能同時(shí)在兩個(gè)方向上傳輸。
● 全雙工通信
允許數(shù)據(jù)同時(shí)在兩個(gè)方向上傳輸,通常采用三線(xiàn),分別是:GND、TX、RX,接收設(shè)備與發(fā)送設(shè)備均為雙向通信設(shè)備,若通信雙方有一方需為另一方提供電源,則兩設(shè)備的VDD相連。
異步通信
異步通信過(guò)程中,接收器和發(fā)送器使用各自的時(shí)鐘,以一個(gè)字符為傳輸單位,通信中兩個(gè)字符間的時(shí)間間隔不固定,但在同一個(gè)字符中的兩個(gè)相鄰位間的時(shí)間間隔固定,每一個(gè)字符要用起始位和停止位作為字符開(kāi)始和結(jié)束的標(biāo)志。
UART功能
如圖1所示,Device1做發(fā)送器,Device2做接收器進(jìn)行通信,發(fā)送器對(duì)發(fā)送數(shù)據(jù)執(zhí)行“并->串”轉(zhuǎn)換,然后,數(shù)據(jù)從發(fā)送器的發(fā)送數(shù)據(jù)輸出引腳(TX)輸出,在傳輸線(xiàn)路上一位一位的傳輸?shù)浇邮掌鞯慕邮諗?shù)據(jù)輸入引腳(RX),接收器對(duì)接收到的數(shù)據(jù)進(jìn)行“串->并”轉(zhuǎn)換。
圖1. UART通信
數(shù)據(jù)傳輸
UART的數(shù)據(jù)傳輸如圖2所示,包含起始位、數(shù)據(jù)幀、奇偶校驗(yàn)位、停止位、空閑幀與斷開(kāi)幀。
● 起始位
在發(fā)送器被使能,且無(wú)數(shù)據(jù)發(fā)送時(shí),TX引腳處于高電平,若要進(jìn)行數(shù)據(jù)傳輸,發(fā)送器會(huì)在發(fā)送起始位拉低TX引腳,即將傳輸線(xiàn)從高電平拉到低電平并保持1個(gè)時(shí)鐘周期。
● 數(shù)據(jù)幀
數(shù)據(jù)幀包含需要傳輸?shù)臄?shù)據(jù),數(shù)據(jù)長(zhǎng)度由UART通用控制寄存器(UART_CCR)的CHAR位配置,通常可以設(shè)置為5 ~ 8位,若不使用奇偶校驗(yàn)位,數(shù)據(jù)幀長(zhǎng)度可為9位。
發(fā)送數(shù)據(jù)需要將UART全局控制寄存器(UART_GCR)的TXEN位置1,數(shù)據(jù)從UART發(fā)送數(shù)據(jù)寄存器(UART_TDR)寫(xiě)入,經(jīng)過(guò)一字節(jié)緩沖器緩沖,最后通過(guò)發(fā)送移位寄存器,以最低字節(jié)到最高字節(jié)的順序,串行在TX引腳上輸出。
接收數(shù)據(jù)需要將UART全局控制寄存器(UART_GCR)的RXEN位置1,讀UART接收數(shù)據(jù)寄存器(UART_RDR)可獲取接收到的數(shù)據(jù)并清零中斷狀態(tài)寄存器(UART_ISR)的RX_INTF(接收有效數(shù)據(jù)中斷標(biāo)志)。
● 奇偶校驗(yàn)位
檢驗(yàn)數(shù)據(jù)中1的總個(gè)數(shù)為奇或偶,判斷傳輸器件數(shù)據(jù)是否發(fā)生改變。奇偶校驗(yàn)可以通過(guò)UART通用控制寄存器(UART_CCR)的PEN位置1使能發(fā)送接收校驗(yàn),UART_CCR寄存器的PSEL位為1則數(shù)據(jù)偶校驗(yàn),PSEL位為0則數(shù)據(jù)奇校驗(yàn)。
奇校驗(yàn):若數(shù)據(jù)位中1的數(shù)目是偶數(shù),則校驗(yàn)位為1,如果1的數(shù)目是奇數(shù),校驗(yàn)位為0。
偶校驗(yàn):若數(shù)據(jù)位中1的數(shù)目是偶數(shù),則校驗(yàn)位為0,如果1的數(shù)目是奇數(shù),校驗(yàn)位為1。
● 停止位
停止位用1表示一幀的結(jié)束,可通過(guò)配置UART通用控制寄存器(UART_CCR)的SPB0位設(shè)置停止位位數(shù),位數(shù)可設(shè)置為0.5、1、1.5、2個(gè)停止位。
● 空閑幀
包括停止位在內(nèi),一個(gè)完全由1組成的完整數(shù)據(jù)幀,定義為一個(gè)空閑符號(hào),下一個(gè)數(shù)據(jù)幀的起始位跟在空閑符之后。
● 斷開(kāi)幀
包括停止位在內(nèi),一個(gè)完全由0組成的完整數(shù)據(jù)幀,定義為一個(gè)斷開(kāi)符號(hào),在斷開(kāi)幀結(jié)束時(shí),發(fā)送器再發(fā)送一個(gè)停止位1,使得下一幀的起始位能夠被識(shí)別到(產(chǎn)生下降沿被檢測(cè)到)。斷開(kāi)符號(hào)通過(guò)設(shè)置UART_CCR寄存器的BRK位進(jìn)行發(fā)送,若BKP位置1,在當(dāng)前數(shù)據(jù)發(fā)送完成后,將會(huì)發(fā)送一個(gè)斷開(kāi)符號(hào)到TX引腳上。
圖2. UART數(shù)據(jù)傳輸
波特率
波特率表示數(shù)據(jù)傳輸速率,波特率發(fā)生器產(chǎn)生時(shí)鐘,經(jīng)過(guò)發(fā)送器和接收器的使能位置位控制后,供給發(fā)送或接收使用。對(duì)于大多數(shù)串行通信,需要將發(fā)送和接收設(shè)備的波特率設(shè)置為相同的值,若波特率不同,則發(fā)送與接收數(shù)據(jù)的時(shí)序可能受到影響。波特率的計(jì)算公式如圖3所示,UART波特率寄存器(UART_BRR)存放UART分配器除法因子(UARTDIV)的整數(shù)部分,UART分?jǐn)?shù)波特率寄存器(UART_FRA)存放UARTDIV的小數(shù)部分。例如,若系統(tǒng)時(shí)鐘為48M,配置波特率為9600(每秒傳輸9600bit的數(shù)據(jù)),則(48000000 /9600) / 16的結(jié)果賦值到UART_BRR寄存器中,(48000000 / 9600) % 16的取余結(jié)果賦值到UART_FRA寄存器中。
圖3. UART的波特率公式
實(shí)驗(yàn)
本實(shí)驗(yàn)配置UART的基本發(fā)送與接收功能,配置時(shí)鐘速率為48MHz,波特率為9600,數(shù)據(jù)長(zhǎng)度為8位,不使用校驗(yàn)及自動(dòng)流控制,設(shè)置PA9為T(mén)X引腳,PA10為RX引腳。通過(guò)串口調(diào)試工具觀察數(shù)據(jù)的傳輸,發(fā)送數(shù)據(jù)與接收數(shù)據(jù)相同。
配置系統(tǒng)時(shí)鐘 clock_init()
如圖4所示,高速外部時(shí)鐘(HSE)的頻率范圍為4 ~ 24MHz,實(shí)驗(yàn)所使用的晶振為12M,要使系統(tǒng)時(shí)鐘為48MHz,則配置PLL輸出48MHz做系統(tǒng)時(shí)鐘,操作時(shí)鐘控制寄存器(RCC_CR)的HSEON位使能HSE,等待HSERDY位拉高(即HSE時(shí)鐘被釋放),設(shè)置PLL配置寄存器(RCC_PLLCFGR)中的PLLSRC位為1,并根據(jù)公式配置對(duì)應(yīng)參數(shù),PLL配置公式如圖5所示。配置閃存訪問(wèn)控制寄存器(FLASH_ACR)啟用閃存預(yù)取,配置時(shí)鐘配置寄存器(RCC_CFGR)設(shè)置分頻并配置PLL輸出做系統(tǒng)時(shí)鐘。
void clock_init() { /* Enable HSE. */ RCC->CR |= RCC_CR_HSEON_MASK; while ( RCC_CR_HSERDY_MASK != (RCC->CR RCC_CR_HSERDY_MASK ) ) /* Waiting HSE ready. */ { } /* F_clko = F_refin * N/(M * P), F_refin = 12M, 12*8/(1*2) = 48. */ RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC(1) /* HSE clock is used as PLL input clock. */ | RCC_PLLCFGR_PLLDN(7) /* N = DN + 1 = 7 + 1 = 8. */ | RCC_PLLCFGR_PLLDM(1) /* M = DM + 1 = 1 + 1 = 2. */ | RCC_PLLCFGR_PLLDP(0) /* P = DP + 1 = 0 + 1 = 1. */ | RCC_PLLCFGR_PLLLDS(1) /* PLL lock detector accuracy select. */ | RCC_PLLCFGR_PLLICTRL(3) /* 10uA. */ ; /* Enable PLL. */ RCC->CR |= RCC_CR_PLLON_MASK; while( 0u == ( RCC->CR RCC_CR_PLLRDY_MASK ) ) /* Waiting PLL ready. */ { } /* Enable the FLASH prefetch. */ RCC->AHB1ENR |= RCC_AHB1ENR_FLITFEN_MASK; /* Enable the access to FLASH. */ FLASH->ACR = FLASH_ACR_LATENCY(1u) /* Setup divider: 1 for 48Mhz. */ | FLASH_ACR_PRFTBE_MASK /* Enable flash prefetch. */ ; /* Setup the dividers for each bus. */ RCC->CFGR = RCC_CFGR_HPRE(0) /* Div=1 for AHB freq. */ | RCC_CFGR_PPRE1(0x0) /* Div=1 for APB1 freq. */ | RCC_CFGR_PPRE2(0x0) /* Div=1 for APB2 freq. */ | RCC_CFGR_MCO(7) /* Use PLL/2 as output. */ ; /* Switch the system clock source to PLL. */ RCC->CFGR = ( (RCC->CFGR ~RCC_CFGR_SW_MASK ) | RCC_CFGR_SW(2) ); /* Use PLL as SYSCLK. */ /* Wait till PLL is used as system clock source. */ while ( (RCC->CFGR RCC_CFGR_SWS_MASK ) != RCC_CFGR_SWS(2) ) { } }
圖4. MM32F0140部分時(shí)鐘樹(shù)
圖5. PLL配置公式
啟用UART外設(shè)時(shí)鐘 enable_clock()
UART1的UART1_TX與UART1_RX復(fù)用引腳為PA9與PA10,因此初始化GPIOA與UART1的外設(shè)時(shí)鐘,UART1在APB2上,GPIOA在AHB上。
void enable_clock() { /* Enable UART1 clock. */ RCC->APB2ENR |= RCC_APB2_PERIPH_UART1; /* Enable GPIOA clock. */ RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA; }
配置引腳 pin_init()
由于UART的TX與RX引腳配置為復(fù)用功能配置,如圖6所示,PA9, PA10的UART1_TX與UART1_RX均使用AF1,對(duì)端口復(fù)用功能高位寄存器(GPIO_AFRH)的端口9、端口10對(duì)應(yīng)位賦值。
void pin_init() { /* Setup PA9, PA10. */ GPIOA->CRH = ~GPIO_CRH_MODE9_MASK; GPIOA->CRH |= GPIO_PinMode_AF_PushPull; /* PA9 multiplexed push-pull output. */ GPIOA->AFRH = ~GPIO_AFRH_AFR_MASK; GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE9_SHIFT); /* Use AF1. */ GPIOA->CRH = ~GPIO_CRH_MODE10_MASK; GPIOA->CRH |= GPIO_PinMode_In_Floating; /* PA10 floating input. */ GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE10_SHIFT); /* Use AF1. */ }
圖6. 部分引腳復(fù)用表格
UART初始化 uart_init()
初始化UART需要配置:時(shí)鐘頻率、波特率、數(shù)據(jù)長(zhǎng)度、停止位、傳輸模式及是否使用校驗(yàn)。
如圖7所示,UART全局控制寄存器(UART_GCR)的TXEN位與RXEN位控制傳輸模式,兩位均置1表示傳輸模式為T(mén)X與RX,AUTOFLOWEN位控制是否使用自動(dòng)流控制,UARTEN位控制UART的使能。
如圖8所示,UART通用控制寄存器(UART_CCR)的SPB1、SPB0位控制停止位位數(shù),CHAR位控制數(shù)據(jù)寬度,PSEL位選擇采用奇校驗(yàn)還是偶校驗(yàn),PEN位控制校驗(yàn)使能;UART波特率寄存器(UART_BRR)與UART分?jǐn)?shù)波特率寄存器(UART_FRA)分別存儲(chǔ)UART分頻器除法因子的整數(shù)與小數(shù)。
void uart_init() { /* Clear the corresponding bit to be used. */ UART1->CCR = ~( UART_CCR_PEN_MASK | UART_CCR_PSEL_MASK | UART_CCR_SPB0_MASK | UART_CCR_SPB1_MASK | UART_CCR_CHAR_MASK ); UART1->GCR = ~( UART_GCR_AUTOFLOWEN_MASK | UART_GCR_RXEN_MASK | UART_GCR_TXEN_MASK ); /* WordLength. */ UART1->CCR |= UART_CCR_CHAR_MASK; /* XferMode. */ UART1->GCR |= (UART_XferMode_RxTx << UART_GCR_RXEN_SHIFT); /* Setup baudrate, BOARD_DEBUG_UART_FREQ = 48000000u, BOARD_DEBUG_UART_BAUDRATE = 9600u. */ UART1->BRR = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) / 16u; UART1->FRA = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) % 16u; /* Enable UART1. */ UART1->GCR |= UART_GCR_UARTEN_MASK; }
圖7. MM32F0140 UART_GCR寄存器
圖8. MM32F0140 UART_CCR寄存器部分位
UART發(fā)送數(shù)據(jù) uart_putchar()
通過(guò)讀取UART當(dāng)前狀態(tài)寄存器(UART_CSR)獲取當(dāng)前狀態(tài),當(dāng)發(fā)送緩沖區(qū)為空時(shí),可進(jìn)行數(shù)據(jù)發(fā)送,將發(fā)送數(shù)據(jù)傳入U(xiǎn)ART發(fā)送數(shù)據(jù)寄存器(UART_TDR),定義發(fā)送數(shù)據(jù)函數(shù)uart_putchar(),變量“c”為需要發(fā)送的數(shù)據(jù)。
void uart_putchar(uint8_t c) { while ( 0u == ( UART_STATUS_TX_EMPTY (UART1->CSR) ) ) /* Waiting tx buffer empty. */ {} UART1->TDR = (uint8_t)c; }
UART接收數(shù)據(jù) uart_getchar()
通過(guò)讀取UART當(dāng)前狀態(tài)寄存器(UART_CSR)獲取當(dāng)前狀態(tài),當(dāng)接收緩沖接收了一個(gè)完整字節(jié)的數(shù)據(jù)時(shí),可讀取UART接收數(shù)據(jù)寄存器(UART_RDR)獲取接收數(shù)據(jù),定義接收數(shù)據(jù)函數(shù)uart_getchar(),該函數(shù)返回接收的數(shù)據(jù)。
uint8_t uart_getchar(void) { while ( 0u == ( UART_STATUS_RX_DONE (UART1->CSR) ) ) /* Waiting rx buffer receives a complete byte of data. */ {} return (uint8_t)(UART1->RDR 0xff); }
UART輸出字符串 uart_putbuffer()
使用UART發(fā)送函數(shù)編寫(xiě)發(fā)送字符串函數(shù)。
void uart_putbuffer(uint8_t *str) { while ((*str) != '?') { uart_putchar(*str); str++; } }
main()函數(shù)
main()函數(shù)結(jié)合上述操作,不斷循環(huán)接收數(shù)據(jù)函數(shù)uart_getchar()與發(fā)送數(shù)據(jù)函數(shù)uart_putchar(),將接收到的數(shù)據(jù)發(fā)送出去,實(shí)驗(yàn)現(xiàn)象如圖9所示,程序運(yùn)行后串口輸出"uart_basic example.",通過(guò)串口調(diào)試工具輸入"mindmotion",UART輸出"mindmotion",輸入數(shù)據(jù)與輸出數(shù)據(jù)相同。
int main(void) { uint8_t c; clock_init(); enable_clock(); pin_init(); uart_init(); uart_putbuffer((uint8_t *)"rnuart_basic example.rn"); while (1) { c = uart_getchar(); uart_putchar(c); } }
圖9. 實(shí)驗(yàn)現(xiàn)象
來(lái)源:靈動(dòng)MM32MCU
-
收發(fā)器
+關(guān)注
關(guān)注
10文章
3438瀏覽量
106068 -
uart
+關(guān)注
關(guān)注
22文章
1240瀏覽量
101491 -
串行通信
+關(guān)注
關(guān)注
4文章
576瀏覽量
35456 -
GND
+關(guān)注
關(guān)注
2文章
539瀏覽量
38786
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論