TM4C123GH6PM 總共有 8 組 UART . 這次是使用 UART0 , 對應的接腳是 PA0 和 PA1 , 在 Launchpad 上是已經透過 USB 接到電腦了. 所以不需要另外接線 . LEDs 部分 還是直接使用 Launchpad 上的 PF1, PF2 和 PF3 . System Clock 部分還是使用 PLL 設定最高時脈 80MHZ .
這次會需要使用超級終端機來與 Launchpad 互動. 如果你的作業系統是 XP , 則本身就已經有超級終端機了, 如果不是 , 那也可以使用 Putty 這個軟體 .
在使用 UART 之前 , 還是先來了解一下一些相關的暫存器 . 還記得 TM4C123GH6PM 預設所有的 I/O 的 Clock 都是關閉的 , 所以第一部要啟動 UART0 的 Clock 以及其對應的 GPIO Pin, 也就是 PA0 和 PA1 . 先來看一下 RCGC1 .
由上圖中可以看出, UART0 是 bit0, 也就是將 RCGC1 暫存器的 bit0 寫入 1 , 就啟動了 UART0 的 Clock 了 . 還有一點要說明的是也可以使用另外一個暫存器 RCGCUART .
在此暫存器中 , R7 代表 UART7, R6 代表 UART6, R5 代表 UART5, 以此類推 R0 代表 UART0, 所以如果是使用此暫存器 , 也是將 bit0 寫入 1 . 這兩個暫存器的差別只是 RCGC1 是為了與以前的 MCU 相容 , 以方便程式移植 . 如果沒有這方面的考量 , Data Sheet 是建議使用 RCGCUART 這個暫存器 . 然而並非只有UART是如此 , 其他所有的 I/O interface 都是一樣的 , 例如 GPIO, TIMER, I2C, CAN, SSI(SPI), ADC.....等 .
UARTCTL 暫存器是一個控制暫存器 , 我們這次只使用 bit0 , Enable 和 Disable UART. 不過記得設定 UART (例如 Baudrate) 之前要把它Disable , 設定好了再 Enable 它 .
UARTIBRD 和 UARTFBRD 這兩個暫存器是設定 Baudrate 的 . UARTIBRD 是整數部分 . UARTFBRD 是分數部分 . 計算公式如下 :
BRD = BRDI + BRDF = UARTSysClk / (ClkDiv * Baud Rate)
UARTFBRD[DIVFRAC] = integer(BRDF * 64 + 0.5)
BRDI 是整數部分 , BRDF 是分數部分 . UARTSysClk 是連接到UART的系統時脈 , ClkDiv 為 16 或者為 8 . 這部分可在 UARTCTL 暫存器的 bit 5 (HSE) 中設定 , 如果 HSE 這個 bit Clear (0), 則 ClkDiv 為 16 , 如果 HSE 這個 bit Set (1), 則 ClkDiv 為 8 . 在這裡我們使用 16 . 第二個算式是取分數的部分 , 舉例來說 : 如果系統時脈為 80MHZ, BaudRate 為 115200 bits/Sec.
80MHZ / (16*115200) = 43.4027 (IBRD = 43)
0.4027 * 64 + 0.5 = 26 (FBRD = 26)
由以上計算結果就可以設定 UARTIBRD 和 UARTFBRD 這兩個暫存器了 :
UART0_IBRD_R = 43;
UART0_FBRD_R = 26;
UARTLCRH 暫存器是設定資料長度 , Parity, Stop bit 等等. 暫存器的內容如下 :
WLEN ( bit 6 和 bit 5 ) 設置 0x0 是 5 bits , 0x1 是 6 bits , 0x2 是 7 bits , 0x3 是 8 bits . FEN ( bit 6 )是設置是否啟用 FIFO buffer . STP2 ( bit 3 ) 是設置 Stop bit . ' 0 ' 是 One Stop bit , ' 1 ' 是 Two Stop bit . 一般的應用大概會是 8 bits 資料長度 , No Parity , One Stop bit , 再加上起用 FIFO . 也就是 0x0000.0070 .
到了這裡我們來看看 UART0 初始化的程式 :
void UART0_Init(void)
{
SYSCTL_RCGCUART_R |= 0x00000001;
SYSCTL_RCGCGPIO_R |= 0x00000001;
UART0_CTL_R &= ~0x00000001;
UART0_IBRD_R = 43;
UART0_FBRD_R = 26;
UART0_LCRH_R = 0x00000070;
UART0_CTL_R |= 0x00000001;
GPIO_PORTA_AFSEL_R |= 0x03;
GPIO_PORTA_DEN_R |= 0x03;
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)+0x00000011;
GPIO_PORTA_AMSEL_R &= ~0x03;
}
除了設定 UART0 之外還設定了 PORTA , 這是因為 PA0 和 PA1 的替代功能是 UART0 , 所以也必須設定啟用這兩個 PINs , 另外也看到了設置替代功能的暫存器也做了些設定 . 這部分有一點複雜 , 這裡稍微說明一下 , 先看下表 ( 這裡只截取一部分 , 完整的表格可以再 Data Sheet GPIO 中找到 ) :
先看 UART0 Rx 和 UART0 Tx 分別對應到 PA0 和 PA1 , 再看對應到上面的數字是 1 . 這就是我們要寫入暫存器 PCTL 的數字 , 那寫在 PCTL 的哪個位置呢 ? 我們再來回顧一下 PCTL 暫存器 :
從 PMC7 ~ PMC0 分別代表著 GPIO Pin 7 ~ GPIO Pin 0. 那我們使用的是 PA0 和 PA1 , 所以就是寫入 PMC1 和 PMC0 這兩個位置 . 那寫入什麼值呢 ? 剛剛提到就是UART0 Rx 和 UART0 Tx 對應到上面的數字 1 . 所以就是 GPIO_PORTA_PCTL_R = 0x0000.0011 , 這樣是不是很清楚了呢 ? 再舉個例子 : 假設我們要使用 CAN1 , 從表中可以看出 GPIO 的部分對應的也是 PA0 和 PA1 , CAN1Rx 和 CAN1Tx 對應到上面的數字是 8 . 所以就是 GPIO_PORTA_PCTL_R = 0x0000.0088 . 或許你想問那 "(GPIO_PORTA_PCTL_R&0xFFFFFF00) " 是做什麼 ? 其實很簡單就是 Friendly Code . 不去動到其他的 bits 並且先把 PMC1 和 PMC0 清為 0 .
UART0 到了這裡算是初始化完成 . 那我要傳送和接收資料怎辦 ? UART 有一個 UART Flag 暫存器 , 我們可以判讀這個暫存器的狀態來做傳送或接收資料 . 以下是 UARTFR 暫存器的內容 :
在這裡我們會用到 TXFF 和 RXFE , TXFF 為 0 時 FIFO 未滿 , 為 1 時 FIFO 已滿 , RXFE 為 0 時 FIFO 不是空的 , 為 1 時 FIFO 是空的 . 根據此特性 , 我們就可以做接收和傳送了. ( 此處採用等待的方式. 比較好的方式是用中斷的方法, 這部分等以後寫到中斷時再說明)
void UartWrite(char *pstr){
while(*pstr != 0){
Transmitter(*pstr++);
}
}
unsigned char Receiver(void){
while((UART0_FR_R&0x10) != 0){};
return UART0_DR_R&0xFF;
}
void Transmitter(unsigned char data){
while((UART0_FR_R&0x20) != 0){};
UART0_DR_R = data;
}
UART 部分到這裡總算完成了 , 那接下來就來看一下完整的程式吧 :
#include <stdint.h>
#include "inc/tm4c123gh6pm.h"
void PLL_Init(void);
void UART0_Init(void);
void PortF_Init(void);
void UartWrite(char *pstr);
unsigned char Receiver(void);
void Transmitter(unsigned char data);
int main(void){
unsigned char command;
PLL_Init();
UART0_Init();
PortF_Init();
UartWrite("This program control Leds through UART.\r\n");
while(1)
{
UartWrite("Enter Command \'0\',\'1\',\'2\',\'3\':");
command = Receiver();
Transmitter(command);
UartWrite("\r\n");
switch (command){
case '0':
GPIO_PORTF_DATA_R = 0x00;
break;
case '1':
GPIO_PORTF_DATA_R = 0x02;
break;
case '2':
GPIO_PORTF_DATA_R = 0x04;
break;
case '3':
GPIO_PORTF_DATA_R = 0x08;
break;
default:
UartWrite("Wrong command ! \r\n");
break;
}
}
}
void UART0_Init(void)
{
SYSCTL_RCGCUART_R |= 0x00000001;
SYSCTL_RCGCGPIO_R |= 0x00000001;
UART0_CTL_R &= ~0x00000001;
UART0_IBRD_R = 43;
UART0_FBRD_R = 26;
UART0_LCRH_R = 0x00000070;
UART0_CTL_R |= 0x00000001;
GPIO_PORTA_AFSEL_R |= 0x03;
GPIO_PORTA_DEN_R |= 0x03;
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)+0x00000011;
GPIO_PORTA_AMSEL_R &= ~0x03;
}
void PLL_Init(void)
{
SYSCTL_RCC2_R |= 0x80000000;
SYSCTL_RCC2_R |= 0x00000800;
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) + 0x00000540;
SYSCTL_RCC2_R &= ~0x00000070;
SYSCTL_RCC2_R &= ~0x00002000;
SYSCTL_RCC2_R |= 0x40000000;
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) + (4<<22);
while((SYSCTL_RIS_R&0x00000040)==0){};
SYSCTL_RCC2_R &= ~0x00000800;
}
void PortF_Init(void)
{
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000020;
delay = SYSCTL_RCGC2_R;
GPIO_PORTF_AMSEL_R &= ~0x0E;
GPIO_PORTF_PCTL_R &= ~0x0000FFF0;
GPIO_PORTF_DIR_R |= 0x0E;
GPIO_PORTF_AFSEL_R &= ~0x0E;
GPIO_PORTF_DEN_R |= 0x0E;
}
void UartWrite(char *pstr){
while(*pstr != 0) {
Transmitter(*pstr++);
}
}
unsigned char Receiver(void){
while((UART0_FR_R&0x10) != 0){};
return UART0_DR_R&0xFF;
}
void Transmitter(unsigned char data){
while((UART0_FR_R&0x20) != 0){};
UART0_DR_R = data;
}
了解了 UART 的設定後 , 整個程式看起來就簡單多了 . 先初始化 PLL , 80MHZ , 再初始化 UART0 , 最後再初始化 PORTF . 然後就等待輸入 0 ~ 3 , 再用 Switch - Case 來判斷輸入的值並點亮相對應的 LED . 好了 Compiler and Download !
接著 , 我們先查詢一下 Launchpad 連接的 COM Port 是哪一個 . 打開裝置管理員 , 點擊連接埠(COM 和 LPT) , 找到 Stellaris Virtual Serial Port(COMx) 如下圖 : (我的是 COM5)
然後打開 putty , 先點選 Serial , 在 Serial line 輸入你的 COM number , 我的例子是 COM5 , Speed 的地方輸入 115200 . 在 Saved Sessions 的地方可以輸入一個名稱 , 例如 TM4C123GXL Launchpad , 按下 Save . 以後可以直接點選此名稱再按 Load 就好了 .
接著點選左下角的 Serial , 把右邊的 Flow control 選 None . 然後按下 Open , 就開啟 Putty 了 .
接下來按一下 Launchpad 上的 Reset 鍵 . 在Putty 的視窗上出現了 "Enter Command 0,1,2,3:" 此時 Launchpad 正等待你的輸入 , (如下圖)
先輸入 1 , 觀察 Launchpad 上紅色 LED 點亮了 . 再輸入 2 , 點亮了藍色 LED 燈 , 輸入 3 點亮綠色 LED 燈 , 輸入 0 看看, 嗯 , LED 燈全滅了 . 輸入 4 看看 , Launchpad 回應 Wrong command ! 要我們重新輸入 . 不錯 ! 我們成功了 !
Embedded Systems: Introduction to ARM® Cortex™-M Microcontrollers - Jonathan Valvano
Getting Started with the Tiva™ TM4C123G LaunchPad Workshop
TM4C123GH6PM DATA SHEET
Embedded Systems Shape The World



















