CH57x 的串口跟沁恆其他的MCU串口外設使用基本一致, 收發分別有8個字節的FIFO,支持fifo閾值中斷,以及超時中斷,
支持的波特率
CH577/578/579 波特率計算與誤差
<待編輯>
CH571/573/581/582/583 波特率計算與誤差
<待編輯>
CH57X/58x 系列芯片串口波特率計算在線工具
<待編輯>
UART中斷接收處理:
uint16_t user_rx_buffer_length_mask = 1024-1;
uint16_t user_rx_buffer_write_index = 0;
uint8_t uart_rx_buffer[1024];
//Not every uart reception will end with a UART_II_RECV_TOUT
//UART_II_RECV_TOUT can only be triggered when R8_UARTx_RFC is not 0
//Here we cannot rely on UART_II_RECV_TOUT as the end of a uart reception
/*** Keep at least 1 byte in the RX fifo and UART_II_RECV_TOUT will be triggered at the end of every reception .***/
void UART3_IRQHandler(void){
switch( UART3_GetITFlag() ){
case UART_II_LINE_STAT: // 線路狀態錯誤
UART3_GetLinSTA();
break;
case UART_II_RECV_RDY: // 數據達到設置觸發點 ,這里可以留一個在接收fifo里面,保證每次都能產生接收超時
while( R8_UART3_RFC > 1) { // 這個方式必須保證uart的接收觸發中斷是大於1字節的
uart_rx_buffer[user_rx_buffer_write_index & user_rx_buffer_length_mask] = R8_UART3_RBR;
user_rx_buffer_write_index += 1;
}
break;
case UART_II_RECV_TOUT: // 接收超時,暫時一幀數據接收完成
//for(uint8_t i=0;i < R8_UART3_RFC;i++) //There is an issue here
while(0 != R8_UART3_RFC) {
uart_rx_buffer[user_rx_buffer_write_index & user_rx_buffer_length_mask] = R8_UART3_RBR;
user_rx_buffer_write_index += 1;
}
break;
case UART_II_THR_EMPTY: // 發送緩存區空,可繼續發送
break;
case UART_II_MODEM_CHG: // 只支持串口0
break;
default:
break;
}
}
UART 查詢發送
//tx process
//本查詢函數需要扔到主循環不斷調用
while(R8_UART1_TFC < UART_FIFO_SIZE){
//判斷發送軟件緩沖區,是否空,如果不空,就一個一個讀出來,填到硬件fifo里
if((user_tx_buffer_write_index - user_tx_buffer_read_index )& user_tx_buffer_length_mask) {
//把軟件緩沖區的數據填到uart的硬件發送fifo里
R8_UART1_THR = uart_tx_buffer[user_tx_buffer_read_index & user_tx_buffer_length_mask] ;
user_tx_buffer_read_index += 1;
}else{
break;
}
}
UART 中斷發送
//開始發送,這里,我們需要先向串口的發送fifo里面寫入數據,然后串口的發送fifo空的時候才會報中斷上來,接下來我們在中斷服務程序里面處理就好了
void uart_start_send(void) {
//這里涉及到中斷中修改標志位,我們關中斷后進行查標志位
__disable_irq();
if(false == uart1_tx_on_going) {
__enable_irq();
//由於寫fifo的操作非常快,我們這里直接while循環即可
while(R8_UART1_TFC < UART_FIFO_SIZE){
//發送緩沖區是否有數據,這里我們用軟件實現了一個緩沖區,如果有數據,就把數據取出來放到uart的fifo里
if((user_rx_buffer_write_index - user_rx_buffer_read_index )& user_rx_buffer_length_mask) {
R8_UART1_THR = uart_rx_buffer[user_rx_buffer_read_index & user_rx_buffer_length_mask] ;
user_rx_buffer_read_index += 1;
uart1_tx_on_going = true;
}else{
break;
}
}
}else{
__enable_irq();
}
}
//中斷服務程序中的處理,這里主要關注 UART_II_THR_EMPTY 里面的處理
void UART1_IRQHandler(void) {
UINT8 i;
//GPIOA_SetBits(GPIO_Pin_0);
//GPIOA_ResetBits(GPIO_Pin_0);
switch( UART1_GetITFlag() ) {
case UART_II_LINE_STAT: // 線路狀態錯誤
UART1_GetLinSTA();
break;
case UART_II_RECV_RDY: // 數據達到設置觸發點
case UART_II_RECV_TOUT: // 接收超時,暫時一幀數據接收完成
while(0 != R8_UART1_RFC) {
uart_rx_buffer[user_rx_buffer_write_index & user_rx_buffer_length_mask] = R8_UART1_RBR;
user_rx_buffer_write_index += 1;
}
break;
case UART_II_THR_EMPTY: // 發送緩存區空,可繼續發送
while(R8_UART1_TFC < UART_FIFO_SIZE){
if((user_tx_buffer_write_index - user_tx_buffer_read_index )& user_tx_buffer_length_mask) {
R8_UART1_THR = uart_tx_buffer[user_tx_buffer_read_index & user_tx_buffer_length_mask] ;
user_tx_buffer_read_index += 1;
}else{
uart1_tx_on_going = false;
break;
}
}
break;
case UART_II_MODEM_CHG: // 只支持串口0
break;
default:
break;
}
}
BLE工程中UART收發處理:
CH57x的ble協議棧是查詢方式實現的,實際應用中,中斷在微觀上會打斷BLE的運行,所以能少用中斷就少用中斷,在中斷張能少占用時間就少占用一些,
但是而ch57x的uart 又沒有dma,只有有8個直接的fifo,所以,
在沒有串口流控(CTS RTS)的情況下,建議uart的接收使用中斷方式,而uart發送使用查詢方式
Q&A
1.休眠情況下UART能收發數據嗎
UART依賴於高頻時鍾