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依赖于高频时钟