前言
華大單片機HC32L110、HC32F003和HC32F005系列MCU有相同的UART通訊模塊,因此這三個系列UART模塊的使用程序也相同,本文將介紹通過中斷的方式進行UART的通訊。
數據格式
此UART模塊共有模式0~模式3四種通訊模式,其中模式0為半雙工同步通訊模式,此模式為同步模式不在我們今天的討論范圍之內。此模塊支持8bit、9bit的數據格式,因此異步通訊的數據格式為:1位起始位,8bit或9bit的數據位,1位結束位。模式1為8bit數據位的全雙工異步模式;模式2和模式3為9bit數據位的全雙工異步通訊模式。具體如下圖:
由上圖可知模式2和模式3中數據多了個TB8位。該位在多機通訊環境下使用時,當 TB8=1,表明所接收的是地址幀;當 TB8=0,表明所接收的是數據幀。當不需要多機通訊時,此位作為奇偶校驗位來使用。大家在使用UART模塊之前一定要注意確定自己要使用的模式,模式如果選錯會直接導致通訊數據出現錯誤。
波特率產生
異步通訊時波特率有兩種產生方式。Mode2為一種方式,Mode1和Mode3為一種方式。
Mode2:
當工作在 Mode2 時,波特率被固定在如下公式所得值:
其中,UARTx_SCON.DBAUD 表示雙倍波特率,Freq 為 PCLK 時鍾頻率。
Mode1/3:
當工作在 Mode1 或者 Mode3 時,波特率由 TIMER 的溢出時間決定。具體公式如下圖
所示:
其中,UARTx_SCON.DBAUD 表示雙倍波特率,Freq 為 PCLK 時鍾頻率,TM 為TIMER 計數值。注意,TIMER 必須配置為 16 位自動重載入模式,計數寄存器和重載寄存器都得寫入 TM 值。UART0對應使用的TIMER是TIM0,UART1對應使用的TIMER是TIM1。對於不同的PCLK產生的不同的波特率誤差是有差別的,大家在使用的時候最好先查下誤表,看下自己的配置所對應的誤差是否在可接受的范圍,如果誤差不可接受,更改到自己可以接受的誤差所對應的配置。不同配置波特率誤差表在本文最后。
發送數據
發送數據時,與 UARTx_SCON.REN 的值無關,將所發送數據寫入 UARTx_SBUF 寄存器中,數據就會從 TXD 移出(低位在先,高位在后)。
接收數據
接收數據時,需將 UARTx_SCON.REN 位置 1,並將 UARTx_ISR.RI 位清 0。開始接收 RXD 上數據(低位在先,高位在后),當接收完畢,可以從 UARTx_SBUF 寄存器讀出。
接收緩存
通用 UART(UART0/1)接收端有一個幀長度(8/9bits)的接收緩存,也就是說當一幀數據接收完畢后,接收緩存中的數據會被一直保持,直到下一幀數據的 Stop 位接收完畢后,接收緩存才會更新為新一幀數據。
發送緩存
通用 UART(UART0/1)發送端不支持發送緩存。如果在發送數據過程中,填寫UARTx_SBUF 寄存器,將會破壞當前正在發送數據。軟件應該避免這種操作。
相關寄存器
寄存器 | 位 | 符號 | 描述 | 說明 |
---|---|---|---|---|
UARTx_SBUF | 數據寄存器 | |||
7:0 | SBUF | 數據寄存器 | 發送數據時,待發送數據寫入該寄存器; 接收數據時,從該寄存器中讀出接收到的數據; 注意,對該寄存器讀的值實際是 RxBuffer 中的值,對該寄存器寫的值實際是寫到了 TXShifter 中。 |
|
UARTx_SCON | 控制寄存器 | |||
9 | DBAUD | 波特率倍率設置 | 0:單倍波特率; 1:雙倍波特率 |
|
7:6 | SM01 | 工作模式配置 | 00:mode0;01:mode1; 10:mode2;11:mode3 |
|
5 | SM2 | 多機通訊使能控制 | 0:關閉多機通信功能 1:使能多機通信功能 |
|
4 | REN | 接收使能 | mode0: 0:發送,1:接收 其他: 0:發送,1:接收/發送 |
|
3 | TB8 | 發送數據時待發送的TB8位 | ||
2 | RB8 | 接收數據時收到的RB8位 | ||
1 | TIEN | 發送完成中斷使能 | 0:禁止發送完成中斷 1:使能發送完成中斷 |
|
0 | RIEN | 接收完成中斷使能 | 0:禁止接收完成中斷 1:使能接收完成中斷 |
|
UARTx_ISR | 標志位寄存器 | |||
2 | FE | 接收幀錯誤標志位;硬件置位,軟件清零 | 1:FE中斷標志有效 0:FE中斷標志無效 |
|
1 | TI | 發送完成中斷標志位;硬件置位,軟件清零 | 1:TI中斷標志有效 0:TI中斷標志無效 |
|
0 | RI | 接收完成中斷標志位;硬件置位,軟件清零 | 1:RI中斷標志有效 0:RI中斷標志無效 |
|
UARTx_ICR | 中斷標志位清除寄存器 | |||
2 | FECLR | 清除接收幀錯誤標志位 | 寫0清零,寫1無效 | |
1 | TICLR | 清除發送完成中斷標志位 | 寫0清零,寫1無效 | |
0 | RICLR | 清除接收完成中斷標志位 | 寫0清零,寫1無效 |
相關程序
配置中斷相關內容
stcUartIrqCb.pfnRxIrqCb = RxIntCallback; //配置接收中斷回調函數
stcUartIrqCb.pfnTxIrqCb = NULL;
stcUartIrqCb.pfnRxErrIrqCb = ErrIntCallback; //配置錯誤中斷回調函數
stcConfig.pstcIrqCb = &stcUartIrqCb; //配置中斷服務函數
stcConfig.bTouchNvic = TRUE; //允許中斷
配置通訊相關內容
stcConfig.enRunMode = UartMode3; //測試項,更改此處來轉換4種模式測試
stcMulti.enMulti_mode = UartNormal; //測試項,更改此處來轉換多主機模式,mode2/3才有多主機模//式,此處配置為正常工作模式
stcConfig.pstcMultiMode = &stcMulti; //配置正常或多機工作模式
配置波特率
stcBaud.bDbaud = 0u; //雙倍波特率功能 stcBaud.u32Baud = 9600u; //更新波特率位置 stcBaud.u8Mode = UartMode3; //計算波特率需要模式參數 pclk = Clk_GetPClkFreq(); //獲得PCLK timer=Uart_SetBaudRate(UARTCH1,pclk,&stcBaud); //計算波特率所需TIMER值 stcBtConfig.enMD = BtMode2; //自動重裝載16位計數器/定時器 stcBtConfig.enCT = BtTimer; //定時模式 Bt_Init(TIM1, &stcBtConfig); //調用basetimer1設置函數產生波特率 Bt_ARRSet(TIM1,timer); //配置重載值 Bt_Cnt16Set(TIM1,timer); //配置計數值 Bt_Run(TIM1); //啟動定時
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
串口及接收中斷配置
Uart_Init(UARTCH1, &stcConfig); //串口1初始化 Uart_EnableIrq(UARTCH1,UartRxIrq); //允許串口1接收中斷 Uart_ClrStatus(UARTCH1,UartRxFull); //清串口1接收中斷標志 Uart_EnableFunc(UARTCH1,UartRx); //串口1接收中斷使能
- 1
- 2
- 3
- 4
接收中斷回調函數
void RxIntCallback(void) { u8RxData[1]=M0P_UART1->SBUF; //取出接收數據 u8RxFlg = 1; //接收標志置1 }
- 1
- 2
- 3
- 4
- 5
主邏輯
while(1)
{
CheckFlg = 0; //校驗出錯標志清零
if(u8RxFlg) //有接收數據進入,無數據跳過
{
u8RxFlg = 0; //接收標志清零
if(Uart_CheckEvenOrOdd(UARTCH1,Even,u8RxData[1])!=Ok) //檢查偶檢驗是否成功
{
CheckFlg = 1; //偶校驗出錯
}
else
{
Uart_SetTb8(UARTCH1,Even,u8RxData[0]); //根據數據設置TB8位
Uart_SendData(UARTCH1,u8RxData[0]); //發送數據
Uart_SetTb8(UARTCH1,Even,u8RxData[1]);
Uart_SendData(UARTCH1,u8RxData[1]);
}
}
}
UART模式對比
好多朋友在使用UART的時候因為沒有掌握4種模式的差別,所示調試的時候總是接收數據不對,走了很多彎路,現在就把不同種的差別總結一下。
半雙工同步模式
Mode0 波特率為固定的 PCLK 時鍾的 1/12。不常用。
全雙工異步模式
Mode1 數據位8位,不帶檢驗位,不帶多機通訊功能,波特率由TIMER產生,常用;
Mode2 數據位9位,帶檢驗位,帶多機通訊功能,波特率為與PCLK有關的固定值,不常用;
Mode3 數據位9位,帶檢驗位,帶多機通訊功能,波特率由TIMER產生,常用。
不同模式的總結可以參考下表: