我們以KEA64系列來學習UART 。這是最常用的外設之一了,必須要掌握的。
簡介
KEA64有3個串口:UART0, UART1, UART2, 時鐘來自Bus Clock。
幾個重要的參數:
- 起始位(固定1位)
- 波特率(300 - 1500000bps)
- 數據位 (5 - 8位,低位數據先發送)
- 校驗位 (None、奇校驗或偶校驗)
- 停止位 (1、1.5 或2)
- 流控(不常用)
比較常見的配置之一:
- 波特率(9600bps)
- 數據位 (8位)
- 校驗位 (None)
- 停止位 (1)
- 流控(無)
則發送一個字節,需要發送的有:起始位1位、數據位8位、停止位1位,總共10位,總共時間是 10 bit * (1/9600) s/bit ≈ 1.04 ms, 串口波形如下(TTL電平):
從上圖可以看到,空閒時,UART的TX都是高電平(約2.2V),起始位是低電平,數據位(高電平表示1,低電平表示0,低位先發送,對應波形是b10101010,反過來就是b01010101,即最終發送的數據是0x55),停止位是高電平。更多的串口解讀,可以參考:深入剖析串口通信數據格式
串口初始化的過程發下:
- 使能串口時鐘
- 設置停止位
- 設置波特率
- 設置校驗位和數據位
- 允許發送或 接收
- 允許中斷(可選)
- 使能串口管腳
串口發送過程(非中斷)如下:
- 等待發送緩衝區爲空
- 清除TDRE 標誌位
- 加載數據到串口數據寄存器發送
發送程序
#include "derivative.h" /* include peripheral declarations SSKEAZN64M2 */
void Clk_Init(void);
void Enable_Interrupt(uint8_t vector_number);
void init_PIT(void);
void UART_Init(void);
void UART_Transmit_Char(char send);
void UART_Transmit_String(char data_string[]);
uint8_t timer1sFlag = 0;
int main(void)
{
Clk_Init();
init_PIT();
init_GPIO();
UART_Init();
Enable_Interrupt(PIT_CH1_IRQn);
for(;;)
{
if (timer1sFlag)
{
timer1sFlag = 0;
UART_Transmit_Char(0x55);
}
}
return 0;
}
/***********************************************************************************************
*
* @brief CLK_Init - Initialize Core Clock to 40MHz, Bus Clock to 20MHz
* @param none
* @return none
*
************************************************************************************************/
void Clk_Init(void)
{
ICS_C1|= ICS_C1_IRCLKEN_MASK; /* Enable the internal reference clock*/
ICS_C3 = 0x50; /* Reference clock frequency = 31.25 kHz*/
while(!(ICS_S & ICS_S_LOCK_MASK)); /* Wait for PLL lock, now running at 40 MHz (1024*39.0625 kHz) */
ICS_C2 |= ICS_C2_BDIV(1) ; /* BDIV=b001, Bus clock = 20 MHz*/
ICS_S |= ICS_S_LOCK_MASK ; /* Clear Loss of lock sticky bit */
}
/***********************************************************************************************
*
* @brief init_PIT - 設定定時器週期溢出時間1s, 啓動中斷
* @param none
* @return none
*
************************************************************************************************/
void init_PIT(void)
{
SIM_SCGC |= SIM_SCGC_PIT_MASK; /* Enable bus clock to PIT module */
PIT_MCR = 0x0; /* Turn on PIT module, Freeze disabled */
PIT_LDVAL1 = 20000000 - 1; /* PIT1: Load value to count 20M bus clocks */
PIT_TCTRL1 |= PIT_TCTRL_TIE_MASK; /* Enable interrupt */
PIT_TCTRL1 |= PIT_TCTRL_TEN_MASK; /* PIT1: Start timer */
PIT_TCTRL1 |= PIT_TCTRL_TEN_MASK;
}
/***********************************************************************************************
*
* @brief Enable_Interrupt(uint8_t vector_number). Enable interrupts from desired module.
* @param Module interrupt number from the interrupts vector table
* @return none
*
************************************************************************************************/
void Enable_Interrupt(uint8_t vector_number)
{
NVIC_ClearPendingIRQ(vector_number); /* Clear pending interrupt register */
NVIC_EnableIRQ(vector_number); /* Enable required Interrupt */
}
/***********************************************************************************************
*
* @brief PIT_CH1_IRQHandler - PIT CH1中斷程序
* @param none
* @return none
*
************************************************************************************************/
void PIT_CH1_IRQHandler (void)
{
PIT_TFLG1 |= PIT_TFLG_TIF_MASK; /* Clear PIT1 flag */
timer1sFlag = 1;
}
void UART_Init(void)
{
SIM_SCGC |= SIM_SCGC_UART0_MASK; /* Enable bus clock in UART0 */
UART0_BDH = 0; /* One stop bit*/
UART0_BDL = 130; /* For 9600 baud: baud divisor=20M/9600/16 = ~130 */
UART0_C1 = 0; /* No parity enable,8-bit format*/
UART0_C2 |= UART_C2_TE_MASK; /* Enable Transmitter*/
UART0_C2 |= UART_C2_RE_MASK; /* Enable Receiver*/
//UART0_C2 |= UART_C2_RIE_MASK; /* Enable Receiver interrupts*/
SIM_PINSEL |= SIM_PINSEL_UART0PS_MASK; /* UART0_RX and UART0_TX are mapped on PTA2 and PTA3 */
}
/* Function to Transmit single Char */
void UART_Transmit_Char(char send)
{
while((UART0_S1 & UART_S1_TDRE_MASK)==0); /* Wait for transmit buffer to be empty */
(void)UART0_S1; /* Read UART0_S1 register to clear TDRE */
UART0_D = send; /* Send data */
}
/* Function to Transmit whole string */
void UART_Transmit_String(char data_string[])
{
int i = 0;
while(data_string[i] != '\0')
{
/* Send chars one at a time */
transmit_char(data_string[i]);
i++;
}
}